Get rid of CHashBucketCleanup; CHashBucketScan can do what we need.
authorRobert Haas <rhaas@postgresql.org>
Thu, 2 Aug 2012 17:03:34 +0000 (17:03 +0000)
committerRobert Haas <rhaas@postgresql.org>
Tue, 27 Jan 2015 02:24:25 +0000 (02:24 +0000)
This might seem less efficient because we actually examine the hash codes
and node contents this way, and that's true, but on the upside we get to
stop the scan early sometimes.  Furthermore, benchmarking reveals that
cleanup scans are (thankfully) quite rare, even in highly concurrent
scenarios, so it doesn't seem worth expending extra code (with the
attendant risk of bugs) to optimize that path.

src/backend/utils/hash/chash.c
src/include/utils/chash.h

index 42e66910430b9cc817996cae0aaf0ce97ccaaa5f..4168f06fbd6e575701726231f5f94e192b825dcb 100644 (file)
@@ -199,9 +199,6 @@ char *CHashStatisticsNames[] = {
        "scan expunges failed",
        "scans restarted",
        "cleanup scans",
-       "cleanup expunges",
-       "cleanup expunges failed",
-       "cleanups restarted",
        "allocations failed",
        "garbage enqueues retried",
        "garbage dequeues failed",
@@ -221,9 +218,6 @@ static void CHashBucketScan(CHashTable table,
                                uint32 hashcode,
                                const void *key,
                                CHashScanResult *res);
-static void CHashBucketCleanup(CHashTable table,
-                               CHashPtr *start,
-                               uint32 hashcode);
 
 /*
  * First stage of CHashTable initialization.  We fill in all the constants
@@ -591,12 +585,17 @@ CHashDelete(CHashTable table, void *entry)
 
        /*
         * If we weren't able to remove the deleted item, rescan the bucket
-        * to make sure it's really gone.
+        * to make sure it's really gone.  This is just like a regular bucket
+        * scan, except that we don't care about the results.  We're just doing
+        * it to achieve the side-effect of removing delete-marked nodes from
+        * the bucket chain.
         */
        if (cleanup_scan)
        {
+               CHashScanResult cleanup_scan;
+
                CHashTableIncrementStatistic(table, CHS_Cleanup_Scan);
-               CHashBucketCleanup(table, b, hashcode);
+               CHashBucketScan(table, b, hashcode, entry, &cleanup_scan);
        }
 
        /* Allow garbage collection for this bucket. */
@@ -634,9 +633,6 @@ CHashStatistics(CHashTable table, uint64 *stats)
  * the address where the value of target was found.  res->target_node will be
  * a pointer to the address of the CHashNode referenced by res->target, unless
  * res->target is invalid.
- *
- * NB: If you change this function, make sure to adjust CHashBucketCleanup
- * similarly.
  */
 static void
 CHashBucketScan(CHashTable table,
@@ -794,80 +790,6 @@ zap:
        res->target_node = target_node;
 }
 
-/*
- * Scan one bucket of a concurrent hash table and clean up any delete-marked
- * items by clipping them out of the chain.  This is basically the same logic
- * as CHashBucketScan, except that we're not searching for an element; the
- * only purpose is to make sure that there are no residual deleted elements
- * in the chain.
- *
- * In practice this will usually not be necessary, because the next scan of
- * the relevant bucket will clean it up anyway.  But we want to make sure we
- * don't have deleted elements eating up our limited storage and making new
- * inserts fail, so let's be safe.
- */
-static void
-CHashBucketCleanup(CHashTable table, CHashPtr *start, uint32 hashcode)
-{
-       CHashPtr        target;
-       CHashPtr   *pointer_to_target;
-       CHashNode  *target_node;
-
-retry:
-       pointer_to_target = start;
-       target = *pointer_to_target;
-       for (;;)
-       {
-               CHashPtr        next;
-
-               /*
-                * If we've reached the end of the bucket chain, stop; otherwise,
-                * figure out the actual address of the next item.
-                */
-               if (CHashPtrIsInvalid(target))
-                       break;
-               target_node = CHashTableGetNode(table, target);
-
-               /*
-                * target may have been fetched from an arena entry that could be
-                * concurrently modified, so a dependency barrier is required before
-                * dereferencing the derived pointer.
-                */
-               pg_read_barrier_depends();
-               next = target_node->next;
-
-               /* If element is delete-marked, try to remove it. */
-               if (CHashPtrIsMarked(next))
-               {
-                       if (__sync_bool_compare_and_swap(pointer_to_target,
-                                                                                        target,
-                                                                                        CHashPtrUnmark(next)))
-                       {
-                               /* We removed the item. */
-                               CHashTableIncrementStatistic(table, CHS_Cleanup_Expunge);
-                               CHashAddToGarbage(table, hashcode & table->bucket_mask,
-                                                                 target);
-                               target = CHashPtrUnmark(next);
-                       }
-                       else
-                       {
-                               /* Someone else removed the item first. */
-                               CHashTableIncrementStatistic(table, CHS_Cleanup_Expunge_Fail);
-                               target = *pointer_to_target;
-                               if (CHashPtrIsMarked(target))
-                               {
-                                       CHashTableIncrementStatistic(table, CHS_Cleanup_Restart);
-                                       goto retry;
-                               }
-                       }
-                       continue;
-               }
-
-               pointer_to_target = &target_node->next;
-               target = next;
-       }
-}
-
 /*
  * Allocate an arena slot for a new item to be inserted into a hash table.
  *
index 2c4a1af1a0404614a73cdc2efaa18a84ecd628d6..ee0573c9c75497d7f3dc43cd7a4d45d5cb0ac18c 100644 (file)
@@ -37,9 +37,6 @@ typedef enum
        CHS_Scan_Expunge_Fail,          /* scan failed to expunge */
        CHS_Scan_Restart,                       /* concurrent deletes forced a scan restart */
        CHS_Cleanup_Scan,                       /* concurrent update forced a cleanup scan */
-       CHS_Cleanup_Expunge,            /* cleanup scan expunged an item */
-       CHS_Cleanup_Expunge_Fail,       /* cleanup scan failed to expunge */
-       CHS_Cleanup_Restart,            /* concurrent deletes forced cleanup restart */
        CHS_Allocate_Fail,                      /* allocation failed to pop freelist */
        CHS_Garbage_Enqueue_Retry,      /* enqueue on garbage list retried */
        CHS_Garbage_Dequeue_Fail,       /* dequeue of garbage failed */