PostgreSQL Source Code git master
dshash.c File Reference
#include "postgres.h"
#include <limits.h>
#include "common/hashfn.h"
#include "lib/dshash.h"
#include "storage/lwlock.h"
#include "utils/dsa.h"
Include dependency graph for dshash.c:

Go to the source code of this file.

Data Structures

struct  dshash_table_item
 
struct  dshash_partition
 
struct  dshash_table_control
 
struct  dshash_table
 

Macros

#define DSHASH_NUM_PARTITIONS_LOG2   7
 
#define DSHASH_NUM_PARTITIONS   (1 << DSHASH_NUM_PARTITIONS_LOG2)
 
#define DSHASH_MAGIC   0x75ff6a20
 
#define ENTRY_FROM_ITEM(item)    ((char *)(item) + MAXALIGN(sizeof(dshash_table_item)))
 
#define ITEM_FROM_ENTRY(entry)
 
#define NUM_SPLITS(size_log2)    (size_log2 - DSHASH_NUM_PARTITIONS_LOG2)
 
#define NUM_BUCKETS(size_log2)    (((size_t) 1) << (size_log2))
 
#define BUCKETS_PER_PARTITION(size_log2)    (((size_t) 1) << NUM_SPLITS(size_log2))
 
#define MAX_COUNT_PER_PARTITION(hash_table)
 
#define PARTITION_FOR_HASH(hash)    (hash >> ((sizeof(dshash_hash) * CHAR_BIT) - DSHASH_NUM_PARTITIONS_LOG2))
 
#define BUCKET_INDEX_FOR_HASH_AND_SIZE(hash, size_log2)    (hash >> ((sizeof(dshash_hash) * CHAR_BIT) - (size_log2)))
 
#define BUCKET_INDEX_FOR_PARTITION(partition, size_log2)    ((partition) << NUM_SPLITS(size_log2))
 
#define PARTITION_FOR_BUCKET_INDEX(bucket_idx, size_log2)    ((bucket_idx) >> NUM_SPLITS(size_log2))
 
#define BUCKET_FOR_HASH(hash_table, hash)
 
#define PARTITION_LOCK(hash_table, i)    (&(hash_table)->control->partitions[(i)].lock)
 
#define ASSERT_NO_PARTITION_LOCKS_HELD_BY_ME(hash_table)
 

Typedefs

typedef struct dshash_partition dshash_partition
 
typedef struct dshash_table_control dshash_table_control
 

Functions

static void delete_item (dshash_table *hash_table, dshash_table_item *item)
 
static void resize (dshash_table *hash_table, size_t new_size_log2)
 
static void ensure_valid_bucket_pointers (dshash_table *hash_table)
 
static dshash_table_itemfind_in_bucket (dshash_table *hash_table, const void *key, dsa_pointer item_pointer)
 
static void insert_item_into_bucket (dshash_table *hash_table, dsa_pointer item_pointer, dshash_table_item *item, dsa_pointer *bucket)
 
static dshash_table_iteminsert_into_bucket (dshash_table *hash_table, const void *key, dsa_pointer *bucket)
 
static bool delete_key_from_bucket (dshash_table *hash_table, const void *key, dsa_pointer *bucket_head)
 
static bool delete_item_from_bucket (dshash_table *hash_table, dshash_table_item *item, dsa_pointer *bucket_head)
 
static dshash_hash hash_key (dshash_table *hash_table, const void *key)
 
static bool equal_keys (dshash_table *hash_table, const void *a, const void *b)
 
static void copy_key (dshash_table *hash_table, void *dest, const void *src)
 
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)
 
void dshash_destroy (dshash_table *hash_table)
 
dshash_table_handle dshash_get_hash_table_handle (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)
 
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_memcpy (void *dest, const void *src, size_t size, void *arg)
 
int dshash_strcmp (const void *a, const void *b, size_t size, void *arg)
 
dshash_hash dshash_strhash (const void *v, size_t size, void *arg)
 
void dshash_strcpy (void *dest, const void *src, size_t size, void *arg)
 
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)
 
void dshash_dump (dshash_table *hash_table)
 

Macro Definition Documentation

◆ ASSERT_NO_PARTITION_LOCKS_HELD_BY_ME

#define ASSERT_NO_PARTITION_LOCKS_HELD_BY_ME (   hash_table)
Value:
Assert(!LWLockAnyHeldByMe(&(hash_table)->control->partitions[0].lock, \
#define DSHASH_NUM_PARTITIONS
Definition: dshash.c:62
Assert(PointerIsAligned(start, uint64))
bool LWLockAnyHeldByMe(LWLock *lock, int nlocks, size_t stride)
Definition: lwlock.c:1995

Definition at line 197 of file dshash.c.

◆ BUCKET_FOR_HASH

#define BUCKET_FOR_HASH (   hash_table,
  hash 
)
Value:
(hash_table->buckets[ \
BUCKET_INDEX_FOR_HASH_AND_SIZE(hash, \
hash_table->size_log2)])
static unsigned hash(unsigned *uv, int n)
Definition: rege_dfa.c:715

Definition at line 163 of file dshash.c.

◆ BUCKET_INDEX_FOR_HASH_AND_SIZE

#define BUCKET_INDEX_FOR_HASH_AND_SIZE (   hash,
  size_log2 
)     (hash >> ((sizeof(dshash_hash) * CHAR_BIT) - (size_log2)))

