summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--erts/emulator/beam/erl_db_hash.c20
-rw-r--r--erts/emulator/beam/erl_db_tree.c8
-rw-r--r--erts/emulator/beam/erl_db_util.c22
-rw-r--r--erts/emulator/beam/erl_db_util.h3
-rw-r--r--lib/stdlib/test/ets_SUITE.erl114
5 files changed, 113 insertions, 54 deletions
diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c
index 92ff7de268..73cb58547b 100644
--- a/erts/emulator/beam/erl_db_hash.c
+++ b/erts/emulator/beam/erl_db_hash.c
@@ -1598,12 +1598,18 @@ static int match_traverse(traverse_context_t* ctx,
for(;;) {
if (*current_ptr != NULL) {
if (!is_pseudo_deleted(*current_ptr)) {
- match_res = db_match_dbterm(&tb->common, ctx->p, mpi.mp,
- &(*current_ptr)->dbterm, hpp, 2);
+ DbTerm* obj = &(*current_ptr)->dbterm;
+ if (tb->common.compress)
+ obj = db_alloc_tmp_uncompressed(&tb->common, obj);
+ match_res = db_match_dbterm_uncompressed(&tb->common, ctx->p, mpi.mp,
+ obj, hpp, 2);
saved_current = *current_ptr;
if (ctx->on_match_res(ctx, slot_ix, &current_ptr, match_res)) {
++got;
}
+ if (tb->common.compress)
+ db_free_tmp_uncompressed(obj);
+
--iterations_left;
if (*current_ptr != saved_current) {
/* Don't advance to next, the callback did it already */
@@ -1717,12 +1723,18 @@ static int match_traverse_continue(traverse_context_t* ctx,
for(;;) {
if (*current_ptr != NULL) {
if (!is_pseudo_deleted(*current_ptr)) {
- match_res = db_match_dbterm(&tb->common, ctx->p, *mpp,
- &(*current_ptr)->dbterm, hpp, 2);
+ DbTerm* obj = &(*current_ptr)->dbterm;
+ if (tb->common.compress)
+ obj = db_alloc_tmp_uncompressed(&tb->common, obj);
+ match_res = db_match_dbterm_uncompressed(&tb->common, ctx->p, *mpp,
+ obj, hpp, 2);
saved_current = *current_ptr;
if (ctx->on_match_res(ctx, slot_ix, &current_ptr, match_res)) {
++got;
}
+ if (tb->common.compress)
+ db_free_tmp_uncompressed(obj);
+
--iterations_left;
if (*current_ptr != saved_current) {
/* Don't advance to next, the callback did it already */
diff --git a/erts/emulator/beam/erl_db_tree.c b/erts/emulator/beam/erl_db_tree.c
index 131ec123b0..90e37c4b4e 100644
--- a/erts/emulator/beam/erl_db_tree.c
+++ b/erts/emulator/beam/erl_db_tree.c
@@ -4161,6 +4161,7 @@ static int doit_select_replace(DbTableCommon *tb, TreeDbTerm **this,
int forward)
{
struct select_replace_context *sc = (struct select_replace_context *) ptr;
+ DbTerm* obj;
Eterm ret;
sc->lastobj = (*this)->dbterm.tpl;
@@ -4171,7 +4172,10 @@ static int doit_select_replace(DbTableCommon *tb, TreeDbTerm **this,
GETKEY_WITH_POS(sc->keypos, (*this)->dbterm.tpl)) > 0)) {
return 0;
}
- ret = db_match_dbterm(tb, sc->p, sc->mp, &(*this)->dbterm, NULL, 0);
+ obj = &(*this)->dbterm;
+ if (tb->compress)
+ obj = db_alloc_tmp_uncompressed(tb, obj);
+ ret = db_match_dbterm_uncompressed(tb, sc->p, sc->mp, obj, NULL, 0);
if (is_value(ret)) {
TreeDbTerm* new;
@@ -4190,6 +4194,8 @@ static int doit_select_replace(DbTableCommon *tb, TreeDbTerm **this,
free_term((DbTable*)tb, old);
++(sc->replaced);
}
+ if (tb->compress)
+ db_free_tmp_uncompressed(obj);
if (--(sc->max) <= 0) {
return 0;
}
diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c
index a0be53c896..2087e1c337 100644
--- a/erts/emulator/beam/erl_db_util.c
+++ b/erts/emulator/beam/erl_db_util.c
@@ -953,8 +953,6 @@ static Eterm match_spec_test(Process *p, Eterm against, Eterm spec, int trace);
static Eterm seq_trace_fake(Process *p, Eterm arg1);
-static void db_free_tmp_uncompressed(DbTerm* obj);
-
/*
** Interface routines.
@@ -5410,17 +5408,13 @@ void db_free_tmp_uncompressed(DbTerm* obj)
erts_free(ERTS_ALC_T_TMP, obj);
}
-Eterm db_match_dbterm(DbTableCommon* tb, Process* c_p, Binary* bprog,
- DbTerm* obj, Eterm** hpp, Uint extra)
+Eterm db_match_dbterm_uncompressed(DbTableCommon* tb, Process* c_p, Binary* bprog,
+ DbTerm* obj, Eterm** hpp, Uint extra)
{
enum erts_pam_run_flags flags;
Uint32 dummy;
Eterm res;
- if (tb->compress) {
- obj = db_alloc_tmp_uncompressed(tb, obj);
- }
-
flags = (hpp ?
ERTS_PAM_COPY_RESULT | ERTS_PAM_CONTIGUOUS_TUPLE :
ERTS_PAM_TMP_RESULT | ERTS_PAM_CONTIGUOUS_TUPLE);
@@ -5432,9 +5426,19 @@ Eterm db_match_dbterm(DbTableCommon* tb, Process* c_p, Binary* bprog,
if (is_value(res) && hpp!=NULL) {
*hpp = HAlloc(c_p, extra);
}
+ return res;
+}
+Eterm db_match_dbterm(DbTableCommon* tb, Process* c_p, Binary* bprog,
+ DbTerm* obj, Eterm** hpp, Uint extra)
+{
+ Eterm res;
+ if (tb->compress) {
+ obj = db_alloc_tmp_uncompressed(tb, obj);
+ }
+ res = db_match_dbterm_uncompressed(tb, c_p, bprog, obj, hpp, extra);
if (tb->compress) {
- db_free_tmp_uncompressed(obj);
+ db_free_tmp_uncompressed(obj);
}
return res;
}
diff --git a/erts/emulator/beam/erl_db_util.h b/erts/emulator/beam/erl_db_util.h
index 8049d40eff..86170677ba 100644
--- a/erts/emulator/beam/erl_db_util.h
+++ b/erts/emulator/beam/erl_db_util.h
@@ -373,6 +373,7 @@ Eterm db_copy_from_comp(DbTableCommon* tb, DbTerm* bp, Eterm** hpp,
ErlOffHeap* off_heap);
int db_eq_comp(DbTableCommon* tb, Eterm a, DbTerm* b);
DbTerm* db_alloc_tmp_uncompressed(DbTableCommon* tb, DbTerm* org);
+void db_free_tmp_uncompressed(DbTerm* obj);
ERTS_GLB_INLINE Eterm db_copy_object_from_ets(DbTableCommon* tb, DbTerm* bp,
Eterm** hpp, ErlOffHeap* off_heap);
@@ -543,6 +544,8 @@ Binary *db_match_compile(Eterm *matchexpr, Eterm *guards,
Uint *freasonp);
/* Returns newly allocated MatchProg binary with refc == 0*/
+Eterm db_match_dbterm_uncompressed(DbTableCommon* tb, Process* c_p, Binary* bprog,
+ DbTerm* obj, Eterm** hpp, Uint extra);
Eterm db_match_dbterm(DbTableCommon* tb, Process* c_p, Binary* bprog,
DbTerm* obj, Eterm** hpp, Uint extra);
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index 9e5410c10f..08cedf704d 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -1653,7 +1653,11 @@ t_select_delete(Config) when is_list(Config) ->
%% Tests the ets:select_replace/2 BIF
t_select_replace(Config) when is_list(Config) ->
EtsMem = etsmem(),
- Tables = fill_sets_int(10000) ++ fill_sets_int(10000, [{write_concurrency,true}]),
+ repeat_for_opts(fun do_select_replace/1),
+ verify_etsmem(EtsMem).
+
+do_select_replace(Opts) ->
+ Tables = fill_sets_intup(10000, Opts),
TestFun = fun (Table, TableType) when TableType =:= bag ->
% Operation not supported; bag implementation
@@ -1662,80 +1666,80 @@ t_select_replace(Config) when is_list(Config) ->
(Table, TableType) ->
% Invalid replacement doesn't keep the key
- MatchSpec1 = [{{'$1', '$2'},
+ MatchSpec1 = [{{{'$1','$3'}, '$2'},
[{'=:=', {'band', '$1', 2#11}, 2#11},
{'=/=', {'hd', '$2'}, $x}],
- [{{'$2', '$1'}}]}],
+ [{{{{'$2','$3'}}, '$1'}}]}],
{'EXIT',{badarg,_}} = (catch ets:select_replace(Table, MatchSpec1)),
% Invalid replacement doesn't keep the key (even though it would be the same value)
- MatchSpec2 = [{{'$1', '$2'},
+ MatchSpec2 = [{{{'$1','$3'}, '$2'},
[{'=:=', {'band', '$1', 2#11}, 2#11}],
- [{{{'+', '$1', 0}, '$2'}}]},
- {{'$1', '$2'},
+ [{{{{{'+', '$1', 0},'$3'}}, '$2'}}]},
+ {{{'$1','$3'}, '$2'},
[{'=/=', {'band', '$1', 2#11}, 2#11}],
- [{{{'-', '$1', 0}, '$2'}}]}],
+ [{{{{{'-', '$1', 0},'$3'}}, '$2'}}]}],
{'EXIT',{badarg,_}} = (catch ets:select_replace(Table, MatchSpec2)),
% Invalid replacement changes key to float equivalent
- MatchSpec3 = [{{'$1', '$2'},
+ MatchSpec3 = [{{{'$1','$3'}, '$2'},
[{'=:=', {'band', '$1', 2#11}, 2#11},
{'=/=', {'hd', '$2'}, $x}],
- [{{{'*', '$1', 1.0}, '$2'}}]}],
+ [{{{{{'*', '$1', 1.0},'$3'}}, '$2'}}]}],
{'EXIT',{badarg,_}} = (catch ets:select_replace(Table, MatchSpec3)),
% Replacements are differently-sized tuples
- MatchSpec4_A = [{{'$1','$2'},
+ MatchSpec4_A = [{{{'$1','$3'},'$2'},
[{'<', {'rem', '$1', 5}, 2}],
- [{{'$1', [$x | '$2'], stuff}}]}],
- MatchSpec4_B = [{{'$1','$2','_'},
+ [{{{{'$1','$3'}}, [$x | '$2'], stuff}}]}],
+ MatchSpec4_B = [{{{'$1','$3'},'$2','_'},
[],
- [{{'$1','$2'}}]}],
+ [{{{{'$1','$3'}},'$2'}}]}],
4000 = ets:select_replace(Table, MatchSpec4_A),
4000 = ets:select_replace(Table, MatchSpec4_B),
% Replacement is the same tuple
- MatchSpec5 = [{{'$1', '$2'},
+ MatchSpec5 = [{{{'$1','$3'}, '$2'},
[{'>', {'rem', '$1', 5}, 3}],
['$_']}],
2000 = ets:select_replace(Table, MatchSpec5),
% Replacement reconstructs an equal tuple
- MatchSpec6 = [{{'$1', '$2'},
+ MatchSpec6 = [{{{'$1','$3'}, '$2'},
[{'>', {'rem', '$1', 5}, 3}],
- [{{'$1', '$2'}}]}],
+ [{{{{'$1','$3'}}, '$2'}}]}],
2000 = ets:select_replace(Table, MatchSpec6),
% Replacement uses {element,KeyPos,T} for key
2000 = ets:select_replace(Table,
- [{{'$1', '$2'},
+ [{{{'$1','$3'}, '$2'},
[{'>', {'rem', '$1', 5}, 3}],
[{{{element, 1, '$_'}, '$2'}}]}]),
% Replacement uses wrong {element,KeyPos,T} for key
{'EXIT',{badarg,_}} = (catch ets:select_replace(Table,
- [{{'$1', '$2'},
+ [{{{'$1','$3'}, '$2'},
[],
[{{{element, 2, '$_'}, '$2'}}]}])),
check(Table,
- fun ({N, [$x, C | _]}) when ((N rem 5) < 2) -> (C >= $0) andalso (C =< $9);
- ({N, [C | _]}) when is_float(N) -> (C >= $0) andalso (C =< $9);
- ({N, [C | _]}) when ((N rem 5) > 3) -> (C >= $0) andalso (C =< $9);
+ fun ({{N,_}, [$x, C | _]}) when ((N rem 5) < 2) -> (C >= $0) andalso (C =< $9);
+ ({{N,_}, [C | _]}) when is_float(N) -> (C >= $0) andalso (C =< $9);
+ ({{N,_}, [C | _]}) when ((N rem 5) > 3) -> (C >= $0) andalso (C =< $9);
({_, [C | _]}) -> (C >= $0) andalso (C =< $9)
end,
10000),
% Replace unbound range (>)
- MatchSpec7 = [{{'$1', '$2'},
+ MatchSpec7 = [{{{'$1','$3'}, '$2'},
[{'>', '$1', 7000}],
- [{{'$1', {{gt_range, '$2'}}}}]}],
+ [{{{{'$1','$3'}}, {{gt_range, '$2'}}}}]}],
3000 = ets:select_replace(Table, MatchSpec7),
% Replace unbound range (<)
- MatchSpec8 = [{{'$1', '$2'},
+ MatchSpec8 = [{{{'$1','$3'}, '$2'},
[{'<', '$1', 3000}],
- [{{'$1', {{le_range, '$2'}}}}]}],
+ [{{{{'$1','$3'}}, {{le_range, '$2'}}}}]}],
case TableType of
ordered_set -> 2999 = ets:select_replace(Table, MatchSpec8);
set -> 2999 = ets:select_replace(Table, MatchSpec8);
@@ -1743,10 +1747,10 @@ t_select_replace(Config) when is_list(Config) ->
end,
% Replace bound range
- MatchSpec9 = [{{'$1', '$2'},
+ MatchSpec9 = [{{{'$1','$3'}, '$2'},
[{'>=', '$1', 3001},
{'<', '$1', 7000}],
- [{{'$1', {{range, '$2'}}}}]}],
+ [{{{{'$1','$3'}}, {{range, '$2'}}}}]}],
case TableType of
ordered_set -> 3999 = ets:select_replace(Table, MatchSpec9);
set -> 3999 = ets:select_replace(Table, MatchSpec9);
@@ -1754,12 +1758,12 @@ t_select_replace(Config) when is_list(Config) ->
end,
% Replace particular keys
- MatchSpec10 = [{{'$1', '$2'},
+ MatchSpec10 = [{{{'$1','$3'}, '$2'},
[{'==', '$1', 3000}],
- [{{'$1', {{specific1, '$2'}}}}]},
- {{'$1', '$2'},
+ [{{{{'$1','$3'}}, {{specific1, '$2'}}}}]},
+ {{{'$1','$3'}, '$2'},
[{'==', '$1', 7000}],
- [{{'$1', {{specific2, '$2'}}}}]}],
+ [{{{{'$1','$3'}}, {{specific2, '$2'}}}}]}],
case TableType of
ordered_set -> 2 = ets:select_replace(Table, MatchSpec10);
set -> 2 = ets:select_replace(Table, MatchSpec10);
@@ -1767,11 +1771,11 @@ t_select_replace(Config) when is_list(Config) ->
end,
check(Table,
- fun ({N, {gt_range, _}}) -> N > 7000;
- ({N, {le_range, _}}) -> N < 3000;
- ({N, {range, _}}) -> (N >= 3001) andalso (N < 7000);
- ({N, {specific1, _}}) -> N == 3000;
- ({N, {specific2, _}}) -> N == 7000
+ fun ({{N,_}, {gt_range, _}}) -> N > 7000;
+ ({{N,_}, {le_range, _}}) -> N < 3000;
+ ({{N,_}, {range, _}}) -> (N >= 3001) andalso (N < 7000);
+ ({{N,_}, {specific1, _}}) -> N == 3000;
+ ({{N,_}, {specific2, _}}) -> N == 7000
end,
10000),
@@ -1811,7 +1815,7 @@ t_select_replace(Config) when is_list(Config) ->
]
end,
- T2 = ets:new(x, []),
+ T2 = ets:new(x, Opts),
[lists:foreach(fun({A, B}) ->
%% just check that matchspec is accepted
0 = ets:select_replace(T2, [{{A, '$2', '$3'}, [], [{{B, '$3', '$2'}}]}])
@@ -1872,8 +1876,7 @@ t_select_replace(Config) when is_list(Config) ->
ets:delete(T2),
-
- verify_etsmem(EtsMem).
+ ok.
%% OTP-15346: Bug caused select_replace of bound key to corrupt static stack
%% used by ets:next and ets:prev.
@@ -5902,6 +5905,7 @@ make_table(Name, Options, Elements) ->
T = ets_new(Name, Options),
lists:foreach(fun(E) -> ets:insert(T, E) end, Elements),
T.
+
filltabint(Tab,0) ->
Tab;
filltabint(Tab,N) ->
@@ -5929,6 +5933,22 @@ xfilltabint(Tab,N) ->
filltabint(Tab,N)
end.
+filltabintup(Tab,0) ->
+ Tab;
+filltabintup(Tab,N) ->
+ ets:insert(Tab,{{N,integer_to_list(N)},integer_to_list(N)}),
+ filltabintup(Tab,N-1).
+
+filltabintup2(Tab,0) ->
+ Tab;
+filltabintup2(Tab,N) ->
+ ets:insert(Tab,{{N + N rem 2,integer_to_list(N)},integer_to_list(N)}),
+ filltabintup2(Tab,N-1).
+filltabintup3(Tab,0) ->
+ Tab;
+filltabintup3(Tab,N) ->
+ ets:insert(Tab,{{N + N rem 2,integer_to_list(N + N rem 2)},integer_to_list(N + N rem 2)}),
+ filltabintup3(Tab,N-1).
filltabstr(Tab,N) ->
filltabstr(Tab,0,N).
@@ -5974,6 +5994,19 @@ fill_sets_int(N,Opts) ->
filltabint3(Tab4,N),
[Tab1,Tab2,Tab3,Tab4].
+fill_sets_intup(N) ->
+ fill_sets_int(N,[]).
+fill_sets_intup(N,Opts) ->
+ Tab1 = ets_new(xxx, [ordered_set|Opts]),
+ filltabintup(Tab1,N),
+ Tab2 = ets_new(xxx, [set|Opts]),
+ filltabintup(Tab2,N),
+ Tab3 = ets_new(xxx, [bag|Opts]),
+ filltabintup2(Tab3,N),
+ Tab4 = ets_new(xxx, [duplicate_bag|Opts]),
+ filltabintup3(Tab4,N),
+ [Tab1,Tab2,Tab3,Tab4].
+
check_fun(_Tab,_Fun,'$end_of_table') ->
ok;
check_fun(Tab,Fun,Item) ->
@@ -6941,7 +6974,8 @@ smp_select_delete_do(Opts) ->
smp_select_replace(Config) when is_list(Config) ->
repeat_for_opts(fun smp_select_replace_do/1,
- [[set,ordered_set,stim_cat_ord_set,duplicate_bag]]).
+ [[set,ordered_set,stim_cat_ord_set,duplicate_bag],
+ compressed]).
smp_select_replace_do(Opts) ->
KeyRange = 20,