aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSverker Eriksson <[email protected]>2016-07-08 15:13:35 +0200
committerLukas Larsson <[email protected]>2016-07-11 09:11:13 +0200
commita6d87854c3ae65dba8dba6571b4d31d901316a39 (patch)
tree5646694703622bfd604010bdbc4763b314522a00
parent382adc9e5d7c7dbd4e1f12adc483bc6eb7ed6c3d (diff)
downloadotp-a6d87854c3ae65dba8dba6571b4d31d901316a39.tar.gz
otp-a6d87854c3ae65dba8dba6571b4d31d901316a39.tar.bz2
otp-a6d87854c3ae65dba8dba6571b4d31d901316a39.zip
erts: Fix deadlock in ets:update_counter/4
in 'set' with 'write_concurrency' when inserting default object causes table to grow and the bucket to split is protected by same lock as the key.
-rw-r--r--erts/emulator/beam/erl_db_hash.c34
-rw-r--r--erts/emulator/beam/erl_db_util.h1
2 files changed, 19 insertions, 16 deletions
diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c
index 6b23be1adf..12ae086b31 100644
--- a/erts/emulator/beam/erl_db_hash.c
+++ b/erts/emulator/beam/erl_db_hash.c
@@ -2866,15 +2866,7 @@ db_lookup_dbterm_hash(Process *p, DbTable *tbl, Eterm key, Eterm obj,
q->hvalue = hval;
q->next = NULL;
*bp = b = q;
-
- {
- int nitems = erts_smp_atomic_inc_read_nob(&tb->common.nitems);
- int nactive = NACTIVE(tb);
-
- if (nitems > nactive * (CHAIN_LEN + 1) && !IS_FIXED(tb)) {
- grow(tb, nactive);
- }
- }
+ flags |= DB_INC_TRY_GROW;
} else {
HashDbTerm *q, *next = b->next;
@@ -2928,13 +2920,23 @@ db_finalize_dbterm_hash(int cret, DbUpdateHandle* handle)
WUNLOCK_HASH(lck);
erts_smp_atomic_dec_nob(&tb->common.nitems);
try_shrink(tb);
- } else if (handle->flags & DB_MUST_RESIZE) {
- db_finalize_resize(handle, offsetof(HashDbTerm,dbterm));
- WUNLOCK_HASH(lck);
- free_me = b;
- }
- else {
- WUNLOCK_HASH(lck);
+ } else {
+ if (handle->flags & DB_MUST_RESIZE) {
+ db_finalize_resize(handle, offsetof(HashDbTerm,dbterm));
+ free_me = b;
+ }
+ if (handle->flags & DB_INC_TRY_GROW) {
+ int nactive;
+ int nitems = erts_smp_atomic_inc_read_nob(&tb->common.nitems);
+ WUNLOCK_HASH(lck);
+ nactive = NACTIVE(tb);
+
+ if (nitems > nactive * (CHAIN_LEN + 1) && !IS_FIXED(tb)) {
+ grow(tb, nactive);
+ }
+ } else {
+ WUNLOCK_HASH(lck);
+ }
}
if (free_me)
diff --git a/erts/emulator/beam/erl_db_util.h b/erts/emulator/beam/erl_db_util.h
index 60f7067d70..4acedbfed0 100644
--- a/erts/emulator/beam/erl_db_util.h
+++ b/erts/emulator/beam/erl_db_util.h
@@ -79,6 +79,7 @@ typedef union db_table DbTable;
#define DB_MUST_RESIZE 1
#define DB_NEW_OBJECT 2
+#define DB_INC_TRY_GROW 4
/* Info about a database entry while it's being updated
* (by update_counter or update_element)