4
%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
4
%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
6
6
%% The contents of this file are subject to the Erlang Public License,
7
7
%% Version 1.1, (the "License"); you may not use this file except in
8
8
%% compliance with the License. You should have received a copy of the
9
9
%% Erlang Public License along with this software. If not, it can be
10
10
%% retrieved online at http://www.erlang.org/.
12
12
%% Software distributed under the License is distributed on an "AS IS"
13
13
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
14
14
%% the License for the specific language governing rights and limitations
15
15
%% under the License.
19
19
-module(ets_SUITE).
22
-export([new/1,default/1,setbag/1,badnew/1,verybadnew/1,named/1,keypos2/1,
21
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
22
init_per_group/2,end_per_group/2]).
23
-export([default/1,setbag/1,badnew/1,verybadnew/1,named/1,keypos2/1,
23
24
privacy/1,privacy_owner/2]).
24
-export([insert/1,empty/1,badinsert/1]).
25
-export([lookup/1,time_lookup/1,badlookup/1,lookup_order/1]).
26
-export([delete/1,delete_elem/1,delete_tab/1,delete_large_tab/1,
25
-export([empty/1,badinsert/1]).
26
-export([time_lookup/1,badlookup/1,lookup_order/1]).
27
-export([delete_elem/1,delete_tab/1,delete_large_tab/1,
27
28
delete_large_named_table/1,
28
29
evil_delete/1,baddelete/1,match_delete/1,table_leak/1]).
29
30
-export([match_delete3/1]).
30
31
-export([firstnext/1,firstnext_concurrent/1]).
32
-export([match/1, match1/1, match2/1, match_object/1, match_object2/1]).
33
-export([misc/1, dups/1, misc1/1, safe_fixtable/1, info/1, tab2list/1]).
34
-export([files/1, tab2file/1, tab2file2/1, tab2file3/1, tabfile_ext1/1,
33
-export([ match1/1, match2/1, match_object/1, match_object2/1]).
34
-export([ dups/1, misc1/1, safe_fixtable/1, info/1, tab2list/1]).
35
-export([ tab2file/1, tab2file2/1, tabfile_ext1/1,
35
36
tabfile_ext2/1, tabfile_ext3/1, tabfile_ext4/1]).
36
-export([heavy/1, heavy_lookup/1, heavy_lookup_element/1]).
37
-export([lookup_element/1, lookup_element_mult/1]).
37
-export([ heavy_lookup/1, heavy_lookup_element/1, heavy_concurrent/1]).
38
-export([ lookup_element_mult/1]).
39
40
-export([foldl_ordered/1, foldr_ordered/1, foldl/1, foldr/1, fold_empty/1]).
40
41
-export([t_delete_object/1, t_init_table/1, t_whitebox/1,
41
42
t_delete_all_objects/1, t_insert_list/1, t_test_ms/1,
59
60
-export([otp_7665/1]).
60
61
-export([meta_wb/1]).
61
62
-export([grow_shrink/1, grow_pseudo_deleted/1, shrink_pseudo_deleted/1]).
63
64
meta_lookup_unnamed_read/1, meta_lookup_unnamed_write/1,
64
65
meta_lookup_named_read/1, meta_lookup_named_write/1,
65
66
meta_newdel_unnamed/1, meta_newdel_named/1]).
66
-export([smp_insert/1, smp_fixed_delete/1, smp_unfix_fix/1, smp_select_delete/1, otp_8166/1]).
67
-export([smp_insert/1, smp_fixed_delete/1, smp_unfix_fix/1, smp_select_delete/1,
68
otp_8166/1, otp_8732/1]).
67
69
-export([exit_large_table_owner/1,
68
70
exit_many_large_table_owner/1,
69
71
exit_many_tables_owner/1,
70
72
exit_many_many_tables_owner/1]).
71
73
-export([write_concurrency/1, heir/1, give_away/1, setopts/1]).
72
-export([bad_table/1]).
74
-export([bad_table/1, types/1]).
74
-export([init_per_testcase/2, fin_per_testcase/2, end_per_suite/1]).
76
-export([init_per_testcase/2, end_per_testcase/2]).
75
77
%% Convenience for manual testing
76
78
-export([random_test/0]).
79
81
-export([dont_make_worse_sub/0, make_better_sub1/0, make_better_sub2/0]).
80
-export([t_repair_continuation_do/1, default_do/1, t_bucket_disappears_do/1,
82
-export([t_repair_continuation_do/1, t_bucket_disappears_do/1,
81
83
select_fail_do/1, whitebox_1/1, whitebox_2/1, t_delete_all_objects_do/1,
82
84
t_delete_object_do/1, t_init_table_do/1, t_insert_list_do/1,
83
85
update_element_opts/1, update_element_opts/4, update_element/4, update_element_do/4,
103
112
Dog=test_server:timetrap(test_server:minutes(20)),
104
113
[{watchdog, Dog}, {test_case, Case} | Config].
106
fin_per_testcase(_Func, Config) ->
115
end_per_testcase(_Func, Config) ->
107
116
Dog=?config(watchdog, Config),
108
117
wait_for_test_procs(true),
109
118
test_server:timetrap_cancel(Dog).
121
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
123
suite() -> [{ct_hooks,[ts_install_cth]}].
126
[{group, new}, {group, insert}, {group, lookup},
127
{group, delete}, firstnext, firstnext_concurrent, slot,
128
{group, match}, t_match_spec_run,
129
{group, lookup_element}, {group, misc}, {group, files},
130
{group, heavy}, ordered, ordered_match,
131
interface_equality, fixtable_next, fixtable_insert,
132
rename, rename_unnamed, evil_rename, update_element,
133
update_counter, evil_update_counter, partly_bound,
134
match_heavy, {group, fold}, member, t_delete_object,
135
t_init_table, t_whitebox, t_delete_all_objects,
136
t_insert_list, t_test_ms, t_select_delete, t_ets_dets,
137
memory, t_select_reverse, t_bucket_disappears,
138
select_fail, t_insert_new, t_repair_continuation,
139
otp_5340, otp_6338, otp_6842_select_1000, otp_7665,
140
otp_8732, meta_wb, grow_shrink, grow_pseudo_deleted,
141
shrink_pseudo_deleted, {group, meta_smp}, smp_insert,
142
smp_fixed_delete, smp_unfix_fix, smp_select_delete,
143
otp_8166, exit_large_table_owner,
144
exit_many_large_table_owner, exit_many_tables_owner,
145
exit_many_many_tables_owner, write_concurrency, heir,
146
give_away, setopts, bad_table, types].
150
[default, setbag, badnew, verybadnew, named, keypos2,
152
{insert, [], [empty, badinsert]},
153
{lookup, [], [time_lookup, badlookup, lookup_order]},
154
{lookup_element, [], [lookup_element_mult]},
156
[delete_elem, delete_tab, delete_large_tab,
157
delete_large_named_table, evil_delete, table_leak,
158
baddelete, match_delete, match_delete3]},
160
[match1, match2, match_object, match_object2]},
162
[misc1, safe_fixtable, info, dups, tab2list]},
164
[tab2file, tab2file2, tabfile_ext1,
165
tabfile_ext2, tabfile_ext3, tabfile_ext4]},
167
[heavy_lookup, heavy_lookup_element, heavy_concurrent]},
169
[foldl_ordered, foldr_ordered, foldl, foldr,
172
[meta_lookup_unnamed_read, meta_lookup_unnamed_write,
173
meta_lookup_named_read, meta_lookup_named_write,
174
meta_newdel_unnamed, meta_newdel_named]}].
176
init_per_suite(Config) ->
112
179
end_per_suite(_Config) ->
113
180
stop_spawn_logger(),
114
181
catch erts_debug:set_internal_state(available_internal_state, false).
116
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
120
new,insert,lookup,delete,firstnext,firstnext_concurrent,slot,match,
122
lookup_element, misc,files, heavy,
123
ordered, ordered_match, interface_equality,
124
fixtable_next, fixtable_insert, rename, rename_unnamed, evil_rename,
125
update_element, update_counter, evil_update_counter, partly_bound,
126
match_heavy, fold, member,
127
t_delete_object, t_init_table, t_whitebox,
128
t_delete_all_objects, t_insert_list, t_test_ms,
129
t_select_delete, t_ets_dets, memory,
131
select_fail,t_insert_new, t_repair_continuation, otp_5340, otp_6338,
132
otp_6842_select_1000, otp_7665,
134
grow_shrink, grow_pseudo_deleted, shrink_pseudo_deleted,
136
smp_insert, smp_fixed_delete, smp_unfix_fix, smp_select_delete, otp_8166,
137
exit_large_table_owner,
138
exit_many_large_table_owner,
139
exit_many_tables_owner,
140
exit_many_many_tables_owner,
141
write_concurrency, heir, give_away, setopts,
183
init_per_group(_GroupName, Config) ->
186
end_per_group(_GroupName, Config) ->
145
190
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171
216
t_match_spec_run(doc) ->
172
217
["Check ets:match_spec_run/2."];
173
218
t_match_spec_run(Config) when is_list(Config) ->
174
220
?line EtsMem = etsmem(),
175
?line [2,3] = ets:match_spec_run([{1},{2},{3}],
176
ets:match_spec_compile(
177
[{{'$1'},[{'>','$1',1}],['$1']}])),
222
t_match_spec_run_test([{1},{2},{3}],
223
[{{'$1'},[{'>','$1',1}],['$1']}],
178
226
?line Huge = [{X} || X <- lists:seq(1,2500)],
179
227
?line L = lists:seq(2476,2500),
180
?line L = ets:match_spec_run(Huge,
181
ets:match_spec_compile(
182
[{{'$1'},[{'>','$1',2475}],['$1']}])),
228
t_match_spec_run_test(Huge, [{{'$1'},[{'>','$1',2475}],['$1']}], L),
183
230
?line L2 = [{X*16#FFFFFFF} || X <- L],
184
?line L2 = ets:match_spec_run(Huge,
185
ets:match_spec_compile(
188
[{{{'*','$1',16#FFFFFFF}}}]}])),
189
?line [500,1000,1500,2000,2500] =
190
ets:match_spec_run(Huge,
191
ets:match_spec_compile(
193
[{'=:=',{'rem','$1',500},0}],
231
t_match_spec_run_test(Huge,
232
[{{'$1'}, [{'>','$1',2475}], [{{{'*','$1',16#FFFFFFF}}}]}],
235
t_match_spec_run_test(Huge, [{{'$1'}, [{'=:=',{'rem','$1',500},0}], ['$1']}],
236
[500,1000,1500,2000,2500]),
238
%% More matching fun with several match clauses and guards,
239
%% applied to a variety of terms.
241
CTerm = {const, Term},
243
N_List = [{Term, "0", "v-element"},
244
{"=hidden_node", "0", Term},
246
{"something", Term, "something else"},
247
{"guard and res", Term, 872346},
248
{Term, {'and',Term,'again'}, 3.14},
249
{Term, {'and',Term,'again'}, "m&g"},
250
{Term, {'and',Term,'again'}, "m&g&r"},
251
{[{second,Term}, 'and', "tail"], Term, ['and',"tail"]}],
253
N_MS = [{{'$1','$2','$3'},
254
[{'=:=','$1',CTerm}, {'=:=','$2',{const,"0"}}],
255
[{{"Guard only for $1",'$3'}}]},
258
[{'=:=','$3',"=hidden_node"}, {'=:=','$1',{const,"0"}}],
259
[{{"Result only for $4",'$4'}}]},
262
[{'=:=','$2',{const,"0"}}],
263
[{{"Match only for $1",'$2'}}]},
265
{{'$2',Term,['$3'|'_']},
266
[{is_list,'$2'},{'=:=','$3',$s}],
267
[{{"Matching term",'$2'}}]},
270
[{'=:=','$2',CTerm}, {is_list,'$1'}],
271
[{{"Guard and result",'$2'}}]},
273
{{'$1', {'and','$1','again'}, '$2'},
275
[{{"Match and result",'$1'}}]},
277
{{'$1', {'and','$1','again'}, '$2'},
278
[{'=:=','$1',CTerm}, {'=:=', '$2', "m&g"}],
279
[{{"Match and guard",'$2'}}]},
281
{{'$1', {'and','$1','again'}, "m&g&r"},
282
[{'=:=','$1',CTerm}],
283
[{{"Match, guard and result",'$1'}}]},
286
[{'=:=','$1',[{{second,'$2'}} | '$3']}],
287
[{{"Building guard"}}]}
290
N_Result = [{"Guard only for $1", "v-element"},
291
{"Result only for $4", Term},
292
{"Match only for $1", "0"},
293
{"Matching term","something"},
294
{"Guard and result",Term},
295
{"Match and result",Term},
296
{"Match and guard","m&g"},
297
{"Match, guard and result",Term},
300
F = fun(N_MS_Perm) ->
301
t_match_spec_run_test(N_List, N_MS_Perm, N_Result)
303
repeat_for_permutations(F, N_MS)
306
test_terms(Fun, skip_refc_check),
195
308
?line verify_etsmem(EtsMem).
310
t_match_spec_run_test(List, MS, Result) ->
312
%%io:format("ms = ~p\n",[MS]),
314
?m(Result, ets:match_spec_run(List, ets:match_spec_compile(MS))),
316
%% Check that ets:select agree
317
Tab = ets:new(xxx, [bag]),
318
ets:insert(Tab, List),
319
SRes = lists:sort(Result),
320
?m(SRes, lists:sort(ets:select(Tab, MS))),
323
%% Check that tracing agree
325
{Tracee, MonRef} = spawn_monitor(fun() -> ms_tracee(Self, List) end),
326
receive {Tracee, ready} -> ok end,
328
MST = lists:map(fun(Clause) -> ms_clause_ets_to_trace(Clause) end, MS),
330
%%io:format("MS = ~p\nMST= ~p\n",[MS,MST]),
332
erlang:trace_pattern({?MODULE,ms_tracee_dummy,'_'}, MST , [local]),
333
erlang:trace(Tracee, true, [call]),
335
TRes = ms_tracer_collect(Tracee, MonRef, []),
336
%erlang:trace(Tracee, false, [call]),
341
io:format("TRACE MATCH FAILED\n"),
342
io:format("Input = ~p\nMST = ~p\nExpected = ~p\nGot = ~p\n", [List, MST, SRes, TRes]),
343
?t:fail("TRACE MATCH FAILED")
349
ms_tracer_collect(Tracee, Ref, Acc) ->
351
{trace, Tracee, call, _Args, [Msg]} ->
352
%io:format("trace Args=~p Msg=~p\n", [_Args, Msg]),
353
ms_tracer_collect(Tracee, Ref, [Msg | Acc]);
355
{'DOWN', Ref, process, Tracee, _} ->
356
%io:format("monitor DOWN for ~p\n", [Tracee]),
357
TDRef = erlang:trace_delivered(Tracee),
358
ms_tracer_collect(Tracee, TDRef, Acc);
360
{trace_delivered, Tracee, Ref} ->
361
%%io:format("trace delivered for ~p\n", [Tracee]),
365
io:format("Unexpected message = ~p\n", [Other]),
366
?t:fail("Unexpected tracer msg")
370
ms_tracee(Parent, CallArgList) ->
371
%io:format("ms_tracee ~p started with ArgList = ~p\n", [self(), CallArgList]),
372
Parent ! {self(), ready},
373
receive start -> ok end,
374
lists:foreach(fun(Args) ->
375
erlang:apply(?MODULE, ms_tracee_dummy, tuple_to_list(Args))
377
%%receive stop -> ok end.
381
ms_tracee_dummy(_) -> ok.
382
ms_tracee_dummy(_,_) -> ok.
383
ms_tracee_dummy(_,_,_) -> ok.
384
ms_tracee_dummy(_,_,_,_) -> ok.
386
ms_clause_ets_to_trace({Head, Guard, Body}) ->
387
{tuple_to_list(Head), Guard, [{message, Body}]}.
389
assert_eq(A,A) -> ok;
391
io:format("FAILED MATCH:\n~p\n =/=\n~p\n",[A,B]),
392
?t:fail("assert_eq failed").
199
395
t_repair_continuation(suite) ->
279
475
?line true = ets:delete(T)
282
?line T = ets:new(x,[set|Opts]),
283
?line F = fun(0,_)->ok;(N,F) ->
284
ets:insert(T,{integer_to_list(N),N}),
288
?line {_,C} = ets:select(T,MS,5),
289
?line C2 = erlang:setelement(4,C,<<>>),
290
?line {'EXIT',{badarg,_}} = (catch ets:select(C2)),
291
?line C3 = ets:repair_continuation(C2,MS),
292
?line {[true,true,true,true,true],_} = ets:select(C3),
293
?line {[true,true,true,true,true],_} = ets:select(C),
294
?line true = ets:delete(T)
297
?line T = ets:new(x,[bag|Opts]),
298
?line F = fun(0,_)->ok;(N,F) ->
299
ets:insert(T,{integer_to_list(N),N}),
303
?line {_,C} = ets:select(T,MS,5),
304
?line C2 = erlang:setelement(4,C,<<>>),
305
?line {'EXIT',{badarg,_}} = (catch ets:select(C2)),
306
?line C3 = ets:repair_continuation(C2,MS),
307
?line {[true,true,true,true,true],_} = ets:select(C3),
308
?line {[true,true,true,true,true],_} = ets:select(C),
309
?line true = ets:delete(T)
312
?line T = ets:new(x,[duplicate_bag|Opts]),
478
?line T = ets_new(x,[set|Opts]),
479
?line F = fun(0,_)->ok;(N,F) ->
480
ets:insert(T,{integer_to_list(N),N}),
484
?line {_,C} = ets:select(T,MS,5),
485
?line C2 = erlang:setelement(4,C,<<>>),
486
?line {'EXIT',{badarg,_}} = (catch ets:select(C2)),
487
?line C3 = ets:repair_continuation(C2,MS),
488
?line {[true,true,true,true,true],_} = ets:select(C3),
489
?line {[true,true,true,true,true],_} = ets:select(C),
490
?line true = ets:delete(T)
493
?line T = ets_new(x,[bag|Opts]),
494
?line F = fun(0,_)->ok;(N,F) ->
495
ets:insert(T,{integer_to_list(N),N}),
499
?line {_,C} = ets:select(T,MS,5),
500
?line C2 = erlang:setelement(4,C,<<>>),
501
?line {'EXIT',{badarg,_}} = (catch ets:select(C2)),
502
?line C3 = ets:repair_continuation(C2,MS),
503
?line {[true,true,true,true,true],_} = ets:select(C3),
504
?line {[true,true,true,true,true],_} = ets:select(C),
505
?line true = ets:delete(T)
508
?line T = ets_new(x,[duplicate_bag|Opts]),
313
509
?line F = fun(0,_)->ok;(N,F) ->
314
510
ets:insert(T,{integer_to_list(N),N}),
379
576
-define(S(T),ets:info(T,memory)).
380
577
-define(TAB_STRUCT_SZ, erts_debug:get_internal_state('DbTable_words')).
381
-define(NORMAL_TAB_STRUCT_SZ, 26). %% SunOS5.8, 32-bit, non smp, private heap
578
%%-define(NORMAL_TAB_STRUCT_SZ, 26). %% SunOS5.8, 32-bit, non smp, private heap
383
580
%% The hardcoded expected memory sizes (in words) are the ones we expect on:
384
581
%% SunOS5.8, 32-bit, non smp, private heap
387
["Whitebox test of ets:info(X,memory)"];
583
memory(doc) -> ["Whitebox test of ets:info(X,memory)"];
390
585
memory(Config) when is_list(Config) ->
391
586
?line erts_debug:set_internal_state(available_internal_state, true),
392
587
?line ok = chk_normal_tab_struct_size(),
393
?line L = [T1,T2,T3,T4] = fill_sets_int(1000),
394
?line XRes1 = adjust_xmem(L, {16862,16072,16072,16078}),
588
repeat_for_opts(memory_do,[compressed]),
589
?line catch erts_debug:set_internal_state(available_internal_state, false).
592
?line L = [T1,T2,T3,T4] = fill_sets_int(1000,Opts),
593
XR1 = case mem_mode(T1) of
594
{normal,_} -> {13836,13046,13046,13052}; %{13862,13072,13072,13078};
595
{compressed,4} -> {11041,10251,10251,10252}; %{11067,10277,10277,10278};
596
{compressed,8} -> {10050,9260,9260,9260} %{10076,9286,9286,9286}
598
?line XRes1 = adjust_xmem(L, XR1),
395
599
?line Res1 = {?S(T1),?S(T2),?S(T3),?S(T4)},
396
600
?line lists:foreach(fun(T) ->
397
601
Before = ets:info(T,size),
462
682
erlang:system_info(smp_support),
463
683
erlang:system_info(heap_type)},
464
684
?line ?t:format("System = ~p~n", [System]),
465
?line ?t:format("?NORMAL_TAB_STRUCT_SZ=~p~n", [?NORMAL_TAB_STRUCT_SZ]),
685
%%?line ?t:format("?NORMAL_TAB_STRUCT_SZ=~p~n", [?NORMAL_TAB_STRUCT_SZ]),
466
686
?line ?t:format("?TAB_STRUCT_SZ=~p~n", [?TAB_STRUCT_SZ]),
468
{{unix, sunos}, {5, 8, 0}, 4, false, private} ->
469
?line ?NORMAL_TAB_STRUCT_SZ = ?TAB_STRUCT_SZ,
475
adjust_xmem([T1,T2,T3,T4], {A0,B0,C0,D0} = Mem0) ->
688
% ?line case System of
689
% {{unix, sunos}, {5, 8, 0}, 4, false, private} ->
690
% ?line ?NORMAL_TAB_STRUCT_SZ = ?TAB_STRUCT_SZ,
696
-define(DB_TREE_STACK_NEED,50). % The static stack for a tree, in halfword pointers are two internal words
697
% so the stack gets twice as big
698
-define(DB_HASH_SIZEOF_EXTSEG,260). % The segment size in words, in halfword this will be twice as large.
700
adjust_xmem([T1,T2,T3,T4], {A0,B0,C0,D0} = _Mem0) ->
476
701
%% Adjust for 64-bit, smp, and os:
477
702
%% Table struct size may differ.
478
Mem1 = case ?TAB_STRUCT_SZ of
479
?NORMAL_TAB_STRUCT_SZ ->
482
TabDiff = TabStructSz - ?NORMAL_TAB_STRUCT_SZ,
483
{A0+TabDiff, B0+TabDiff, C0+TabDiff, D0+TabDiff}
704
% Mem1 = case ?TAB_STRUCT_SZ of
705
% ?NORMAL_TAB_STRUCT_SZ ->
708
% TabDiff = TabStructSz - ?NORMAL_TAB_STRUCT_SZ,
709
% {A0+TabDiff, B0+TabDiff, C0+TabDiff, D0+TabDiff}
712
TabDiff = ?TAB_STRUCT_SZ,
713
Mem1 = {A0+TabDiff, B0+TabDiff, C0+TabDiff, D0+TabDiff},
715
Mem2 = case {erlang:system_info({wordsize,internal}),erlang:system_info({wordsize,external})} of
716
%% Halfword, corrections for regular pointers occupying two internal words.
718
{A1,B1,C1,D1} = Mem1,
719
{A1+4*ets:info(T1, size)+?DB_TREE_STACK_NEED,
720
B1+3*ets:info(T2, size)+?DB_HASH_SIZEOF_EXTSEG,
721
C1+3*ets:info(T3, size)+?DB_HASH_SIZEOF_EXTSEG,
722
D1+3*ets:info(T4, size)+?DB_HASH_SIZEOF_EXTSEG};
485
727
%% Adjust for hybrid and shared heaps:
486
728
%% Each record is one word smaller.
487
Mem2 = case erlang:system_info(heap_type) of
491
{A1,B1,C1,D1} = Mem1,
492
{A1-ets:info(T1, size),B1-ets:info(T2, size),
493
C1-ets:info(T3, size),D1-ets:info(T4, size)}
729
%%Mem2 = case erlang:system_info(heap_type) of
733
%% {A1,B1,C1,D1} = Mem1,
734
%% {A1-ets:info(T1, size),B1-ets:info(T2, size),
735
%% C1-ets:info(T3, size),D1-ets:info(T4, size)}
495
737
%%{Mem2,{ets:info(T1,stats),ets:info(T2,stats),ets:info(T3,stats),ets:info(T4,stats)}}.
786
1028
?line true = (if is_list(String) -> true; true -> false end),
787
1029
?line verify_etsmem(EtsMem).
1031
t_select_reverse(doc) ->
1032
["Test the select reverse BIF's"];
1033
t_select_reverse(suite) ->
1035
t_select_reverse(Config) when is_list(Config) ->
1036
?line Table = ets_new(xxx, [ordered_set]),
1037
?line filltabint(Table,1000),
1038
?line A = lists:reverse(ets:select(Table,[{{'$1', '_'},
1044
?line A = ets:select_reverse(Table,[{{'$1', '_'},
1050
?line A = reverse_chunked(Table,[{{'$1', '_'},
1056
% A set/bag/duplicate_bag should get the same result regardless
1057
% of select or select_reverse
1058
?line Table2 = ets_new(xxx, [set]),
1059
?line filltabint(Table2,1000),
1060
?line Table3 = ets_new(xxx, [bag]),
1061
?line filltabint(Table3,1000),
1062
?line Table4 = ets_new(xxx, [duplicate_bag]),
1063
?line filltabint(Table4,1000),
1064
?line lists:map(fun(Tab) ->
1065
B = ets:select(Tab,[{{'$1', '_'},
1071
B = ets:select_reverse(Tab,[{{'$1', '_'},
1077
end,[Table2, Table3, Table4]),
1082
reverse_chunked(T,MS,N) ->
1083
do_reverse_chunked(ets:select_reverse(T,MS,N),[]).
1085
do_reverse_chunked('$end_of_table',Acc) ->
1087
do_reverse_chunked({L,C},Acc) ->
1088
NewAcc = lists:reverse(L)++Acc,
1089
do_reverse_chunked(ets:select_reverse(C), NewAcc).
789
1092
t_select_delete(doc) ->
790
1093
["Test the ets:select_delete/2 and ets:select_count/2 BIF's"];
791
1094
t_select_delete(suite) ->
1756
2063
write_concurrency(suite) -> [];
1757
2064
write_concurrency(Config) when is_list(Config) ->
1758
2065
?line EtsMem = etsmem(),
1759
Yes1 = ets:new(foo,[public,{write_concurrency,true}]),
1760
Yes2 = ets:new(foo,[protected,{write_concurrency,true}]),
1761
No1 = ets:new(foo,[private,{write_concurrency,true}]),
1763
Yes3 = ets:new(foo,[bag,public,{write_concurrency,true}]),
1764
Yes4 = ets:new(foo,[bag,protected,{write_concurrency,true}]),
1765
No2 = ets:new(foo,[bag,private,{write_concurrency,true}]),
1767
Yes5 = ets:new(foo,[duplicate_bag,public,{write_concurrency,true}]),
1768
Yes6 = ets:new(foo,[duplicate_bag,protected,{write_concurrency,true}]),
1769
No3 = ets:new(foo,[duplicate_bag,private,{write_concurrency,true}]),
1771
No4 = ets:new(foo,[ordered_set,public,{write_concurrency,true}]),
1772
No5 = ets:new(foo,[ordered_set,protected,{write_concurrency,true}]),
1773
No6 = ets:new(foo,[ordered_set,private,{write_concurrency,true}]),
1775
No7 = ets:new(foo,[public,{write_concurrency,false}]),
1776
No8 = ets:new(foo,[protected,{write_concurrency,false}]),
2066
Yes1 = ets_new(foo,[public,{write_concurrency,true}]),
2067
Yes2 = ets_new(foo,[protected,{write_concurrency,true}]),
2068
No1 = ets_new(foo,[private,{write_concurrency,true}]),
2070
Yes3 = ets_new(foo,[bag,public,{write_concurrency,true}]),
2071
Yes4 = ets_new(foo,[bag,protected,{write_concurrency,true}]),
2072
No2 = ets_new(foo,[bag,private,{write_concurrency,true}]),
2074
Yes5 = ets_new(foo,[duplicate_bag,public,{write_concurrency,true}]),
2075
Yes6 = ets_new(foo,[duplicate_bag,protected,{write_concurrency,true}]),
2076
No3 = ets_new(foo,[duplicate_bag,private,{write_concurrency,true}]),
2078
No4 = ets_new(foo,[ordered_set,public,{write_concurrency,true}]),
2079
No5 = ets_new(foo,[ordered_set,protected,{write_concurrency,true}]),
2080
No6 = ets_new(foo,[ordered_set,private,{write_concurrency,true}]),
2082
No7 = ets_new(foo,[public,{write_concurrency,false}]),
2083
No8 = ets_new(foo,[protected,{write_concurrency,false}]),
1778
2085
?line YesMem = ets:info(Yes1,memory),
1779
2086
?line NoHashMem = ets:info(No1,memory),
3037
3335
exit_large_table_owner(suite) ->
3039
3337
exit_large_table_owner(Config) when is_list(Config) ->
3040
?line Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 500000)],
3338
%%?line Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 500000)],
3339
?line FEData = fun(Do) -> repeat_while(fun(500000) -> {false,ok};
3340
(I) -> Do({erlang:phash2(I, 16#ffffff),I}),
3041
3344
?line EtsMem = etsmem(),
3042
repeat_for_opts(fun(Opts) -> exit_large_table_owner_do(Opts,Data,Config) end),
3345
repeat_for_opts({exit_large_table_owner_do,{FEData,Config}}),
3043
3346
?line verify_etsmem(EtsMem).
3045
exit_large_table_owner_do(Opts,Data,Config) ->
3046
?line verify_rescheduling_exit(Config, Data, [named_table | Opts], true, 1, 1),
3047
?line verify_rescheduling_exit(Config, Data, Opts, false, 1, 1).
3348
exit_large_table_owner_do(Opts,{FEData,Config}) ->
3349
?line verify_rescheduling_exit(Config, FEData, [named_table | Opts], true, 1, 1),
3350
?line verify_rescheduling_exit(Config, FEData, Opts, false, 1, 1).
3049
3352
exit_many_large_table_owner(doc) -> [];
3050
3353
exit_many_large_table_owner(suite) -> [];
3051
3354
exit_many_large_table_owner(Config) when is_list(Config) ->
3052
?line Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 500000)],
3355
%%?line Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 500000)],
3356
?line FEData = fun(Do) -> repeat_while(fun(500000) -> {false,ok};
3357
(I) -> Do({erlang:phash2(I, 16#ffffff),I}),
3053
3361
?line EtsMem = etsmem(),
3054
repeat_for_opts(fun(Opts) -> exit_many_large_table_owner_do(Opts,Data,Config) end),
3362
repeat_for_opts(fun(Opts) -> exit_many_large_table_owner_do(Opts,FEData,Config) end),
3055
3363
?line verify_etsmem(EtsMem).
3057
exit_many_large_table_owner_do(Opts,Data,Config) ->
3058
?line verify_rescheduling_exit(Config, Data, Opts, true, 1, 4),
3059
?line verify_rescheduling_exit(Config, Data, [named_table | Opts], false, 1, 4).
3365
exit_many_large_table_owner_do(Opts,FEData,Config) ->
3366
?line verify_rescheduling_exit(Config, FEData, Opts, true, 1, 4),
3367
?line verify_rescheduling_exit(Config, FEData, [named_table | Opts], false, 1, 4).
3061
3369
exit_many_tables_owner(doc) -> [];
3062
3370
exit_many_tables_owner(suite) -> [];
3063
3371
exit_many_tables_owner(Config) when is_list(Config) ->
3372
NoData = fun(_Do) -> ok end,
3064
3373
?line EtsMem = etsmem(),
3065
?line verify_rescheduling_exit(Config, [], [named_table], false, 1000, 1),
3066
?line verify_rescheduling_exit(Config, [], [named_table,{write_concurrency,true}], false, 1000, 1),
3374
?line verify_rescheduling_exit(Config, NoData, [named_table], false, 1000, 1),
3375
?line verify_rescheduling_exit(Config, NoData, [named_table,{write_concurrency,true}], false, 1000, 1),
3067
3376
?line verify_etsmem(EtsMem).
3069
3378
exit_many_many_tables_owner(doc) -> [];
3070
3379
exit_many_many_tables_owner(suite) -> [];
3071
3380
exit_many_many_tables_owner(Config) when is_list(Config) ->
3072
3381
?line Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 50)],
3073
repeat_for_opts(fun(Opts) -> exit_many_many_tables_owner_do(Opts,Data,Config) end).
3382
?line FEData = fun(Do) -> lists:foreach(Do, Data) end,
3383
repeat_for_opts(fun(Opts) -> exit_many_many_tables_owner_do(Opts,FEData,Config) end).
3075
exit_many_many_tables_owner_do(Opts,Data,Config) ->
3076
?line verify_rescheduling_exit(Config, Data, [named_table | Opts], true, 200, 5),
3077
?line verify_rescheduling_exit(Config, Data, Opts, false, 200, 5),
3385
exit_many_many_tables_owner_do(Opts,FEData,Config) ->
3386
?line verify_rescheduling_exit(Config, FEData, [named_table | Opts], true, 200, 5),
3387
?line verify_rescheduling_exit(Config, FEData, Opts, false, 200, 5),
3078
3388
?line wait_for_test_procs(),
3079
3389
?line EtsMem = etsmem(),
3080
?line verify_rescheduling_exit(Config, Data, Opts, true, 200, 5),
3081
?line verify_rescheduling_exit(Config, Data, [named_table | Opts], false, 200, 5),
3390
?line verify_rescheduling_exit(Config, FEData, Opts, true, 200, 5),
3391
?line verify_rescheduling_exit(Config, FEData, [named_table | Opts], false, 200, 5),
3082
3392
?line verify_etsmem(EtsMem).
3634
3939
?line verify_etsmem(EtsMem).
3636
3941
tab2file2(doc) -> ["Check the ets:tab2file function on a ",
3637
"filled set type ets table."];
3942
"filled set/bag type ets table."];
3638
3943
tab2file2(suite) -> [];
3639
tab2file2(Config) when is_list(Config) ->
3640
%% Try the same on a filled set table.
3944
tab2file2(Config) when is_list(Config) ->
3945
repeat_for_opts({tab2file2_do,Config}, [[set,bag],compressed]).
3947
tab2file2_do(Opts, Config) ->
3641
3948
?line EtsMem = etsmem(),
3642
?line Tab = ets:new(ets_SUITE_foo_tab, [named_table, set, private,
3949
?line Tab = ets_new(ets_SUITE_foo_tab, [named_table, private,
3950
{keypos, 2} | Opts]),
3644
3951
?line FName = filename:join([?config(priv_dir, Config),"tab2file2_case"]),
3645
3952
?line ok = fill_tab2(Tab, 0, 10000), % Fill up the table (grucho mucho!)
3646
3953
?line Len = length(ets:tab2list(Tab)),
3647
?line ok = ets:tab2file(Tab, FName),
3648
?line true = ets:delete(Tab),
3650
?line {ok, Tab2} = ets:file2tab(FName),
3651
?line private = ets:info(Tab2, protection),
3652
?line true = ets:info(Tab2, named_table),
3653
?line 2 = ets:info(Tab2, keypos),
3654
?line set = ets:info(Tab2, type),
3655
?line Len = length(ets:tab2list(Tab2)),
3656
?line true = ets:delete(Tab2),
3657
?line verify_etsmem(EtsMem).
3659
tab2file3(doc) -> ["Check the ets:tab2file function on a ",
3660
"filled bag type ets table."];
3661
tab2file3(suite) -> [];
3662
tab2file3(Config) when is_list(Config) ->
3663
%% Try the same on a filled bag table.
3664
?line EtsMem = etsmem(),
3665
?line Tab = ets:new(ets_SUITE_foo_tab, [named_table, bag, private,
3667
?line FName = filename:join([?config(priv_dir, Config),"tab2file3_case"]),
3668
?line ok = fill_tab2(Tab, 0, 10000), % Fill up the table (grucho mucho!)
3669
?line Len = length(ets:tab2list(Tab)),
3670
3954
?line Mem = ets:info(Tab, memory),
3955
?line Type = ets:info(Tab, type),
3956
%%io:format("org tab: ~p\n",[ets:info(Tab)]),
3671
3957
?line ok = ets:tab2file(Tab, FName),
3672
3958
?line true = ets:delete(Tab),
3960
?line EtsMem4 = etsmem(),
3674
3962
?line {ok, Tab2} = ets:file2tab(FName),
3963
%%io:format("loaded tab: ~p\n",[ets:info(Tab2)]),
3675
3964
?line private = ets:info(Tab2, protection),
3676
3965
?line true = ets:info(Tab2, named_table),
3677
3966
?line 2 = ets:info(Tab2, keypos),
3678
?line bag = ets:info(Tab2, type),
3967
?line Type = ets:info(Tab2, type),
3679
3968
?line Len = length(ets:tab2list(Tab2)),
3680
3969
?line Mem = ets:info(Tab2, memory),
3681
3970
?line true = ets:delete(Tab2),
3971
io:format("Between = ~p\n", [EtsMem4]),
3682
3972
?line verify_etsmem(EtsMem).
3684
3974
-define(test_list, [8,5,4,1,58,125,255, 250, 245, 240, 235,
4446
4770
otp_6338(Config) when is_list(Config) ->
4447
4771
L = binary_to_term(<<131,108,0,0,0,2,104,2,108,0,0,0,2,103,100,0,19,112,112,98,49,95,98,115,49,50,64,98,108,97,100,101,95,48,95,53,0,0,33,50,0,0,0,4,1,98,0,0,23,226,106,100,0,4,101,120,105,116,104,2,108,0,0,0,2,104,2,100,0,3,115,98,109,100,0,19,112,112,98,50,95,98,115,49,50,64,98,108,97,100,101,95,48,95,56,98,0,0,18,231,106,100,0,4,114,101,99,118,106>>),
4448
T = ets:new(xxx,[ordered_set]),
4772
T = ets_new(xxx,[ordered_set]),
4449
4773
lists:foreach(fun(X) -> ets:insert(T,X) end,L),
4450
4774
[[4839,recv]] = ets:match(T,{[{sbm,ppb2_bs12@blade_0_8},'$1'],'$2'}),
5326
5728
{true,_} -> Func()
5731
%% Copy-paste from emulator/test/binary_SUITE.erl
5732
-define(heap_binary_size, 64).
5733
test_terms(Test_Func, Mode) ->
5735
?line Pib0 = process_info(self(),binary),
5737
?line Test_Func(atom),
5738
?line Test_Func(''),
5739
?line Test_Func('a'),
5740
?line Test_Func('ab'),
5741
?line Test_Func('abc'),
5742
?line Test_Func('abcd'),
5743
?line Test_Func('abcde'),
5744
?line Test_Func('abcdef'),
5745
?line Test_Func('abcdefg'),
5746
?line Test_Func('abcdefgh'),
5748
?line Test_Func(fun() -> ok end),
5749
X = id([a,{b,c},c]),
5751
Z = id(1 bsl 8*257),
5752
?line Test_Func(fun() -> X end),
5753
?line Test_Func(fun() -> {X,Y} end),
5754
?line Test_Func([fun() -> {X,Y,Z} end,
5755
fun() -> {Z,X,Y} end,
5756
fun() -> {Y,Z,X} end]),
5758
?line Test_Func({trace_ts,{even_bigger,{some_data,fun() -> ok end}},{1,2,3}}),
5759
?line Test_Func({trace_ts,{even_bigger,{some_data,<<1,2,3,4,5,6,7,8,9,10>>}},
5763
?line Test_Func(42),
5764
?line Test_Func(-23),
5765
?line Test_Func(256),
5766
?line Test_Func(25555),
5767
?line Test_Func(-3333),
5769
?line Test_Func(1.0),
5771
?line Test_Func(183749783987483978498378478393874),
5772
?line Test_Func(-37894183749783987483978498378478393874),
5773
Very_Big = very_big_num(),
5774
?line Test_Func(Very_Big),
5775
?line Test_Func(-Very_Big+1),
5777
?line Test_Func([]),
5778
?line Test_Func("abcdef"),
5779
?line Test_Func([a, b, 1, 2]),
5780
?line Test_Func([a|b]),
5782
?line Test_Func({}),
5783
?line Test_Func({1}),
5784
?line Test_Func({a, b}),
5785
?line Test_Func({a, b, c}),
5786
?line Test_Func(list_to_tuple(lists:seq(0, 255))),
5787
?line Test_Func(list_to_tuple(lists:seq(0, 256))),
5789
?line Test_Func(make_ref()),
5790
?line Test_Func([make_ref(), make_ref()]),
5792
?line Test_Func(make_port()),
5794
?line Test_Func(make_pid()),
5795
?line Test_Func(make_ext_pid()),
5796
?line Test_Func(make_ext_port()),
5797
?line Test_Func(make_ext_ref()),
5799
Bin0 = list_to_binary(lists:seq(0, 14)),
5800
?line Test_Func(Bin0),
5801
Bin1 = list_to_binary(lists:seq(0, ?heap_binary_size)),
5802
?line Test_Func(Bin1),
5803
Bin2 = list_to_binary(lists:seq(0, ?heap_binary_size+1)),
5804
?line Test_Func(Bin2),
5805
Bin3 = list_to_binary(lists:seq(0, 255)),
5807
Pib = process_info(self(),binary),
5808
?line Test_Func(Bin3),
5811
strict -> ?line Pib = process_info(self(),binary);
5812
skip_refc_check -> ok
5815
?line Test_Func(make_unaligned_sub_binary(Bin0)),
5816
?line Test_Func(make_unaligned_sub_binary(Bin1)),
5817
?line Test_Func(make_unaligned_sub_binary(Bin2)),
5818
?line Test_Func(make_unaligned_sub_binary(Bin3)),
5820
?line Test_Func(make_sub_binary(lists:seq(42, 43))),
5821
?line Test_Func(make_sub_binary([42,43,44])),
5822
?line Test_Func(make_sub_binary([42,43,44,45])),
5823
?line Test_Func(make_sub_binary([42,43,44,45,46])),
5824
?line Test_Func(make_sub_binary([42,43,44,45,46,47])),
5825
?line Test_Func(make_sub_binary([42,43,44,45,46,47,48])),
5826
?line Test_Func(make_sub_binary(lists:seq(42, 49))),
5827
?line Test_Func(make_sub_binary(lists:seq(0, 14))),
5828
?line Test_Func(make_sub_binary(lists:seq(0, ?heap_binary_size))),
5829
?line Test_Func(make_sub_binary(lists:seq(0, ?heap_binary_size+1))),
5830
?line Test_Func(make_sub_binary(lists:seq(0, 255))),
5832
?line Test_Func(make_unaligned_sub_binary(lists:seq(42, 43))),
5833
?line Test_Func(make_unaligned_sub_binary([42,43,44])),
5834
?line Test_Func(make_unaligned_sub_binary([42,43,44,45])),
5835
?line Test_Func(make_unaligned_sub_binary([42,43,44,45,46])),
5836
?line Test_Func(make_unaligned_sub_binary([42,43,44,45,46,47])),
5837
?line Test_Func(make_unaligned_sub_binary([42,43,44,45,46,47,48])),
5838
?line Test_Func(make_unaligned_sub_binary(lists:seq(42, 49))),
5839
?line Test_Func(make_unaligned_sub_binary(lists:seq(0, 14))),
5840
?line Test_Func(make_unaligned_sub_binary(lists:seq(0, ?heap_binary_size))),
5841
?line Test_Func(make_unaligned_sub_binary(lists:seq(0, ?heap_binary_size+1))),
5842
?line Test_Func(make_unaligned_sub_binary(lists:seq(0, 255))),
5844
%% Bit level binaries.
5845
?line Test_Func(<<1:1>>),
5846
?line Test_Func(<<2:2>>),
5847
?line Test_Func(<<42:10>>),
5848
?line Test_Func(list_to_bitstring([<<5:6>>|lists:seq(0, 255)])),
5850
?line Test_Func(F = fun(A) -> 42*A end),
5851
?line Test_Func(lists:duplicate(32, F)),
5853
?line Test_Func(FF = fun binary_SUITE:all/1),
5854
?line Test_Func(lists:duplicate(32, FF)),
5858
strict -> ?line Pib0 = process_info(self(),binary);
5859
skip_refc_check -> ok
5867
very_big_num(33, 1).
5869
very_big_num(Left, Result) when Left > 0 ->
5870
?line very_big_num(Left-1, Result*256);
5871
very_big_num(0, Result) ->
5875
?line open_port({spawn, efile}, [eof]).
5878
?line spawn_link(?MODULE, sleeper, []).
5881
?line receive after infinity -> ok end.
5884
{Pid, _, _} = get(externals),
5888
{_, Port, _} = get(externals),
5891
{_, _, Ref} = get(externals),
5895
case get(externals) of
5897
SysDistSz = ets:info(sys_dist,size),
5898
?line Pa = filename:dirname(code:which(?MODULE)),
5899
?line {ok, Node} = test_server:start_node(plopp, slave, [{args, " -pa " ++ Pa}]),
5900
?line Res = case rpc:call(Node, ?MODULE, rpc_externals, []) of
5901
{badrpc, {'EXIT', E}} ->
5902
test_server:fail({rpcresult, E});
5905
?line test_server:stop_node(Node),
5907
%% Wait for table 'sys_dist' to stabilize
5908
repeat_while(fun() ->
5909
case ets:info(sys_dist,size) of
5912
io:format("Waiting for sys_dist to revert size from ~p to size ~p\n",
5914
receive after 1000 -> true end
5917
put(externals, Res);
5923
{self(), make_port(), make_ref()}.
5925
make_sub_binary(Bin) when is_binary(Bin) ->
5926
{_,B} = split_binary(list_to_binary([0,1,3,Bin]), 3),
5928
make_sub_binary(List) ->
5929
make_sub_binary(list_to_binary(List)).
5931
make_unaligned_sub_binary(Bin0) when is_binary(Bin0) ->
5932
Bin1 = <<0:3,Bin0/binary,31:5>>,
5934
<<0:3,Bin:Sz/binary,31:5>> = id(Bin1),
5936
make_unaligned_sub_binary(List) ->
5937
make_unaligned_sub_binary(list_to_binary(List)).
5330
5939
%% Repeat test function with different combination of table options
5332
5941
repeat_for_opts(F) ->
5333
repeat_for_opts(F, [write_concurrency]).
5942
repeat_for_opts(F, [write_concurrency, read_concurrency, compressed]).
5335
5944
repeat_for_opts(F, OptGenList) when is_atom(F) ->
5336
5945
repeat_for_opts(fun(Opts) -> ?MODULE:F(Opts) end, OptGenList);
5946
repeat_for_opts({F,Args}, OptGenList) when is_atom(F) ->
5947
repeat_for_opts(fun(Opts) -> ?MODULE:F(Opts,Args) end, OptGenList);
5337
5948
repeat_for_opts(F, OptGenList) ->
5338
5949
repeat_for_opts(F, OptGenList, []).
5340
5951
repeat_for_opts(F, [], Acc) ->
5341
lists:map(fun(Opts) ->
5342
io:format("Calling with options ~p\n",[Opts]),
5952
lists:map(fun(Opts) ->
5953
OptList = lists:filter(fun(E) -> E =/= void end, Opts),
5954
io:format("Calling with options ~p\n",[OptList]),
5345
5957
repeat_for_opts(F, [OptList | Tail], []) when is_list(OptList) ->
5346
5958
repeat_for_opts(F, Tail, [[Opt] || Opt <- OptList]);
5347
5959
repeat_for_opts(F, [OptList | Tail], AccList) when is_list(OptList) ->