First attempt at CHashDelete - slightly incomplete, and untested.
authorRobert Haas <rhaas@postgresql.org>
Wed, 25 Jul 2012 21:10:29 +0000 (17:10 -0400)
committerRobert Haas <rhaas@postgresql.org>
Tue, 27 Jan 2015 02:24:22 +0000 (02:24 +0000)
src/backend/utils/hash/chash.c

index dd40413694be6043230539afc8e929fc2325aad0..6893a36d81459c2529be51c3c0f5725656ed0632 100644 (file)
@@ -548,6 +548,106 @@ retry:
        return !found;
 }
 
+/*
+ * Delete from a concurrent hash table.  entry need only contain the key field.
+ * Returns true if we find and delete a matching key and false otherwise.
+ */
+bool
+CHashDelete(CHashTable table, void *entry)
+{
+       uint32  hashcode = hash_any(entry, table->desc.key_size);
+       uint32  bucket = hashcode & table->bucket_mask;
+       CHashPtr        c;
+       volatile CHashPtr   *p;
+       volatile CHashNode  *n;
+       bool            found = false;
+
+       /* Suppress garbage collection for target bucket. */
+       CHashTableSuppressGC(table, bucket);
+
+       /* Scan bucket. */
+retry:
+       p = &table->bucket[bucket].head;
+       c = *p;
+       while (c != InvalidCHashPtr)
+       {
+               int             cmp;
+               uint32  h;
+
+               /* Compare current node by hashcode, then by memcmp. */
+               n = CHashTableGetNode(table, c);
+               pg_read_barrier_depends();
+               h = n->un.hashcode;
+               if (h == hashcode)
+                       cmp = memcmp(CHashNodeGetItem(n), entry, table->desc.key_size);
+               else if (h > hashcode)
+                       cmp = 1;
+               else
+                       cmp = -1;
+
+               /* If we found the key, or passed where it should be, we're done. */
+               if (cmp >= 0)
+               {
+                       found = (cmp == 0);
+                       break;
+               }
+
+               /* Move to next node. */
+               p = &n->next;
+               c = *p;
+
+               /*
+                * We can't safely update a delete-marked pointer, so remove any
+                * such pointers we find from the bucket chain.  Sometimes, concurrent
+                * activity may force us to restart the whole scan, but that should
+                * be rare.
+                */
+               if (CHashPtrIsMarked(c) && CHashRemoveMarked(table, bucket, &c, p))
+                       goto retry;
+       }
+
+       if (found)
+       {
+               CHashPtr        cc;
+               bool            needs_cleanup = false;
+
+               /*
+                * Really do the deletion.  Since we've held no lock up to this
+                * point, it may well be that someone else has deleted the item out
+                * from under us, so we recheck that after taking the lock.
+                */
+               SpinLockAcquire(&table->bucket[bucket].mutex);
+               cc = n->next;
+               if (CHashPtrIsMarked(cc))
+                       found = false;
+               else
+               {
+                       n->next = CHashPtrMark(cc);
+                       if (*p == c)
+                               *p = cc;
+                       else
+                               needs_cleanup = true;
+               }
+               SpinLockRelease(&table->bucket[bucket].mutex);
+
+               /*
+                * At this point the deletion is done.  However, it's possible that
+                * we weren't able to redirect the pointer that formerly addressed the
+                * deleted item.  If so, rescan the bucket chain and excise any deleted
+                * items in the chain.  We don't have to worry about not finding it;
+                * that just means someone else did the work for us.
+                */
+               if (needs_cleanup)
+               {
+                       /* XXX */
+               }
+       }
+
+       /* We're done. */
+       CHashTableUnsuppressGC();
+       return found;
+}
+
 /*
  * Allocate an arena slot for a new item to be inserted into a hash table.
  *