Definition at line 151 of file dshash.c.

◆ BUCKET_INDEX_FOR_PARTITION

#define BUCKET_INDEX_FOR_PARTITION (   partition,
  size_log2 
)     ((partition) << NUM_SPLITS(size_log2))

Definition at line 155 of file dshash.c.

◆ BUCKETS_PER_PARTITION

#define BUCKETS_PER_PARTITION (   size_log2)     (((size_t) 1) << NUM_SPLITS(size_log2))

Definition at line 133 of file dshash.c.

◆ DSHASH_MAGIC

#define DSHASH_MAGIC   0x75ff6a20

Definition at line 65 of file dshash.c.

◆ DSHASH_NUM_PARTITIONS

#define DSHASH_NUM_PARTITIONS   (1 << DSHASH_NUM_PARTITIONS_LOG2)

Definition at line 62 of file dshash.c.

◆ DSHASH_NUM_PARTITIONS_LOG2

#define DSHASH_NUM_PARTITIONS_LOG2   7

Definition at line 61 of file dshash.c.

◆ ENTRY_FROM_ITEM

#define ENTRY_FROM_ITEM (   item)     ((char *)(item) + MAXALIGN(sizeof(dshash_table_item)))

Definition at line 116 of file dshash.c.

◆ ITEM_FROM_ENTRY

#define ITEM_FROM_ENTRY (   entry)
Value:
((dshash_table_item *)((char *)(entry) - \
#define MAXALIGN(LEN)
Definition: c.h:813

Definition at line 120 of file dshash.c.

◆ MAX_COUNT_PER_PARTITION

#define MAX_COUNT_PER_PARTITION (   hash_table)
Value:
(BUCKETS_PER_PARTITION(hash_table->size_log2) / 2 + \
BUCKETS_PER_PARTITION(hash_table->size_log2) / 4)
#define BUCKETS_PER_PARTITION(size_log2)
Definition: dshash.c:133

Definition at line 137 of file dshash.c.

◆ NUM_BUCKETS

#define NUM_BUCKETS (   size_log2)     (((size_t) 1) << (size_log2))

Definition at line 129 of file dshash.c.

◆ NUM_SPLITS

#define NUM_SPLITS (   size_log2)     (size_log2 - DSHASH_NUM_PARTITIONS_LOG2)

Definition at line 125 of file dshash.c.

◆ PARTITION_FOR_BUCKET_INDEX

#define PARTITION_FOR_BUCKET_INDEX (   bucket_idx,
  size_log2 
)     ((bucket_idx) >> NUM_SPLITS(size_log2))

Definition at line 159 of file dshash.c.

◆ PARTITION_FOR_HASH

#define PARTITION_FOR_HASH (   hash)     (hash >> ((sizeof(dshash_hash) * CHAR_BIT) - DSHASH_NUM_PARTITIONS_LOG2))

Definition at line 142 of file dshash.c.

◆ PARTITION_LOCK

#define PARTITION_LOCK (   hash_table,
  i 
)     (&(hash_table)->control->partitions[(i)].lock)

Definition at line 194 of file dshash.c.

Typedef Documentation

◆ dshash_partition

◆ dshash_table_control

Function Documentation

◆ copy_key()

static void copy_key ( dshash_table hash_table,
void *  dest,
const void *  src 
)
inlinestatic

Definition at line 1087 of file dshash.c.

1088{
1089 hash_table->params.copy_function(dest, src,
1090 hash_table->params.key_size,
1091 hash_table->arg);
1092}
size_t key_size
Definition: dshash.h:56
dshash_copy_function copy_function
Definition: dshash.h:60
dshash_parameters params
Definition: dshash.c:108
void * arg
Definition: dshash.c:109

References dshash_table::arg, dshash_parameters::copy_function, generate_unaccent_rules::dest, dshash_parameters::key_size, and dshash_table::params.

Referenced by insert_into_bucket().

◆ delete_item()

static void delete_item ( dshash_table hash_table,
dshash_table_item item 
)
static

Definition at line 834 of file dshash.c.

