PostgreSQL Source Code  git master
dshash.h File Reference
#include "utils/dsa.h"
Include dependency graph for dshash.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  dshash_parameters
 
struct  dshash_seq_status
 

Typedefs

typedef struct dshash_table dshash_table
 
typedef dsa_pointer dshash_table_handle
 
typedef uint32 dshash_hash
 
typedef int(* dshash_compare_function) (const void *a, const void *b, size_t size, void *arg)
 
typedef dshash_hash(* dshash_hash_function) (const void *v, size_t size, void *arg)
 
typedef struct dshash_parameters dshash_parameters
 
typedef struct dshash_table_item dshash_table_item
 
typedef struct dshash_seq_status dshash_seq_status
 

Functions

dshash_tabledshash_create (dsa_area *area, const dshash_parameters *params, void *arg)
 
dshash_tabledshash_attach (dsa_area *area, const dshash_parameters *params, dshash_table_handle handle, void *arg)
 
void dshash_detach (dshash_table *hash_table)
 
dshash_table_handle dshash_get_hash_table_handle (dshash_table *hash_table)
 
void dshash_destroy (dshash_table *hash_table)
 
void * dshash_find (dshash_table *hash_table, const void *key, bool exclusive)
 
void * dshash_find_or_insert (dshash_table *hash_table, const void *key, bool *found)
 
bool dshash_delete_key (dshash_table *hash_table, const void *key)
 
void dshash_delete_entry (dshash_table *hash_table, void *entry)
 
void dshash_release_lock (dshash_table *hash_table, void *entry)
 
void dshash_seq_init (dshash_seq_status *status, dshash_table *hash_table, bool exclusive)
 
void * dshash_seq_next (dshash_seq_status *status)
 
void dshash_seq_term (dshash_seq_status *status)
 
void dshash_delete_current (dshash_seq_status *status)
 
int dshash_memcmp (const void *a, const void *b, size_t size, void *arg)
 
dshash_hash dshash_memhash (const void *v, size_t size, void *arg)
 
void dshash_dump (dshash_table *hash_table)
 

Typedef Documentation

◆ dshash_compare_function

typedef int(* dshash_compare_function) (const void *a, const void *b, size_t size, void *arg)

Definition at line 30 of file dshash.h.

◆ dshash_hash

Definition at line 27 of file dshash.h.

◆ dshash_hash_function

typedef dshash_hash(* dshash_hash_function) (const void *v, size_t size, void *arg)

Definition at line 34 of file dshash.h.

◆ dshash_parameters

◆ dshash_seq_status

◆ dshash_table

typedef struct dshash_table dshash_table

Definition at line 1 of file dshash.h.

◆ dshash_table_handle

Definition at line 24 of file dshash.h.

◆ dshash_table_item

Definition at line 34 of file dshash.h.

Function Documentation

◆ dshash_attach()

dshash_table* dshash_attach ( dsa_area area,
const dshash_parameters params,
dshash_table_handle  handle,
void *  arg 
)

Definition at line 271 of file dshash.c.

