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. */
+ CHashAddToGarbage(table, hashcode & table->bucket_mask,
+ target);
+ target = CHashPtrUnmark(next);
+ continue;
+ }
+ else
+ {
+ /* Someone else removed the item first. */
+ target = *pointer_to_target;
+ if (CHashPtrIsMarked(target))
+ 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.
*
n->un.gcnext = f;
} while (!__sync_bool_compare_and_swap(free, f, c));
}
-
-/*
- * 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. */
- CHashAddToGarbage(table, hashcode & table->bucket_mask,
- target);
- target = CHashPtrUnmark(next);
- continue;
- }
- else
- {
- /* Someone else removed the item first. */
- target = *pointer_to_target;
- if (CHashPtrIsMarked(target))
- goto retry;
- continue;
- }
- }
-
- pointer_to_target = &target_node->next;
- target = next;
- }
-}