835{
836 size_t hash = item->hash;
837 size_t partition = PARTITION_FOR_HASH(hash);
838
839 Assert(LWLockHeldByMe(PARTITION_LOCK(hash_table, partition)));
840
841 if (delete_item_from_bucket(hash_table, item,
842 &BUCKET_FOR_HASH(hash_table, hash)))
843 {
844 Assert(hash_table->control->partitions[partition].count > 0);
845 --hash_table->control->partitions[partition].count;
846 }
847 else
848 {
849 Assert(false);
850 }
851}
#define PARTITION_LOCK(hash_table, i)
Definition: dshash.c:194
static bool delete_item_from_bucket(dshash_table *hash_table, dshash_table_item *item, dsa_pointer *bucket_head)
Definition: dshash.c:1037
#define PARTITION_FOR_HASH(hash)
Definition: dshash.c:142
#define BUCKET_FOR_HASH(hash_table, hash)
Definition: dshash.c:163
bool LWLockHeldByMe(LWLock *lock)
Definition: lwlock.c:1977
size_t count
Definition: dshash.c:78
dshash_partition partitions[DSHASH_NUM_PARTITIONS]
Definition: dshash.c:89
dshash_hash hash
Definition: dshash.c:51
dshash_table_control * control
Definition: dshash.c:110

References Assert(), BUCKET_FOR_HASH, dshash_table::control, dshash_partition::count, delete_item_from_bucket(), dshash_table_item::hash, hash(), LWLockHeldByMe(), PARTITION_FOR_HASH, PARTITION_LOCK, and dshash_table_control::partitions.

Referenced by dshash_delete_current(), and dshash_delete_entry().

◆ delete_item_from_bucket()

static bool delete_item_from_bucket ( dshash_table hash_table,
dshash_table_item item,
dsa_pointer bucket_head 
)
static

Definition at line 1037 of file dshash.c.