273 {
274  dshash_table *hash_table;
275  dsa_pointer control;
276 
277  /* Allocate the backend-local object representing the hash table. */
278  hash_table = palloc(sizeof(dshash_table));
279 
280  /* Find the control object in shared memory. */
281  control = handle;
282 
283  /* Set up the local hash table struct. */
284  hash_table->area = area;
285  hash_table->params = *params;
286  hash_table->arg = arg;
287  hash_table->control = dsa_get_address(area, control);
288  hash_table->find_locked = false;
289  hash_table->find_exclusively_locked = false;
290  Assert(hash_table->control->magic == DSHASH_MAGIC);
291 
292  /*
293  * These will later be set to the correct values by
294  * ensure_valid_bucket_pointers(), at which time we'll be holding a
295  * partition lock for interlocking against concurrent resizing.
296  */
297  hash_table->buckets = NULL;
298  hash_table->size_log2 = 0;
299 
300  return hash_table;
301 }
void * dsa_get_address(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:932
uint64 dsa_pointer
Definition: dsa.h:62
#define DSHASH_MAGIC
Definition: dshash.c:65
Assert(fmt[strlen(fmt) - 1] !='\n')
void * palloc(Size size)
Definition: mcxt.c:1068
void * arg
bool find_locked
Definition: dshash.c:113
dshash_parameters params
Definition: dshash.c:108
dsa_pointer * buckets
Definition: dshash.c:111
bool find_exclusively_locked
Definition: dshash.c:114
dsa_area * area
Definition: dshash.c:107
void * arg
Definition: dshash.c:109
size_t size_log2
Definition: dshash.c:112
dshash_table_control * control
Definition: dshash.c:110

References dshash_table::area, dshash_table::arg, arg, Assert(), dshash_table::buckets, dshash_table::control, dsa_get_address(), DSHASH_MAGIC, dshash_table::find_exclusively_locked, dshash_table::find_locked, dshash_table_control::magic, palloc(), dshash_table::params, and dshash_table::size_log2.

Referenced by pgstat_attach_shmem(), and SharedRecordTypmodRegistryAttach().

◆ dshash_create()

dshash_table* dshash_create ( dsa_area area,
const dshash_parameters params,
void *  arg 
)

Definition at line 204 of file dshash.c.

205 {
206  dshash_table *hash_table;
207  dsa_pointer control;
208 
209  /* Allocate the backend-local object representing the hash table. */
210  hash_table = palloc(sizeof(dshash_table));
211 
212  /* Allocate the control object in shared memory. */
213  control = dsa_allocate(area, sizeof(dshash_table_control));
214 
215  /* Set up the local and shared hash table structs. */
216  hash_table->area = area;
217  hash_table->params = *params;
218  hash_table->arg = arg;
219  hash_table->control = dsa_get_address(area, control);
220  hash_table->control->handle = control;
221  hash_table->control->magic = DSHASH_MAGIC;
222  hash_table->control->lwlock_tranche_id = params->tranche_id;
223 
224  /* Set up the array of lock partitions. */
225  {
227  int tranche_id = hash_table->control->lwlock_tranche_id;
228  int i;
229 
230  for (i = 0; i < DSHASH_NUM_PARTITIONS; ++i)
231  {
232  LWLockInitialize(&partitions[i].lock, tranche_id);
233  partitions[i].count = 0;
234  }
235  }
236 
237  hash_table->find_locked = false;
238  hash_table->find_exclusively_locked = false;
239 
240  /*
241  * Set up the initial array of buckets. Our initial size is the same as
242  * the number of partitions.
243  */
245  hash_table->control->buckets =
249  if (!DsaPointerIsValid(hash_table->control->buckets))
250  {
251  dsa_free(area, control);
252  ereport(ERROR,
253  (errcode(ERRCODE_OUT_OF_MEMORY),
254  errmsg("out of memory"),
255  errdetail("Failed on DSA request of size %zu.",
256  sizeof(dsa_pointer) * DSHASH_NUM_PARTITIONS)));
257  }
258  hash_table->buckets = dsa_get_address(area,
259  hash_table->control->buckets);
260  hash_table->size_log2 = hash_table->control->size_log2;
261 
262  return hash_table;
263 }
dsa_pointer dsa_allocate_extended(dsa_area *area, size_t size, int flags)
Definition: dsa.c:665
void dsa_free(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:820
#define dsa_allocate(area, size)
Definition: dsa.h:84
#define DSA_ALLOC_NO_OOM
Definition: dsa.h:74
#define DsaPointerIsValid(x)
Definition: dsa.h:81
#define DSA_ALLOC_ZERO
Definition: dsa.h:75
#define DSHASH_NUM_PARTITIONS
Definition: dshash.c:62
#define DSHASH_NUM_PARTITIONS_LOG2
Definition: dshash.c:61
int errdetail(const char *fmt,...)
Definition: elog.c:1037
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ERROR
Definition: elog.h:33
#define ereport(elevel,...)
Definition: elog.h:143
int i
Definition: isn.c:73
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition: lwlock.c:734
static int partitions
Definition: pgbench.c:236
size_t size_log2
Definition: dshash.c:98
dshash_partition partitions[DSHASH_NUM_PARTITIONS]
Definition: dshash.c:89
dshash_table_handle handle
Definition: dshash.c:87
dsa_pointer buckets
Definition: dshash.c:99

References dshash_table::area, dshash_table::arg, arg, dshash_table_control::buckets, dshash_table::buckets, dshash_table::control, DSA_ALLOC_NO_OOM, DSA_ALLOC_ZERO, dsa_allocate, dsa_allocate_extended(), dsa_free(), dsa_get_address(), DsaPointerIsValid, DSHASH_MAGIC, DSHASH_NUM_PARTITIONS, DSHASH_NUM_PARTITIONS_LOG2, ereport, errcode(), errdetail(), errmsg(), ERROR, dshash_table::find_exclusively_locked, dshash_table::find_locked, dshash_table_control::handle, i, dshash_table_control::lwlock_tranche_id, LWLockInitialize(), dshash_table_control::magic, palloc(), dshash_table::params, dshash_table_control::partitions, partitions, dshash_table_control::size_log2, dshash_table::size_log2, and dshash_parameters::tranche_id.

Referenced by SharedRecordTypmodRegistryInit(), and StatsShmemInit().

◆ dshash_delete_current()

void dshash_delete_current ( dshash_seq_status status)

Definition at line 736 of file dshash.c.

737 {
738  dshash_table *hash_table = status->hash_table;
739  dshash_table_item *item = status->curitem;
740  size_t partition PG_USED_FOR_ASSERTS_ONLY;
741 
742  partition = PARTITION_FOR_HASH(item->hash);
743 
744  Assert(status->exclusive);
745  Assert(hash_table->control->magic == DSHASH_MAGIC);
746  Assert(hash_table->find_locked);
747  Assert(hash_table->find_exclusively_locked);
748  Assert(LWLockHeldByMeInMode(PARTITION_LOCK(hash_table, partition),
749  LW_EXCLUSIVE));
750 
751  delete_item(hash_table, item);
752 }
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:155
#define PARTITION_LOCK(hash_table, i)
Definition: dshash.c:194
static void delete_item(dshash_table *hash_table, dshash_table_item *item)
Definition: dshash.c:813
#define PARTITION_FOR_HASH(hash)
Definition: dshash.c:144
bool LWLockHeldByMeInMode(LWLock *l, LWLockMode mode)
Definition: lwlock.c:1934
@ LW_EXCLUSIVE
Definition: lwlock.h:104
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:229
dshash_hash hash
Definition: dshash.c:51

References Assert(), dshash_table::control, delete_item(), DSHASH_MAGIC, dshash_table::find_exclusively_locked, dshash_table::find_locked, dshash_table_item::hash, LW_EXCLUSIVE, LWLockHeldByMeInMode(), dshash_table_control::magic, PARTITION_FOR_HASH, PARTITION_LOCK, PG_USED_FOR_ASSERTS_ONLY, and status().

Referenced by pgstat_free_entry().

◆ dshash_delete_entry()

void dshash_delete_entry ( dshash_table hash_table,
void *  entry 
)

Definition at line 548 of file dshash.c.

549 {
550  dshash_table_item *item = ITEM_FROM_ENTRY(entry);
551  size_t partition = PARTITION_FOR_HASH(item->hash);
552 
553  Assert(hash_table->control->magic == DSHASH_MAGIC);
554  Assert(hash_table->find_locked);
555  Assert(hash_table->find_exclusively_locked);
556  Assert(LWLockHeldByMeInMode(PARTITION_LOCK(hash_table, partition),
557  LW_EXCLUSIVE));
558 
559  delete_item(hash_table, item);
560  hash_table->find_locked = false;
561  hash_table->find_exclusively_locked = false;
562  LWLockRelease(PARTITION_LOCK(hash_table, partition));
563 }
#define ITEM_FROM_ENTRY(entry)
Definition: dshash.c:122
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1800

References Assert(), dshash_table::control, delete_item(), DSHASH_MAGIC, dshash_table::find_exclusively_locked, dshash_table::find_locked, dshash_table_item::hash, ITEM_FROM_ENTRY, LW_EXCLUSIVE, LWLockHeldByMeInMode(), LWLockRelease(), dshash_table_control::magic, PARTITION_FOR_HASH, and PARTITION_LOCK.

Referenced by pgstat_free_entry().

◆ dshash_delete_key()

bool dshash_delete_key ( dshash_table hash_table,
const void *  key 
)

Definition at line 510 of file dshash.c.

511 {
513  size_t partition;
514  bool found;
515 
516  Assert(hash_table->control->magic == DSHASH_MAGIC);
517  Assert(!hash_table->find_locked);
518 
519  hash = hash_key(hash_table, key);
520  partition = PARTITION_FOR_HASH(hash);
521 
522  LWLockAcquire(PARTITION_LOCK(hash_table, partition), LW_EXCLUSIVE);
523  ensure_valid_bucket_pointers(hash_table);
524 
525  if (delete_key_from_bucket(hash_table, key,
526  &BUCKET_FOR_HASH(hash_table, hash)))
527  {
528  Assert(hash_table->control->partitions[partition].count > 0);
529  found = true;
530  --hash_table->control->partitions[partition].count;
531  }
532  else
533  found = false;
534 
535  LWLockRelease(PARTITION_LOCK(hash_table, partition));
536 
537  return found;
538 }
static bool delete_key_from_bucket(dshash_table *hash_table, const void *key, dsa_pointer *bucket_head)
Definition: dshash.c:985
static dshash_hash hash_key(dshash_table *hash_table, const void *key)
Definition: dshash.c:1042
static void ensure_valid_bucket_pointers(dshash_table *hash_table)
Definition: dshash.c:916
#define BUCKET_FOR_HASH(hash_table, hash)
Definition: dshash.c:165
uint32 dshash_hash
Definition: dshash.h:27
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1196
static unsigned hash(unsigned *uv, int n)
Definition: rege_dfa.c:715
size_t count
Definition: dshash.c:78

References Assert(), BUCKET_FOR_HASH, dshash_table::control, dshash_partition::count, delete_key_from_bucket(), DSHASH_MAGIC, ensure_valid_bucket_pointers(), dshash_table::find_locked, hash(), hash_key(), sort-test::key, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), dshash_table_control::magic, PARTITION_FOR_HASH, PARTITION_LOCK, and dshash_table_control::partitions.

Referenced by find_or_make_matching_shared_tupledesc().

◆ dshash_destroy()

void dshash_destroy ( dshash_table hash_table)

Definition at line 326 of file dshash.c.

327 {
328  size_t size;
329  size_t i;
330 
331  Assert(hash_table->control->magic == DSHASH_MAGIC);
332  ensure_valid_bucket_pointers(hash_table);
333 
334  /* Free all the entries. */
335  size = NUM_BUCKETS(hash_table->size_log2);
336  for (i = 0; i < size; ++i)
337  {
338  dsa_pointer item_pointer = hash_table->buckets[i];
339 
340  while (DsaPointerIsValid(item_pointer))
341  {
342  dshash_table_item *item;
343  dsa_pointer next_item_pointer;
344 
345  item = dsa_get_address(hash_table->area, item_pointer);
346  next_item_pointer = item->next;
347  dsa_free(hash_table->area, item_pointer);
348  item_pointer = next_item_pointer;
349  }
350  }
351 
352  /*
353  * Vandalize the control block to help catch programming errors where
354  * other backends access the memory formerly occupied by this hash table.
355  */
356  hash_table->control->magic = 0;
357 
358  /* Free the active table and control object. */
359  dsa_free(hash_table->area, hash_table->control->buckets);
360  dsa_free(hash_table->area, hash_table->control->handle);
361 
362  pfree(hash_table);
363 }
#define NUM_BUCKETS(size_log2)
Definition: dshash.c:131
void pfree(void *pointer)
Definition: mcxt.c:1175
dsa_pointer next
Definition: dshash.c:49

References dshash_table::area, Assert(), dshash_table_control::buckets, dshash_table::buckets, dshash_table::control, dsa_free(), dsa_get_address(), DsaPointerIsValid, DSHASH_MAGIC, ensure_valid_bucket_pointers(), dshash_table_control::handle, i, dshash_table_control::magic, dshash_table_item::next, NUM_BUCKETS, pfree(), and dshash_table::size_log2.

◆ dshash_detach()

void dshash_detach ( dshash_table hash_table)

Definition at line 310 of file dshash.c.

311 {
312  Assert(!hash_table->find_locked);
313 
314  /* The hash table may have been destroyed. Just free local memory. */
315  pfree(hash_table);
316 }

References Assert(), dshash_table::find_locked, and pfree().

Referenced by pgstat_detach_shmem(), shared_record_typmod_registry_detach(), and StatsShmemInit().

◆ dshash_dump()

void dshash_dump ( dshash_table hash_table)

Definition at line 759 of file dshash.c.

760 {
761  size_t i;
762  size_t j;
763 
764  Assert(hash_table->control->magic == DSHASH_MAGIC);
765  Assert(!hash_table->find_locked);
766 
767  for (i = 0; i < DSHASH_NUM_PARTITIONS; ++i)
768  {
769  Assert(!LWLockHeldByMe(PARTITION_LOCK(hash_table, i)));
770  LWLockAcquire(PARTITION_LOCK(hash_table, i), LW_SHARED);
771  }
772 
773  ensure_valid_bucket_pointers(hash_table);
774 
775  fprintf(stderr,
776  "hash table size = %zu\n", (size_t) 1 << hash_table->size_log2);
777  for (i = 0; i < DSHASH_NUM_PARTITIONS; ++i)
778  {
779  dshash_partition *partition = &hash_table->control->partitions[i];
780  size_t begin = BUCKET_INDEX_FOR_PARTITION(i, hash_table->size_log2);
781  size_t end = BUCKET_INDEX_FOR_PARTITION(i + 1, hash_table->size_log2);
782 
783  fprintf(stderr, " partition %zu\n", i);
784  fprintf(stderr,
785  " active buckets (key count = %zu)\n", partition->count);
786 
787  for (j = begin; j < end; ++j)
788  {
789  size_t count = 0;
790  dsa_pointer bucket = hash_table->buckets[j];
791 
792  while (DsaPointerIsValid(bucket))
793  {
794  dshash_table_item *item;
795 
796  item = dsa_get_address(hash_table->area, bucket);
797 
798  bucket = item->next;
799  ++count;
800  }
801  fprintf(stderr, " bucket %zu (key count = %zu)\n", j, count);
802  }
803  }
804 
805  for (i = 0; i < DSHASH_NUM_PARTITIONS; ++i)
806  LWLockRelease(PARTITION_LOCK(hash_table, i));
807 }
#define BUCKET_INDEX_FOR_PARTITION(partition, size_log2)
Definition: dshash.c:157
int j
Definition: isn.c:74
bool LWLockHeldByMe(LWLock *l)
Definition: lwlock.c:1916
@ LW_SHARED
Definition: lwlock.h:105
#define fprintf
Definition: port.h:229

References dshash_table::area, Assert(), BUCKET_INDEX_FOR_PARTITION, dshash_table::buckets, dshash_table::control, dshash_partition::count, dsa_get_address(), DsaPointerIsValid, DSHASH_MAGIC, DSHASH_NUM_PARTITIONS, ensure_valid_bucket_pointers(), dshash_table::find_locked, fprintf, i, j, LW_SHARED, LWLockAcquire(), LWLockHeldByMe(), LWLockRelease(), dshash_table_control::magic, dshash_table_item::next, PARTITION_LOCK, dshash_table_control::partitions, and dshash_table::size_log2.

◆ dshash_find()

void* dshash_find ( dshash_table hash_table,
const void *  key,
bool  exclusive 
)

Definition at line 393 of file dshash.c.

394 {
396  size_t partition;
397  dshash_table_item *item;
398 
399  hash = hash_key(hash_table, key);
400  partition = PARTITION_FOR_HASH(hash);
401 
402  Assert(hash_table->control->magic == DSHASH_MAGIC);
403  Assert(!hash_table->find_locked);
404 
405  LWLockAcquire(PARTITION_LOCK(hash_table, partition),
406  exclusive ? LW_EXCLUSIVE : LW_SHARED);
407  ensure_valid_bucket_pointers(hash_table);
408 
409  /* Search the active bucket. */
410  item = find_in_bucket(hash_table, key, BUCKET_FOR_HASH(hash_table, hash));
411 
412  if (!item)
413  {
414  /* Not found. */
415  LWLockRelease(PARTITION_LOCK(hash_table, partition));
416  return NULL;
417  }
418  else
419  {
420  /* The caller will free the lock by calling dshash_release_lock. */
421  hash_table->find_locked = true;
422  hash_table->find_exclusively_locked = exclusive;
423  return ENTRY_FROM_ITEM(item);
424  }
425 }
#define ENTRY_FROM_ITEM(item)
Definition: dshash.c:118
static dshash_table_item * find_in_bucket(dshash_table *hash_table, const void *key, dsa_pointer item_pointer)
Definition: dshash.c:930

References Assert(), BUCKET_FOR_HASH, dshash_table::control, DSHASH_MAGIC, ensure_valid_bucket_pointers(), ENTRY_FROM_ITEM, dshash_table::find_exclusively_locked, find_in_bucket(), dshash_table::find_locked, hash(), hash_key(), sort-test::key, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), dshash_table_control::magic, PARTITION_FOR_HASH, and PARTITION_LOCK.

