From: Robert Haas Date: Thu, 2 Aug 2012 17:03:34 +0000 (+0000) Subject: Get rid of CHashBucketCleanup; CHashBucketScan can do what we need. X-Git-Url: http://git.postgresql.org/gitweb/static/gitweb.js?a=commitdiff_plain;h=1c6e43448e9131c9a21538fe9185af700ae497de;p=users%2Fandresfreund%2Fpostgres.git Get rid of CHashBucketCleanup; CHashBucketScan can do what we need. 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. --- diff --git a/src/backend/utils/hash/chash.c b/src/backend/utils/hash/chash.c index 42e6691043..4168f06fbd 100644 --- a/src/backend/utils/hash/chash.c +++ b/src/backend/utils/hash/chash.c @@ -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. * diff --git a/src/include/utils/chash.h b/src/include/utils/chash.h index 2c4a1af1a0..ee0573c9c7 100644 --- a/src/include/utils/chash.h +++ b/src/include/utils/chash.h @@ -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 */