From 1c61f20ae4bf45d1f918819ffd2f92efedc39448 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Sat, 21 Mar 2026 13:07:28 +0200
Subject: [PATCH v9 02/16] refactor: Move ShmemInitHash to separate file

In preparation for next commits
---
 src/backend/storage/ipc/Makefile     |  1 +
 src/backend/storage/ipc/meson.build  |  1 +
 src/backend/storage/ipc/shmem.c      | 77 ----------------------
 src/backend/storage/ipc/shmem_hash.c | 98 ++++++++++++++++++++++++++++
 src/include/storage/shmem.h          |  1 +
 5 files changed, 101 insertions(+), 77 deletions(-)
 create mode 100644 src/backend/storage/ipc/shmem_hash.c

diff --git a/src/backend/storage/ipc/Makefile b/src/backend/storage/ipc/Makefile
index 9a07f6e1d92..f71653bbe48 100644
--- a/src/backend/storage/ipc/Makefile
+++ b/src/backend/storage/ipc/Makefile
@@ -22,6 +22,7 @@ OBJS = \
 	shm_mq.o \
 	shm_toc.o \
 	shmem.o \
+	shmem_hash.o \
 	signalfuncs.o \
 	sinval.o \
 	sinvaladt.o \
diff --git a/src/backend/storage/ipc/meson.build b/src/backend/storage/ipc/meson.build
index 9c1ca954d9d..b8c31e29967 100644
--- a/src/backend/storage/ipc/meson.build
+++ b/src/backend/storage/ipc/meson.build
@@ -14,6 +14,7 @@ backend_sources += files(
   'shm_mq.c',
   'shm_toc.c',
   'shmem.c',
+  'shmem_hash.c',
   'signalfuncs.c',
   'sinval.c',
   'sinvaladt.c',
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index 0e49debaaac..1485f1ff38f 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -100,7 +100,6 @@ 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 */
@@ -235,15 +234,6 @@ ShmemAllocNoError(Size size)
 	return ShmemAllocRaw(size, &allocated_size);
 }
 