Referenced by find_or_make_matching_shared_tupledesc(), lookup_rowtype_tupdesc_internal(), pgstat_drop_entry(), pgstat_get_entry_ref(), and pgstat_release_entry_ref().

◆ dshash_find_or_insert()

void* dshash_find_or_insert ( dshash_table hash_table,
const void *  key,
bool found 
)

Definition at line 438 of file dshash.c.

441 {
443  size_t partition_index;
444  dshash_partition *partition;
445  dshash_table_item *item;
446 
447  hash = hash_key(hash_table, key);
448  partition_index = PARTITION_FOR_HASH(hash);
449  partition = &hash_table->control->partitions[partition_index];
450 
451  Assert(hash_table->control->magic == DSHASH_MAGIC);
452  Assert(!hash_table->find_locked);
453 
454 restart:
455  LWLockAcquire(PARTITION_LOCK(hash_table, partition_index),
456  LW_EXCLUSIVE);
457  ensure_valid_bucket_pointers(hash_table);
458 
459  /* Search the active bucket. */
460  item = find_in_bucket(hash_table, key, BUCKET_FOR_HASH(hash_table, hash));
461 
462  if (item)
463  *found = true;
464  else
465  {
466  *found = false;
467 
468  /* Check if we are getting too full. */
469  if (partition->count > MAX_COUNT_PER_PARTITION(hash_table))
470  {
471  /*
472  * The load factor (= keys / buckets) for all buckets protected by
473  * this partition is > 0.75. Presumably the same applies
474  * generally across the whole hash table (though we don't attempt
475  * to track that directly to avoid contention on some kind of
476  * central counter; we just assume that this partition is
477  * representative). This is a good time to resize.
478  *
479  * Give up our existing lock first, because resizing needs to
480  * reacquire all the locks in the right order to avoid deadlocks.
481  */
482  LWLockRelease(PARTITION_LOCK(hash_table, partition_index));
483  resize(hash_table, hash_table->size_log2 + 1);
484 
485  goto restart;
486  }
487 
488  /* Finally we can try to insert the new item. */
489  item = insert_into_bucket(hash_table, key,
490  &BUCKET_FOR_HASH(hash_table, hash));
491  item->hash = hash;
492  /* Adjust per-lock-partition counter for load factor knowledge. */
493  ++partition->count;
494  }
495 
496  /* The caller must release the lock with dshash_release_lock. */
497  hash_table->find_locked = true;
498  hash_table->find_exclusively_locked = true;
499  return ENTRY_FROM_ITEM(item);
500 }
static void resize(dshash_table *hash_table, size_t new_size)
Definition: dshash.c:839
static dshash_table_item * insert_into_bucket(dshash_table *hash_table, const void *key, dsa_pointer *bucket)
Definition: dshash.c:965
#define MAX_COUNT_PER_PARTITION(hash_table)
Definition: dshash.c:139

