v2-0001-typcache-Make-initialization-more-resilient-on-OO.patch

text/plain

Filename: v2-0001-typcache-Make-initialization-more-resilient-on-OO.patch
Type: text/plain
Part: 0
Message: Re: Unexpected behavior after OOM errors

Patch

Format: format-patch
Series: patch v2-0001
Subject: typcache: Make initialization more resilient on OOM
File+
src/backend/utils/cache/typcache.c 33 24
From 8b2ecd4df82750ca98cf7e67244cb46b1e4239ed Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Thu, 18 Jun 2026 13:24:47 +0900
Subject: [PATCH v2] typcache: Make initialization more resilient on OOM

---
 src/backend/utils/cache/typcache.c | 57 +++++++++++++++++-------------
 1 file changed, 33 insertions(+), 24 deletions(-)

diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c
index da91a2ff1dd8..b96554a4b32e 100644
--- a/src/backend/utils/cache/typcache.c
+++ b/src/backend/utils/cache/typcache.c
@@ -392,50 +392,59 @@ lookup_type_cache(Oid type_id, int flags)
 	bool		found;
 	int			in_progress_offset;
 
-	if (TypeCacheHash == NULL)
+	if (in_progress_list == NULL)
 	{
 		/* First time through: initialize the hash table */
 		HASHCTL		ctl;
 		int			allocsize;
 
-		ctl.keysize = sizeof(Oid);
-		ctl.entrysize = sizeof(TypeCacheEntry);
+		if (TypeCacheHash == NULL)
+		{
+			ctl.keysize = sizeof(Oid);
+			ctl.entrysize = sizeof(TypeCacheEntry);
 
-		/*
-		 * TypeCacheEntry takes hash value from the system cache. For
-		 * TypeCacheHash we use the same hash in order to speedup search by
-		 * hash value. This is used by hash_seq_init_with_hash_value().
-		 */
-		ctl.hash = type_cache_syshash;
+			/*
+			 * TypeCacheEntry takes hash value from the system cache. For
+			 * TypeCacheHash we use the same hash in order to speedup search
+			 * by hash value. This is used by
+			 * hash_seq_init_with_hash_value().
+			 */
+			ctl.hash = type_cache_syshash;
 
-		TypeCacheHash = hash_create("Type information cache", 64,
-									&ctl, HASH_ELEM | HASH_FUNCTION);
+			TypeCacheHash = hash_create("Type information cache", 64,
+										&ctl, HASH_ELEM | HASH_FUNCTION);
+		}
 
-		Assert(RelIdToTypeIdCacheHash == NULL);
-
-		ctl.keysize = sizeof(Oid);
-		ctl.entrysize = sizeof(RelIdToTypeIdCacheEntry);
-		RelIdToTypeIdCacheHash = hash_create("Map from relid to OID of cached composite type", 64,
-											 &ctl, HASH_ELEM | HASH_BLOBS);
-
-		/* Also set up callbacks for SI invalidations */
-		CacheRegisterRelcacheCallback(TypeCacheRelCallback, (Datum) 0);
-		CacheRegisterSyscacheCallback(TYPEOID, TypeCacheTypCallback, (Datum) 0);
-		CacheRegisterSyscacheCallback(CLAOID, TypeCacheOpcCallback, (Datum) 0);
-		CacheRegisterSyscacheCallback(CONSTROID, TypeCacheConstrCallback, (Datum) 0);
+		if (RelIdToTypeIdCacheHash == NULL)
+		{
+			ctl.keysize = sizeof(Oid);
+			ctl.entrysize = sizeof(RelIdToTypeIdCacheEntry);
+			RelIdToTypeIdCacheHash = hash_create("Map from relid to OID of cached composite type", 64,
+												 &ctl, HASH_ELEM | HASH_BLOBS);
+		}
 
 		/* Also make sure CacheMemoryContext exists */
 		if (!CacheMemoryContext)
 			CreateCacheMemoryContext();
 
 		/*
-		 * reserve enough in_progress_list slots for many cases
+		 * Reserve enough in_progress_list slots for many cases.  This is
+		 * the last allocation on purpose, done after the two others.
 		 */
 		allocsize = 4;
 		in_progress_list =
 			MemoryContextAlloc(CacheMemoryContext,
 							   allocsize * sizeof(*in_progress_list));
 		in_progress_list_maxlen = allocsize;
+
+		/*
+		 * Set up callbacks for SI invalidations.  These are done last,
+		 * once all the other initializations are done.
+		 */
+		CacheRegisterRelcacheCallback(TypeCacheRelCallback, (Datum) 0);
+		CacheRegisterSyscacheCallback(TYPEOID, TypeCacheTypCallback, (Datum) 0);
+		CacheRegisterSyscacheCallback(CLAOID, TypeCacheOpcCallback, (Datum) 0);
+		CacheRegisterSyscacheCallback(CONSTROID, TypeCacheConstrCallback, (Datum) 0);
 	}
 
 	Assert(TypeCacheHash != NULL && RelIdToTypeIdCacheHash != NULL);
-- 
2.54.0