v1-0001-typcache-Use-new-LAZY_INIT-system.patch
application/octet-stream
Filename: v1-0001-typcache-Use-new-LAZY_INIT-system.patch
Type: application/octet-stream
Part: 1
Patch
Format: format-patch
Series: patch v1-0001
Subject: typcache: Use new LAZY_INIT system
| File | + | − |
|---|---|---|
| src/backend/utils/cache/typcache.c | 37 | 16 |
| src/include/miscadmin.h | 39 | 0 |
From df023ee26492199e0a120416ebdcc1e3af1d4c76 Mon Sep 17 00:00:00 2001
From: Matthias van de Meent <boekewurm+postgres@gmail.com>
Date: Wed, 17 Jun 2026 14:13:17 +0200
Subject: [PATCH v1 1/2] typcache: Use new LAZY_INIT system
This allows us to recover from OOMs when they happen during the
initialization of the typcache.
---
src/backend/utils/cache/typcache.c | 53 +++++++++++++++++++++---------
src/include/miscadmin.h | 39 ++++++++++++++++++++++
2 files changed, 76 insertions(+), 16 deletions(-)
diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c
index da91a2ff1dd..997f0e1cb1c 100644
--- a/src/backend/utils/cache/typcache.c
+++ b/src/backend/utils/cache/typcache.c
@@ -73,6 +73,7 @@
#include "utils/rel.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
+#include "miscadmin.h"
/* The main type cache hashtable searched by lookup_type_cache */
@@ -388,11 +389,12 @@ type_cache_syshash(const void *key, Size keysize)
TypeCacheEntry *
lookup_type_cache(Oid type_id, int flags)
{
+ LAZY_INIT_SYSTEM(typcache, 5);
TypeCacheEntry *typentry;
bool found;
int in_progress_offset;
- if (TypeCacheHash == NULL)
+ if (!LAZY_INIT_DONE(typcache))
{
/* First time through: initialize the hash table */
HASHCTL ctl;
@@ -408,34 +410,53 @@ lookup_type_cache(Oid type_id, int flags)
*/
ctl.hash = type_cache_syshash;
- TypeCacheHash = hash_create("Type information cache", 64,
- &ctl, HASH_ELEM | HASH_FUNCTION);
+ LAZY_INIT_STEP(typcache, {
+ 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);
+ LAZY_INIT_STEP(typcache, {
+ 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.
+ * A critical section is used, because we must not run out of slots
+ * for syscache callbacks; this backend cannot recover from that.
+ */
+ LAZY_INIT_STEP(typcache, {
+ START_CRIT_SECTION();
+ CacheRegisterRelcacheCallback(TypeCacheRelCallback, (Datum) 0);
+ CacheRegisterSyscacheCallback(TYPEOID, TypeCacheTypCallback, (Datum) 0);
+ CacheRegisterSyscacheCallback(CLAOID, TypeCacheOpcCallback, (Datum) 0);
+ CacheRegisterSyscacheCallback(CONSTROID, TypeCacheConstrCallback, (Datum) 0);
+ END_CRIT_SECTION();
+ });
/* Also make sure CacheMemoryContext exists */
- if (!CacheMemoryContext)
- CreateCacheMemoryContext();
+ LAZY_INIT_STEP(typcache, {
+ if (!CacheMemoryContext)
+ CreateCacheMemoryContext();
+ });
/*
* reserve enough in_progress_list slots for many cases
*/
allocsize = 4;
- in_progress_list =
- MemoryContextAlloc(CacheMemoryContext,
- allocsize * sizeof(*in_progress_list));
- in_progress_list_maxlen = allocsize;
+ LAZY_INIT_STEP(typcache, {
+ in_progress_list =
+ MemoryContextAlloc(CacheMemoryContext,
+ allocsize * sizeof(*in_progress_list));
+ in_progress_list_maxlen = allocsize;
+ });
+
+ Assert(LAZY_INIT_DONE(typcache));
}
Assert(TypeCacheHash != NULL && RelIdToTypeIdCacheHash != NULL);
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 7de0a115402..5c4392a3da3 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -158,6 +158,45 @@ do { \
} while(0)
+/*
+ * Helpers to allow subsystems to run lazy initialization code that can deal
+ * with temporary resource constraints, like OOMs, without significant manual
+ * coding to support errors in every call to a subcomponent.
+ *
+ * The user is expected to run one _STEP per fallible resource allocation, or
+ * wrap the code that should be executed just once per session in a critical
+ * section.
+ *
+ * Usage:
+ *
+ * LAZY_INIT_SYSTEM(name, # of _STEP invocations for this system);
+ * if (!LAZY_INIT_DONE(name))
+ * {
+ * ...locals;
+ * ...infallible code;
+ * LAZY_INIT_STEP(name, { code });
+ * ...
+ * Assert(LAZY_INIT_DONE(name));
+ * }
+ */
+
+#define LAZY_INIT_SYSTEM(sysname, nsteps) \
+ static const int LI_STEPS_TOTAL_ ## sysname = (nsteps); \
+ static int LI_STEPS_DONE_ ## sysname = 0; \
+ int LI_CURRENT_STEP_ ## sysname = 0
+
+#define LAZY_INIT_STEP(sysname, operation) \
+ do { \
+ if ((LI_STEPS_DONE_ ## sysname) == (LI_CURRENT_STEP_ ## sysname)++) \
+ { \
+ operation; \
+ (LI_STEPS_DONE_ ## sysname) += 1; \
+ } \
+ } while (false)
+
+#define LAZY_INIT_DONE(sysname) \
+ ((LI_STEPS_DONE_ ## sysname) == (LI_STEPS_TOTAL_ ## sysname))
+
/*****************************************************************************
* globals.h -- *
*****************************************************************************/
--
2.50.1 (Apple Git-155)