References Assert(), BUCKET_FOR_HASH, dshash_table::control, dshash_partition::count, DSHASH_MAGIC, ensure_valid_bucket_pointers(), ENTRY_FROM_ITEM, dshash_table::find_exclusively_locked, find_in_bucket(), dshash_table::find_locked, dshash_table_item::hash, hash(), hash_key(), insert_into_bucket(), sort-test::key, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), dshash_table_control::magic, MAX_COUNT_PER_PARTITION, PARTITION_FOR_HASH, PARTITION_LOCK, dshash_table_control::partitions, resize(), and dshash_table::size_log2.

Referenced by find_or_make_matching_shared_tupledesc(), pgstat_get_entry_ref(), pgstat_read_statsfile(), and SharedRecordTypmodRegistryInit().

◆ dshash_get_hash_table_handle()

dshash_table_handle dshash_get_hash_table_handle ( dshash_table hash_table)

Definition at line 370 of file dshash.c.

371 {
372  Assert(hash_table->control->magic == DSHASH_MAGIC);
373 
374  return hash_table->control->handle;
375 }

References Assert(), dshash_table::control, DSHASH_MAGIC, dshash_table_control::handle, and dshash_table_control::magic.

Referenced by SharedRecordTypmodRegistryInit(), and StatsShmemInit().

