v2-0003-Change-the-signature-of-dynahash-s-alloc-function.patch

text/x-patch

Filename: v2-0003-Change-the-signature-of-dynahash-s-alloc-function.patch
Type: text/x-patch
Part: 2
Message: Re: Shared hash table allocations

Patch

Format: format-patch
Series: patch v2-0003
Subject: Change the signature of dynahash's alloc function
File+
src/backend/storage/ipc/shmem.c 13 2
src/backend/utils/hash/dynahash.c 27 25
src/include/utils/hsearch.h 2 1
From 684d8f9f9c22636c628af1dc5b5694b214e1d194 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Mon, 30 Mar 2026 18:20:58 +0300
Subject: [PATCH v2 3/8] Change the signature of dynahash's alloc function

Instead of passing the current memory context to the alloc function
via a shared variable, pass it directly as an argument.

Reviewed-by: Tomas Vondra <tomas@vondra.me>
Discussion: https://www.postgresql.org/message-id/01ab1d41-3eda-4705-8bbd-af898f5007f1@iki.fi
---
 src/backend/storage/ipc/shmem.c   | 15 +++++++--
 src/backend/utils/hash/dynahash.c | 52 ++++++++++++++++---------------
 src/include/utils/hsearch.h       |  3 +-
 3 files changed, 42 insertions(+), 28 deletions(-)

diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index 3cc38450949..a6fd4c30059 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -100,6 +100,7 @@ typedef struct ShmemAllocatorData
 
 #define ShmemIndexLock (&ShmemAllocator->index_lock)
 
+static void *ShmemHashAlloc(Size size, void *alloc_arg);
 static void *ShmemAllocRaw(Size size, Size *allocated_size);
 
 /* shared memory global variables */
@@ -184,7 +185,8 @@ InitShmemAllocator(PGShmemHeader *seghdr)
 	info.keysize = SHMEM_INDEX_KEYSIZE;
 	info.entrysize = sizeof(ShmemIndexEnt);
 	info.dsize = info.max_dsize = hash_select_dirsize(SHMEM_INDEX_SIZE);
-	info.alloc = ShmemAllocNoError;
+	info.alloc = ShmemHashAlloc;
+	info.alloc_arg = NULL;
 	hash_flags = HASH_ELEM | HASH_STRINGS | HASH_SHARED_MEM | HASH_ALLOC | HASH_DIRSIZE;
 	if (!IsUnderPostmaster)
 	{
@@ -233,6 +235,14 @@ ShmemAllocNoError(Size size)
 	return ShmemAllocRaw(size, &allocated_size);
 }
 
+static void *
+ShmemHashAlloc(Size size, void *alloc_arg)
+{
+	Size		allocated_size;
+
+	return ShmemAllocRaw(size, &allocated_size);
+}
+
 /*
  * ShmemAllocRaw -- allocate align chunk and return allocated size
  *
@@ -339,7 +349,8 @@ ShmemInitHash(const char *name,		/* table string name for shmem index */
 	 * The shared memory allocator must be specified too.
 	 */
 	infoP->dsize = infoP->max_dsize = hash_select_dirsize(max_size);
-	infoP->alloc = ShmemAllocNoError;
+	infoP->alloc = ShmemHashAlloc;
+	infoP->alloc_arg = NULL;
 	hash_flags |= HASH_SHARED_MEM | HASH_ALLOC | HASH_DIRSIZE;
 
 	/* look it up in the shmem index */
diff --git a/src/backend/utils/hash/dynahash.c b/src/backend/utils/hash/dynahash.c
index af3f7142afb..16cf103b8e4 100644
--- a/src/backend/utils/hash/dynahash.c
+++ b/src/backend/utils/hash/dynahash.c
@@ -224,6 +224,7 @@ struct HTAB
 	HashCompareFunc match;		/* key comparison function */
 	HashCopyFunc keycopy;		/* key copying function */
 	HashAllocFunc alloc;		/* memory allocator */