1040{
1041 while (DsaPointerIsValid(*bucket_head))
1042 {
1043 dshash_table_item *bucket_item;
1044
1045 bucket_item = dsa_get_address(hash_table->area, *bucket_head);
1046
1047 if (bucket_item == item)
1048 {
1050
1051 next = item->next;
1052 dsa_free(hash_table->area, *bucket_head);
1053 *bucket_head = next;
1054 return true;
1055 }
1056 bucket_head = &bucket_item->next;
1057 }
1058 return false;
1059}
static int32 next
Definition: blutils.c:224
void * dsa_get_address(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:957
void dsa_free(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:841
uint64 dsa_pointer
Definition: dsa.h:62
#define DsaPointerIsValid(x)
Definition: dsa.h:106
dsa_pointer next
Definition: dshash.c:49
dsa_area * area
Definition: dshash.c:107

References dshash_table::area, dsa_free(), dsa_get_address(), DsaPointerIsValid, next, and dshash_table_item::next.

Referenced by delete_item().

◆ delete_key_from_bucket()

static bool delete_key_from_bucket ( dshash_table hash_table,
const void *  key,
dsa_pointer bucket_head 
)
static

Definition at line 1008 of file dshash.c.

1011{
1012 while (DsaPointerIsValid(*bucket_head))
1013 {
1014 dshash_table_item *item;
1015
1016 item = dsa_get_address(hash_table->area, *bucket_head);
1017
1018 if (equal_keys(hash_table, key, ENTRY_FROM_ITEM(item)))
1019 {
1021
1022 next = item->next;
1023 dsa_free(hash_table->area, *bucket_head);
1024 *bucket_head = next;
1025
1026 return true;
1027 }
1028 bucket_head = &item->next;
1029 }
1030 return false;
1031}
static bool equal_keys(dshash_table *hash_table, const void *a, const void *b)
Definition: dshash.c:1076
#define ENTRY_FROM_ITEM(item)
Definition: dshash.c:116

References dshash_table::area, dsa_free(), dsa_get_address(), DsaPointerIsValid, ENTRY_FROM_ITEM, equal_keys(), sort-test::key, next, and dshash_table_item::next.

Referenced by dshash_delete_key().

◆ dshash_attach()

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

Definition at line 272 of file dshash.c.

274{
275 dshash_table *hash_table;
276 dsa_pointer control;
277
278 /* Allocate the backend-local object representing the hash table. */
279 hash_table = palloc(sizeof(dshash_table));
280
281 /* Find the control object in shared memory. */
282 control = handle;
283
284 /* Set up the local hash table struct. */
285 hash_table->area = area;
286 hash_table->params = *params;
287 hash_table->arg = arg;
288 hash_table->control = dsa_get_address(area, control);
289 Assert(hash_table->control->magic == DSHASH_MAGIC);
290
291 /*
292 * These will later be set to the correct values by
293 * ensure_valid_bucket_pointers(), at which time we'll be holding a
294 * partition lock for interlocking against concurrent resizing.
295 */
296 hash_table->buckets = NULL;
297 hash_table->size_log2 = 0;
298
299 return hash_table;
300}
#define DSHASH_MAGIC
Definition: dshash.c:65
void * palloc(Size size)
Definition: mcxt.c:1365
void * arg
dsa_pointer * buckets
Definition: dshash.c:111
size_t size_log2
Definition: dshash.c:112

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

Referenced by GetNamedDSHash(), init_dsm_registry(), logicalrep_launcher_attach_dshmem(), pgstat_attach_shmem(), and SharedRecordTypmodRegistryAttach().

◆ dshash_create()

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

Definition at line 208 of file dshash.c.

209{
210 dshash_table *hash_table;
211 dsa_pointer control;
212
213 /* Allocate the backend-local object representing the hash table. */
214 hash_table = palloc(sizeof(dshash_table));
215
216 /* Allocate the control object in shared memory. */
217 control = dsa_allocate(area, sizeof(dshash_table_control));
218
219 /* Set up the local and shared hash table structs. */
220 hash_table->area = area;
221 hash_table->params = *params;
222 hash_table->arg = arg;
223 hash_table->control = dsa_get_address(area, control);
224 hash_table->control->handle = control;
225 hash_table->control->magic = DSHASH_MAGIC;
226 hash_table->control->lwlock_tranche_id = params->tranche_id;
227
228 /* Set up the array of lock partitions. */
229 {
231 int tranche_id = hash_table->control->lwlock_tranche_id;
232 int i;
233
234 for (i = 0; i < DSHASH_NUM_PARTITIONS; ++i)
235 {
236 LWLockInitialize(&partitions[i].lock, tranche_id);
237 partitions[i].count = 0;
238 }
239 }
240
241 /*
242 * Set up the initial array of buckets. Our initial size is the same as
243 * the number of partitions.
244 */
246 hash_table->control->buckets =
250 if (!DsaPointerIsValid(hash_table->control->buckets))
251 {
252 dsa_free(area, control);
254 (errcode(ERRCODE_OUT_OF_MEMORY),
255 errmsg("out of memory"),
256 errdetail("Failed on DSA request of size %zu.",
258 }
259 hash_table->buckets = dsa_get_address(area,
260 hash_table->control->buckets);
261 hash_table->size_log2 = hash_table->control->size_log2;
262
263 return hash_table;
264}
dsa_pointer dsa_allocate_extended(dsa_area *area, size_t size, int flags)
Definition: dsa.c:686
#define dsa_allocate(area, size)
Definition: dsa.h:109
#define DSA_ALLOC_NO_OOM
Definition: dsa.h:74
#define DSA_ALLOC_ZERO
Definition: dsa.h:75
#define DSHASH_NUM_PARTITIONS_LOG2
Definition: dshash.c:61
int errdetail(const char *fmt,...)
Definition: elog.c:1216
int errcode(int sqlerrcode)
Definition: elog.c:863
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:150
int i
Definition: isn.c:77
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition: lwlock.c:698
static int partitions
Definition: pgbench.c:224
size_t size_log2
Definition: dshash.c:98
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_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 GetNamedDSHash(), init_dsm_registry(), logicalrep_launcher_attach_dshmem(), SharedRecordTypmodRegistryInit(), and StatsShmemInit().

◆ dshash_delete_current()

void dshash_delete_current ( dshash_seq_status status)

Definition at line 759 of file dshash.c.

760{
761 dshash_table *hash_table = status->hash_table;
762 dshash_table_item *item = status->curitem;
763 size_t partition PG_USED_FOR_ASSERTS_ONLY;
764
765 partition = PARTITION_FOR_HASH(item->hash);
766
767 Assert(status->exclusive);
768 Assert(hash_table->control->magic == DSHASH_MAGIC);
769 Assert(LWLockHeldByMeInMode(PARTITION_LOCK(hash_table, partition),
770 LW_EXCLUSIVE));
771
772 delete_item(hash_table, item);
773}
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:228
static void delete_item(dshash_table *hash_table, dshash_table_item *item)
Definition: dshash.c:834
bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:2021
@ LW_EXCLUSIVE
Definition: lwlock.h:112
bool exclusive
Definition: dshash.h:80
dshash_table_item * curitem
Definition: dshash.h:77
dshash_table * hash_table
Definition: dshash.h:74

References Assert(), dshash_table::control, dshash_seq_status::curitem, delete_item(), DSHASH_MAGIC, dshash_seq_status::exclusive, dshash_table_item::hash, dshash_seq_status::hash_table, LW_EXCLUSIVE, LWLockHeldByMeInMode(), dshash_table_control::magic, PARTITION_FOR_HASH, PARTITION_LOCK, and PG_USED_FOR_ASSERTS_ONLY.

Referenced by pgstat_free_entry().

◆ dshash_delete_entry()

void dshash_delete_entry ( dshash_table hash_table,
void *  entry 
)

Definition at line 543 of file dshash.c.

544{
545 dshash_table_item *item = ITEM_FROM_ENTRY(entry);
546 size_t partition = PARTITION_FOR_HASH(item->hash);
547
548 Assert(hash_table->control->magic == DSHASH_MAGIC);
549 Assert(LWLockHeldByMeInMode(PARTITION_LOCK(hash_table, partition),
550 LW_EXCLUSIVE));
551
552 delete_item(hash_table, item);
553 LWLockRelease(PARTITION_LOCK(hash_table, partition));
554}
#define ITEM_FROM_ENTRY(entry)
Definition: dshash.c:120
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1894

References Assert(), dshash_table::control, delete_item(), DSHASH_MAGIC, 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(), and pgstat_get_entry_ref().

◆ dshash_delete_key()

bool dshash_delete_key ( dshash_table hash_table,
const void *  key 
)

Definition at line 505 of file dshash.c.

506{
508 size_t partition;
509 bool found;
510
511 Assert(hash_table->control->magic == DSHASH_MAGIC);
513
514 hash = hash_key(hash_table, key);
515 partition = PARTITION_FOR_HASH(hash);
516
517 LWLockAcquire(PARTITION_LOCK(hash_table, partition), LW_EXCLUSIVE);
519
520 if (delete_key_from_bucket(hash_table, key,
521 &BUCKET_FOR_HASH(hash_table, hash)))
522 {
523 Assert(hash_table->control->partitions[partition].count > 0);
524 found = true;
525 --hash_table->control->partitions[partition].count;
526 }
527 else
528 found = false;
529
530 LWLockRelease(PARTITION_LOCK(hash_table, partition));
531
532 return found;
533}
static bool delete_key_from_bucket(dshash_table *hash_table, const void *key, dsa_pointer *bucket_head)
Definition: dshash.c:1008
static dshash_hash hash_key(dshash_table *hash_table, const void *key)
Definition: dshash.c:1065
#define ASSERT_NO_PARTITION_LOCKS_HELD_BY_ME(hash_table)
Definition: dshash.c:197
static void ensure_valid_bucket_pointers(dshash_table *hash_table)
Definition: dshash.c:939
uint32 dshash_hash
Definition: dshash.h:30
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1174

References Assert(), ASSERT_NO_PARTITION_LOCKS_HELD_BY_ME, BUCKET_FOR_HASH, dshash_table::control, dshash_partition::count, delete_key_from_bucket(), DSHASH_MAGIC, ensure_valid_bucket_pointers(), 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 ApplyLauncherForgetWorkerStartTime(), and find_or_make_matching_shared_tupledesc().

◆ dshash_destroy()

void dshash_destroy ( dshash_table hash_table)

Definition at line 325 of file dshash.c.

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

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 309 of file dshash.c.

310{
312
313 /* The hash table may have been destroyed. Just free local memory. */
314 pfree(hash_table);
315}

References ASSERT_NO_PARTITION_LOCKS_HELD_BY_ME, 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 780 of file dshash.c.

781{
782 size_t i;
783 size_t j;
784
785 Assert(hash_table->control->magic == DSHASH_MAGIC);
787
788 for (i = 0; i < DSHASH_NUM_PARTITIONS; ++i)
789 {
790 Assert(!LWLockHeldByMe(PARTITION_LOCK(hash_table, i)));
792 }
793
795
796 fprintf(stderr,
797 "hash table size = %zu\n", (size_t) 1 << hash_table->size_log2);
798 for (i = 0; i < DSHASH_NUM_PARTITIONS; ++i)
799 {
800 dshash_partition *partition = &hash_table->control->partitions[i];
801 size_t begin = BUCKET_INDEX_FOR_PARTITION(i, hash_table->size_log2);
802 size_t end = BUCKET_INDEX_FOR_PARTITION(i + 1, hash_table->size_log2);
803
804 fprintf(stderr, " partition %zu\n", i);
805 fprintf(stderr,
806 " active buckets (key count = %zu)\n", partition->count);
807
808 for (j = begin; j < end; ++j)
809 {
810 size_t count = 0;
811 dsa_pointer bucket = hash_table->buckets[j];
812
813 while (DsaPointerIsValid(bucket))
814 {
815 dshash_table_item *item;
816
817 item = dsa_get_address(hash_table->area, bucket);
818
819 bucket = item->next;
820 ++count;
821 }
822 fprintf(stderr, " bucket %zu (key count = %zu)\n", j, count);
823 }
824 }
825
826 for (i = 0; i < DSHASH_NUM_PARTITIONS; ++i)
827 LWLockRelease(PARTITION_LOCK(hash_table, i));
828}
#define fprintf(file, fmt, msg)
Definition: cubescan.l:21
#define BUCKET_INDEX_FOR_PARTITION(partition, size_log2)
Definition: dshash.c:155
int j
Definition: isn.c:78
@ LW_SHARED
Definition: lwlock.h:113

References dshash_table::area, Assert(), ASSERT_NO_PARTITION_LOCKS_HELD_BY_ME, 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(), 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 392 of file dshash.c.

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

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

Referenced by ApplyLauncherGetWorkerStartTime(), find_or_make_matching_shared_tupledesc(), get_val_in_hash(), 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 435 of file dshash.c.

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

References Assert(), ASSERT_NO_PARTITION_LOCKS_HELD_BY_ME, BUCKET_FOR_HASH, dshash_table::control, dshash_partition::count, DSHASH_MAGIC, ensure_valid_bucket_pointers(), ENTRY_FROM_ITEM, find_in_bucket(), 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 ApplyLauncherSetWorkerStartTime(), find_or_make_matching_shared_tupledesc(), GetNamedDSA(), GetNamedDSHash(), GetNamedDSMSegment(), pgstat_get_entry_ref(), pgstat_read_statsfile(), set_val_in_hash(), and SharedRecordTypmodRegistryInit().

◆ dshash_get_hash_table_handle()

dshash_table_handle dshash_get_hash_table_handle ( dshash_table hash_table)

◆ dshash_memcmp()

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

Definition at line 574 of file dshash.c.

575{
576 return memcmp(a, b, size);
577}
int b
Definition: isn.c:74
int a
Definition: isn.c:73

References a, and b.

◆ dshash_memcpy()

void dshash_memcpy ( void *  dest,
const void *  src,
size_t  size,
void *  arg 
)

Definition at line 592 of file dshash.c.

593{
594 (void) memcpy(dest, src, size);
595}

References generate_unaccent_rules::dest.

◆ dshash_memhash()

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

Definition at line 583 of file dshash.c.

584{
585 return tag_hash(v, size);
586}
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 
)

◆ dshash_seq_next()

void * dshash_seq_next ( dshash_seq_status status)

Definition at line 659 of file dshash.c.

660{
661 dsa_pointer next_item_pointer;
662
663 /*
664 * Not yet holding any partition locks. Need to determine the size of the
665 * hash table, it could have been resized since we were looking last.
666 * Since we iterate in partition order, we can start by unconditionally
667 * lock partition 0.
668 *
669 * Once we hold the lock, no resizing can happen until the scan ends. So
670 * we don't need to repeatedly call ensure_valid_bucket_pointers().
671 */
672 if (status->curpartition == -1)
673 {
674 Assert(status->curbucket == 0);
676
677 status->curpartition = 0;
678
680 status->curpartition),
681 status->exclusive ? LW_EXCLUSIVE : LW_SHARED);
682
684
685 status->nbuckets =
687 next_item_pointer = status->hash_table->buckets[status->curbucket];
688 }
689 else
690 next_item_pointer = status->pnextitem;
691
693 status->curpartition),
694 status->exclusive ? LW_EXCLUSIVE : LW_SHARED));
695
696 /* Move to the next bucket if we finished the current bucket */
697 while (!DsaPointerIsValid(next_item_pointer))
698 {
699 int next_partition;
700
701 if (++status->curbucket >= status->nbuckets)
702 {
703 /* all buckets have been scanned. finish. */
704 return NULL;
705 }
706
707 /* Check if move to the next partition */
708 next_partition =
710 status->hash_table->size_log2);
711
712 if (status->curpartition != next_partition)
713 {
714 /*
715 * Move to the next partition. Lock the next partition then
716 * release the current, not in the reverse order to avoid
717 * concurrent resizing. Avoid dead lock by taking lock in the
718 * same order with resize().
719 */
721 next_partition),
722 status->exclusive ? LW_EXCLUSIVE : LW_SHARED);
724 status->curpartition));
725 status->curpartition = next_partition;
726 }
727
728 next_item_pointer = status->hash_table->buckets[status->curbucket];
729 }
730
731 status->curitem =
732 dsa_get_address(status->hash_table->area, next_item_pointer);
733
734 /*
735 * The caller may delete the item. Store the next item in case of
736 * deletion.
737 */
738 status->pnextitem = status->curitem->next;
739
740 return ENTRY_FROM_ITEM(status->curitem);
741}
#define PARTITION_FOR_BUCKET_INDEX(bucket_idx, size_log2)
Definition: dshash.c:159

