diff --git a/src/backend/utils/hash/dynahash.c b/src/backend/utils/hash/dynahash.c index 5948b01abc..f4fbccdd7e 100644 --- a/src/backend/utils/hash/dynahash.c +++ b/src/backend/utils/hash/dynahash.c @@ -1,7 +1,7 @@ /*------------------------------------------------------------------------- * * dynahash.c - * dynamic hash tables + * dynamic chained hash tables * * dynahash.c supports both local-to-a-backend hash tables and hash tables in * shared memory. For shared hash tables, it is the caller's responsibility @@ -41,6 +41,16 @@ * function must be supplied; comparison defaults to memcmp() and key copying * to memcpy() when a user-defined hashing function is selected. * + * Compared to simplehash, dynahash has the following benefits: + * + * - It supports partitioning, which is useful for shared memory access using + * locks. + * - Shared memory hashes are allocated in a fixed size area at startup and + * are discoverable by name from other processes. + * - Because entries don't need to be moved in the case of hash conflicts, has + * better performance for large entries + * - Guarantees stable pointers to entries. + * * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * diff --git a/src/include/lib/simplehash.h b/src/include/lib/simplehash.h index 90dfa8a695..96f0c21f60 100644 --- a/src/include/lib/simplehash.h +++ b/src/include/lib/simplehash.h @@ -1,10 +1,27 @@ /* * simplehash.h * - * Hash table implementation which will be specialized to user-defined - * types, by including this file to generate the required code. It's - * probably not worthwhile to do so for hash tables that aren't performance - * or space sensitive. + * When included this file generates a "templated" (by way of macros) + * open-addressing hash table implementation specialized to user-defined + * types. + * + * It's probably not worthwhile to generate such a specialized implementation + * for hash tables that aren't performance or space sensitive. + * + * Compared to dynahash, simplehash has the following benefits: + * + * - Due to the "templated" code generation has known structure sizes and no + * indirect function calls (which show up substantially in dynahash + * profiles). These features considerably increase speed for small + * entries. + * - Open addressing has better CPU cache behavior than dynahash's chained + * hashtables. + * - The generated interface is type-safe and easier to use than dynahash, + * though at the cost of more complex setup. + * - Allocates memory in a MemoryContext or another allocator with a + * malloc/free style interface (which isn't easily usable in a shared + * memory context) + * - Does not require the overhead of a separate memory context. * * Usage notes: * @@ -34,6 +51,19 @@ * - SH_STORE_HASH - if defined the hash is stored in the elements * - SH_GET_HASH(tb, a) - return the field to store the hash in * + * The element type is required to contain a "uint32 status" member. + * + * While SH_STORE_HASH (and subsequently SH_GET_HASH) are optional, because + * the hash table implementation needs to compare hashes to move elements + * (particularly when growing the hash), it's preferable, if possible, to + * store the element's hash in the element's data type. If the hash is so + * stored, the hash table will also compare hashes before calling SH_EQUAL + * when comparing two keys. + * + * For convenience the hash table create functions accept a void pointer + * that will be stored in the hash table type's member private_data. This + * allows callbacks to reference caller provided data. + * * For examples of usage look at tidbitmap.c (file local definition) and * execnodes.h/execGrouping.c (exposed declaration, file local * implementation). @@ -149,24 +179,59 @@ typedef struct SH_ITERATOR /* externally visible function prototypes */ #ifdef SH_RAW_ALLOCATOR +/* _hash _create(uint32 nelements, void *private_data) */ SH_SCOPE SH_TYPE *SH_CREATE(uint32 nelements, void *private_data); #else +/* + * _hash _create(MemoryContext ctx, uint32 nelements, + * void *private_data) + */ SH_SCOPE SH_TYPE *SH_CREATE(MemoryContext ctx, uint32 nelements, void *private_data); #endif + +/* void _destroy(_hash *tb) */ SH_SCOPE void SH_DESTROY(SH_TYPE * tb); + +/* void _reset(_hash *tb) */ SH_SCOPE void SH_RESET(SH_TYPE * tb); + +/* void _grow(_hash *tb) */ SH_SCOPE void SH_GROW(SH_TYPE * tb, uint32 newsize); + +/* *_insert(_hash *tb, key, bool *found) */ SH_SCOPE SH_ELEMENT_TYPE *SH_INSERT(SH_TYPE * tb, SH_KEY_TYPE key, bool *found); + +/* + * *_insert_hash(_hash *tb, key, uint32 hash, + * bool *found) + */ SH_SCOPE SH_ELEMENT_TYPE *SH_INSERT_HASH(SH_TYPE * tb, SH_KEY_TYPE key, uint32 hash, bool *found); + +/* *_lookup(_hash *tb, key) */ SH_SCOPE SH_ELEMENT_TYPE *SH_LOOKUP(SH_TYPE * tb, SH_KEY_TYPE key); + +/* *_lookup_hash(_hash *tb, key, uint32 hash) */ SH_SCOPE SH_ELEMENT_TYPE *SH_LOOKUP_HASH(SH_TYPE * tb, SH_KEY_TYPE key, uint32 hash); + +/* bool _delete(_hash *tb, key) */ SH_SCOPE bool SH_DELETE(SH_TYPE * tb, SH_KEY_TYPE key); + +/* void _start_iterate(_hash *tb, _iterator *iter) */ SH_SCOPE void SH_START_ITERATE(SH_TYPE * tb, SH_ITERATOR * iter); + +/* + * void _start_iterate_at(_hash *tb, _iterator *iter, + * uint32 at) + */ SH_SCOPE void SH_START_ITERATE_AT(SH_TYPE * tb, SH_ITERATOR * iter, uint32 at); + +/* *_iterate(_hash *tb, _iterator *iter) */ SH_SCOPE SH_ELEMENT_TYPE *SH_ITERATE(SH_TYPE * tb, SH_ITERATOR * iter); + +/* void _stat(_hash *tb */ SH_SCOPE void SH_STAT(SH_TYPE * tb); #endif /* SH_DECLARE */