◆ dshash_memcmp()

int dshash_memcmp ( const void *  a,
const void *  b,
size_t  size,
void *  arg 
)

Definition at line 589 of file dshash.c.

590 {
591  return memcmp(a, b, size);
592 }
int b
Definition: isn.c:70
int a
Definition: isn.c:69

References a, and b.

◆ dshash_memhash()

dshash_hash dshash_memhash ( const void *  v,
size_t  size,
void *  arg 
)

Definition at line 598 of file dshash.c.

599 {
600  return tag_hash(v, size);
601 }
uint32 tag_hash(const void *key, Size keysize)
Definition: hashfn.c:677

References tag_hash().

◆ dshash_release_lock()

◆ dshash_seq_init()

void dshash_seq_init ( dshash_seq_status status,
dshash_table hash_table,
bool  exclusive 
)

Definition at line 612 of file dshash.c.

614 {
615  status->hash_table = hash_table;
616  status->curbucket = 0;
617  status->nbuckets = 0;
618  status->curitem = NULL;
619  status->pnextitem = InvalidDsaPointer;
620  status->curpartition = -1;
621  status->exclusive = exclusive;
622 }
#define InvalidDsaPointer
Definition: dsa.h:78

References InvalidDsaPointer, and status().

Referenced by pgstat_build_snapshot(), pgstat_drop_all_entries(), pgstat_drop_database_and_contents(), pgstat_reset_matching_entries(), and pgstat_write_statsfile().