References dshash_table::area, Assert(), ASSERT_NO_PARTITION_LOCKS_HELD_BY_ME, dshash_table::buckets, dshash_table::control, dshash_seq_status::curbucket, dshash_seq_status::curitem, dshash_seq_status::curpartition, dsa_get_address(), DsaPointerIsValid, ensure_valid_bucket_pointers(), ENTRY_FROM_ITEM, dshash_seq_status::exclusive, dshash_seq_status::hash_table, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockHeldByMeInMode(), LWLockRelease(), dshash_seq_status::nbuckets, dshash_table_item::next, NUM_BUCKETS, PARTITION_FOR_BUCKET_INDEX, PARTITION_LOCK, dshash_seq_status::pnextitem, dshash_table_control::size_log2, and dshash_table::size_log2.

Referenced by pg_get_dsm_registry_allocations(), pgstat_build_snapshot(), pgstat_drop_database_and_contents(), pgstat_drop_matching_entries(), pgstat_reset_matching_entries(), and pgstat_write_statsfile().

◆ dshash_seq_term()

◆ dshash_strcmp()

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

Definition at line 601 of file dshash.c.

602{
603 Assert(strlen((const char *) a) < size);
604 Assert(strlen((const char *) b) < size);
605
606 return strcmp((const char *) a, (const char *) b);
607}

