bool found;
} CHashScanResult;
-/*
- * We need a memory barrier to make sure that our bucket advertisement is
- * committed to memory before we begin scanning the bucket, and another one
- * to make sure the scan is done before we cease advertising it.
- */
-#define CHashTableSuppressGC(table, bno) \
- do { \
- Assert(MyProc->chash_bucket == 0); \
- MyProc->chash_bucket = \
- ((uint64) table->desc.id)<<32 | (bucket>>table->garbage_shift); \
- pg_memory_barrier(); \
- } while (0)
-#define CHashTableUnsuppressGC() \
- do { \
- Assert(MyProc->chash_bucket != 0); \
- pg_memory_barrier(); \
- MyProc->chash_bucket = 0; \
- } while (0)
-
/* Function prototypes. */
static CHashPtr CHashAllocate(CHashTable table);
static void CHashAddToGarbage(CHashTable table, uint32 bucket, CHashPtr c);
memcpy(&table->desc, desc, sizeof(CHashDescriptor));
/* Sanity checks. */
- if (desc->id == 0)
- elog(ERROR, "concurrent hash table id must not be zero");
if (desc->capacity < 1 || desc->capacity > CHashMaxCapacity)
elog(ERROR, "invalid capacity for concurrent hash");
if (desc->key_size < 1 || desc->key_size > desc->element_size)
{
uint32 hashcode = hash_any(entry, table->desc.key_size);
uint32 bucket = hashcode & table->bucket_mask;
+ CHashPtr *b = &table->bucket[bucket];
CHashScanResult scan;
/* Prevent garbage collection for this bucket. */
- CHashTableSuppressGC(table, bucket);
+ Assert(MyProc->hazard[0] == NULL);
+ MyProc->hazard[0] = b;
+ pg_memory_barrier();
/* Scan bucket and return data from any matching entry. */
- CHashBucketScan(table, &table->bucket[bucket], hashcode, entry, &scan);
+ CHashBucketScan(table, b, hashcode, entry, &scan);
if (scan.found)
memcpy(((char *) entry) + table->desc.key_size,
CHashNodeGetItem(scan.target_node) + table->desc.key_size,
table->desc.element_size - table->desc.key_size);
/* Allow garbage collection for this bucket. */
- CHashTableUnsuppressGC();
+ Assert(MyProc->hazard[0] != NULL);
+ pg_memory_barrier();
+ MyProc->hazard[0] = NULL;
return scan.found;
}
{
uint32 hashcode = hash_any(entry, table->desc.key_size);
uint32 bucket = hashcode & table->bucket_mask;
+ CHashPtr *b = &table->bucket[bucket];
CHashPtr new;
CHashNode *nnew;
CHashScanResult scan;
memcpy(CHashNodeGetItem(nnew), entry, table->desc.element_size);
/* Prevent garbage collection for this bucket. */
- CHashTableSuppressGC(table, bucket);
+ Assert(MyProc->hazard[0] == NULL);
+ MyProc->hazard[0] = b;
+ pg_memory_barrier();
/*
* Scan the bucket. If we don't find a match, use compare-and-swap to
* return the data to the caller.
*/
retry:
- CHashBucketScan(table, &table->bucket[bucket], hashcode, entry, &scan);
+ CHashBucketScan(table, b, hashcode, entry, &scan);
if (scan.found)
memcpy(((char *) entry) + table->desc.key_size,
CHashNodeGetItem(scan.target_node) + table->desc.key_size,
}
/* Allow garbage collection for this bucket. */
- CHashTableUnsuppressGC();
+ Assert(MyProc->hazard[0] != NULL);
+ pg_memory_barrier();
+ MyProc->hazard[0] = NULL;
/* If the insert failed, free the entry we allocated. */
if (scan.found)
{
uint32 hashcode = hash_any(entry, table->desc.key_size);
uint32 bucket = hashcode & table->bucket_mask;
+ CHashPtr *b = &table->bucket[bucket];
bool cleanup_scan = false;
CHashScanResult scan;
/* Prevent garbage collection for this bucket. */
- CHashTableSuppressGC(table, bucket);
+ Assert(MyProc->hazard[0] == NULL);
+ MyProc->hazard[0] = b;
+ pg_memory_barrier();
/* Scan bucket. */
- CHashBucketScan(table, &table->bucket[bucket], hashcode, entry, &scan);
+ CHashBucketScan(table, b, hashcode, entry, &scan);
/*
* If we found a match, then loop until we succesfully delete-mark the
if (cleanup_scan)
{
table->stats.s_cleanup_scan++;
- CHashBucketCleanup(table, &table->bucket[bucket], hashcode);
+ CHashBucketCleanup(table, b, hashcode);
}
/* Allow garbage collection for this bucket. */
- CHashTableUnsuppressGC();
+ Assert(MyProc->hazard[0] != NULL);
+ pg_memory_barrier();
+ MyProc->hazard[0] = NULL;
/* We're done. */
return scan.found;
table->stats.s_gc_pop_fail++;
else
{
- uint64 chash_bucket;
uint32 i;
CHashPtr fhead;
CHashNode *n;
* might want to eventually enter a longer sleep here, or PANIC,
* but it's not clear exactly how to calibrate that.
*/
- chash_bucket = ((uint64) table->desc.id)<<32 | table->gc_next;
for (i = 0; i < ProcGlobal->allProcCount; i++)
{
PGPROC *proc = &ProcGlobal->allProcs[i];
- while (proc->chash_bucket == chash_bucket)
+ while (proc->hazard[0] == b)
;
}
/* Remove one item from list to satisfy current allocation. */
new = garbage;
n = CHashTableGetNode(table, new);
+ pg_read_barrier_depends();
fhead = n->un.gcnext;
/* Put any remaining elements back on the free list. */