+	void	   *alloc_arg;		/* opaque argument to pass to allocator function */
 	MemoryContext hcxt;			/* memory context if default allocator used */
 	char	   *tabname;		/* table name (for error messages) */
 	bool		isshared;		/* true if table is in shared memory */
@@ -264,7 +265,7 @@ struct HTAB
 /*
  * Private function prototypes
  */
-static void *DynaHashAlloc(Size size);
+static void *DynaHashAlloc(Size size, void *alloc_arg);
 static HASHSEGMENT seg_alloc(HTAB *hashp);
 static bool element_alloc(HTAB *hashp, int nelem, int freelist_idx);
 static bool dir_realloc(HTAB *hashp);
@@ -287,14 +288,13 @@ static bool has_seq_scans(HTAB *hashp);
 /*
  * memory allocation support
  */
-static MemoryContext CurrentDynaHashCxt = NULL;
-
 static void *
-DynaHashAlloc(Size size)
+DynaHashAlloc(Size size, void *alloc_arg)
 {
-	Assert(MemoryContextIsValid(CurrentDynaHashCxt));
-	return MemoryContextAllocExtended(CurrentDynaHashCxt, size,
-									  MCXT_ALLOC_NO_OOM);
+	MemoryContext cxt = (MemoryContext) alloc_arg;
+
+	Assert(MemoryContextIsValid(cxt));
+	return MemoryContextAllocExtended(cxt, size,  MCXT_ALLOC_NO_OOM);
 }
 
 
@@ -355,6 +355,7 @@ hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
 {
 	HTAB	   *hashp;
 	HASHHDR    *hctl;
+	MemoryContext hcxt;
 
 	/*
 	 * Hash tables now allocate space for key and data, but you have to say
@@ -377,22 +378,21 @@ hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
 	if (flags & HASH_SHARED_MEM)
 	{
 		/* Set up to allocate the hash header */
-		CurrentDynaHashCxt = TopMemoryContext;
+		hcxt = TopMemoryContext;
 	}
 	else
 	{
 		/* Create the hash table's private memory context */
 		if (flags & HASH_CONTEXT)
-			CurrentDynaHashCxt = info->hcxt;
+			hcxt = info->hcxt;
 		else
-			CurrentDynaHashCxt = TopMemoryContext;
-		CurrentDynaHashCxt = AllocSetContextCreate(CurrentDynaHashCxt,
-												   "dynahash",
-												   ALLOCSET_DEFAULT_SIZES);
+			hcxt = TopMemoryContext;
+		hcxt = AllocSetContextCreate(hcxt, "dynahash",
+									 ALLOCSET_DEFAULT_SIZES);
 	}
 
 	/* Initialize the hash header, plus a copy of the table name */