◆ dshash_seq_next()

void* dshash_seq_next ( dshash_seq_status status)

Definition at line 631 of file dshash.c.

632 {
633  dsa_pointer next_item_pointer;
634 
635  /*
636  * Not yet holding any partition locks. Need to determine the size of the
637  * hash table, it could have been resized since we were looking last.
638  * Since we iterate in partition order, we can start by unconditionally
639  * lock partition 0.
640  *
641  * Once we hold the lock, no resizing can happen until the scan ends. So
642  * we don't need to repeatedly call ensure_valid_bucket_pointers().
643  */
644  if (status->curpartition == -1)
645  {
646  Assert(status->curbucket == 0);
647  Assert(!status->hash_table->find_locked);
648 
649  status->curpartition = 0;
650 
651  LWLockAcquire(PARTITION_LOCK(status->hash_table,
652  status->curpartition),
653  status->exclusive ? LW_EXCLUSIVE : LW_SHARED);
654 
656 
657  status->nbuckets =
658  NUM_BUCKETS(status->hash_table->control->size_log2);
659  next_item_pointer = status->hash_table->buckets[status->curbucket];
660  }
661  else
662  next_item_pointer = status->pnextitem;
663 
665  status->curpartition),
666  status->exclusive ? LW_EXCLUSIVE : LW_SHARED));
667 
668  /* Move to the next bucket if we finished the current bucket */
669  while (!DsaPointerIsValid(next_item_pointer))
670  {
671  int next_partition;
672 
673  if (++status->curbucket >= status->nbuckets)
674  {
675  /* all buckets have been scanned. finish. */
676  return NULL;
677  }
678 
679  /* Check if move to the next partition */
680  next_partition =
682  status->hash_table->size_log2);
683 
684  if (status->curpartition != next_partition)
685  {
686  /*
687  * Move to the next partition. Lock the next partition then
688  * release the current, not in the reverse order to avoid
689  * concurrent resizing. Avoid dead lock by taking lock in the
690  * same order with resize().
691  */
692  LWLockAcquire(PARTITION_LOCK(status->hash_table,
693  next_partition),
694  status->exclusive ? LW_EXCLUSIVE : LW_SHARED);
695  LWLockRelease(PARTITION_LOCK(status->hash_table,
696  status->curpartition));
697  status->curpartition = next_partition;
698  }
699 
700  next_item_pointer = status->hash_table->buckets[status->curbucket];
701  }
702 
703  status->curitem =
704  dsa_get_address(status->hash_table->area, next_item_pointer);
705  status->hash_table->find_locked = true;
706  status->hash_table->find_exclusively_locked = status->exclusive;
707 
708  /*
709  * The caller may delete the item. Store the next item in case of
710  * deletion.
711  */
712  status->pnextitem = status->curitem->next;
713 
714  return ENTRY_FROM_ITEM(status->curitem);
715 }
#define PARTITION_FOR_BUCKET_INDEX(bucket_idx, size_log2)
Definition: dshash.c:161

References Assert(), dsa_get_address(), DsaPointerIsValid, ensure_valid_bucket_pointers(), ENTRY_FROM_ITEM, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockHeldByMeInMode(), LWLockRelease(), NUM_BUCKETS, PARTITION_FOR_BUCKET_INDEX, PARTITION_LOCK, and status().

Referenced by pgstat_build_snapshot(), pgstat_drop_all_entries(), pgstat_drop_database_and_contents(), pgstat_reset_matching_entries(), and pgstat_write_statsfile().

◆ dshash_seq_term()

void dshash_seq_term ( dshash_seq_status status)

Definition at line 723 of file dshash.c.

724 {
725  status->hash_table->find_locked = false;
726  status->hash_table->find_exclusively_locked = false;
727 
728  if (status->curpartition >= 0)
729  LWLockRelease(PARTITION_LOCK(status->hash_table, status->curpartition));
730 }

References LWLockRelease(), PARTITION_LOCK, and status().

Referenced by pgstat_build_snapshot(), pgstat_drop_all_entries(), pgstat_drop_database_and_contents(), pgstat_reset_matching_entries(), and pgstat_write_statsfile().