References a, Assert(), and b.

◆ dshash_strcpy()

void dshash_strcpy ( void *  dest,
const void *  src,
size_t  size,
void *  arg 
)

Definition at line 624 of file dshash.c.

625{
626 Assert(strlen((const char *) src) < size);
627
628 (void) strcpy((char *) dest, (const char *) src);
629}

References Assert(), and generate_unaccent_rules::dest.

◆ dshash_strhash()

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

Definition at line 613 of file dshash.c.

614{
615 Assert(strlen((const char *) v) < size);
616
617 return string_hash((const char *) v, size);
618}
uint32 string_hash(const void *key, Size keysize)
Definition: hashfn.c:660

References Assert(), and string_hash().

◆ ensure_valid_bucket_pointers()

static void ensure_valid_bucket_pointers ( dshash_table hash_table)
inlinestatic

Definition at line 939 of file dshash.c.

940{
941 if (hash_table->size_log2 != hash_table->control->size_log2)
942 {
943 hash_table->buckets = dsa_get_address(hash_table->area,
944 hash_table->control->buckets);
945 hash_table->size_log2 = hash_table->control->size_log2;
946 }
947}

References dshash_table::area, dshash_table_control::buckets, dshash_table::buckets, dshash_table::control, dsa_get_address(), dshash_table_control::size_log2, and dshash_table::size_log2.