-/* Alloc callback for shared memory hash tables */
-static void *
-ShmemHashAlloc(Size size, void *alloc_arg)
-{
-	Size		allocated_size;
-
-	return ShmemAllocRaw(size, &allocated_size);
-}
-
 /*
  * ShmemAllocRaw -- allocate align chunk and return allocated size
  *
@@ -305,73 +295,6 @@ ShmemAddrIsValid(const void *addr)
 	return (addr >= ShmemBase) && (addr < ShmemEnd);
 }
 
-/*
- * ShmemInitHash -- Create and initialize, or attach to, a
- *		shared memory hash table.
- *
- * We assume caller is doing some kind of synchronization
- * so that two processes don't try to create/initialize the same
- * table at once.  (In practice, all creations are done in the postmaster
- * process; child processes should always be attaching to existing tables.)
- *
- * max_size is the estimated maximum number of hashtable entries.  This is
- * not a hard limit, but the access efficiency will degrade if it is
- * exceeded substantially (since it's used to compute directory size and
- * the hash table buckets will get overfull).
- *
- * init_size is the number of hashtable entries to preallocate.  For a table
- * whose maximum size is certain, this should be equal to max_size; that
- * ensures that no run-time out-of-shared-memory failures can occur.
- *
- * *infoP and hash_flags must specify at least the entry sizes and key
- * comparison semantics (see hash_create()).  Flag bits and values specific
- * to shared-memory hash tables are added here, except that callers may
- * choose to specify HASH_PARTITION and/or HASH_FIXED_SIZE.
- *
- * Note: before Postgres 9.0, this function returned NULL for some failure
- * cases.  Now, it always throws error instead, so callers need not check
- * for NULL.
- */
-HTAB *
-ShmemInitHash(const char *name,		/* table string name for shmem index */
-			  int64 init_size,	/* initial table size */
-			  int64 max_size,	/* max size of the table */
-			  HASHCTL *infoP,	/* info about key and bucket size */
-			  int hash_flags)	/* info about infoP */
-{
-	bool		found;
-	void	   *location;
-
-	/*
-	 * Hash tables allocated in shared memory have a fixed directory; it can't
-	 * grow or other backends wouldn't be able to find it. So, make sure we
-	 * make it big enough to start with.
-	 *
-	 * The shared memory allocator must be specified too.
-	 */
-	infoP->dsize = infoP->max_dsize = hash_select_dirsize(max_size);
-	infoP->alloc = ShmemHashAlloc;
-	infoP->alloc_arg = NULL;
-	hash_flags |= HASH_SHARED_MEM | HASH_ALLOC | HASH_DIRSIZE;
-
-	/* look it up in the shmem index */
-	location = ShmemInitStruct(name,
-							   hash_get_shared_size(infoP, hash_flags),
-							   &found);
-
-	/*
-	 * if it already exists, attach to it rather than allocate and initialize
-	 * new space
-	 */
-	if (found)
-		hash_flags |= HASH_ATTACH;
-
-	/* Pass location of hashtable header to hash_create */
-	infoP->hctl = (HASHHDR *) location;
-
-	return hash_create(name, init_size, infoP, hash_flags);
-}
-
 /*
  * ShmemInitStruct -- Create/attach to a structure in shared memory.
  *
diff --git a/src/backend/storage/ipc/shmem_hash.c b/src/backend/storage/ipc/shmem_hash.c
new file mode 100644
index 00000000000..47166ff301d
--- /dev/null
+++ b/src/backend/storage/ipc/shmem_hash.c
@@ -0,0 +1,98 @@
+/*-------------------------------------------------------------------------
+ *
+ * shmem_hash.c
+ *	  hash table implementation in shared memory
+ *
+ * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * A shared memory hash table implementation on top of the named, fixed-size
+ * shared memory areas managed by shmem.c.  Hash tables have a fixed maximum
+ * size, but their actual size can vary dynamically.  When entries are added
+ * to the table, more space is allocated.  Each shared data structure and hash
+ * has a string name to identify it.
+ *
+ * IDENTIFICATION
+ *	  src/backend/storage/ipc/shmem_hash.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "storage/shmem.h"
+
+
+/*
+ * ShmemInitHash -- Create and initialize, or attach to, a
+ *		shared memory hash table.
+ *
+ * We assume caller is doing some kind of synchronization
+ * so that two processes don't try to create/initialize the same
+ * table at once.  (In practice, all creations are done in the postmaster
+ * process; child processes should always be attaching to existing tables.)
+ *
+ * max_size is the estimated maximum number of hashtable entries.  This is
+ * not a hard limit, but the access efficiency will degrade if it is
+ * exceeded substantially (since it's used to compute directory size and
+ * the hash table buckets will get overfull).
+ *
+ * init_size is the number of hashtable entries to preallocate.  For a table
+ * whose maximum size is certain, this should be equal to max_size; that
+ * ensures that no run-time out-of-shared-memory failures can occur.
+ *
+ * *infoP and hash_flags must specify at least the entry sizes and key
+ * comparison semantics (see hash_create()).  Flag bits and values specific
+ * to shared-memory hash tables are added here, except that callers may
+ * choose to specify HASH_PARTITION and/or HASH_FIXED_SIZE.
+ *
+ * Note: before Postgres 9.0, this function returned NULL for some failure
+ * cases.  Now, it always throws error instead, so callers need not check
+ * for NULL.
+ */
+HTAB *
+ShmemInitHash(const char *name,		/* table string name for shmem index */
+			  int64 init_size,	/* initial table size */
+			  int64 max_size,	/* max size of the table */
+			  HASHCTL *infoP,	/* info about key and bucket size */
+			  int hash_flags)	/* info about infoP */
+{
+	bool		found;
+	void	   *location;
+
+	/*
+	 * Hash tables allocated in shared memory have a fixed directory; it can't
+	 * grow or other backends wouldn't be able to find it. So, make sure we
+	 * make it big enough to start with.
+	 *
+	 * The shared memory allocator must be specified too.
+	 */
+	infoP->dsize = infoP->max_dsize = hash_select_dirsize(max_size);
+	infoP->alloc = ShmemHashAlloc;
+	infoP->alloc_arg = NULL;
+	hash_flags |= HASH_SHARED_MEM | HASH_ALLOC | HASH_DIRSIZE;
+
+	/* look it up in the shmem index */
+	location = ShmemInitStruct(name,
+							   hash_get_shared_size(infoP, hash_flags),
+							   &found);
+
+	/*
+	 * if it already exists, attach to it rather than allocate and initialize
+	 * new space
+	 */
+	if (found)
+		hash_flags |= HASH_ATTACH;
+
+	/* Pass location of hashtable header to hash_create */
+	infoP->hctl = (HASHHDR *) location;
+
+	return hash_create(name, init_size, infoP, hash_flags);
+}
+
+/* Alloc callback for shared memory hash tables */
+void *
+ShmemHashAlloc(Size size, void *alloc_arg)
+{
+	return ShmemAllocNoError(size);
+}
diff --git a/src/include/storage/shmem.h b/src/include/storage/shmem.h
index 2a9e9becd26..d26206131d7 100644
--- a/src/include/storage/shmem.h
+++ b/src/include/storage/shmem.h
@@ -31,6 +31,7 @@ typedef struct PGShmemHeader PGShmemHeader; /* avoid including
 extern void InitShmemAllocator(PGShmemHeader *seghdr);
 extern void *ShmemAlloc(Size size);
 extern void *ShmemAllocNoError(Size size);
+extern void *ShmemHashAlloc(Size size, void *alloc_arg);
 extern bool ShmemAddrIsValid(const void *addr);
 extern HTAB *ShmemInitHash(const char *name, int64 init_size, int64 max_size,
 						   HASHCTL *infoP, int hash_flags);
-- 
2.47.3