-	hashp = (HTAB *) MemoryContextAlloc(CurrentDynaHashCxt,
+	hashp = (HTAB *) MemoryContextAlloc(hcxt,
 										sizeof(HTAB) + strlen(tabname) + 1);
 	MemSet(hashp, 0, sizeof(HTAB));
 
@@ -401,7 +401,7 @@ hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
 
 	/* If we have a private context, label it with hashtable's name */
 	if (!(flags & HASH_SHARED_MEM))
-		MemoryContextSetIdentifier(CurrentDynaHashCxt, hashp->tabname);
+		MemoryContextSetIdentifier(hcxt, hashp->tabname);
 
 	/*
 	 * Select the appropriate hash function (see comments at head of file).
@@ -473,9 +473,15 @@ hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
 
 	/* And select the entry allocation function, too. */
 	if (flags & HASH_ALLOC)
+	{
 		hashp->alloc = info->alloc;
+		hashp->alloc_arg = info->alloc_arg;
+	}
 	else
+	{
 		hashp->alloc = DynaHashAlloc;
+		hashp->alloc_arg = hcxt;
+	}
 
 	if (flags & HASH_SHARED_MEM)
 	{
@@ -504,13 +510,13 @@ hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
 		/* setup hash table defaults */
 		hashp->hctl = NULL;
 		hashp->dir = NULL;
-		hashp->hcxt = CurrentDynaHashCxt;
+		hashp->hcxt = hcxt;
 		hashp->isshared = false;
 	}
 
 	if (!hashp->hctl)
 	{
-		hashp->hctl = (HASHHDR *) hashp->alloc(sizeof(HASHHDR));
+		hashp->hctl = (HASHHDR *) hashp->alloc(sizeof(HASHHDR), hashp->alloc_arg);
 		if (!hashp->hctl)
 			ereport(ERROR,
 					(errcode(ERRCODE_OUT_OF_MEMORY),
@@ -732,9 +738,8 @@ init_htab(HTAB *hashp, int64 nelem)
 	/* Allocate a directory */
 	if (!(hashp->dir))
 	{
-		CurrentDynaHashCxt = hashp->hcxt;
 		hashp->dir = (HASHSEGMENT *)
-			hashp->alloc(hctl->dsize * sizeof(HASHSEGMENT));
+			hashp->alloc(hctl->dsize * sizeof(HASHSEGMENT), hashp->alloc_arg);
 		if (!hashp->dir)
 			return false;
 	}
@@ -1636,8 +1641,7 @@ dir_realloc(HTAB *hashp)
 	new_dirsize = new_dsize * sizeof(HASHSEGMENT);
 
 	old_p = hashp->dir;
-	CurrentDynaHashCxt = hashp->hcxt;
-	p = (HASHSEGMENT *) hashp->alloc((Size) new_dirsize);
+	p = (HASHSEGMENT *) hashp->alloc((Size) new_dirsize, hashp->alloc_arg);
 
 	if (p != NULL)
 	{
@@ -1662,8 +1666,7 @@ seg_alloc(HTAB *hashp)
 {
 	HASHSEGMENT segp;
 
-	CurrentDynaHashCxt = hashp->hcxt;
-	segp = (HASHSEGMENT) hashp->alloc(sizeof(HASHBUCKET) * HASH_SEGSIZE);
+	segp = (HASHSEGMENT) hashp->alloc(sizeof(HASHBUCKET) * HASH_SEGSIZE, hashp->alloc_arg);
 
 	if (!segp)
 		return NULL;
@@ -1703,8 +1706,7 @@ element_alloc(HTAB *hashp, int nelem, int freelist_idx)
 #endif
 
 	/* Allocate the memory. */
-	CurrentDynaHashCxt = hashp->hcxt;
-	allocedBlock = hashp->alloc(requestSize);
+	allocedBlock = hashp->alloc(requestSize, hashp->alloc_arg);
 
 	if (!allocedBlock)
 		return false;
diff --git a/src/include/utils/hsearch.h b/src/include/utils/hsearch.h
index 0721849c036..03bc1c171cd 100644
--- a/src/include/utils/hsearch.h
+++ b/src/include/utils/hsearch.h
@@ -41,7 +41,7 @@ typedef void *(*HashCopyFunc) (void *dest, const void *src, Size keysize);
  * Note: there is no free function API; can't destroy a hashtable unless you
  * use the default allocator.
  */
-typedef void *(*HashAllocFunc) (Size request);
+typedef void *(*HashAllocFunc) (Size request, void *alloc_arg);
 
 /*
  * HASHELEMENT is the private part of a hashtable entry.  The caller's data
@@ -80,6 +80,7 @@ typedef struct HASHCTL
 	HashCopyFunc keycopy;		/* key copying function */
 	/* Used if HASH_ALLOC flag is set: */
 	HashAllocFunc alloc;		/* memory allocator */
+	void	   *alloc_arg;		/* opaque argument to pass to allocator function */
 	/* Used if HASH_CONTEXT flag is set: */
 	MemoryContext hcxt;			/* memory context to use for allocations */
 	/* Used if HASH_SHARED_MEM flag is set: */
-- 
2.47.3