Referenced by dshash_delete_key(), dshash_destroy(), dshash_dump(), dshash_find(), dshash_find_or_insert(), and dshash_seq_next().

◆ equal_keys()

static bool equal_keys ( dshash_table hash_table,
const void *  a,
const void *  b 
)
inlinestatic

Definition at line 1076 of file dshash.c.

1077{
1078 return hash_table->params.compare_function(a, b,
1079 hash_table->params.key_size,
1080 hash_table->arg) == 0;
1081}
dshash_compare_function compare_function
Definition: dshash.h:58

References a, dshash_table::arg, b, dshash_parameters::compare_function, dshash_parameters::key_size, and dshash_table::params.

Referenced by delete_key_from_bucket(), and find_in_bucket().

◆ find_in_bucket()

static dshash_table_item * find_in_bucket ( dshash_table hash_table,
const void *  key,
dsa_pointer  item_pointer 
)
inlinestatic

Definition at line 953 of file dshash.c.

955{
956 while (DsaPointerIsValid(item_pointer))
957 {
958 dshash_table_item *item;
959
960 item = dsa_get_address(hash_table->area, item_pointer);
961 if (equal_keys(hash_table, key, ENTRY_FROM_ITEM(item)))
962 return item;
963 item_pointer = item->next;
964 }
965 return NULL;
966}

References dshash_table::area, dsa_get_address(), DsaPointerIsValid, ENTRY_FROM_ITEM, equal_keys(), sort-test::key, and dshash_table_item::next.

Referenced by dshash_find(), and dshash_find_or_insert().

◆ hash_key()

static dshash_hash hash_key ( dshash_table hash_table,
const void *  key 
)
inlinestatic

Definition at line 1065 of file dshash.c.

1066{
1067 return hash_table->params.hash_function(key,
1068 hash_table->params.key_size,
1069 hash_table->arg);
1070}
dshash_hash_function hash_function
Definition: dshash.h:59

References dshash_table::arg, dshash_parameters::hash_function, sort-test::key, dshash_parameters::key_size, and dshash_table::params.

Referenced by compute_tsvector_stats(), dshash_delete_key(), dshash_find(), and dshash_find_or_insert().

◆ insert_into_bucket()

static dshash_table_item * insert_into_bucket ( dshash_table hash_table,
const void *  key,
dsa_pointer bucket 
)
static

Definition at line 988 of file dshash.c.

991{
992 dsa_pointer item_pointer;
993 dshash_table_item *item;
994
995 item_pointer = dsa_allocate(hash_table->area,
996 hash_table->params.entry_size +
997 MAXALIGN(sizeof(dshash_table_item)));
998 item = dsa_get_address(hash_table->area, item_pointer);
999 copy_key(hash_table, ENTRY_FROM_ITEM(item), key);
1000 insert_item_into_bucket(hash_table, item_pointer, item, bucket);
1001 return item;
1002}
static void insert_item_into_bucket(dshash_table *hash_table, dsa_pointer item_pointer, dshash_table_item *item, dsa_pointer *bucket)
Definition: dshash.c:972
static void copy_key(dshash_table *hash_table, void *dest, const void *src)
Definition: dshash.c:1087
size_t entry_size
Definition: dshash.h:57

