On Wed, Jun 17, 2026 at 02:27:25PM +0200, Matthias van de Meent wrote:
> On Wed, 17 Jun 2026 at 08:00, Alexander Lakhin <[email protected]> wrote:
>> 1) An issue in lookup_type_cache()
> 
> I believe this is caused by partial subsystem initialization. Attached
> patch 0001 should address this failure without causing the server to
> restart on OOM.

Hmm.  I think that this is an ordering problem.  We could make the
callbacks be registered last, once we are sure that the two hash 
tables and the in-progress list have been initialized.  I am not sure
that this requires a new facility; it is also an advantage to keep the
initialization sequence in a one code path, without an abstraction.

RelIdToTypeIdCacheHash and RelIdToTypeIdCacheHash are in the
TopMemoryContext, static to the process, so we could just check them
for NULL-ness to make the initialization repeatable.  That gives me
the attached v2.  Reusing Alexander's randomness trick, that looks
stable here.

>> 2) An issue in GetSnapshotData()
> 
> Again, caused by partial initialization, though in this case it's of a
> SnapshotData* which is later checked again. Attached patch 0002 should
> address this failure.

Yeah, that seems right to make repeated calls of GetSnapshotData()
able to work.  LGTM.

>> 3) An issue in StandbyAcquireAccessExclusiveLock()
> <snip>
> 
> I'm not sure how to solve this correctly; I think ideally the
> StandbyAcquireAccessExclusiveLock() hash code would be wrapped by a
> critical section, but I'm not 100% sure if that will be a sufficient
> approach; and it'd definitely need some code to allow the various
> hashmaps' memctxs to alloc during critical sections.

Not checked this one yet.

Thoughts about the first part?
--
Michael
From 8b2ecd4df82750ca98cf7e67244cb46b1e4239ed Mon Sep 17 00:00:00 2001
From: Michael Paquier <[email protected]>
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

Attachment: signature.asc
Description: PGP signature

Reply via email to