If we fail to allocate from a non-empty freelist, retry same list.
authorRobert Haas <[email protected]>
Wed, 1 Aug 2012 20:37:28 +0000 (20:37 +0000)
committerRobert Haas <[email protected]>
Wed, 1 Aug 2012 20:37:28 +0000 (20:37 +0000)
src/backend/utils/hash/chash.c

index 40abd53c482f30f7dddb4f12a7ad38f4b332086d..1fc507af1819be7efef6d47ecba0a59df0db81a9 100644 (file)
@@ -869,12 +869,17 @@ CHashAllocate(CHashTable table)
                 * means that we can't allow any element that is currently on this
                 * freelist to be allocated, marked as garbage, garbage collected,
                 * and returned back to this freelist before we finish the CAS.
+                *
+                * If we attempt to pop the free-list and fail, we retry immediately
+                * with the same free-list.  This reduces the frequency with which
+                * we're obliged to update our hazard pointers, which is a material
+                * savings due to the associated memory barrier.
                 */
                b = &table->freelist[f_current];
                MyProc->hazard[0] = b;
                pg_memory_barrier();
                new = *b;
-               if (!CHashPtrIsInvalid(new))
+               while (!CHashPtrIsInvalid(new))
                {
                        CHashNode  *n = CHashTableGetNode(table, new);
 
@@ -887,6 +892,7 @@ CHashAllocate(CHashTable table)
                        if (__sync_bool_compare_and_swap(b, new, n->un.gcnext))
                                return new;
                        table->stats.s_allocate_pop_fail++;
+                       new = *b;
                }
 
                /* If next garbage list is non-empty, empty it via compare-and-swap. */