From 565903af474e85cef28ff712d773f13b6701ded5 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Tue, 7 Feb 2017 15:58:30 -0500 Subject: [PATCH] Allow the element allocator for a simplehash to be specified. This is infrastructure for a pending patch to allow parallel bitmap heap scans. Dilip Kumar, reviewed (in earlier versions) by Andres Freund and (more recently) by me. Some further renaming by me, also. --- src/backend/executor/execGrouping.c | 3 +- src/backend/nodes/tidbitmap.c | 2 +- src/include/lib/simplehash.h | 69 ++++++++++++++++++++++++----- 3 files changed, 60 insertions(+), 14 deletions(-) diff --git a/src/backend/executor/execGrouping.c b/src/backend/executor/execGrouping.c index 47c9656e1b..2d9ce938ba 100644 --- a/src/backend/executor/execGrouping.c +++ b/src/backend/executor/execGrouping.c @@ -330,7 +330,8 @@ BuildTupleHashTable(int numCols, AttrNumber *keyColIdx, else hashtable->hash_iv = 0; - hashtable->hashtab = tuplehash_create(tablecxt, nbuckets); + hashtable->hashtab = + tuplehash_create(tablecxt, nbuckets, NULL, NULL, NULL); hashtable->hashtab->private_data = hashtable; return hashtable; diff --git a/src/backend/nodes/tidbitmap.c b/src/backend/nodes/tidbitmap.c index 7b31948fd2..36102b5dea 100644 --- a/src/backend/nodes/tidbitmap.c +++ b/src/backend/nodes/tidbitmap.c @@ -244,7 +244,7 @@ tbm_create_pagetable(TIDBitmap *tbm) Assert(tbm->status != TBM_HASH); Assert(tbm->pagetable == NULL); - tbm->pagetable = pagetable_create(tbm->mcxt, 128); + tbm->pagetable = pagetable_create(tbm->mcxt, 128, NULL, NULL, NULL); /* If entry1 is valid, push it into the hashtable */ if (tbm->status == TBM_ONE_PAGE) diff --git a/src/include/lib/simplehash.h b/src/include/lib/simplehash.h index 72e18499c0..fd7063c216 100644 --- a/src/include/lib/simplehash.h +++ b/src/include/lib/simplehash.h @@ -87,6 +87,10 @@ #define SH_INITIAL_BUCKET SH_MAKE_NAME(initial_bucket) #define SH_ENTRY_HASH SH_MAKE_NAME(entry_hash) +/* Allocation function for hash table elements */ +typedef void *(*simplehash_allocate) (Size size, void *args); +typedef void (*simplehash_free) (void *pointer, void *args); + /* generate forward declarations necessary to use the hash table */ #ifdef SH_DECLARE @@ -112,6 +116,11 @@ typedef struct SH_TYPE /* hash buckets */ SH_ELEMENT_TYPE *data; + /* Allocation and free functions, and the associated context. */ + simplehash_allocate element_alloc; + simplehash_free element_free; + void *element_args; + /* memory context to use for allocations */ MemoryContext ctx; @@ -133,7 +142,8 @@ typedef struct SH_ITERATOR } SH_ITERATOR; /* externally visible function prototypes */ -SH_SCOPE SH_TYPE *SH_CREATE(MemoryContext ctx, uint32 nelements); +SH_SCOPE SH_TYPE *SH_CREATE(MemoryContext ctx, uint32 nelements, + simplehash_allocate allocfunc, simplehash_free freefunc, void *args); SH_SCOPE void SH_DESTROY(SH_TYPE *tb); SH_SCOPE void SH_GROW(SH_TYPE *tb, uint32 newsize); SH_SCOPE SH_ELEMENT_TYPE *SH_INSERT(SH_TYPE *tb, SH_KEY_TYPE key, bool *found); @@ -276,12 +286,35 @@ SH_ENTRY_HASH(SH_TYPE *tb, SH_ELEMENT_TYPE * entry) #endif } +/* default memory allocator function */ +static void * +SH_DEFAULT_ALLOC(Size size, void *args) +{ + MemoryContext context = (MemoryContext) args; + + return MemoryContextAllocExtended(context, size, + MCXT_ALLOC_HUGE | MCXT_ALLOC_ZERO); +} + +/* default memory free function */ +static void +SH_DEFAULT_FREE(void *pointer, void *args) +{ + pfree(pointer); +} + /* - * Create a hash table with enough space for `nelements` distinct members, - * allocating required memory in the passed-in context. + * Create a hash table with enough space for `nelements` distinct members. + * Memory for the hash table is allocated from the passed-in context. If + * desired, the array of elements can be allocated using a passed-in allocator; + * this could be useful in order to place the array of elements in a shared + * memory, or in a context that will outlive the rest of the hash table. + * Memory other than for the array of elements will still be allocated from + * the passed-in context. */ SH_SCOPE SH_TYPE * -SH_CREATE(MemoryContext ctx, uint32 nelements) +SH_CREATE(MemoryContext ctx, uint32 nelements, simplehash_allocate allocfunc, + simplehash_free freefunc, void *args) { SH_TYPE *tb; uint64 size; @@ -294,9 +327,22 @@ SH_CREATE(MemoryContext ctx, uint32 nelements) SH_COMPUTE_PARAMETERS(tb, size); - tb->data = MemoryContextAllocExtended(tb->ctx, - sizeof(SH_ELEMENT_TYPE) * tb->size, - MCXT_ALLOC_HUGE | MCXT_ALLOC_ZERO); + if (allocfunc == NULL) + { + tb->element_alloc = SH_DEFAULT_ALLOC; + tb->element_free = SH_DEFAULT_FREE; + tb->element_args = ctx; + } + else + { + tb->element_alloc = allocfunc; + tb->element_free = freefunc; + + tb->element_args = args; + } + + tb->data = tb->element_alloc(sizeof(SH_ELEMENT_TYPE) * tb->size, + tb->element_args); return tb; } @@ -305,7 +351,7 @@ SH_CREATE(MemoryContext ctx, uint32 nelements) SH_SCOPE void SH_DESTROY(SH_TYPE *tb) { - pfree(tb->data); + tb->element_free(tb->data, tb->element_args); pfree(tb); } @@ -333,9 +379,8 @@ SH_GROW(SH_TYPE *tb, uint32 newsize) /* compute parameters for new table */ SH_COMPUTE_PARAMETERS(tb, newsize); - tb->data = MemoryContextAllocExtended( - tb->ctx, sizeof(SH_ELEMENT_TYPE) * tb->size, - MCXT_ALLOC_HUGE | MCXT_ALLOC_ZERO); + tb->data = tb->element_alloc(sizeof(SH_ELEMENT_TYPE) * tb->size, + tb->element_args); newdata = tb->data; @@ -421,7 +466,7 @@ SH_GROW(SH_TYPE *tb, uint32 newsize) } } - pfree(olddata); + tb->element_free(olddata, tb->element_args); } /*