References dshash_table::area, copy_key(), dsa_allocate, dsa_get_address(), ENTRY_FROM_ITEM, dshash_parameters::entry_size, insert_item_into_bucket(), sort-test::key, MAXALIGN, and dshash_table::params.

Referenced by dshash_find_or_insert().

◆ insert_item_into_bucket()

static void insert_item_into_bucket ( dshash_table hash_table,
dsa_pointer  item_pointer,
dshash_table_item item,
dsa_pointer bucket 
)
static

Definition at line 972 of file dshash.c.

976{
977 Assert(item == dsa_get_address(hash_table->area, item_pointer));
978
979 item->next = *bucket;
980 *bucket = item_pointer;
981}

References dshash_table::area, Assert(), dsa_get_address(), and dshash_table_item::next.

Referenced by insert_into_bucket(), and resize().

◆ resize()

static void resize ( dshash_table hash_table,
size_t  new_size_log2 
)
static

Definition at line 860 of file dshash.c.

861{
862 dsa_pointer old_buckets;
863 dsa_pointer new_buckets_shared;
864 dsa_pointer *new_buckets;
865 size_t size;
866 size_t new_size = ((size_t) 1) << new_size_log2;
867 size_t i;
868
869 /*
870 * Acquire the locks for all lock partitions. This is expensive, but we
871 * shouldn't have to do it many times.
872 */
873 for (i = 0; i < DSHASH_NUM_PARTITIONS; ++i)
874 {
875 Assert(!LWLockHeldByMe(PARTITION_LOCK(hash_table, i)));
876
878 if (i == 0 && hash_table->control->size_log2 >= new_size_log2)
879 {
880 /*
881 * Another backend has already increased the size; we can avoid
882 * obtaining all the locks and return early.
883 */
884 LWLockRelease(PARTITION_LOCK(hash_table, 0));
885 return;
886 }
887 }
888
889 Assert(new_size_log2 == hash_table->control->size_log2 + 1);
890
891 /* Allocate the space for the new table. */
892 new_buckets_shared =
893 dsa_allocate_extended(hash_table->area,
894 sizeof(dsa_pointer) * new_size,
896 new_buckets = dsa_get_address(hash_table->area, new_buckets_shared);
897
898 /*
899 * We've allocated the new bucket array; all that remains to do now is to
900 * reinsert all items, which amounts to adjusting all the pointers.
901 */
902 size = ((size_t) 1) << hash_table->control->size_log2;
903 for (i = 0; i < size; ++i)
904 {
905 dsa_pointer item_pointer = hash_table->buckets[i];
906
907 while (DsaPointerIsValid(item_pointer))
908 {
909 dshash_table_item *item;
910 dsa_pointer next_item_pointer;
911
912 item = dsa_get_address(hash_table->area, item_pointer);
913 next_item_pointer = item->next;
914 insert_item_into_bucket(hash_table, item_pointer, item,
915 &new_buckets[BUCKET_INDEX_FOR_HASH_AND_SIZE(item->hash,
916 new_size_log2)]);
917 item_pointer = next_item_pointer;
918 }
919 }
920
921 /* Swap the hash table into place and free the old one. */
922 old_buckets = hash_table->control->buckets;
923 hash_table->control->buckets = new_buckets_shared;
924 hash_table->control->size_log2 = new_size_log2;
925 hash_table->buckets = new_buckets;
926 dsa_free(hash_table->area, old_buckets);
927
928 /* Release all the locks. */
929 for (i = 0; i < DSHASH_NUM_PARTITIONS; ++i)
930 LWLockRelease(PARTITION_LOCK(hash_table, i));
931}
#define DSA_ALLOC_HUGE
Definition: dsa.h:73
#define BUCKET_INDEX_FOR_HASH_AND_SIZE(hash, size_log2)
Definition: dshash.c:151

References dshash_table::area, Assert(), BUCKET_INDEX_FOR_HASH_AND_SIZE, dshash_table_control::buckets, dshash_table::buckets, dshash_table::control, DSA_ALLOC_HUGE, DSA_ALLOC_ZERO, dsa_allocate_extended(), dsa_free(), dsa_get_address(), DsaPointerIsValid, DSHASH_NUM_PARTITIONS, dshash_table_item::hash, i, insert_item_into_bucket(), LW_EXCLUSIVE, LWLockAcquire(), LWLockHeldByMe(), LWLockRelease(), dshash_table_item::next, PARTITION_LOCK, and dshash_table_control::size_log2.

Referenced by dshash_find_or_insert().