diff options
Diffstat (limited to 'lib/stdlib/test/ets_SUITE.erl')
-rw-r--r-- | lib/stdlib/test/ets_SUITE.erl | 1462 |
1 files changed, 1064 insertions, 398 deletions
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl index 13c87ca005..57df963ae2 100644 --- a/lib/stdlib/test/ets_SUITE.erl +++ b/lib/stdlib/test/ets_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -18,24 +18,25 @@ %% -module(ets_SUITE). --export([all/1]). --export([new/1,default/1,setbag/1,badnew/1,verybadnew/1,named/1,keypos2/1, +-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, + init_per_group/2,end_per_group/2]). +-export([default/1,setbag/1,badnew/1,verybadnew/1,named/1,keypos2/1, privacy/1,privacy_owner/2]). --export([insert/1,empty/1,badinsert/1]). --export([lookup/1,time_lookup/1,badlookup/1,lookup_order/1]). --export([delete/1,delete_elem/1,delete_tab/1,delete_large_tab/1, +-export([empty/1,badinsert/1]). +-export([time_lookup/1,badlookup/1,lookup_order/1]). +-export([delete_elem/1,delete_tab/1,delete_large_tab/1, delete_large_named_table/1, evil_delete/1,baddelete/1,match_delete/1,table_leak/1]). -export([match_delete3/1]). -export([firstnext/1,firstnext_concurrent/1]). -export([slot/1]). --export([match/1, match1/1, match2/1, match_object/1, match_object2/1]). --export([misc/1, dups/1, misc1/1, safe_fixtable/1, info/1, tab2list/1]). --export([files/1, tab2file/1, tab2file2/1, tab2file3/1, tabfile_ext1/1, +-export([ match1/1, match2/1, match_object/1, match_object2/1]). +-export([ dups/1, misc1/1, safe_fixtable/1, info/1, tab2list/1]). +-export([ tab2file/1, tab2file2/1, tabfile_ext1/1, tabfile_ext2/1, tabfile_ext3/1, tabfile_ext4/1]). --export([heavy/1, heavy_lookup/1, heavy_lookup_element/1]). --export([lookup_element/1, lookup_element_mult/1]). --export([fold/1]). +-export([ heavy_lookup/1, heavy_lookup_element/1, heavy_concurrent/1]). +-export([ lookup_element_mult/1]). +-export([]). -export([foldl_ordered/1, foldr_ordered/1, foldl/1, foldr/1, fold_empty/1]). -export([t_delete_object/1, t_init_table/1, t_whitebox/1, t_delete_all_objects/1, t_insert_list/1, t_test_ms/1, @@ -59,25 +60,27 @@ -export([otp_7665/1]). -export([meta_wb/1]). -export([grow_shrink/1, grow_pseudo_deleted/1, shrink_pseudo_deleted/1]). --export([meta_smp/1, +-export([ meta_lookup_unnamed_read/1, meta_lookup_unnamed_write/1, meta_lookup_named_read/1, meta_lookup_named_write/1, meta_newdel_unnamed/1, meta_newdel_named/1]). --export([smp_insert/1, smp_fixed_delete/1, smp_unfix_fix/1, smp_select_delete/1, otp_8166/1]). +-export([smp_insert/1, smp_fixed_delete/1, smp_unfix_fix/1, smp_select_delete/1, + otp_8166/1, otp_8732/1]). -export([exit_large_table_owner/1, exit_many_large_table_owner/1, exit_many_tables_owner/1, exit_many_many_tables_owner/1]). -export([write_concurrency/1, heir/1, give_away/1, setopts/1]). --export([bad_table/1]). +-export([bad_table/1, types/1]). +-export([otp_9423/1]). --export([init_per_testcase/2, fin_per_testcase/2, end_per_suite/1]). +-export([init_per_testcase/2, end_per_testcase/2]). %% Convenience for manual testing -export([random_test/0]). % internal exports -export([dont_make_worse_sub/0, make_better_sub1/0, make_better_sub2/0]). --export([t_repair_continuation_do/1, default_do/1, t_bucket_disappears_do/1, +-export([t_repair_continuation_do/1, t_bucket_disappears_do/1, select_fail_do/1, whitebox_1/1, whitebox_2/1, t_delete_all_objects_do/1, t_delete_object_do/1, t_init_table_do/1, t_insert_list_do/1, update_element_opts/1, update_element_opts/4, update_element/4, update_element_do/4, @@ -89,10 +92,17 @@ match_delete_do/1, match_delete3_do/1, firstnext_do/1, slot_do/1, match1_do/1, match2_do/1, match_object_do/1, match_object2_do/1, misc1_do/1, safe_fixtable_do/1, info_do/1, dups_do/1, heavy_lookup_do/1, - heavy_lookup_element_do/1, member_do/1, otp_5340_do/1, otp_7665_do/1, meta_wb_do/1 + heavy_lookup_element_do/1, member_do/1, otp_5340_do/1, otp_7665_do/1, meta_wb_do/1, + do_heavy_concurrent/1, tab2file2_do/2, exit_large_table_owner_do/2, + types_do/1, sleeper/0, rpc_externals/0, memory_do/1, + ms_tracee_dummy/1, ms_tracee_dummy/2, ms_tracee_dummy/3, ms_tracee_dummy/4 ]). --include("test_server.hrl"). +-export([t_select_reverse/1]). + +-include_lib("test_server/include/test_server.hrl"). + +-define(m(A,B), ?line assert_eq(A,B)). init_per_testcase(Case, Config) -> Seed = {S1,S2,S3} = random:seed0(), %now(), @@ -103,44 +113,81 @@ init_per_testcase(Case, Config) -> Dog=test_server:timetrap(test_server:minutes(20)), [{watchdog, Dog}, {test_case, Case} | Config]. -fin_per_testcase(_Func, Config) -> +end_per_testcase(_Func, Config) -> Dog=?config(watchdog, Config), wait_for_test_procs(true), test_server:timetrap_cancel(Dog). - + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [{group, new}, {group, insert}, {group, lookup}, + {group, delete}, firstnext, firstnext_concurrent, slot, + {group, match}, t_match_spec_run, + {group, lookup_element}, {group, misc}, {group, files}, + {group, heavy}, ordered, ordered_match, + interface_equality, fixtable_next, fixtable_insert, + rename, rename_unnamed, evil_rename, update_element, + update_counter, evil_update_counter, partly_bound, + match_heavy, {group, fold}, member, t_delete_object, + t_init_table, t_whitebox, t_delete_all_objects, + t_insert_list, t_test_ms, t_select_delete, t_ets_dets, + memory, t_select_reverse, t_bucket_disappears, + select_fail, t_insert_new, t_repair_continuation, + otp_5340, otp_6338, otp_6842_select_1000, otp_7665, + otp_8732, meta_wb, grow_shrink, grow_pseudo_deleted, + shrink_pseudo_deleted, {group, meta_smp}, smp_insert, + smp_fixed_delete, smp_unfix_fix, smp_select_delete, + otp_8166, exit_large_table_owner, + exit_many_large_table_owner, exit_many_tables_owner, + exit_many_many_tables_owner, write_concurrency, heir, + give_away, setopts, bad_table, types, + otp_9423]. + +groups() -> + [{new, [], + [default, setbag, badnew, verybadnew, named, keypos2, + privacy]}, + {insert, [], [empty, badinsert]}, + {lookup, [], [time_lookup, badlookup, lookup_order]}, + {lookup_element, [], [lookup_element_mult]}, + {delete, [], + [delete_elem, delete_tab, delete_large_tab, + delete_large_named_table, evil_delete, table_leak, + baddelete, match_delete, match_delete3]}, + {match, [], + [match1, match2, match_object, match_object2]}, + {misc, [], + [misc1, safe_fixtable, info, dups, tab2list]}, + {files, [], + [tab2file, tab2file2, tabfile_ext1, + tabfile_ext2, tabfile_ext3, tabfile_ext4]}, + {heavy, [], + [heavy_lookup, heavy_lookup_element, heavy_concurrent]}, + {fold, [], + [foldl_ordered, foldr_ordered, foldl, foldr, + fold_empty]}, + {meta_smp, [], + [meta_lookup_unnamed_read, meta_lookup_unnamed_write, + meta_lookup_named_read, meta_lookup_named_write, + meta_newdel_unnamed, meta_newdel_named]}]. + +init_per_suite(Config) -> + Config. end_per_suite(_Config) -> stop_spawn_logger(), catch erts_debug:set_internal_state(available_internal_state, false). -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. -all(suite) -> - [ - new,insert,lookup,delete,firstnext,firstnext_concurrent,slot,match, - t_match_spec_run, - lookup_element, misc,files, heavy, - ordered, ordered_match, interface_equality, - fixtable_next, fixtable_insert, rename, rename_unnamed, evil_rename, - update_element, update_counter, evil_update_counter, partly_bound, - match_heavy, fold, member, - t_delete_object, t_init_table, t_whitebox, - t_delete_all_objects, t_insert_list, t_test_ms, - t_select_delete, t_ets_dets, memory, - t_bucket_disappears, - select_fail,t_insert_new, t_repair_continuation, otp_5340, otp_6338, - otp_6842_select_1000, otp_7665, - meta_wb, - grow_shrink, grow_pseudo_deleted, shrink_pseudo_deleted, - meta_smp, - smp_insert, smp_fixed_delete, smp_unfix_fix, smp_select_delete, otp_8166, - exit_large_table_owner, - exit_many_large_table_owner, - exit_many_tables_owner, - exit_many_many_tables_owner, - write_concurrency, heir, give_away, setopts, - bad_table - ]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -153,7 +200,7 @@ t_bucket_disappears(Config) when is_list(Config) -> t_bucket_disappears_do(Opts) -> ?line EtsMem = etsmem(), - ?line ets:new(abcd, [named_table, public, {keypos, 2} | Opts]), + ?line ets_new(abcd, [named_table, public, {keypos, 2} | Opts]), ?line ets:insert(abcd, {abcd,1,2}), ?line ets:insert(abcd, {abcd,2,2}), ?line ets:insert(abcd, {abcd,3,2}), @@ -171,29 +218,180 @@ t_match_spec_run(suite) -> t_match_spec_run(doc) -> ["Check ets:match_spec_run/2."]; t_match_spec_run(Config) when is_list(Config) -> + init_externals(), ?line EtsMem = etsmem(), - ?line [2,3] = ets:match_spec_run([{1},{2},{3}], - ets:match_spec_compile( - [{{'$1'},[{'>','$1',1}],['$1']}])), + + t_match_spec_run_test([{1},{2},{3}], + [{{'$1'},[{'>','$1',1}],['$1']}], + [2,3]), + ?line Huge = [{X} || X <- lists:seq(1,2500)], ?line L = lists:seq(2476,2500), - ?line L = ets:match_spec_run(Huge, - ets:match_spec_compile( - [{{'$1'},[{'>','$1',2475}],['$1']}])), + t_match_spec_run_test(Huge, [{{'$1'},[{'>','$1',2475}],['$1']}], L), + ?line L2 = [{X*16#FFFFFFF} || X <- L], - ?line L2 = ets:match_spec_run(Huge, - ets:match_spec_compile( - [{{'$1'}, - [{'>','$1',2475}], - [{{{'*','$1',16#FFFFFFF}}}]}])), - ?line [500,1000,1500,2000,2500] = - ets:match_spec_run(Huge, - ets:match_spec_compile( - [{{'$1'}, - [{'=:=',{'rem','$1',500},0}], - ['$1']}])), + t_match_spec_run_test(Huge, + [{{'$1'}, [{'>','$1',2475}], [{{{'*','$1',16#FFFFFFF}}}]}], + L2), + + t_match_spec_run_test(Huge, [{{'$1'}, [{'=:=',{'rem','$1',500},0}], ['$1']}], + [500,1000,1500,2000,2500]), + + %% More matching fun with several match clauses and guards, + %% applied to a variety of terms. + Fun = fun(Term) -> + CTerm = {const, Term}, + + N_List = [{Term, "0", "v-element"}, + {"=hidden_node", "0", Term}, + {"0", Term, Term}, + {"something", Term, "something else"}, + {"guard and res", Term, 872346}, + {Term, {'and',Term,'again'}, 3.14}, + {Term, {'and',Term,'again'}, "m&g"}, + {Term, {'and',Term,'again'}, "m&g&r"}, + {[{second,Term}, 'and', "tail"], Term, ['and',"tail"]}], + + N_MS = [{{'$1','$2','$3'}, + [{'=:=','$1',CTerm}, {'=:=','$2',{const,"0"}}], + [{{"Guard only for $1",'$3'}}]}, + + {{'$3','$1','$4'}, + [{'=:=','$3',"=hidden_node"}, {'=:=','$1',{const,"0"}}], + [{{"Result only for $4",'$4'}}]}, + + {{'$2','$1','$1'}, + [{'=:=','$2',{const,"0"}}], + [{{"Match only for $1",'$2'}}]}, + + {{'$2',Term,['$3'|'_']}, + [{is_list,'$2'},{'=:=','$3',$s}], + [{{"Matching term",'$2'}}]}, + + {{'$1','$2',872346}, + [{'=:=','$2',CTerm}, {is_list,'$1'}], + [{{"Guard and result",'$2'}}]}, + + {{'$1', {'and','$1','again'}, '$2'}, + [{is_float,'$2'}], + [{{"Match and result",'$1'}}]}, + + {{'$1', {'and','$1','again'}, '$2'}, + [{'=:=','$1',CTerm}, {'=:=', '$2', "m&g"}], + [{{"Match and guard",'$2'}}]}, + + {{'$1', {'and','$1','again'}, "m&g&r"}, + [{'=:=','$1',CTerm}], + [{{"Match, guard and result",'$1'}}]}, + + {{'$1', '$2', '$3'}, + [{'=:=','$1',[{{second,'$2'}} | '$3']}], + [{{"Building guard"}}]} + ], + + N_Result = [{"Guard only for $1", "v-element"}, + {"Result only for $4", Term}, + {"Match only for $1", "0"}, + {"Matching term","something"}, + {"Guard and result",Term}, + {"Match and result",Term}, + {"Match and guard","m&g"}, + {"Match, guard and result",Term}, + {"Building guard"}], + + F = fun(N_MS_Perm) -> + t_match_spec_run_test(N_List, N_MS_Perm, N_Result) + end, + repeat_for_permutations(F, N_MS) + end, + + test_terms(Fun, skip_refc_check), + ?line verify_etsmem(EtsMem). +t_match_spec_run_test(List, MS, Result) -> + + %%io:format("ms = ~p\n",[MS]), + + ?m(Result, ets:match_spec_run(List, ets:match_spec_compile(MS))), + + %% Check that ets:select agree + Tab = ets:new(xxx, [bag]), + ets:insert(Tab, List), + SRes = lists:sort(Result), + ?m(SRes, lists:sort(ets:select(Tab, MS))), + ets:delete(Tab), + + %% Check that tracing agree + Self = self(), + {Tracee, MonRef} = spawn_monitor(fun() -> ms_tracee(Self, List) end), + receive {Tracee, ready} -> ok end, + + MST = lists:map(fun(Clause) -> ms_clause_ets_to_trace(Clause) end, MS), + + %%io:format("MS = ~p\nMST= ~p\n",[MS,MST]), + + erlang:trace_pattern({?MODULE,ms_tracee_dummy,'_'}, MST , [local]), + erlang:trace(Tracee, true, [call]), + Tracee ! start, + TRes = ms_tracer_collect(Tracee, MonRef, []), + %erlang:trace(Tracee, false, [call]), + %Tracee ! stop, + case TRes of + SRes -> ok; + _ -> + io:format("TRACE MATCH FAILED\n"), + io:format("Input = ~p\nMST = ~p\nExpected = ~p\nGot = ~p\n", [List, MST, SRes, TRes]), + ?t:fail("TRACE MATCH FAILED") + end, + ok. + + + +ms_tracer_collect(Tracee, Ref, Acc) -> + receive + {trace, Tracee, call, _Args, [Msg]} -> + %io:format("trace Args=~p Msg=~p\n", [_Args, Msg]), + ms_tracer_collect(Tracee, Ref, [Msg | Acc]); + + {'DOWN', Ref, process, Tracee, _} -> + %io:format("monitor DOWN for ~p\n", [Tracee]), + TDRef = erlang:trace_delivered(Tracee), + ms_tracer_collect(Tracee, TDRef, Acc); + + {trace_delivered, Tracee, Ref} -> + %%io:format("trace delivered for ~p\n", [Tracee]), + lists:sort(Acc); + + Other -> + io:format("Unexpected message = ~p\n", [Other]), + ?t:fail("Unexpected tracer msg") + end. + + +ms_tracee(Parent, CallArgList) -> + %io:format("ms_tracee ~p started with ArgList = ~p\n", [self(), CallArgList]), + Parent ! {self(), ready}, + receive start -> ok end, + lists:foreach(fun(Args) -> + erlang:apply(?MODULE, ms_tracee_dummy, tuple_to_list(Args)) + end, CallArgList). + %%receive stop -> ok end. + + + +ms_tracee_dummy(_) -> ok. +ms_tracee_dummy(_,_) -> ok. +ms_tracee_dummy(_,_,_) -> ok. +ms_tracee_dummy(_,_,_,_) -> ok. + +ms_clause_ets_to_trace({Head, Guard, Body}) -> + {tuple_to_list(Head), Guard, [{message, Body}]}. + +assert_eq(A,A) -> ok; +assert_eq(A,B) -> + io:format("FAILED MATCH:\n~p\n =/=\n~p\n",[A,B]), + ?t:fail("assert_eq failed"). t_repair_continuation(suite) -> @@ -209,7 +407,7 @@ t_repair_continuation_do(Opts) -> ?line MS = [{'_',[],[true]}], ?line MS2 = [{{{'$1','_'},'_'},[],['$1']}], (fun() -> - ?line T = ets:new(x,[ordered_set|Opts]), + ?line T = ets_new(x,[ordered_set|Opts]), ?line F = fun(0,_)->ok;(N,F) -> ets:insert(T,{N,N}), F(N-1,F) end, ?line F(1000,F), ?line {_,C} = ets:select(T,MS,5), @@ -221,7 +419,7 @@ t_repair_continuation_do(Opts) -> ?line true = ets:delete(T) end)(), (fun() -> - ?line T = ets:new(x,[ordered_set|Opts]), + ?line T = ets_new(x,[ordered_set|Opts]), ?line F = fun(0,_)->ok;(N,F) -> ets:insert(T,{N,N}), F(N-1,F) end, ?line F(1000,F), ?line {_,C} = ets:select(T,MS,1001), @@ -233,7 +431,7 @@ t_repair_continuation_do(Opts) -> end)(), (fun() -> - ?line T = ets:new(x,[ordered_set|Opts]), + ?line T = ets_new(x,[ordered_set|Opts]), ?line F = fun(0,_)->ok;(N,F) -> ets:insert(T,{integer_to_list(N),N}), F(N-1,F) @@ -248,7 +446,7 @@ t_repair_continuation_do(Opts) -> ?line true = ets:delete(T) end)(), (fun() -> - ?line T = ets:new(x,[ordered_set|Opts]), + ?line T = ets_new(x,[ordered_set|Opts]), ?line F = fun(0,_)->ok;(N,F) -> ets:insert(T,{{integer_to_list(N),N},N}), F(N-1,F) @@ -264,7 +462,7 @@ t_repair_continuation_do(Opts) -> end)(), (fun() -> - ?line T = ets:new(x,[set|Opts]), + ?line T = ets_new(x,[set|Opts]), ?line F = fun(0,_)->ok;(N,F) -> ets:insert(T,{N,N}), F(N-1,F) @@ -279,7 +477,7 @@ t_repair_continuation_do(Opts) -> ?line true = ets:delete(T) end)(), (fun() -> - ?line T = ets:new(x,[set|Opts]), + ?line T = ets_new(x,[set|Opts]), ?line F = fun(0,_)->ok;(N,F) -> ets:insert(T,{integer_to_list(N),N}), F(N-1,F) @@ -294,7 +492,7 @@ t_repair_continuation_do(Opts) -> ?line true = ets:delete(T) end)(), (fun() -> - ?line T = ets:new(x,[bag|Opts]), + ?line T = ets_new(x,[bag|Opts]), ?line F = fun(0,_)->ok;(N,F) -> ets:insert(T,{integer_to_list(N),N}), F(N-1,F) @@ -309,7 +507,7 @@ t_repair_continuation_do(Opts) -> ?line true = ets:delete(T) end)(), (fun() -> - ?line T = ets:new(x,[duplicate_bag|Opts]), + ?line T = ets_new(x,[duplicate_bag|Opts]), ?line F = fun(0,_)->ok;(N,F) -> ets:insert(T,{integer_to_list(N),N}), F(N-1,F) @@ -327,21 +525,22 @@ t_repair_continuation_do(Opts) -> ?line true = ets:is_compiled_ms(ets:match_spec_compile(MS)), ?line verify_etsmem(EtsMem). -new(suite) -> [default,setbag,badnew,verybadnew,named,keypos2,privacy]. default(doc) -> - ["Test case to check that a new ets table is defined as a `set' and " - "`protected'"]; + ["Check correct default vaules of a new ets table"]; default(suite) -> []; default(Config) when is_list(Config) -> %% Default should be set,protected - repeat_for_opts(default_do). - -default_do(Opts) -> ?line EtsMem = etsmem(), - ?line Def = ets:new(def,Opts), + ?line Def = ets_new(def,[]), ?line set = ets:info(Def,type), ?line protected = ets:info(Def,protection), + Compressed = erlang:system_info(ets_always_compress), + ?line Compressed = ets:info(Def,compressed), + Self = self(), + ?line Self = ets:info(Def,owner), + ?line none = ets:info(Def, heir), + ?line false = ets:info(Def,named_table), ?line ets:delete(Def), ?line verify_etsmem(EtsMem). @@ -355,7 +554,7 @@ select_fail(Config) when is_list(Config) -> ?line verify_etsmem(EtsMem). select_fail_do(Opts) -> - ?line T = ets:new(x,Opts), + ?line T = ets_new(x,Opts), ?line ets:insert(T,{a,a}), ?line case (catch ets:select(T,[{{a,'_'},[],[{snuffla}]}])) of @@ -378,20 +577,27 @@ select_fail_do(Opts) -> -define(S(T),ets:info(T,memory)). -define(TAB_STRUCT_SZ, erts_debug:get_internal_state('DbTable_words')). --define(NORMAL_TAB_STRUCT_SZ, 26). %% SunOS5.8, 32-bit, non smp, private heap +%%-define(NORMAL_TAB_STRUCT_SZ, 26). %% SunOS5.8, 32-bit, non smp, private heap %% %% The hardcoded expected memory sizes (in words) are the ones we expect on: %% SunOS5.8, 32-bit, non smp, private heap %% -memory(doc) -> - ["Whitebox test of ets:info(X,memory)"]; -memory(suite) -> - []; +memory(doc) -> ["Whitebox test of ets:info(X,memory)"]; +memory(suite) -> []; memory(Config) when is_list(Config) -> ?line erts_debug:set_internal_state(available_internal_state, true), ?line ok = chk_normal_tab_struct_size(), - ?line L = [T1,T2,T3,T4] = fill_sets_int(1000), - ?line XRes1 = adjust_xmem(L, {16862,16072,16072,16078}), + repeat_for_opts(memory_do,[compressed]), + ?line catch erts_debug:set_internal_state(available_internal_state, false). + +memory_do(Opts) -> + ?line L = [T1,T2,T3,T4] = fill_sets_int(1000,Opts), + XR1 = case mem_mode(T1) of + {normal,_} -> {13836,13046,13046,13052}; %{13862,13072,13072,13078}; + {compressed,4} -> {11041,10251,10251,10252}; %{11067,10277,10277,10278}; + {compressed,8} -> {10050,9260,9260,9260} %{10076,9286,9286,9286} + end, + ?line XRes1 = adjust_xmem(L, XR1), ?line Res1 = {?S(T1),?S(T2),?S(T3),?S(T4)}, ?line lists:foreach(fun(T) -> Before = ets:info(T,size), @@ -402,7 +608,12 @@ memory(Config) when is_list(Config) -> [Key, ets:info(T,type), Before, ets:info(T,size), Objs]) end, L), - ?line XRes2 = adjust_xmem(L, {16849,16060,16048,16054}), + XR2 = case mem_mode(T1) of + {normal,_} -> {13826,13037,13028,13034}; %{13852,13063,13054,13060}; + {compressed,4} -> {11031,10242,10233,10234}; %{11057,10268,10259,10260}; + {compressed,8} -> {10040,9251,9242,9242} %10066,9277,9268,9268} + end, + ?line XRes2 = adjust_xmem(L, XR2), ?line Res2 = {?S(T1),?S(T2),?S(T3),?S(T4)}, ?line lists:foreach(fun(T) -> Before = ets:info(T,size), @@ -413,13 +624,18 @@ memory(Config) when is_list(Config) -> [Key, ets:info(T,type), Before, ets:info(T,size), Objs]) end, L), - ?line XRes3 = adjust_xmem(L, {16836,16048,16024,16030}), + XR3 = case mem_mode(T1) of + {normal,_} -> {13816,13028,13010,13016}; %{13842,13054,13036,13042}; + {compressed,4} -> {11021,10233,10215,10216}; %{11047,10259,10241,10242}; + {compressed,8} -> {10030,9242,9224,9224} %{10056,9268,9250,9250} + end, + ?line XRes3 = adjust_xmem(L, XR3), ?line Res3 = {?S(T1),?S(T2),?S(T3),?S(T4)}, ?line lists:foreach(fun(T) -> ?line ets:delete_all_objects(T) end, L), - ?line XRes4 = adjust_xmem(L, {76,286,286,286}), + ?line XRes4 = adjust_xmem(L, {50,260,260,260}), %{76,286,286,286}), ?line Res4 = {?S(T1),?S(T2),?S(T3),?S(T4)}, lists:foreach(fun(T) -> ?line ets:delete(T) @@ -430,9 +646,9 @@ memory(Config) when is_list(Config) -> ?line ets:select_delete(T,[{'_',[],[true]}]) end, L2), - ?line XRes5 = adjust_xmem(L2, {76,286,286,286}), + ?line XRes5 = adjust_xmem(L2, {50,260,260,260}), %{76,286,286,286}), ?line Res5 = {?S(T11),?S(T12),?S(T13),?S(T14)}, - ?line ?t:format("XRes1 = ~p~n" + ?line io:format("XRes1 = ~p~n" " Res1 = ~p~n~n" "XRes2 = ~p~n" " Res2 = ~p~n~n" @@ -452,9 +668,15 @@ memory(Config) when is_list(Config) -> ?line XRes3 = Res3, ?line XRes4 = Res4, ?line XRes5 = Res5, - ?line catch erts_debug:set_internal_state(available_internal_state, false), ?line ok. +mem_mode(T) -> + {case ets:info(T,compressed) of + true -> compressed; + false -> normal + end, + erlang:system_info(wordsize)}. + chk_normal_tab_struct_size() -> ?line System = {os:type(), os:version(), @@ -462,36 +684,58 @@ chk_normal_tab_struct_size() -> erlang:system_info(smp_support), erlang:system_info(heap_type)}, ?line ?t:format("System = ~p~n", [System]), - ?line ?t:format("?NORMAL_TAB_STRUCT_SZ=~p~n", [?NORMAL_TAB_STRUCT_SZ]), + %%?line ?t:format("?NORMAL_TAB_STRUCT_SZ=~p~n", [?NORMAL_TAB_STRUCT_SZ]), ?line ?t:format("?TAB_STRUCT_SZ=~p~n", [?TAB_STRUCT_SZ]), - ?line case System of - {{unix, sunos}, {5, 8, 0}, 4, false, private} -> - ?line ?NORMAL_TAB_STRUCT_SZ = ?TAB_STRUCT_SZ, - ?line ok; - _ -> - ?line ok - end. - -adjust_xmem([T1,T2,T3,T4], {A0,B0,C0,D0} = Mem0) -> + ok. +% ?line case System of +% {{unix, sunos}, {5, 8, 0}, 4, false, private} -> +% ?line ?NORMAL_TAB_STRUCT_SZ = ?TAB_STRUCT_SZ, +% ?line ok; +% _ -> +% ?line ok +% end. + +-define(DB_TREE_STACK_NEED,50). % The static stack for a tree, in halfword pointers are two internal words + % so the stack gets twice as big +-define(DB_HASH_SIZEOF_EXTSEG,260). % The segment size in words, in halfword this will be twice as large. + +adjust_xmem([T1,T2,T3,T4], {A0,B0,C0,D0} = _Mem0) -> %% Adjust for 64-bit, smp, and os: %% Table struct size may differ. - Mem1 = case ?TAB_STRUCT_SZ of - ?NORMAL_TAB_STRUCT_SZ -> - Mem0; - TabStructSz -> - TabDiff = TabStructSz - ?NORMAL_TAB_STRUCT_SZ, - {A0+TabDiff, B0+TabDiff, C0+TabDiff, D0+TabDiff} - end, + +% Mem1 = case ?TAB_STRUCT_SZ of +% ?NORMAL_TAB_STRUCT_SZ -> +% Mem0; +% TabStructSz -> +% TabDiff = TabStructSz - ?NORMAL_TAB_STRUCT_SZ, +% {A0+TabDiff, B0+TabDiff, C0+TabDiff, D0+TabDiff} +% end, + + TabDiff = ?TAB_STRUCT_SZ, + Mem1 = {A0+TabDiff, B0+TabDiff, C0+TabDiff, D0+TabDiff}, + + Mem2 = case {erlang:system_info({wordsize,internal}),erlang:system_info({wordsize,external})} of + %% Halfword, corrections for regular pointers occupying two internal words. + {4,8} -> + {A1,B1,C1,D1} = Mem1, + {A1+4*ets:info(T1, size)+?DB_TREE_STACK_NEED, + B1+3*ets:info(T2, size)+?DB_HASH_SIZEOF_EXTSEG, + C1+3*ets:info(T3, size)+?DB_HASH_SIZEOF_EXTSEG, + D1+3*ets:info(T4, size)+?DB_HASH_SIZEOF_EXTSEG}; + _ -> + Mem1 + end, + %% Adjust for hybrid and shared heaps: %% Each record is one word smaller. - Mem2 = case erlang:system_info(heap_type) of - private -> - Mem1; - _ -> - {A1,B1,C1,D1} = Mem1, - {A1-ets:info(T1, size),B1-ets:info(T2, size), - C1-ets:info(T3, size),D1-ets:info(T4, size)} - end, + %%Mem2 = case erlang:system_info(heap_type) of + %% private -> + %% Mem1; + %% _ -> + %% {A1,B1,C1,D1} = Mem1, + %% {A1-ets:info(T1, size),B1-ets:info(T2, size), + %% C1-ets:info(T3, size),D1-ets:info(T4, size)} + %% end, %%{Mem2,{ets:info(T1,stats),ets:info(T2,stats),ets:info(T3,stats),ets:info(T4,stats)}}. Mem2. @@ -510,7 +754,7 @@ t_whitebox(Config) when is_list(Config) -> ?line verify_etsmem(EtsMem). whitebox_1(Opts) -> - ?line T=ets:new(x,[bag | Opts]), + ?line T=ets_new(x,[bag | Opts]), ?line ets:insert(T,[{du,glade},{ta,en}]), ?line ets:insert(T,[{hej,hopp2},{du,glade2},{ta,en2}]), ?line {_,C}=ets:match(T,{ta,'$1'},1), @@ -520,8 +764,8 @@ whitebox_1(Opts) -> ok. whitebox_2(Opts) -> - ?line T=ets:new(x,[ordered_set, {keypos,2} | Opts]), - ?line T2=ets:new(x,[set, {keypos,2}| Opts]), + ?line T=ets_new(x,[ordered_set, {keypos,2} | Opts]), + ?line T2=ets_new(x,[set, {keypos,2}| Opts]), ?line 0 = ets:select_delete(T,[{{hej},[],[true]}]), ?line 0 = ets:select_delete(T,[{{hej,hopp},[],[true]}]), ?line 0 = ets:select_delete(T2,[{{hej},[],[true]}]), @@ -543,7 +787,7 @@ t_ets_dets(Config, Opts) -> ?line (catch file:delete(Fname)), ?line {ok,DTab} = dets:open_file(testdets_1, [{file, Fname}]), - ?line ETab = ets:new(x,Opts), + ?line ETab = ets_new(x,Opts), ?line filltabint(ETab,3000), ?line DTab = ets:to_dets(ETab,DTab), ?line ets:delete_all_objects(ETab), @@ -555,7 +799,7 @@ t_ets_dets(Config, Opts) -> (catch ets:to_dets(ETab,DTab)), ?line {'EXIT',{badarg,[{ets,from_dets,[ETab,DTab]}|_]}} = (catch ets:from_dets(ETab,DTab)), - ?line ETab2 = ets:new(x,Opts), + ?line ETab2 = ets_new(x,Opts), ?line filltabint(ETab2,3000), ?line dets:close(DTab), ?line {'EXIT',{badarg,[{ets,to_dets,[ETab2,DTab]}|_]}} = @@ -575,8 +819,16 @@ t_delete_all_objects(Config) when is_list(Config) -> repeat_for_opts(t_delete_all_objects_do), ?line verify_etsmem(EtsMem). +get_kept_objects(T) -> + case ets:info(T,stats) of + false -> + 0; + {_,_,_,_,_,_,KO} -> + KO + end. + t_delete_all_objects_do(Opts) -> - ?line T=ets:new(x,Opts), + ?line T=ets_new(x,Opts), ?line filltabint(T,4000), ?line O=ets:first(T), ?line ets:next(T,O), @@ -584,10 +836,10 @@ t_delete_all_objects_do(Opts) -> ?line true = ets:delete_all_objects(T), ?line '$end_of_table' = ets:next(T,O), ?line 0 = ets:info(T,size), - ?line 4000 = ets:info(T,kept_objects), + ?line 4000 = get_kept_objects(T), ?line ets:safe_fixtable(T,false), ?line 0 = ets:info(T,size), - ?line 0 = ets:info(T,kept_objects), + ?line 0 = get_kept_objects(T), ?line filltabint(T,4000), ?line 4000 = ets:info(T,size), ?line true = ets:delete_all_objects(T), @@ -605,7 +857,7 @@ t_delete_object(Config) when is_list(Config) -> ?line verify_etsmem(EtsMem). t_delete_object_do(Opts) -> - ?line T = ets:new(x,Opts), + ?line T = ets_new(x,Opts), ?line filltabint(T,4000), ?line del_one_by_one_set(T,1,4001), ?line filltabint(T,4000), @@ -617,24 +869,24 @@ t_delete_object_do(Opts) -> ?line ets:delete_object(T,{First, integer_to_list(First)}), ?line Next = ets:next(T,First), ?line 3999 = ets:info(T,size), - ?line 1 = ets:info(T,kept_objects), + ?line 1 = get_kept_objects(T), ?line ets:safe_fixtable(T,false), ?line 3999 = ets:info(T,size), - ?line 0 = ets:info(T,kept_objects), + ?line 0 = get_kept_objects(T), ?line ets:delete(T), - ?line T1 = ets:new(x,[ordered_set | Opts]), + ?line T1 = ets_new(x,[ordered_set | Opts]), ?line filltabint(T1,4000), ?line del_one_by_one_set(T1,1,4001), ?line filltabint(T1,4000), ?line del_one_by_one_set(T1,4000,0), ?line ets:delete(T1), - ?line T2 = ets:new(x,[bag | Opts]), + ?line T2 = ets_new(x,[bag | Opts]), ?line filltabint2(T2,4000), ?line del_one_by_one_bag(T2,1,4001), ?line filltabint2(T2,4000), ?line del_one_by_one_bag(T2,4000,0), ?line ets:delete(T2), - ?line T3 = ets:new(x,[duplicate_bag | Opts]), + ?line T3 = ets_new(x,[duplicate_bag | Opts]), ?line filltabint3(T3,4000), ?line del_one_by_one_dbag_1(T3,1,4001), ?line filltabint3(T3,4000), @@ -681,7 +933,7 @@ t_init_table(Config) when is_list(Config)-> ?line verify_etsmem(EtsMem). t_init_table_do(Opts) -> - ?line T = ets:new(x,[duplicate_bag | Opts]), + ?line T = ets_new(x,[duplicate_bag | Opts]), ?line filltabint(T,4000), ?line ets:init_table(T, make_init_fun(1)), ?line del_one_by_one_dbag_1(T,4000,0), @@ -763,7 +1015,7 @@ t_insert_list(Config) when is_list(Config) -> ?line verify_etsmem(EtsMem). t_insert_list_do(Opts) -> - ?line T = ets:new(x,[duplicate_bag | Opts]), + ?line T = ets_new(x,[duplicate_bag | Opts]), ?line do_fill_dbag_using_lists(T,4000), ?line del_one_by_one_dbag_2(T,4000,0), ?line ets:delete(T). @@ -786,6 +1038,67 @@ t_test_ms(Config) when is_list(Config) -> ?line true = (if is_list(String) -> true; true -> false end), ?line verify_etsmem(EtsMem). +t_select_reverse(doc) -> + ["Test the select reverse BIF's"]; +t_select_reverse(suite) -> + []; +t_select_reverse(Config) when is_list(Config) -> + ?line Table = ets_new(xxx, [ordered_set]), + ?line filltabint(Table,1000), + ?line A = lists:reverse(ets:select(Table,[{{'$1', '_'}, + [{'>', + {'rem', + '$1', 5}, + 2}], + ['$_']}])), + ?line A = ets:select_reverse(Table,[{{'$1', '_'}, + [{'>', + {'rem', + '$1', 5}, + 2}], + ['$_']}]), + ?line A = reverse_chunked(Table,[{{'$1', '_'}, + [{'>', + {'rem', + '$1', 5}, + 2}], + ['$_']}],3), + % A set/bag/duplicate_bag should get the same result regardless + % of select or select_reverse + ?line Table2 = ets_new(xxx, [set]), + ?line filltabint(Table2,1000), + ?line Table3 = ets_new(xxx, [bag]), + ?line filltabint(Table3,1000), + ?line Table4 = ets_new(xxx, [duplicate_bag]), + ?line filltabint(Table4,1000), + ?line lists:map(fun(Tab) -> + B = ets:select(Tab,[{{'$1', '_'}, + [{'>', + {'rem', + '$1', 5}, + 2}], + ['$_']}]), + B = ets:select_reverse(Tab,[{{'$1', '_'}, + [{'>', + {'rem', + '$1', 5}, + 2}], + ['$_']}]) + end,[Table2, Table3, Table4]), + ok. + + + +reverse_chunked(T,MS,N) -> + do_reverse_chunked(ets:select_reverse(T,MS,N),[]). + +do_reverse_chunked('$end_of_table',Acc) -> + lists:reverse(Acc); +do_reverse_chunked({L,C},Acc) -> + NewAcc = lists:reverse(L)++Acc, + do_reverse_chunked(ets:select_reverse(C), NewAcc). + + t_select_delete(doc) -> ["Test the ets:select_delete/2 and ets:select_count/2 BIF's"]; t_select_delete(suite) -> @@ -1064,8 +1377,8 @@ random_test() -> do_random_test() -> ?line EtsMem = etsmem(), - ?line OrdSet = ets:new(xxx,[ordered_set]), - ?line Set = ets:new(xxx,[]), + ?line OrdSet = ets_new(xxx,[ordered_set]), + ?line Set = ets_new(xxx,[]), ?line do_n_times(fun() -> ?line Key = create_random_string(25), ?line Value = create_random_tuple(25), @@ -1269,8 +1582,8 @@ update_element_opts(Opts) -> update_element_opts(Tuple,KeyPos,UpdPos,Opts) -> - Set = ets:new(set,[{keypos,KeyPos} | Opts]), - OrdSet = ets:new(ordered_set,[ordered_set,{keypos,KeyPos} | Opts]), + Set = ets_new(set,[{keypos,KeyPos} | Opts]), + OrdSet = ets_new(ordered_set,[ordered_set,{keypos,KeyPos} | Opts]), update_element(Set,Tuple,KeyPos,UpdPos), update_element(OrdSet,Tuple,KeyPos,UpdPos), true = ets:delete(Set), @@ -1278,7 +1591,7 @@ update_element_opts(Tuple,KeyPos,UpdPos,Opts) -> ok. update_element(T,Tuple,KeyPos,UpdPos) -> - KeyList = [Key || Key <- lists:seq(1,100)], + KeyList = [17,"seventeen",<<"seventeen">>,{17},list_to_binary(lists:seq(1,100)),make_ref(), self()], lists:foreach(fun(Key) -> TupleWithKey = setelement(KeyPos,Tuple,Key), update_element_do(T,TupleWithKey,Key,UpdPos) @@ -1292,6 +1605,8 @@ update_element_do(Tab,Tuple,Key,UpdPos) -> % This will try all combinations of {fromValue,toValue} % % IMPORTANT: size(Values) must be a prime number for this to work!!! + + %io:format("update_element_do for key=~p\n",[Key]), Big32 = 16#12345678, Big64 = 16#123456789abcdef0, Values = { 623, -27, 0, Big32, -Big32, Big64, -Big64, Big32*Big32, @@ -1312,14 +1627,6 @@ update_element_do(Tab,Tuple,Key,UpdPos) -> (ToIx, [], Pos, _Rand, _MeF) -> {Pos, element(ToIx+1,Values)} % single {pos,value} arg end, - - NewTupleF = fun({Pos,Val}, Tpl, _MeF) -> - setelement(Pos, Tpl, Val); - ([{Pos,Val} | Tail], Tpl, MeF) -> - MeF(Tail,setelement(Pos, Tpl, Val),MeF); - ([], Tpl, _MeF) -> - Tpl - end, UpdateF = fun(ToIx,Rand) -> PosValArg = PosValArgF(ToIx,[],UpdPos,Rand,PosValArgF), @@ -1327,7 +1634,7 @@ update_element_do(Tab,Tuple,Key,UpdPos) -> ArgHash = erlang:phash2({Tab,Key,PosValArg}), ?line true = ets:update_element(Tab, Key, PosValArg), ?line ArgHash = erlang:phash2({Tab,Key,PosValArg}), - NewTuple = NewTupleF(PosValArg,Tuple,NewTupleF), + NewTuple = update_tuple(PosValArg,Tuple), ?line [NewTuple] = ets:lookup(Tab,Key) end, @@ -1355,9 +1662,18 @@ update_element_do(Tab,Tuple,Key,UpdPos) -> ?line Checksum = (Length-1)*Length*(Length+1) div 2, % if Length is a prime ok. +update_tuple({Pos,Val}, Tpl) -> + setelement(Pos, Tpl, Val); +update_tuple([{Pos,Val} | Tail], Tpl) -> + update_tuple(Tail,setelement(Pos, Tpl, Val)); +update_tuple([], Tpl) -> + Tpl. + + + update_element_neg(Opts) -> - Set = ets:new(set,Opts), - OrdSet = ets:new(ordered_set,[ordered_set | Opts]), + Set = ets_new(set,Opts), + OrdSet = ets_new(ordered_set,[ordered_set | Opts]), update_element_neg_do(Set), update_element_neg_do(OrdSet), ets:delete(Set), @@ -1365,8 +1681,8 @@ update_element_neg(Opts) -> ets:delete(OrdSet), ?line {'EXIT',{badarg,_}} = (catch ets:update_element(OrdSet,key,{2,1})), - ?line Bag = ets:new(bag,[bag | Opts]), - ?line DBag = ets:new(duplicate_bag,[duplicate_bag | Opts]), + ?line Bag = ets_new(bag,[bag | Opts]), + ?line DBag = ets_new(duplicate_bag,[duplicate_bag | Opts]), ?line {'EXIT',{badarg,_}} = (catch ets:update_element(Bag,key,{2,1})), ?line {'EXIT',{badarg,_}} = (catch ets:update_element(DBag,key,{2,1})), true = ets:delete(Bag), @@ -1416,8 +1732,8 @@ update_counter(Config) when is_list(Config) -> ?line verify_etsmem(EtsMem). update_counter_do(Opts) -> - Set = ets:new(set,Opts), - OrdSet = ets:new(ordered_set,[ordered_set | Opts]), + Set = ets_new(set,Opts), + OrdSet = ets_new(ordered_set,[ordered_set | Opts]), update_counter_for(Set), update_counter_for(OrdSet), ets:delete(Set), @@ -1438,6 +1754,7 @@ update_counter_for(T) -> (Obj, Times, Arg3, Myself) -> ?line {NewObj, Ret} = uc_mimic(Obj,Arg3), ArgHash = erlang:phash2({T,a,Arg3}), + %%io:format("update_counter(~p, ~p, ~p) expecting ~p\n",[T,a,Arg3,Ret]), ?line Ret = ets:update_counter(T,a,Arg3), ?line ArgHash = erlang:phash2({T,a,Arg3}), %%io:format("NewObj=~p~n ",[NewObj]), @@ -1563,8 +1880,8 @@ uc_adder(Init, {_Pos, Add, Thres, Warp}) -> end. update_counter_neg(Opts) -> - Set = ets:new(set,Opts), - OrdSet = ets:new(ordered_set,[ordered_set | Opts]), + Set = ets_new(set,Opts), + OrdSet = ets_new(ordered_set,[ordered_set | Opts]), update_counter_neg_for(Set), update_counter_neg_for(OrdSet), ets:delete(Set), @@ -1572,8 +1889,8 @@ update_counter_neg(Opts) -> ets:delete(OrdSet), ?line {'EXIT',{badarg,_}} = (catch ets:update_counter(OrdSet,key,1)), - ?line Bag = ets:new(bag,[bag | Opts]), - ?line DBag = ets:new(duplicate_bag,[duplicate_bag | Opts]), + ?line Bag = ets_new(bag,[bag | Opts]), + ?line DBag = ets_new(duplicate_bag,[duplicate_bag | Opts]), ?line {'EXIT',{badarg,_}} = (catch ets:update_counter(Bag,key,1)), ?line {'EXIT',{badarg,_}} = (catch ets:update_counter(DBag,key,1)), true = ets:delete(Bag), @@ -1646,7 +1963,7 @@ wait_for_all(Pids0) -> end. evil_counter(I,Opts) -> - T = ets:new(a, Opts), + T = ets_new(a, Opts), Start0 = case I rem 3 of 0 -> 16#12345678; 1 -> 16#12345678FFFFFFFF; @@ -1654,7 +1971,7 @@ evil_counter(I,Opts) -> end, Start = Start0 + random:uniform(100000), ets:insert(T, {dracula,Start}), - Iter = 90000, + Iter = 40000, End = Start + Iter, End = evil_counter_1(Iter, T), ets:delete(T). @@ -1675,7 +1992,7 @@ fixtable_next(Config) when is_list(Config) -> fixtable_next_do(Opts) -> ?line EtsMem = etsmem(), - ?line do_fixtable_next(ets:new(set,[public | Opts])), + ?line do_fixtable_next(ets_new(set,[public | Opts])), ?line verify_etsmem(EtsMem). do_fixtable_next(Tab) -> @@ -1756,24 +2073,24 @@ write_concurrency(doc) -> ["The 'write_concurrency' option"]; write_concurrency(suite) -> []; write_concurrency(Config) when is_list(Config) -> ?line EtsMem = etsmem(), - Yes1 = ets:new(foo,[public,{write_concurrency,true}]), - Yes2 = ets:new(foo,[protected,{write_concurrency,true}]), - No1 = ets:new(foo,[private,{write_concurrency,true}]), + Yes1 = ets_new(foo,[public,{write_concurrency,true}]), + Yes2 = ets_new(foo,[protected,{write_concurrency,true}]), + No1 = ets_new(foo,[private,{write_concurrency,true}]), - Yes3 = ets:new(foo,[bag,public,{write_concurrency,true}]), - Yes4 = ets:new(foo,[bag,protected,{write_concurrency,true}]), - No2 = ets:new(foo,[bag,private,{write_concurrency,true}]), + Yes3 = ets_new(foo,[bag,public,{write_concurrency,true}]), + Yes4 = ets_new(foo,[bag,protected,{write_concurrency,true}]), + No2 = ets_new(foo,[bag,private,{write_concurrency,true}]), - Yes5 = ets:new(foo,[duplicate_bag,public,{write_concurrency,true}]), - Yes6 = ets:new(foo,[duplicate_bag,protected,{write_concurrency,true}]), - No3 = ets:new(foo,[duplicate_bag,private,{write_concurrency,true}]), + Yes5 = ets_new(foo,[duplicate_bag,public,{write_concurrency,true}]), + Yes6 = ets_new(foo,[duplicate_bag,protected,{write_concurrency,true}]), + No3 = ets_new(foo,[duplicate_bag,private,{write_concurrency,true}]), - No4 = ets:new(foo,[ordered_set,public,{write_concurrency,true}]), - No5 = ets:new(foo,[ordered_set,protected,{write_concurrency,true}]), - No6 = ets:new(foo,[ordered_set,private,{write_concurrency,true}]), + No4 = ets_new(foo,[ordered_set,public,{write_concurrency,true}]), + No5 = ets_new(foo,[ordered_set,protected,{write_concurrency,true}]), + No6 = ets_new(foo,[ordered_set,private,{write_concurrency,true}]), - No7 = ets:new(foo,[public,{write_concurrency,false}]), - No8 = ets:new(foo,[protected,{write_concurrency,false}]), + No7 = ets_new(foo,[public,{write_concurrency,false}]), + No8 = ets_new(foo,[protected,{write_concurrency,false}]), ?line YesMem = ets:info(Yes1,memory), ?line NoHashMem = ets:info(No1,memory), @@ -1800,10 +2117,10 @@ write_concurrency(Config) when is_list(Config) -> ?line true = YesMem =:= NoHashMem end, - ?line {'EXIT',{badarg,_}} = (catch ets:new(foo,[public,{write_concurrency,foo}])), - ?line {'EXIT',{badarg,_}} = (catch ets:new(foo,[public,{write_concurrency}])), - ?line {'EXIT',{badarg,_}} = (catch ets:new(foo,[public,{write_concurrency,true,foo}])), - ?line {'EXIT',{badarg,_}} = (catch ets:new(foo,[public,write_concurrency])), + ?line {'EXIT',{badarg,_}} = (catch ets_new(foo,[public,{write_concurrency,foo}])), + ?line {'EXIT',{badarg,_}} = (catch ets_new(foo,[public,{write_concurrency}])), + ?line {'EXIT',{badarg,_}} = (catch ets_new(foo,[public,{write_concurrency,true,foo}])), + ?line {'EXIT',{badarg,_}} = (catch ets_new(foo,[public,write_concurrency])), lists:foreach(fun(T) -> ets:delete(T) end, [Yes1,Yes2,Yes3,Yes4,Yes5,Yes6, @@ -1880,7 +2197,7 @@ heir_founder(Master, HeirData, Opts) -> none -> {heir,none}; _ -> {heir, Heir, HeirData} end, - ?line T = ets:new(foo,[named_table, private, HeirTpl | Opts]), + ?line T = ets_new(foo,[named_table, private, HeirTpl | Opts]), ?line true = ets:insert(T,{key,1}), ?line [{key,1}] = ets:lookup(T,key), Self = self(), @@ -1952,7 +2269,7 @@ give_away(Config) when is_list(Config) -> repeat_for_opts(give_away_do). give_away_do(Opts) -> - ?line T = ets:new(foo,[named_table, private | Opts]), + ?line T = ets_new(foo,[named_table, private | Opts]), ?line true = ets:insert(T,{key,1}), ?line [{key,1}] = ets:lookup(T,key), Parent = self(), @@ -1978,7 +2295,7 @@ give_away_do(Opts) -> ?line undefined = ets:info(T), %% Give and then kill receiver to get back - ?line T2 = ets:new(foo,[private | Opts]), + ?line T2 = ets_new(foo,[private | Opts]), ?line true = ets:insert(T2,{key,1}), ?line ets:setopts(T2,{heir,self(),"Som en gummiboll..."}), ?line {Receiver2,Mref2} = spawn_monitor(fun()-> give_away_receiver(T2,Parent) end), @@ -2000,7 +2317,7 @@ give_away_do(Opts) -> ?line give_me = receive_any(), ?line {'EXIT',{badarg,_}} = (catch ets:give_away(T2,ReceiverNeg,"A deleted table")), - ?line T3 = ets:new(foo,[public | Opts]), + ?line T3 = ets_new(foo,[public | Opts]), spawn_link(fun()-> {'EXIT',{badarg,_}} = (catch ets:give_away(T3,ReceiverNeg,"From non owner")), Parent ! done end), @@ -2035,7 +2352,7 @@ setopts(Config) when is_list(Config) -> setopts_do(Opts) -> Self = self(), - ?line T = ets:new(foo,[named_table, private | Opts]), + ?line T = ets_new(foo,[named_table, private | Opts]), ?line none = ets:info(T,heir), Heir = spawn_link(fun()->heir_heir(Self) end), ?line ets:setopts(T,{heir,Heir,"Data"}), @@ -2088,10 +2405,10 @@ bad_table(Config) when is_list(Config) -> bad_table_do(Opts, DummyFile) -> Parent = self(), - {Pid,Mref} = spawn_opt(fun()-> ets:new(priv,[private,named_table | Opts]), - Priv = ets:new(priv,[private | Opts]), - ets:new(prot,[protected,named_table | Opts]), - Prot = ets:new(prot,[protected | Opts]), + {Pid,Mref} = spawn_opt(fun()-> ets_new(priv,[private,named_table | Opts]), + Priv = ets_new(priv,[private | Opts]), + ets_new(prot,[protected,named_table | Opts]), + Prot = ets_new(prot,[protected | Opts]), Parent ! {self(),Priv,Prot}, die_please = receive_any() end, @@ -2149,11 +2466,11 @@ bad_table_do(Opts, DummyFile) -> bad_table_op({Opts,Priv,Prot}, Op) -> %%io:format("Doing Op=~p on ~p's\n",[Op,Type]), - T1 = ets:new(noname,Opts), + T1 = ets_new(noname,Opts), bad_table_call(noname,Op), ets:delete(T1), bad_table_call(T1,Op), - T2 = ets:new(named,[named_table | Opts]), + T2 = ets_new(named,[named_table | Opts]), ets:delete(T2), bad_table_call(named,Op), bad_table_call(T2,Op), @@ -2187,7 +2504,7 @@ rename(Config) when is_list(Config) -> rename_do(Opts) -> ?line EtsMem = etsmem(), - ets:new(foobazz,[named_table, public | Opts]), + ets_new(foobazz,[named_table, public | Opts]), ets:insert(foobazz,{foo,bazz}), ungermanbazz = ets:rename(foobazz,ungermanbazz), {'EXIT',{badarg, _}} = (catch ets:lookup(foobazz,foo)), @@ -2205,7 +2522,7 @@ rename_unnamed(Config) when is_list(Config) -> rename_unnamed_do(Opts) -> ?line EtsMem = etsmem(), - ?line Tab = ets:new(bonkz,[public | Opts]), + ?line Tab = ets_new(bonkz,[public | Opts]), ?line {'EXIT',{badarg, _}} = (catch ets:insert(bonkz,{foo,bazz})), ?line bonkz = ets:info(Tab, name), ?line Tab = ets:rename(Tab, tjabonkz), @@ -2224,7 +2541,7 @@ evil_rename(Config) when is_list(Config) -> evil_rename_1(Old, New, Flags) -> ?line process_flag(trap_exit, true), - ?line Old = ets:new(Old, Flags), + ?line Old = ets_new(Old, Flags), ?line Fixer = fun() -> ets:safe_fixtable(Old, true) end, ?line crazy_fixtable(15000, Fixer), ?line erlang:yield(), @@ -2234,7 +2551,7 @@ evil_rename_1(Old, New, Flags) -> ok. crazy_fixtable(N, Fixer) -> - Dracula = ets:new(count_dracula, [public]), + Dracula = ets_new(count_dracula, [public]), ets:insert(Dracula, {count,0}), SpawnFun = fun() -> Fixer(), @@ -2268,7 +2585,7 @@ evil_creater_destroyer() -> ets:delete(T1). evil_create_fixed_tab() -> - T = ets:new(arne, [public]), + T = ets_new(arne, [public]), ets:safe_fixtable(T, true), T. @@ -2282,8 +2599,8 @@ interface_equality(Config) when is_list(Config) -> interface_equality_do(Opts) -> ?line EtsMem = etsmem(), - ?line Set = ets:new(set,[set | Opts]), - ?line OrderedSet = ets:new(ordered_set,[ordered_set | Opts]), + ?line Set = ets_new(set,[set | Opts]), + ?line OrderedSet = ets_new(ordered_set,[ordered_set | Opts]), ?line F = fun(X,T,FF) -> case X of 0 -> true; _ -> @@ -2362,7 +2679,7 @@ ordered_match_do(Opts) -> FF(X-1,T,FF) end end, - ?line T1 = ets:new(xxx,[ordered_set| Opts]), + ?line T1 = ets_new(xxx,[ordered_set| Opts]), ?line F(3000,T1,F), ?line [[3,3],[3,3],[3,3]] = ets:match(T1, {'_','_','$1','$2',3}), ?line F2 = fun(X,Rem,Res,FF) -> case X of @@ -2400,7 +2717,7 @@ ordered(Config) when is_list(Config) -> ordered_do(Opts) -> ?line EtsMem = etsmem(), - ?line T = ets:new(oset, [ordered_set | Opts]), + ?line T = ets_new(oset, [ordered_set | Opts]), ?line InsList = [ 25,26,27,28, 5,6,7,8, @@ -2408,7 +2725,8 @@ ordered_do(Opts) -> 9,10,11,12, 1,2,3,4, 17,18,19,20, - 13,14,15,16 + 13,14,15,16, + 1 bsl 33 ], ?line lists:foreach(fun(X) -> ets:insert(T,{X,integer_to_list(X)}) @@ -2423,13 +2741,14 @@ ordered_do(Opts) -> ?line S2 = L2, ?line [{1,"1"}] = ets:slot(T,0), ?line [{28,"28"}] = ets:slot(T,27), + ?line [{1 bsl 33,_}] = ets:slot(T,28), ?line 27 = ets:prev(T,28), ?line [{7,"7"}] = ets:slot(T,6), - ?line '$end_of_table' = ets:next(T,28), + ?line '$end_of_table' = ets:next(T,1 bsl 33), ?line [{12,"12"}] = ets:slot(T,11), - ?line '$end_of_table' = ets:slot(T,28), + ?line '$end_of_table' = ets:slot(T,29), ?line [{1,"1"}] = ets:slot(T,0), - ?line 28 = ets:prev(T,29), + ?line 28 = ets:prev(T,1 bsl 33), ?line 1 = ets:next(T,0), ?line pick_all_forward(T), ?line [{7,"7"}] = ets:slot(T,6), @@ -2461,8 +2780,8 @@ setbag(doc) -> ["Small test case for both set and bag type ets tables."]; setbag(suite) -> []; setbag(Config) when is_list(Config) -> ?line EtsMem = etsmem(), - ?line Set = ets:new(set,[set]), - ?line Bag = ets:new(bag,[bag]), + ?line Set = ets_new(set,[set]), + ?line Bag = ets_new(bag,[bag]), ?line Key = {foo,bar}, %% insert some value @@ -2482,15 +2801,15 @@ setbag(Config) when is_list(Config) -> ?line verify_etsmem(EtsMem). badnew(doc) -> - ["Test case to check proper return values for illegal ets:new() calls."]; + ["Test case to check proper return values for illegal ets_new() calls."]; badnew(suite) -> []; badnew(Config) when is_list(Config) -> ?line EtsMem = etsmem(), - ?line {'EXIT',{badarg,_}} = (catch ets:new(12,[])), - ?line {'EXIT',{badarg,_}} = (catch ets:new({a,b},[])), - ?line {'EXIT',{badarg,_}} = (catch ets:new(name,[foo])), - ?line {'EXIT',{badarg,_}} = (catch ets:new(name,{bag})), - ?line {'EXIT',{badarg,_}} = (catch ets:new(name,bag)), + ?line {'EXIT',{badarg,_}} = (catch ets_new(12,[])), + ?line {'EXIT',{badarg,_}} = (catch ets_new({a,b},[])), + ?line {'EXIT',{badarg,_}} = (catch ets_new(name,[foo])), + ?line {'EXIT',{badarg,_}} = (catch ets_new(name,{bag})), + ?line {'EXIT',{badarg,_}} = (catch ets_new(name,bag)), ?line verify_etsmem(EtsMem). verybadnew(doc) -> @@ -2499,7 +2818,7 @@ verybadnew(doc) -> verybadnew(suite) -> []; verybadnew(Config) when is_list(Config) -> ?line EtsMem = etsmem(), - ?line {'EXIT',{badarg,_}} = (catch ets:new(verybad,[set|protected])), + ?line {'EXIT',{badarg,_}} = (catch ets_new(verybad,[set|protected])), ?line verify_etsmem(EtsMem). named(doc) -> ["Small check to see if named tables work."]; @@ -2576,9 +2895,9 @@ privacy_check(Pub,Prot,Priv) -> ?line [] = ets:lookup(Prot,foo). privacy_owner(Boss, Opts) -> - ets:new(pub, [public,named_table | Opts]), - ets:new(prot,[protected,named_table | Opts]), - ets:new(priv,[private,named_table | Opts]), + ets_new(pub, [public,named_table | Opts]), + ets_new(prot,[protected,named_table | Opts]), + ets_new(priv,[private,named_table | Opts]), Boss ! ok, privacy_owner_loop(Boss). @@ -2605,8 +2924,6 @@ rotate_tuple(Tuple, N) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -insert(doc) -> ["Test proper and improper inserts into a table."]; -insert(suite) -> [empty,badinsert]. empty(doc) -> ["Check lookup in an empty table and lookup of a non-existing key"]; @@ -2616,7 +2933,7 @@ empty(Config) when is_list(Config) -> empty_do(Opts) -> ?line EtsMem = etsmem(), - ?line Tab = ets:new(foo,Opts), + ?line Tab = ets_new(foo,Opts), ?line [] = ets:lookup(Tab,key), ?line true = ets:insert(Tab,{key2,val}), ?line [] = ets:lookup(Tab,key), @@ -2633,10 +2950,10 @@ badinsert_do(Opts) -> ?line EtsMem = etsmem(), ?line {'EXIT',{badarg,_}} = (catch ets:insert(foo,{key,val})), - ?line Tab = ets:new(foo,Opts), + ?line Tab = ets_new(foo,Opts), ?line {'EXIT',{badarg,_}} = (catch ets:insert(Tab,{})), - ?line Tab3 = ets:new(foo,[{keypos,3}| Opts]), + ?line Tab3 = ets_new(foo,[{keypos,3}| Opts]), ?line {'EXIT',{badarg,_}} = (catch ets:insert(Tab3,{a,b})), ?line {'EXIT',{badarg,_}} = (catch ets:insert(Tab,[key,val2])), @@ -2646,8 +2963,6 @@ badinsert_do(Opts) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -lookup(doc) -> ["Some tests for lookups (timing, bad lookups, etc.)."]; -lookup(suite) -> [time_lookup,badlookup,lookup_order]. time_lookup(doc) -> ["Lookup timing."]; time_lookup(suite) -> []; @@ -2660,7 +2975,7 @@ time_lookup(Config) when is_list(Config) -> "~p ets lookups/s",[Values]))}. time_lookup_do(Opts) -> - ?line Tab = ets:new(foo,Opts), + ?line Tab = ets_new(foo,Opts), ?line fill_tab(Tab,foo), ?line ets:insert(Tab,{{a,key},foo}), ?line {Time,_} = ?t:timecall(test_server,do_times, @@ -2675,7 +2990,7 @@ badlookup(suite) -> []; badlookup(Config) when is_list(Config) -> ?line EtsMem = etsmem(), ?line {'EXIT',{badarg,_}} = (catch ets:lookup(foo,key)), - ?line Tab = ets:new(foo,[]), + ?line Tab = ets_new(foo,[]), ?line ets:delete(Tab), ?line {'EXIT',{badarg,_}} = (catch ets:lookup(Tab,key)), ?line verify_etsmem(EtsMem). @@ -2700,7 +3015,7 @@ lookup_order_2(Opts, Fixed) -> Pair = [{A,B},{B,A},{A,C},{C,A},{B,C},{C,B}], Combos = [{D1,D2,D3} || D1<-ABC, D2<-Pair, D3<-Pair], lists:foreach(fun({D1,{D2a,D2b},{D3a,D3b}}) -> - T = ets:new(foo,Opts), + T = ets_new(foo,Opts), case Fixed of true -> ets:safe_fixtable(T,true); false -> ok @@ -2774,8 +3089,6 @@ fill_tab(Tab,Val) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -lookup_element(doc) -> ["Some tests for lookup_element."]; -lookup_element(suite) -> [lookup_element_mult]. lookup_element_mult(doc) -> ["Multiple return elements (OTP-2386)"]; lookup_element_mult(suite) -> []; @@ -2784,10 +3097,12 @@ lookup_element_mult(Config) when is_list(Config) -> lookup_element_mult_do(Opts) -> ?line EtsMem = etsmem(), - ?line T = ets:new(service, [bag, {keypos, 2} | Opts]), + ?line T = ets_new(service, [bag, {keypos, 2} | Opts]), ?line D = lists:reverse(lem_data()), ?line lists:foreach(fun(X) -> ets:insert(T, X) end, D), ?line ok = lem_crash_3(T), + ?line ets:insert(T, {0, "heap_key"}), + ?line ets:lookup_element(T, "heap_key", 2), ?line true = ets:delete(T), ?line verify_etsmem(EtsMem). @@ -2815,11 +3130,6 @@ lem_crash_3(T) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -delete(doc) -> - ["Check delete functionality (proper/improper deletes)"]; -delete(suite) -> - [delete_elem,delete_tab,delete_large_tab,delete_large_named_table,evil_delete, - table_leak,baddelete,match_delete,match_delete3]. delete_elem(doc) -> ["Check delete of an element inserted in a `filled' table."]; @@ -2829,7 +3139,7 @@ delete_elem(Config) when is_list(Config) -> delete_elem_do(Opts) -> ?line EtsMem = etsmem(), - ?line Tab = ets:new(foo,Opts), + ?line Tab = ets_new(foo,Opts), ?line fill_tab(Tab,foo), ?line ets:insert(Tab,{{b,key},foo}), ?line ets:insert(Tab,{{c,key},foo}), @@ -2849,17 +3159,17 @@ delete_tab(Config) when is_list(Config) -> delete_tab_do(Opts) -> Name = foo, ?line EtsMem = etsmem(), - ?line Name = ets:new(Name, [named_table | Opts]), + ?line Name = ets_new(Name, [named_table | Opts]), ?line true = ets:delete(foo), %% The name should be available again. - ?line Name = ets:new(Name, [named_table | Opts]), + ?line Name = ets_new(Name, [named_table | Opts]), ?line true = ets:delete(Name), ?line verify_etsmem(EtsMem). delete_large_tab(doc) -> "Check that ets:delete/1 works and that other processes can run."; delete_large_tab(Config) when is_list(Config) -> - ?line Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 500000)], + ?line Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 200000)], ?line EtsMem = etsmem(), repeat_for_opts(fun(Opts) -> delete_large_tab_do(Opts,Data) end), ?line verify_etsmem(EtsMem). @@ -2871,7 +3181,7 @@ delete_large_tab_do(Opts,Data) -> delete_large_tab_1(Name, Flags, Data, Fix) -> - ?line Tab = ets:new(Name, Flags), + ?line Tab = ets_new(Name, Flags), ?line ets:insert(Tab, Data), case Fix of @@ -2938,7 +3248,7 @@ delete_large_named_table_do(Opts,Data) -> ?line delete_large_named_table_1(foo_hash, [named_table | Opts], Data, true). delete_large_named_table_1(Name, Flags, Data, Fix) -> - ?line Tab = ets:new(Name, Flags), + ?line Tab = ets_new(Name, Flags), ?line ets:insert(Tab, Data), case Fix of @@ -2951,7 +3261,7 @@ delete_large_named_table_1(Name, Flags, Data, Fix) -> Pid = spawn_link(fun() -> receive {trace,Parent,call,_} -> - ets:new(Name, [named_table]) + ets_new(Name, [named_table]) end end), ?line erlang:trace(self(), true, [call,{tracer,Pid}]), @@ -2985,7 +3295,7 @@ evil_delete_do(Opts,Data) -> evil_delete_not_owner(Name, Flags, Data, Fix) -> io:format("Not owner: ~p, fix = ~p", [Name,Fix]), - ?line Tab = ets:new(Name, [public|Flags]), + ?line Tab = ets_new(Name, [public|Flags]), ?line ets:insert(Tab, Data), case Fix of false -> ok; @@ -3010,7 +3320,7 @@ evil_delete_not_owner(Name, Flags, Data, Fix) -> evil_delete_owner(Name, Flags, Data, Fix) -> ?line Fun = fun() -> - ?line Tab = ets:new(Name, [public|Flags]), + ?line Tab = ets_new(Name, [public|Flags]), ?line ets:insert(Tab, Data), case Fix of false -> ok; @@ -3037,48 +3347,60 @@ exit_large_table_owner(doc) -> exit_large_table_owner(suite) -> []; exit_large_table_owner(Config) when is_list(Config) -> - ?line Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 500000)], + %%?line Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 500000)], + ?line FEData = fun(Do) -> repeat_while(fun(500000) -> {false,ok}; + (I) -> Do({erlang:phash2(I, 16#ffffff),I}), + {true, I+1} + end, 1) + end, ?line EtsMem = etsmem(), - repeat_for_opts(fun(Opts) -> exit_large_table_owner_do(Opts,Data,Config) end), + repeat_for_opts({exit_large_table_owner_do,{FEData,Config}}), ?line verify_etsmem(EtsMem). -exit_large_table_owner_do(Opts,Data,Config) -> - ?line verify_rescheduling_exit(Config, Data, [named_table | Opts], true, 1, 1), - ?line verify_rescheduling_exit(Config, Data, Opts, false, 1, 1). +exit_large_table_owner_do(Opts,{FEData,Config}) -> + ?line verify_rescheduling_exit(Config, FEData, [named_table | Opts], true, 1, 1), + ?line verify_rescheduling_exit(Config, FEData, Opts, false, 1, 1). exit_many_large_table_owner(doc) -> []; exit_many_large_table_owner(suite) -> []; exit_many_large_table_owner(Config) when is_list(Config) -> - ?line Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 500000)], + %%?line Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 500000)], + ?line FEData = fun(Do) -> repeat_while(fun(500000) -> {false,ok}; + (I) -> Do({erlang:phash2(I, 16#ffffff),I}), + {true, I+1} + end, 1) + end, ?line EtsMem = etsmem(), - repeat_for_opts(fun(Opts) -> exit_many_large_table_owner_do(Opts,Data,Config) end), + repeat_for_opts(fun(Opts) -> exit_many_large_table_owner_do(Opts,FEData,Config) end), ?line verify_etsmem(EtsMem). -exit_many_large_table_owner_do(Opts,Data,Config) -> - ?line verify_rescheduling_exit(Config, Data, Opts, true, 1, 4), - ?line verify_rescheduling_exit(Config, Data, [named_table | Opts], false, 1, 4). +exit_many_large_table_owner_do(Opts,FEData,Config) -> + ?line verify_rescheduling_exit(Config, FEData, Opts, true, 1, 4), + ?line verify_rescheduling_exit(Config, FEData, [named_table | Opts], false, 1, 4). exit_many_tables_owner(doc) -> []; exit_many_tables_owner(suite) -> []; exit_many_tables_owner(Config) when is_list(Config) -> + NoData = fun(_Do) -> ok end, ?line EtsMem = etsmem(), - ?line verify_rescheduling_exit(Config, [], [named_table], false, 1000, 1), - ?line verify_rescheduling_exit(Config, [], [named_table,{write_concurrency,true}], false, 1000, 1), + ?line verify_rescheduling_exit(Config, NoData, [named_table], false, 1000, 1), + ?line verify_rescheduling_exit(Config, NoData, [named_table,{write_concurrency,true}], false, 1000, 1), ?line verify_etsmem(EtsMem). exit_many_many_tables_owner(doc) -> []; exit_many_many_tables_owner(suite) -> []; exit_many_many_tables_owner(Config) when is_list(Config) -> ?line Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 50)], - repeat_for_opts(fun(Opts) -> exit_many_many_tables_owner_do(Opts,Data,Config) end). + ?line FEData = fun(Do) -> lists:foreach(Do, Data) end, + repeat_for_opts(fun(Opts) -> exit_many_many_tables_owner_do(Opts,FEData,Config) end). -exit_many_many_tables_owner_do(Opts,Data,Config) -> - ?line verify_rescheduling_exit(Config, Data, [named_table | Opts], true, 200, 5), - ?line verify_rescheduling_exit(Config, Data, Opts, false, 200, 5), +exit_many_many_tables_owner_do(Opts,FEData,Config) -> + ?line verify_rescheduling_exit(Config, FEData, [named_table | Opts], true, 200, 5), + ?line verify_rescheduling_exit(Config, FEData, Opts, false, 200, 5), ?line wait_for_test_procs(), ?line EtsMem = etsmem(), - ?line verify_rescheduling_exit(Config, Data, Opts, true, 200, 5), - ?line verify_rescheduling_exit(Config, Data, [named_table | Opts], false, 200, 5), + ?line verify_rescheduling_exit(Config, FEData, Opts, true, 200, 5), + ?line verify_rescheduling_exit(Config, FEData, [named_table | Opts], false, 200, 5), ?line verify_etsmem(EtsMem). @@ -3121,7 +3443,7 @@ vre_fix_tables(Tab) -> receive Go -> ok end, ok. -verify_rescheduling_exit(Config, Data, Flags, Fix, NOTabs, NOProcs) -> +verify_rescheduling_exit(Config, ForEachData, Flags, Fix, NOTabs, NOProcs) -> ?line NoFix = 5, ?line TestCase = atom_to_list(?config(test_case, Config)), ?line Parent = self(), @@ -3136,8 +3458,8 @@ verify_rescheduling_exit(Config, Data, Flags, Fix, NOTabs, NOProcs) -> ++ "-" ++ integer_to_list(A) ++ "-" ++ integer_to_list(B) ++ "-" ++ integer_to_list(C)), - Tab = ets:new(Name, Flags), - ets:insert(Tab, Data), + Tab = ets_new(Name, Flags), + ForEachData(fun(Data) -> ets:insert(Tab, Data) end), case Fix of false -> ok; true -> @@ -3145,10 +3467,10 @@ verify_rescheduling_exit(Config, Data, Flags, Fix, NOTabs, NOProcs) -> vre_fix_tables(Tab) end, lists:seq(1,NoFix)), - lists:foreach(fun({K,_}) -> - ets:delete(Tab, K) - end, - Data) + KeyPos = ets:info(Tab,keypos), + ForEachData(fun(Data) -> + ets:delete(Tab, element(KeyPos,Data)) + end) end end, NOTabs), @@ -3195,7 +3517,7 @@ table_leak(Config) when is_list(Config) -> table_leak_1(_,0) -> ok; table_leak_1(Opts,N) -> - ?line T = ets:new(fooflarf, Opts), + ?line T = ets_new(fooflarf, Opts), ?line true = ets:delete(T), table_leak_1(Opts,N-1). @@ -3205,7 +3527,7 @@ baddelete(suite) -> []; baddelete(Config) when is_list(Config) -> ?line EtsMem = etsmem(), ?line {'EXIT',{badarg,_}} = (catch ets:delete(foo)), - ?line Tab = ets:new(foo,[]), + ?line Tab = ets_new(foo,[]), ?line true = ets:delete(Tab), ?line {'EXIT',{badarg,_}} = (catch ets:delete(Tab)), ?line verify_etsmem(EtsMem). @@ -3220,7 +3542,7 @@ match_delete(Config) when is_list(Config) -> match_delete_do(Opts) -> ?line EtsMem = etsmem(), - ?line Tab = ets:new(kad,Opts), + ?line Tab = ets_new(kad,Opts), ?line fill_tab(Tab,foo), ?line ets:insert(Tab,{{c,key},bar}), ?line _ = ets:match_delete(Tab,{'_',foo}), @@ -3264,7 +3586,7 @@ firstnext(Config) when is_list(Config) -> firstnext_do(Opts) -> ?line EtsMem = etsmem(), - ?line Tab = ets:new(foo,Opts), + ?line Tab = ets_new(foo,Opts), ?line [] = firstnext_collect(Tab,ets:first(Tab),[]), ?line fill_tab(Tab,foo), ?line Len = length(ets:tab2list(Tab)), @@ -3287,10 +3609,10 @@ firstnext_concurrent(Config) when is_list(Config) -> [dynamic_go() || _ <- lists:seq(1, 2)], receive after 5000 -> ok - end. + end. ets_init(Tab, N) -> - ets:new(Tab, [named_table,public,ordered_set]), + ets_new(Tab, [named_table,public,ordered_set]), cycle(Tab, lists:seq(1,N+1)). cycle(_Tab, [H|T]) when H > length(T)-> ok; @@ -3323,7 +3645,7 @@ slot(Config) when is_list(Config) -> slot_do(Opts) -> ?line EtsMem = etsmem(), - ?line Tab = ets:new(foo,Opts), + ?line Tab = ets_new(foo,Opts), ?line fill_tab(Tab,foo), ?line Elts = ets:info(Tab,size), ?line Elts = slot_loop(Tab,0,0), @@ -3342,7 +3664,6 @@ slot_loop(Tab,SlotNo,EltsSoFar) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -match(suite) -> [match1, match2, match_object, match_object2]. match1(suite) -> []; match1(Config) when is_list(Config) -> @@ -3350,7 +3671,7 @@ match1(Config) when is_list(Config) -> match1_do(Opts) -> ?line EtsMem = etsmem(), - ?line Tab = ets:new(foo,Opts), + ?line Tab = ets_new(foo,Opts), ?line fill_tab(Tab,foo), ?line [] = ets:match(Tab,{}), ?line ets:insert(Tab,{{one,4},4}), @@ -3415,7 +3736,7 @@ match_object(Config) when is_list(Config) -> match_object_do(Opts) -> ?line EtsMem = etsmem(), - ?line Tab = ets:new(foobar, Opts), + ?line Tab = ets_new(foobar, Opts), ?line fill_tab(Tab, foo), ?line ets:insert(Tab, {{one, 4}, 4}), ?line ets:insert(Tab,{{one,5},5}), @@ -3459,7 +3780,7 @@ match_object2(Config) when is_list(Config) -> match_object2_do(Opts) -> ?line EtsMem = etsmem(), - ?line Tab = ets:new(foo, [bag, {keypos, 2} | Opts]), + ?line Tab = ets_new(foo, [bag, {keypos, 2} | Opts]), ?line fill_tab2(Tab, 0, 13005), % match_db_object does 1000 % elements per pass, might % change in the future. @@ -3477,7 +3798,6 @@ match_object2_do(Opts) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -misc(suite) -> [misc1, safe_fixtable, info, dups, tab2list]. tab2list(doc) -> ["Tests tab2list (OTP-3319)"]; tab2list(suite) -> []; @@ -3498,7 +3818,7 @@ misc1(Config) when is_list(Config) -> misc1_do(Opts) -> ?line EtsMem = etsmem(), - ?line Tab = ets:new(foo,Opts), + ?line Tab = ets_new(foo,Opts), ?line true = lists:member(Tab,ets:all()), ?line ets:delete(Tab), ?line false = lists:member(Tab,ets:all()), @@ -3517,7 +3837,7 @@ safe_fixtable(Config) when is_list(Config) -> safe_fixtable_do(Opts) -> ?line EtsMem = etsmem(), - ?line Tab = ets:new(foo, Opts), + ?line Tab = ets_new(foo, Opts), ?line fill_tab(Tab, foobar), ?line true = ets:safe_fixtable(Tab, true), ?line receive after 1 -> ok end, @@ -3556,7 +3876,7 @@ info_do(Opts) -> ?line EtsMem = etsmem(), ?line MeMyselfI=self(), ?line ThisNode=node(), - ?line Tab = ets:new(foobar, [{keypos, 2} | Opts]), + ?line Tab = ets_new(foobar, [{keypos, 2} | Opts]), %% Note: ets:info/1 used to return a tuple, but from R11B onwards it %% returns a list. @@ -3610,15 +3930,12 @@ dups_do(Opts) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -files(suite) -> [tab2file, tab2file2, tab2file3, tabfile_ext1, tabfile_ext2, - tabfile_ext3, tabfile_ext4]. - tab2file(doc) -> ["Check the ets:tab2file function on an empty " "ets table."]; tab2file(suite) -> []; tab2file(Config) when is_list(Config) -> %% Write an empty ets table to a file, read back and check properties. - ?line Tab = ets:new(ets_SUITE_foo_tab, [named_table, set, private, + ?line Tab = ets_new(ets_SUITE_foo_tab, [named_table, set, private, {keypos, 2}]), ?line FName = filename:join([?config(priv_dir, Config),"tab2file_case"]), ?line ok = ets:tab2file(Tab, FName), @@ -3634,51 +3951,36 @@ tab2file(Config) when is_list(Config) -> ?line verify_etsmem(EtsMem). tab2file2(doc) -> ["Check the ets:tab2file function on a ", - "filled set type ets table."]; + "filled set/bag type ets table."]; tab2file2(suite) -> []; -tab2file2(Config) when is_list(Config) -> - %% Try the same on a filled set table. - ?line EtsMem = etsmem(), - ?line Tab = ets:new(ets_SUITE_foo_tab, [named_table, set, private, - {keypos, 2}]), - ?line FName = filename:join([?config(priv_dir, Config),"tab2file2_case"]), - ?line ok = fill_tab2(Tab, 0, 10000), % Fill up the table (grucho mucho!) - ?line Len = length(ets:tab2list(Tab)), - ?line ok = ets:tab2file(Tab, FName), - ?line true = ets:delete(Tab), - % - ?line {ok, Tab2} = ets:file2tab(FName), - ?line private = ets:info(Tab2, protection), - ?line true = ets:info(Tab2, named_table), - ?line 2 = ets:info(Tab2, keypos), - ?line set = ets:info(Tab2, type), - ?line Len = length(ets:tab2list(Tab2)), - ?line true = ets:delete(Tab2), - ?line verify_etsmem(EtsMem). +tab2file2(Config) when is_list(Config) -> + repeat_for_opts({tab2file2_do,Config}, [[set,bag],compressed]). -tab2file3(doc) -> ["Check the ets:tab2file function on a ", - "filled bag type ets table."]; -tab2file3(suite) -> []; -tab2file3(Config) when is_list(Config) -> - %% Try the same on a filled bag table. +tab2file2_do(Opts, Config) -> ?line EtsMem = etsmem(), - ?line Tab = ets:new(ets_SUITE_foo_tab, [named_table, bag, private, - {keypos, 2}]), - ?line FName = filename:join([?config(priv_dir, Config),"tab2file3_case"]), + ?line Tab = ets_new(ets_SUITE_foo_tab, [named_table, private, + {keypos, 2} | Opts]), + ?line FName = filename:join([?config(priv_dir, Config),"tab2file2_case"]), ?line ok = fill_tab2(Tab, 0, 10000), % Fill up the table (grucho mucho!) ?line Len = length(ets:tab2list(Tab)), ?line Mem = ets:info(Tab, memory), + ?line Type = ets:info(Tab, type), + %%io:format("org tab: ~p\n",[ets:info(Tab)]), ?line ok = ets:tab2file(Tab, FName), ?line true = ets:delete(Tab), + ?line EtsMem4 = etsmem(), + ?line {ok, Tab2} = ets:file2tab(FName), + %%io:format("loaded tab: ~p\n",[ets:info(Tab2)]), ?line private = ets:info(Tab2, protection), ?line true = ets:info(Tab2, named_table), ?line 2 = ets:info(Tab2, keypos), - ?line bag = ets:info(Tab2, type), + ?line Type = ets:info(Tab2, type), ?line Len = length(ets:tab2list(Tab2)), ?line Mem = ets:info(Tab2, memory), ?line true = ets:delete(Tab2), + io:format("Between = ~p\n", [EtsMem4]), ?line verify_etsmem(EtsMem). -define(test_list, [8,5,4,1,58,125,255, 250, 245, 240, 235, @@ -3722,7 +4024,7 @@ tabfile_ext1_do(Opts,Config) -> ?line FName = filename:join([?config(priv_dir, Config),"nisse.dat"]), ?line FName2 = filename:join([?config(priv_dir, Config),"countflip.dat"]), L = lists:seq(1,10), - T = ets:new(x,Opts), + T = ets_new(x,Opts), Name = make_ref(), [ets:insert(T,{X,integer_to_list(X)}) || X <- L], ok = ets:tab2file(T,FName,[{extended_info,[object_count]}]), @@ -3762,7 +4064,7 @@ tabfile_ext2_do(Opts,Config) -> ?line FName = filename:join([?config(priv_dir, Config),"olle.dat"]), ?line FName2 = filename:join([?config(priv_dir, Config),"bitflip.dat"]), L = lists:seq(1,10), - T = ets:new(x,Opts), + T = ets_new(x,Opts), Name = make_ref(), [ets:insert(T,{X,integer_to_list(X)}) || X <- L], ok = ets:tab2file(T,FName,[{extended_info,[md5sum]}]), @@ -3800,7 +4102,7 @@ tabfile_ext3(Config) when is_list(Config) -> ?line FName2 = filename:join([?config(priv_dir, Config),"ncountflip.dat"]), L = lists:seq(1,10), Name = make_ref(), - ?MODULE = ets:new(?MODULE,[named_table]), + ?MODULE = ets_new(?MODULE,[named_table]), [ets:insert(?MODULE,{X,integer_to_list(X)}) || X <- L], ets:tab2file(?MODULE,FName), {error,cannot_create_table} = ets:file2tab(FName), @@ -3832,7 +4134,7 @@ tabfile_ext4(doc) -> tabfile_ext4(Config) when is_list(Config) -> ?line FName = filename:join([?config(priv_dir, Config),"bauta.dat"]), LL = lists:seq(1,10000), - TL = ets:new(x,[]), + TL = ets_new(x,[]), Name2 = make_ref(), [ets:insert(TL,{X,integer_to_list(X)}) || X <- LL], ok = ets:tab2file(TL,FName,[{extended_info,[md5sum]}]), @@ -3877,7 +4179,6 @@ make_sub_binary(List, Num) when is_list(List) -> {_,B} = split_binary(Bin, N+1), B. -heavy(suite) -> [heavy_lookup, heavy_lookup_element]. %% Lookup stuff like crazy... heavy_lookup(doc) -> ["Performs multiple lookups for every key ", @@ -3888,7 +4189,7 @@ heavy_lookup(Config) when is_list(Config) -> heavy_lookup_do(Opts) -> ?line EtsMem = etsmem(), - ?line Tab = ets:new(foobar_table, [set, protected, {keypos, 2} | Opts]), + ?line Tab = ets_new(foobar_table, [set, protected, {keypos, 2} | Opts]), ?line ok = fill_tab2(Tab, 0, 7000), ?line ?t:do_times(50, ?MODULE, do_lookup, [Tab, 6999]), ?line true = ets:delete(Tab), @@ -3911,7 +4212,7 @@ heavy_lookup_element(Config) when is_list(Config) -> heavy_lookup_element_do(Opts) -> ?line EtsMem = etsmem(), - ?line Tab = ets:new(foobar_table, [set, protected, {keypos, 2} | Opts]), + ?line Tab = ets_new(foobar_table, [set, protected, {keypos, 2} | Opts]), ?line ok = fill_tab2(Tab, 0, 7000), case os:type() of vxworks -> @@ -3940,9 +4241,44 @@ do_lookup_element(Tab, N, M) -> end. -fold(suite) -> [foldl_ordered, foldr_ordered, - foldl, foldr, - fold_empty]. +heavy_concurrent(Config) when is_list(Config) -> + repeat_for_opts(do_heavy_concurrent). + +do_heavy_concurrent(Opts) -> + ?line Size = 10000, + ?line EtsMem = etsmem(), + ?line Tab = ets_new(blupp, [set, public, {keypos, 2} | Opts]), + ?line ok = fill_tab2(Tab, 0, Size), + ?line Procs = lists:map( + fun (N) -> + spawn_link( + fun () -> + do_heavy_concurrent_proc(Tab, Size, N) + end) + end, + lists:seq(1, 500)), + ?line lists:foreach(fun (P) -> + M = erlang:monitor(process, P), + receive + {'DOWN', M, process, P, _} -> + ok + end + end, + Procs), + ?line true = ets:delete(Tab), + ?line verify_etsmem(EtsMem). + +do_heavy_concurrent_proc(_Tab, 0, _Offs) -> + done; +do_heavy_concurrent_proc(Tab, N, Offs) when (N+Offs) rem 100 == 0 -> + Data = {"here", are, "S O M E ", data, "toooooooooooooooooo", insert, + make_ref(), make_ref(), make_ref()}, + true=ets:insert(Tab, {{self(),Data}, N}), + do_heavy_concurrent_proc(Tab, N-1, Offs); +do_heavy_concurrent_proc(Tab, N, Offs) -> + _ = ets:lookup(Tab, N), + do_heavy_concurrent_proc(Tab, N-1, Offs). + fold_empty(doc) -> []; @@ -4012,7 +4348,7 @@ member(Config) when is_list(Config) -> member_do(Opts) -> ?line EtsMem = etsmem(), - ?line T = ets:new(xxx, Opts), + ?line T = ets_new(xxx, Opts), ?line false = ets:member(T,hej), ?line E = fun(0,_F)->ok; (N,F) -> @@ -4037,7 +4373,7 @@ member_do(Opts) -> build_table(L1,L2,Num) -> - T = ets:new(xxx, [ordered_set] + T = ets_new(xxx, [ordered_set] ), lists:foreach( fun(X1) -> @@ -4059,7 +4395,7 @@ build_table(L1,L2,Num) -> T. build_table2(L1,L2,Num) -> - T = ets:new(xxx, [ordered_set] + T = ets_new(xxx, [ordered_set] ), lists:foreach( fun(X1) -> @@ -4190,7 +4526,7 @@ do_n_times(Fun,N) -> do_n_times(Fun,N-1). make_table(Name, Options, Elements) -> - T = ets:new(Name, Options), + T = ets_new(Name, Options), lists:foreach(fun(E) -> ets:insert(T, E) end, Elements), T. filltabint(Tab,0) -> @@ -4254,13 +4590,13 @@ xfilltabstr(Tab,N) -> fill_sets_int(N) -> fill_sets_int(N,[]). fill_sets_int(N,Opts) -> - Tab1 = ets:new(xxx, [ordered_set|Opts]), + Tab1 = ets_new(xxx, [ordered_set|Opts]), filltabint(Tab1,N), - Tab2 = ets:new(xxx, [set|Opts]), + Tab2 = ets_new(xxx, [set|Opts]), filltabint(Tab2,N), - Tab3 = ets:new(xxx, [bag|Opts]), + Tab3 = ets_new(xxx, [bag|Opts]), filltabint2(Tab3,N), - Tab4 = ets:new(xxx, [duplicate_bag|Opts]), + Tab4 = ets_new(xxx, [duplicate_bag|Opts]), filltabint3(Tab4,N), [Tab1,Tab2,Tab3,Tab4]. @@ -4412,7 +4748,7 @@ gen_dets_filename(Config,N) -> "testdets_" ++ integer_to_list(N) ++ ".dets"). otp_6842_select_1000(Config) when is_list(Config) -> - ?line Tab = ets:new(xxx,[ordered_set]), + ?line Tab = ets_new(xxx,[ordered_set]), ?line [ets:insert(Tab,{X,X}) || X <- lists:seq(1,10000)], ?line AllTrue = lists:duplicate(10,true), ?line AllTrue = @@ -4445,7 +4781,7 @@ check_seq(A,B,C) -> otp_6338(Config) when is_list(Config) -> 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>>), - T = ets:new(xxx,[ordered_set]), + T = ets_new(xxx,[ordered_set]), lists:foreach(fun(X) -> ets:insert(T,X) end,L), [[4839,recv]] = ets:match(T,{[{sbm,ppb2_bs12@blade_0_8},'$1'],'$2'}), ets:delete(T). @@ -4456,7 +4792,7 @@ otp_5340(Config) when is_list(Config) -> otp_5340_do(Opts) -> N = 3000, - T = ets:new(otp_5340, [bag,public | Opts]), + T = ets_new(otp_5340, [bag,public | Opts]), Ids = [1,2,3,4,5], [w(T, N, Id) || Id <- Ids], verify(T, Ids), @@ -4492,7 +4828,7 @@ otp_7665(Config) when is_list(Config) -> repeat_for_opts(otp_7665_do). otp_7665_do(Opts) -> - Tab = ets:new(otp_7665,[bag | Opts]), + Tab = ets_new(otp_7665,[bag | Opts]), Min = 0, Max = 10, lists:foreach(fun(N)-> otp_7665_act(Tab,Min,Max,N) end, @@ -4555,7 +4891,7 @@ meta_wb_do(Opts) -> Names). meta_wb_new(Name, _, Tabs, Opts) -> - case (catch ets:new(Name,[named_table|Opts])) of + case (catch ets_new(Name,[named_table|Opts])) of Name -> ?line false = lists:member(Name, Tabs), [Name | Tabs]; @@ -4603,7 +4939,7 @@ grow_shrink_0([N|Ns], EtsMem) -> grow_shrink_0([], _) -> ok. grow_shrink_1(N, Flags) -> - ?line T = ets:new(a, Flags), + ?line T = ets_new(a, Flags), ?line grow_shrink_2(N, N, T), ?line ets:delete(T). @@ -4633,7 +4969,7 @@ grow_pseudo_deleted_do() -> grow_pseudo_deleted_do(Type) -> process_flag(scheduler,1), Self = self(), - ?line T = ets:new(kalle,[Type,public,{write_concurrency,true}]), + ?line T = ets_new(kalle,[Type,public,{write_concurrency,true}]), Mod = 7, Mult = 10000, filltabint(T,Mod*Mult), ?line true = ets:safe_fixtable(T,true), @@ -4643,7 +4979,7 @@ grow_pseudo_deleted_do(Type) -> [true]}]), Left = Mult*(Mod-1), ?line Left = ets:info(T,size), - ?line Mult = ets:info(T,kept_objects), + ?line Mult = get_kept_objects(T), filltabstr(T,Mult), spawn_opt(fun()-> ?line true = ets:info(T,fixed), Self ! start, @@ -4657,7 +4993,7 @@ grow_pseudo_deleted_do(Type) -> ?line true = ets:safe_fixtable(T,false), io:format("Unfix table done. ~p nitems=~p\n",[now(),ets:info(T,size)]), ?line false = ets:info(T,fixed), - ?line 0 = ets:info(T,kept_objects), + ?line 0 = get_kept_objects(T), ?line done = receive_any(), %%verify_table_load(T), % may fail if concurrency is poor (genny) ets:delete(T), @@ -4675,7 +5011,7 @@ shrink_pseudo_deleted_do() -> shrink_pseudo_deleted_do(Type) -> process_flag(scheduler,1), Self = self(), - ?line T = ets:new(kalle,[Type,public,{write_concurrency,true}]), + ?line T = ets_new(kalle,[Type,public,{write_concurrency,true}]), Half = 10000, filltabint(T,Half*2), ?line true = ets:safe_fixtable(T,true), @@ -4684,7 +5020,7 @@ shrink_pseudo_deleted_do(Type) -> [{'>', '$1', Half}], [true]}]), ?line Half = ets:info(T,size), - ?line Half = ets:info(T,kept_objects), + ?line Half = get_kept_objects(T), spawn_opt(fun()-> ?line true = ets:info(T,fixed), Self ! start, io:format("Starting to delete... ~p\n",[now()]), @@ -4697,24 +5033,17 @@ shrink_pseudo_deleted_do(Type) -> ?line true = ets:safe_fixtable(T,false), io:format("Unfix table done. ~p nitems=~p\n",[now(),ets:info(T,size)]), ?line false = ets:info(T,fixed), - ?line 0 = ets:info(T,kept_objects), + ?line 0 = get_kept_objects(T), ?line done = receive_any(), %%verify_table_load(T), % may fail if concurrency is poor (genny) ets:delete(T), process_flag(scheduler,0). -meta_smp(suite) -> - [meta_lookup_unnamed_read, - meta_lookup_unnamed_write, - meta_lookup_named_read, - meta_lookup_named_write, - meta_newdel_unnamed, - meta_newdel_named]. meta_lookup_unnamed_read(suite) -> []; meta_lookup_unnamed_read(Config) when is_list(Config) -> - InitF = fun(_) -> Tab = ets:new(unnamed,[]), + InitF = fun(_) -> Tab = ets_new(unnamed,[]), true = ets:insert(Tab,{key,data}), Tab end, @@ -4727,7 +5056,7 @@ meta_lookup_unnamed_read(Config) when is_list(Config) -> meta_lookup_unnamed_write(suite) -> []; meta_lookup_unnamed_write(Config) when is_list(Config) -> - InitF = fun(_) -> Tab = ets:new(unnamed,[]), + InitF = fun(_) -> Tab = ets_new(unnamed,[]), {Tab,0} end, ExecF = fun({Tab,N}) -> true = ets:insert(Tab,{key,N}), @@ -4740,7 +5069,7 @@ meta_lookup_unnamed_write(Config) when is_list(Config) -> meta_lookup_named_read(suite) -> []; meta_lookup_named_read(Config) when is_list(Config) -> InitF = fun([ProcN|_]) -> Name = list_to_atom(integer_to_list(ProcN)), - Tab = ets:new(Name,[named_table]), + Tab = ets_new(Name,[named_table]), true = ets:insert(Tab,{key,data}), Tab end, @@ -4754,7 +5083,7 @@ meta_lookup_named_read(Config) when is_list(Config) -> meta_lookup_named_write(suite) -> []; meta_lookup_named_write(Config) when is_list(Config) -> InitF = fun([ProcN|_]) -> Name = list_to_atom(integer_to_list(ProcN)), - Tab = ets:new(Name,[named_table]), + Tab = ets_new(Name,[named_table]), {Tab,0} end, ExecF = fun({Tab,N}) -> true = ets:insert(Tab,{key,N}), @@ -4767,7 +5096,7 @@ meta_lookup_named_write(Config) when is_list(Config) -> meta_newdel_unnamed(suite) -> []; meta_newdel_unnamed(Config) when is_list(Config) -> InitF = fun(_) -> ok end, - ExecF = fun(_) -> Tab = ets:new(unnamed,[]), + ExecF = fun(_) -> Tab = ets_new(unnamed,[]), true = ets:delete(Tab) end, FiniF = fun(_) -> ok end, @@ -4777,7 +5106,7 @@ meta_newdel_named(suite) -> []; meta_newdel_named(Config) when is_list(Config) -> InitF = fun([ProcN|_]) -> list_to_atom(integer_to_list(ProcN)) end, - ExecF = fun(Name) -> Name = ets:new(Name,[named_table]), + ExecF = fun(Name) -> Name = ets_new(Name,[named_table]), true = ets:delete(Name), Name end, @@ -4787,7 +5116,7 @@ meta_newdel_named(Config) when is_list(Config) -> smp_insert(doc) -> ["Concurrent insert's on same table"]; smp_insert(suite) -> []; smp_insert(Config) when is_list(Config) -> - ets:new(smp_insert,[named_table,public,{write_concurrency,true}]), + ets_new(smp_insert,[named_table,public,{write_concurrency,true}]), InitF = fun(_) -> ok end, ExecF = fun(_) -> true = ets:insert(smp_insert,{random:uniform(10000)}) end, @@ -4802,7 +5131,7 @@ smp_fixed_delete(Config) when is_list(Config) -> only_if_smp(fun()->smp_fixed_delete_do() end). smp_fixed_delete_do() -> - T = ets:new(foo,[public,{write_concurrency,true}]), + T = ets_new(foo,[public,{write_concurrency,true}]), %%Mem = ets:info(T,memory), NumOfObjs = 100000, filltabint(T,NumOfObjs), @@ -4820,7 +5149,7 @@ smp_fixed_delete_do() -> ?line 0 = ets:info(T,size), ?line true = ets:info(T,fixed), ?line Buckets = num_of_buckets(T), - ?line NumOfObjs = ets:info(T,kept_objects), + ?line NumOfObjs = get_kept_objects(T), ets:safe_fixtable(T,false), %% Will fail as unfix does not shrink the table: %%?line Mem = ets:info(T,memory), @@ -4838,7 +5167,7 @@ smp_unfix_fix(Config) when is_list(Config) -> smp_unfix_fix_do() -> process_flag(scheduler,1), Parent = self(), - T = ets:new(foo,[public,{write_concurrency,true}]), + T = ets_new(foo,[public,{write_concurrency,true}]), %%Mem = ets:info(T,memory), NumOfObjs = 100000, Deleted = 50000, @@ -4852,7 +5181,7 @@ smp_unfix_fix_do() -> Left = NumOfObjs - Deleted, ?line Left = ets:info(T,size), ?line true = ets:info(T,fixed), - ?line Deleted = ets:info(T,kept_objects), + ?line Deleted = get_kept_objects(T), {Child, Mref} = spawn_opt(fun()-> ?line true = ets:info(T,fixed), @@ -4869,7 +5198,7 @@ smp_unfix_fix_do() -> end, Deleted), ?line 0 = ets:info(T,size), - ?line true = ets:info(T,kept_objects) >= Left, + ?line true = get_kept_objects(T) >= Left, ?line done = receive_any() end, [link, monitor, {scheduler,2}]), @@ -4882,7 +5211,7 @@ smp_unfix_fix_do() -> Child ! done, {'DOWN', Mref, process, Child, normal} = receive_any(), ?line false = ets:info(T,fixed), - ?line 0 = ets:info(T,kept_objects), + ?line 0 = get_kept_objects(T), %%verify_table_load(T), ets:delete(T), process_flag(scheduler,0). @@ -4898,7 +5227,7 @@ otp_8166_do(WC) -> %% Bug scenario: One process segv while reading the table because another %% process is doing unfix without write-lock at the end of a trapping match_object. process_flag(scheduler,1), - T = ets:new(foo,[public, {write_concurrency,WC}]), + T = ets_new(foo,[public, {write_concurrency,WC}]), NumOfObjs = 3000, %% Need more than 1000 live objects for match_object to trap one time Deleted = NumOfObjs div 2, filltabint(T,NumOfObjs), @@ -4920,7 +5249,7 @@ otp_8166_do(WC) -> ZombieCrPid ! quit, {'DOWN', ZombieCrMref, process, ZombieCrPid, normal} = receive_any(), ?line false = ets:info(T,fixed), - ?line 0 = ets:info(T,kept_objects), + ?line 0 = get_kept_objects(T), %%verify_table_load(T), ets:delete(T), process_flag(scheduler,0). @@ -4987,7 +5316,7 @@ otp_8166_zombie_creator(T,Deleted) -> verify_table_load(T) -> ?line Stats = ets:info(T,stats), - ?line {Buckets,AvgLen,StdDev,ExpSD,_MinLen,_MaxLen} = Stats, + ?line {Buckets,AvgLen,StdDev,ExpSD,_MinLen,_MaxLen,_} = Stats, ?line ok = if AvgLen > 7 -> io:format("Table overloaded: Stats=~p\n~p\n", @@ -5010,14 +5339,20 @@ verify_table_load(T) -> end. - - +otp_8732(doc) -> ["ets:select on a tree with NIL key object"]; +otp_8732(Config) when is_list(Config) -> + Tab = ets_new(noname,[ordered_set]), + filltabstr(Tab,999), + ets:insert(Tab,{[],"nasty NIL object"}), + ?line [] = ets:match(Tab,{'_',nomatch}), %% Will hang if bug not fixed + ok. + smp_select_delete(suite) -> []; smp_select_delete(doc) -> ["Run concurrent select_delete (and inserts) on same table."]; smp_select_delete(Config) when is_list(Config) -> - T = ets:new(smp_select_delete,[named_table,public,{write_concurrency,true}]), + T = ets_new(smp_select_delete,[named_table,public,{write_concurrency,true}]), Mod = 17, Zeros = erlang:make_tuple(Mod,0), InitF = fun(_) -> Zeros end, @@ -5070,6 +5405,71 @@ smp_select_delete(Config) when is_list(Config) -> ?line false = ets:info(T,fixed), ets:delete(T). +types(doc) -> ["Test different types"]; +types(Config) when is_list(Config) -> + init_externals(), + repeat_for_opts(types_do,[[set,ordered_set],compressed]). + +types_do(Opts) -> + EtsMem = etsmem(), + ?line T = ets_new(xxx,Opts), + Fun = fun(Term) -> + ets:insert(T,{Term}), + ?line [{Term}] = ets:lookup(T,Term), + ets:insert(T,{Term,xxx}), + ?line [{Term,xxx}] = ets:lookup(T,Term), + ets:insert(T,{Term,"xxx"}), + ?line [{Term,"xxx"}] = ets:lookup(T,Term), + ets:insert(T,{xxx,Term}), + ?line [{xxx,Term}] = ets:lookup(T,xxx), + ets:insert(T,{"xxx",Term}), + ?line [{"xxx",Term}] = ets:lookup(T,"xxx"), + ets:delete_all_objects(T), + ?line 0 = ets:info(T,size) + end, + test_terms(Fun, strict), + ets:delete(T), + ?line verify_etsmem(EtsMem). + + +otp_9423(doc) -> ["vm-deadlock caused by race between ets:delete and others on write_concurrency table"]; +otp_9423(Config) when is_list(Config) -> + InitF = fun(_) -> {0,0} end, + ExecF = fun({S,F}) -> + receive + stop -> + io:format("~p got stop\n", [self()]), + [end_of_work | {"Succeded=",S,"Failed=",F}] + after 0 -> + %%io:format("~p (~p) doing lookup\n", [self(), {S,F}]), + try ets:lookup(otp_9423, key) of + [] -> {S+1,F} + catch + error:badarg -> {S,F+1} + end + end + end, + FiniF = fun(R) -> R end, + case run_workers(InitF, ExecF, FiniF, infinite, 1) of + Pids when is_list(Pids) -> + %%[P ! start || P <- Pids], + repeat(fun() -> ets:new(otp_9423, [named_table, public, {write_concurrency,true}]), + ets:delete(otp_9423) + end, 10000), + [P ! stop || P <- Pids], + wait_pids(Pids), + ok; + + Skipped -> Skipped + end. + + + + +% +% Utility functions: +% + add_lists(L1,L2) -> add_lists(L1,L2,[]). add_lists([],[],Acc) -> @@ -5078,21 +5478,30 @@ add_lists([E1|T1], [E2|T2], Acc) -> add_lists(T1, T2, [E1+E2 | Acc]). run_workers(InitF,ExecF,FiniF,Laps) -> + run_workers(InitF,ExecF,FiniF,Laps, 0). +run_workers(InitF,ExecF,FiniF,Laps, Exclude) -> case erlang:system_info(smp_support) of true -> - run_workers_do(InitF,ExecF,FiniF,Laps); + run_workers_do(InitF,ExecF,FiniF,Laps, Exclude); false -> {skipped,"No smp support"} end. - + run_workers_do(InitF,ExecF,FiniF,Laps) -> - NumOfProcs = erlang:system_info(schedulers), + run_workers_do(InitF,ExecF,FiniF,Laps, 0). +run_workers_do(InitF,ExecF,FiniF,Laps, Exclude) -> + ?line NumOfProcs = case erlang:system_info(schedulers) of + N when (N > Exclude) -> N - Exclude + end, io:format("smp starting ~p workers\n",[NumOfProcs]), Seeds = [{ProcN,random:uniform(9999)} || ProcN <- lists:seq(1,NumOfProcs)], Parent = self(), Pids = [spawn_link(fun()-> worker(Seed,InitF,ExecF,FiniF,Laps,Parent,NumOfProcs) end) || Seed <- Seeds], - wait_pids(Pids). + case Laps of + infinite -> Pids; + _ -> wait_pids(Pids) + end. worker({ProcN,Seed}, InitF, ExecF, FiniF, Laps, Parent, NumOfProcs) -> io:format("smp worker ~p, seed=~p~n",[self(),Seed]), @@ -5107,6 +5516,8 @@ worker_loop(0, _, State) -> State; worker_loop(_, _, [end_of_work|State]) -> State; +worker_loop(infinite, ExecF, State) -> + worker_loop(infinite,ExecF,ExecF(State)); worker_loop(N, ExecF, State) -> worker_loop(N-1,ExecF,ExecF(State)). @@ -5134,31 +5545,55 @@ my_tab_to_list(_Ts,'$end_of_table', Acc) -> lists:reverse(Acc); my_tab_to_list(Ts,Key, Acc) -> my_tab_to_list(Ts,ets:next(Ts,Key),[ets:lookup(Ts, Key)| Acc]). +wait_for_all_schedulers_online_to_execute() -> + PMs = lists:map(fun (Sched) -> + spawn_opt(fun () -> ok end, + [monitor, {scheduler, Sched}]) + end, + lists:seq(1,erlang:system_info(schedulers_online))), + lists:foreach(fun ({P, M}) -> + receive + {'DOWN', M, process, P, _} -> ok + end + end, + PMs), + ok. + etsmem() -> + %% Wait until it is guaranteed that all already scheduled + %% deallocations of DbTable structures have completed. + wait_for_all_schedulers_online_to_execute(), + + AllTabs = lists:map(fun(T) -> {T,ets:info(T,name),ets:info(T,size), + ets:info(T,memory),ets:info(T,type)} + end, ets:all()), + Mem = {try erlang:memory(ets) catch error:notsup -> notsup end, case erlang:system_info({allocator,ets_alloc}) of false -> undefined; MemInfo -> - MSBCS = lists:foldl( - fun ({instance, _, L}, Acc) -> - {value,{_,MBCS}} = lists:keysearch(mbcs, 1, L), - {value,{_,SBCS}} = lists:keysearch(sbcs, 1, L), - [MBCS,SBCS | Acc] - end, - [], - MemInfo), + CS = lists:foldl( + fun ({instance, _, L}, Acc) -> + {value,{_,SBMBCS}} = lists:keysearch(sbmbcs, 1, L), + {value,{_,MBCS}} = lists:keysearch(mbcs, 1, L), + {value,{_,SBCS}} = lists:keysearch(sbcs, 1, L), + [SBMBCS,MBCS,SBCS | Acc] + end, + [], + MemInfo), lists:foldl( fun(L, {Bl0,BlSz0}) -> {value,{_,Bl,_,_}} = lists:keysearch(blocks, 1, L), {value,{_,BlSz,_,_}} = lists:keysearch(blocks_size, 1, L), {Bl0+Bl,BlSz0+BlSz} - end, {0,0}, MSBCS) - end}. + end, {0,0}, CS) + end}, + {Mem,AllTabs}. -verify_etsmem(MemInfo) -> +verify_etsmem({MemInfo,AllTabs}) -> wait_for_test_procs(), case etsmem() of - MemInfo -> + {MemInfo,_} -> io:format("Ets mem info: ~p", [MemInfo]), case MemInfo of {ErlMem,EtsAlloc} when ErlMem == notsup; EtsAlloc == undefined -> @@ -5167,12 +5602,15 @@ verify_etsmem(MemInfo) -> _ -> ok end; - Other -> + {MemInfo2, AllTabs2} -> io:format("Expected: ~p", [MemInfo]), - io:format("Actual: ~p", [Other]), + io:format("Actual: ~p", [MemInfo2]), + io:format("Changed tables before: ~p\n",[AllTabs -- AllTabs2]), + io:format("Changed tables after: ~p\n", [AllTabs2 -- AllTabs]), ?t:fail() end. + start_loopers(N, Prio, Fun, State) -> lists:map(fun (_) -> my_spawn_opt(fun () -> looper(Fun, State) end, @@ -5277,6 +5715,20 @@ repeat_while(Fun, Arg0) -> {false,Ret} -> Ret end. +%% Some (but not all) permutations of List +repeat_for_permutations(Fun, List) -> + repeat_for_permutations(Fun, List, length(List)-1). +repeat_for_permutations(Fun, List, 0) -> + Fun(List); +repeat_for_permutations(Fun, List, N) -> + {A,B} = lists:split(N, List), + L1 = B++A, + L2 = lists:reverse(L1), + L3 = B++lists:reverse(A), + L4 = lists:reverse(B)++A, + Fun(L1), Fun(L2), Fun(L3), Fun(L4), + repeat_for_permutations(Fun, List, N-1). + receive_any() -> receive M -> io:format("Process ~p got msg ~p\n", [self(),M]), @@ -5332,22 +5784,232 @@ only_if_smp(Schedulers, Func) -> {true,_} -> Func() end. +%% Copy-paste from emulator/test/binary_SUITE.erl +-define(heap_binary_size, 64). +test_terms(Test_Func, Mode) -> + garbage_collect(), + ?line Pib0 = process_info(self(),binary), + + ?line Test_Func(atom), + ?line Test_Func(''), + ?line Test_Func('a'), + ?line Test_Func('ab'), + ?line Test_Func('abc'), + ?line Test_Func('abcd'), + ?line Test_Func('abcde'), + ?line Test_Func('abcdef'), + ?line Test_Func('abcdefg'), + ?line Test_Func('abcdefgh'), + + ?line Test_Func(fun() -> ok end), + X = id([a,{b,c},c]), + Y = id({x,y,z}), + Z = id(1 bsl 8*257), + ?line Test_Func(fun() -> X end), + ?line Test_Func(fun() -> {X,Y} end), + ?line Test_Func([fun() -> {X,Y,Z} end, + fun() -> {Z,X,Y} end, + fun() -> {Y,Z,X} end]), + + ?line Test_Func({trace_ts,{even_bigger,{some_data,fun() -> ok end}},{1,2,3}}), + ?line Test_Func({trace_ts,{even_bigger,{some_data,<<1,2,3,4,5,6,7,8,9,10>>}}, + {1,2,3}}), + + ?line Test_Func(1), + ?line Test_Func(42), + ?line Test_Func(-23), + ?line Test_Func(256), + ?line Test_Func(25555), + ?line Test_Func(-3333), + + ?line Test_Func(1.0), + + ?line Test_Func(183749783987483978498378478393874), + ?line Test_Func(-37894183749783987483978498378478393874), + Very_Big = very_big_num(), + ?line Test_Func(Very_Big), + ?line Test_Func(-Very_Big+1), + + ?line Test_Func([]), + ?line Test_Func("abcdef"), + ?line Test_Func([a, b, 1, 2]), + ?line Test_Func([a|b]), + + ?line Test_Func({}), + ?line Test_Func({1}), + ?line Test_Func({a, b}), + ?line Test_Func({a, b, c}), + ?line Test_Func(list_to_tuple(lists:seq(0, 255))), + ?line Test_Func(list_to_tuple(lists:seq(0, 256))), + + ?line Test_Func(make_ref()), + ?line Test_Func([make_ref(), make_ref()]), + + ?line Test_Func(make_port()), + + ?line Test_Func(make_pid()), + ?line Test_Func(make_ext_pid()), + ?line Test_Func(make_ext_port()), + ?line Test_Func(make_ext_ref()), + + Bin0 = list_to_binary(lists:seq(0, 14)), + ?line Test_Func(Bin0), + Bin1 = list_to_binary(lists:seq(0, ?heap_binary_size)), + ?line Test_Func(Bin1), + Bin2 = list_to_binary(lists:seq(0, ?heap_binary_size+1)), + ?line Test_Func(Bin2), + Bin3 = list_to_binary(lists:seq(0, 255)), + garbage_collect(), + Pib = process_info(self(),binary), + ?line Test_Func(Bin3), + garbage_collect(), + case Mode of + strict -> ?line Pib = process_info(self(),binary); + skip_refc_check -> ok + end, + + ?line Test_Func(make_unaligned_sub_binary(Bin0)), + ?line Test_Func(make_unaligned_sub_binary(Bin1)), + ?line Test_Func(make_unaligned_sub_binary(Bin2)), + ?line Test_Func(make_unaligned_sub_binary(Bin3)), + + ?line Test_Func(make_sub_binary(lists:seq(42, 43))), + ?line Test_Func(make_sub_binary([42,43,44])), + ?line Test_Func(make_sub_binary([42,43,44,45])), + ?line Test_Func(make_sub_binary([42,43,44,45,46])), + ?line Test_Func(make_sub_binary([42,43,44,45,46,47])), + ?line Test_Func(make_sub_binary([42,43,44,45,46,47,48])), + ?line Test_Func(make_sub_binary(lists:seq(42, 49))), + ?line Test_Func(make_sub_binary(lists:seq(0, 14))), + ?line Test_Func(make_sub_binary(lists:seq(0, ?heap_binary_size))), + ?line Test_Func(make_sub_binary(lists:seq(0, ?heap_binary_size+1))), + ?line Test_Func(make_sub_binary(lists:seq(0, 255))), + + ?line Test_Func(make_unaligned_sub_binary(lists:seq(42, 43))), + ?line Test_Func(make_unaligned_sub_binary([42,43,44])), + ?line Test_Func(make_unaligned_sub_binary([42,43,44,45])), + ?line Test_Func(make_unaligned_sub_binary([42,43,44,45,46])), + ?line Test_Func(make_unaligned_sub_binary([42,43,44,45,46,47])), + ?line Test_Func(make_unaligned_sub_binary([42,43,44,45,46,47,48])), + ?line Test_Func(make_unaligned_sub_binary(lists:seq(42, 49))), + ?line Test_Func(make_unaligned_sub_binary(lists:seq(0, 14))), + ?line Test_Func(make_unaligned_sub_binary(lists:seq(0, ?heap_binary_size))), + ?line Test_Func(make_unaligned_sub_binary(lists:seq(0, ?heap_binary_size+1))), + ?line Test_Func(make_unaligned_sub_binary(lists:seq(0, 255))), + + %% Bit level binaries. + ?line Test_Func(<<1:1>>), + ?line Test_Func(<<2:2>>), + ?line Test_Func(<<42:10>>), + ?line Test_Func(list_to_bitstring([<<5:6>>|lists:seq(0, 255)])), + + ?line Test_Func(F = fun(A) -> 42*A end), + ?line Test_Func(lists:duplicate(32, F)), + + ?line Test_Func(FF = fun binary_SUITE:all/1), + ?line Test_Func(lists:duplicate(32, FF)), + + garbage_collect(), + case Mode of + strict -> ?line Pib0 = process_info(self(),binary); + skip_refc_check -> ok + end, + ok. + + +id(I) -> I. + +very_big_num() -> + very_big_num(33, 1). + +very_big_num(Left, Result) when Left > 0 -> + ?line very_big_num(Left-1, Result*256); +very_big_num(0, Result) -> + ?line Result. + +make_port() -> + ?line open_port({spawn, "efile"}, [eof]). + +make_pid() -> + ?line spawn_link(?MODULE, sleeper, []). + +sleeper() -> + ?line receive after infinity -> ok end. + +make_ext_pid() -> + {Pid, _, _} = get(externals), + Pid. + +make_ext_port() -> + {_, Port, _} = get(externals), + Port. +make_ext_ref() -> + {_, _, Ref} = get(externals), + Ref. + +init_externals() -> + case get(externals) of + undefined -> + SysDistSz = ets:info(sys_dist,size), + ?line Pa = filename:dirname(code:which(?MODULE)), + ?line {ok, Node} = test_server:start_node(plopp, slave, [{args, " -pa " ++ Pa}]), + ?line Res = case rpc:call(Node, ?MODULE, rpc_externals, []) of + {badrpc, {'EXIT', E}} -> + test_server:fail({rpcresult, E}); + R -> R + end, + ?line test_server:stop_node(Node), + + %% Wait for table 'sys_dist' to stabilize + repeat_while(fun() -> + case ets:info(sys_dist,size) of + SysDistSz -> false; + Sz -> + io:format("Waiting for sys_dist to revert size from ~p to size ~p\n", + [Sz, SysDistSz]), + receive after 1000 -> true end + end + end), + put(externals, Res); + + {_,_,_} -> ok + end. + +rpc_externals() -> + {self(), make_port(), make_ref()}. + +make_sub_binary(Bin) when is_binary(Bin) -> + {_,B} = split_binary(list_to_binary([0,1,3,Bin]), 3), + B; +make_sub_binary(List) -> + make_sub_binary(list_to_binary(List)). + +make_unaligned_sub_binary(Bin0) when is_binary(Bin0) -> + Bin1 = <<0:3,Bin0/binary,31:5>>, + Sz = size(Bin0), + <<0:3,Bin:Sz/binary,31:5>> = id(Bin1), + Bin; +make_unaligned_sub_binary(List) -> + make_unaligned_sub_binary(list_to_binary(List)). %% Repeat test function with different combination of table options %% repeat_for_opts(F) -> - repeat_for_opts(F, [write_concurrency]). + repeat_for_opts(F, [write_concurrency, read_concurrency, compressed]). repeat_for_opts(F, OptGenList) when is_atom(F) -> repeat_for_opts(fun(Opts) -> ?MODULE:F(Opts) end, OptGenList); +repeat_for_opts({F,Args}, OptGenList) when is_atom(F) -> + repeat_for_opts(fun(Opts) -> ?MODULE:F(Opts,Args) end, OptGenList); repeat_for_opts(F, OptGenList) -> repeat_for_opts(F, OptGenList, []). repeat_for_opts(F, [], Acc) -> - lists:map(fun(Opts) -> - io:format("Calling with options ~p\n",[Opts]), - F(Opts) - end, Acc); + lists:map(fun(Opts) -> + OptList = lists:filter(fun(E) -> E =/= void end, Opts), + io:format("Calling with options ~p\n",[OptList]), + F(OptList) + end, Acc); repeat_for_opts(F, [OptList | Tail], []) when is_list(OptList) -> repeat_for_opts(F, Tail, [[Opt] || Opt <- OptList]); repeat_for_opts(F, [OptList | Tail], AccList) when is_list(OptList) -> @@ -5356,6 +6018,10 @@ repeat_for_opts(F, [Atom | Tail], AccList) when is_atom(Atom) -> repeat_for_opts(F, [repeat_for_opts_atom2list(Atom) | Tail ], AccList). repeat_for_opts_atom2list(all_types) -> [set,ordered_set,bag,duplicate_bag]; -repeat_for_opts_atom2list(write_concurrency) -> [{write_concurrency,false},{write_concurrency,true}]. - +repeat_for_opts_atom2list(write_concurrency) -> [{write_concurrency,false},{write_concurrency,true}]; +repeat_for_opts_atom2list(read_concurrency) -> [{read_concurrency,false},{read_concurrency,true}]; +repeat_for_opts_atom2list(compressed) -> [compressed,void]. +ets_new(Name, Opts) -> + %%ets:new(Name, [compressed | Opts]). + ets:new(Name, Opts). |