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)
/* 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);
/* 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;
}
}
+/*
+ * 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.
*