diff options
author | Sverker Eriksson <[email protected]> | 2018-11-01 16:53:06 +0100 |
---|---|---|
committer | Sverker Eriksson <[email protected]> | 2018-11-01 17:48:20 +0100 |
commit | e5b006ce3361467f77c372a4b6f19f9e0d9ddf23 (patch) | |
tree | 62b1b9d5c3d9aeb76b8f876b2a3b284f4c59cebe | |
parent | cc18836780d7d047bf53b1ff8d94a6b31b58f98a (diff) | |
download | otp-e5b006ce3361467f77c372a4b6f19f9e0d9ddf23.tar.gz otp-e5b006ce3361467f77c372a4b6f19f9e0d9ddf23.tar.bz2 otp-e5b006ce3361467f77c372a4b6f19f9e0d9ddf23.zip |
erts: Fix bug for catree iteration
with keys containing off-heap terms.
The passed key may actually be the one already saved
(if nodes have been joined), in which case we do nothing.
Calling destroy_route_key() may destroy off-heap data.
-rw-r--r-- | erts/emulator/beam/erl_db_catree.c | 3 | ||||
-rw-r--r-- | lib/stdlib/test/ets_SUITE.erl | 24 |
2 files changed, 16 insertions, 11 deletions
diff --git a/erts/emulator/beam/erl_db_catree.c b/erts/emulator/beam/erl_db_catree.c index b52a4a53fe..7a5587f1fd 100644 --- a/erts/emulator/beam/erl_db_catree.c +++ b/erts/emulator/beam/erl_db_catree.c @@ -1585,7 +1585,8 @@ static Eterm copy_iter_search_key(CATreeRootIterator* iter, Eterm key) return key; if (iter->search_key) { - ASSERT(key != iter->search_key->term); + if (key == iter->search_key->term) + return key; /* already saved */ destroy_route_key(iter->search_key); } key_size = size_object(key); diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl index e49181b12f..cc369979f7 100644 --- a/lib/stdlib/test/ets_SUITE.erl +++ b/lib/stdlib/test/ets_SUITE.erl @@ -6052,8 +6052,9 @@ smp_ordered_iteration(Config) when is_list(Config) -> smp_ordered_iteration_do(Opts) -> KeyRange = 1000, + OffHeap = fun() -> dummy end, % To exercise key copy/destroy code. KeyFun = fun(K, Type) -> - {K div 10, K rem 10, Type} + {K div 10, K rem 10, Type, OffHeap} end, StimKeyFun = fun(K) -> KeyFun(K, element(rand:uniform(3), @@ -6084,7 +6085,7 @@ smp_ordered_iteration_do(Opts) -> incr_counter(select_delete_bk, Counters); R when R =< 20 -> %% Delete partially bound key - ets:select_delete(T, [{{{K div 10, '_', volatile}, '_'}, [], [true]}]), + ets:select_delete(T, [{{{K div 10, '_', volatile, '_'}, '_'}, [], [true]}]), incr_counter(select_delete_pbk, Counters); R when R =< 21 -> %% Replace bound key @@ -6093,7 +6094,7 @@ smp_ordered_iteration_do(Opts) -> incr_counter(select_replace_bk, Counters); _ -> %% Replace partially bound key - ets:select_replace(T, [{{{K div 10, '_', volatile}, '$1'}, [], + ets:select_replace(T, [{{{K div 10, '_', volatile, '_'}, '$1'}, [], [{{{element,1,'$_'}, {'+','$1',1}}}]}]), incr_counter(select_replace_pbk, Counters) end, @@ -6106,14 +6107,17 @@ smp_ordered_iteration_do(Opts) -> FiniF = fun (Acc) -> Acc end, Pids = run_sched_workers(InitF, ExecF, FiniF, infinite), timer:send_after(1000, stop), + + Log2ChunkMax = math:log2(NStable*2), Rounds = fun Loop(N) -> - NStable = ets:select_count(T, [{{{'_', '_', stable}, '_'}, [], [true]}]), + MS = [{{{'_', '_', stable, '_'}, '_'}, [], [true]}], + NStable = ets:select_count(T, MS), NStable = count_stable(T, next, ets:first(T), 0), NStable = count_stable(T, prev, ets:last(T), 0), - NStable = length(ets:select(T, [{{{'_', '_', stable}, '_'}, [], [true]}])), - NStable = length(ets:select_reverse(T, [{{{'_', '_', stable}, '_'}, [], [true]}])), - NStable = ets_select_chunks_count(T, [{{{'_', '_', stable}, '_'}, [], [true]}], - rand:uniform(5)), + NStable = length(ets:select(T, MS)), + NStable = length(ets:select_reverse(T, MS)), + Chunk = round(math:pow(2, rand:uniform()*Log2ChunkMax)), + NStable = ets_select_chunks_count(T, MS, Chunk), receive stop -> N after 0 -> Loop(N+1) end @@ -6130,9 +6134,9 @@ smp_ordered_iteration_do(Opts) -> incr_counter(Name, Counters) -> Counters#{Name => maps:get(Name, Counters, 0) + 1}. -count_stable(T, Next, {_, _, stable}=Key, N) -> +count_stable(T, Next, {_, _, stable, _}=Key, N) -> count_stable(T, Next, ets:Next(T, Key), N+1); -count_stable(T, Next, {_, _, volatile}=Key, N) -> +count_stable(T, Next, {_, _, volatile, _}=Key, N) -> count_stable(T, Next, ets:Next(T, Key), N); count_stable(_, _, '$end_of_table', N) -> N. |