From d2d9731291ab917df9b8e535ab54bd771be00e70 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Wed, 25 Jul 2012 10:21:40 -0400 Subject: [PATCH] Avoid leaking nodes on a failed insert. --- contrib/hashtest/hashtest.c | 3 +++ src/backend/utils/hash/chash.c | 27 ++++++++++++++++++++++++--- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/contrib/hashtest/hashtest.c b/contrib/hashtest/hashtest.c index 825f65e0cf..7c68e982a4 100644 --- a/contrib/hashtest/hashtest.c +++ b/contrib/hashtest/hashtest.c @@ -79,6 +79,9 @@ test_chash(PG_FUNCTION_ARGS) ok = CHashInsert(chash, &e); if (!ok) elog(LOG, "insert %u: failed", i); + ok = CHashInsert(chash, &e); + if (ok) + elog(LOG, "insert %u: worked twice", i); } for (i = 0; i < 1000000; ++i) diff --git a/src/backend/utils/hash/chash.c b/src/backend/utils/hash/chash.c index 9053f44539..aa9005ca3a 100644 --- a/src/backend/utils/hash/chash.c +++ b/src/backend/utils/hash/chash.c @@ -185,6 +185,7 @@ typedef struct CHashTableData /* Function prototypes. */ static CHashPtr CHashAllocate(CHashTable table); +static void CHashImmediateFree(CHashTable table, CHashPtr c); static bool CHashRemoveMarked(CHashTable table, uint32 bucket, CHashPtr *cp, volatile CHashPtr *p); @@ -548,9 +549,7 @@ retry: /* If the insert failed, free the entry we allocated. */ if (found) - { - /* XXX Need some code here! */ - } + CHashImmediateFree(table, new); /* The insert succeeded if and only if no duplicate was found. */ return !found; @@ -700,6 +699,28 @@ CHashAllocate(CHashTable table) } } +/* + * Free an arena slot immediately. + * + * When a slot that's actually in use is freed, we can't use this routine, + * because a concurrent bucket scan might have a private pointer to the + * object. However, if an insert fails due to a duplicate key, then we need + * to put it back on the free list immediately. + */ +static void +CHashImmediateFree(CHashTable table, CHashPtr c) +{ + volatile CHashTable vtable = table; + volatile CHashNode *n; + uint32 f_home = ((uint32) MyBackendId) % table->nfreelists; + + n = CHashTableGetNode(table, c); + SpinLockAcquire(&vtable->freelist[f_home].mutex); + n->un.gcnext = vtable->freelist[f_home].head; + vtable->freelist[f_home].head = c; + SpinLockRelease(&vtable->freelist[f_home].mutex); +} + /* * Attempt to remove marked elements from a bucket chain. * -- 2.39.5