From b4b3c285942436a38ffcd8bf73666922d9689ef1 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Tue, 23 Mar 2021 19:56:32 -0700 Subject: [PATCH 1/2] Revert 3dd2157febae5087ca3333d24f69b6de9cbd13cd that removed freeslot tracking. Needed to avoid quadratic behavior when repeatedly inserting and deleting the same key. --- Objects/setobject.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Objects/setobject.c b/Objects/setobject.c index e8912ff1a29d78..d7187e0c39810b 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -103,6 +103,7 @@ static int set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash) { setentry *table; + setentry *freeslot; setentry *entry; size_t perturb; size_t mask; @@ -118,6 +119,7 @@ set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash) mask = so->mask; i = (size_t)hash & mask; + freeslot = NULL; perturb = hash; while (1) { @@ -125,7 +127,7 @@ set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash) probes = (i + LINEAR_PROBES <= mask) ? LINEAR_PROBES: 0; do { if (entry->hash == 0 && entry->key == NULL) - goto found_unused; + goto found_unused_or_dummy; if (entry->hash == hash) { PyObject *startkey = entry->key; assert(startkey != dummy); @@ -147,12 +149,23 @@ set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash) goto restart; mask = so->mask; } + else if (entry->hash == -1) { + freeslot = entry; + } entry++; } while (probes--); perturb >>= PERTURB_SHIFT; i = (i * 5 + 1 + perturb) & mask; } + found_unused_or_dummy: + if (freeslot == NULL) + goto found_unused; + so->used++; + freeslot->key = key; + freeslot->hash = hash; + return 0; + found_unused: so->fill++; so->used++; From 15cd1ada9a78404491bc3739f0227008a5d0f795 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Wed, 24 Mar 2021 14:13:37 -0700 Subject: [PATCH 2/2] Add assertion --- Objects/setobject.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Objects/setobject.c b/Objects/setobject.c index d7187e0c39810b..caff85c9e38939 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -150,6 +150,7 @@ set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash) mask = so->mask; } else if (entry->hash == -1) { + assert (entry->key == dummy); freeslot = entry; } entry++;