Thread
Commits
-
Make type cache initialization more resilient on re-entry after OOM
- 73dab12719ee 19 (unreleased) landed
-
Make StandbyAcquireAccessExclusiveLock() more resilent with OOMs
- b85f9c00fb88 19 (unreleased) landed
-
Make GetSnapshotData() more resilient on out-of-memory errors
- 29fb598b9cad 19 (unreleased) landed
-
Unexpected behavior after OOM errors
Alexander Law <exclusion@gmail.com> — 2026-06-17T06:00:00Z
Hello hackers, I'd like to share my findings related to OOM error handling. I'm not sure how large the class of such anomalies is (and if all of these can be detected and fixed), but please look at a few issues I have discovered so far: 1) An issue in lookup_type_cache() The following modification: --- a/src/backend/utils/hash/dynahash.c +++ b/src/backend/utils/hash/dynahash.c @@ -104,6 +104,7 @@ #include "storage/spin.h" #include "utils/memutils.h" +#include "common/pg_prng.h" /* * Constants @@ -528,7 +529,7 @@ hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags) * that this is the first allocation made with the alloc function. That's * a little ugly, but works for now. */ - hashp->hctl = (HASHHDR *) hashp->alloc(sizeof(HASHHDR), hashp->alloc_arg); + hashp->hctl = (pg_prng_double(&pg_global_prng_state) < 0.001) ? NULL : (HASHHDR *) hashp->alloc(sizeof(HASHHDR), hashp->alloc_arg); if (!hashp->hctl) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), @@ -609,7 +610,7 @@ hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags) { int temp = (i == 0) ? nelem_alloc_first : nelem_alloc; - if (!element_alloc(hashp, temp, i)) + if ((pg_prng_double(&pg_global_prng_state) < 0.001) || !element_alloc(hashp, temp, i)) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); makes this script: for i in {1..10000}; do cat << 'EOS' | psql >>psql.log SELECT 1 ORDER BY 1; SELECT 1 ORDER BY 1; EOS grep "terminated by signal" server.log && break; done trigger an assertion failure: 2026-06-17 07:26:07.837 EEST [87325:3] [unknown] LOG: connection authorized: user=law database=regression application_name=psql 2026-06-17 07:26:07.837 EEST [87325:4] psql LOG: statement: SELECT 1 ORDER BY 1; 2026-06-17 07:26:07.837 EEST [87325:5] psql ERROR: out of memory at character 19 2026-06-17 07:26:07.837 EEST [87325:6] psql LOG: statement: SELECT 1 ORDER BY 1; TRAP: failed Assert("TypeCacheHash != NULL && RelIdToTypeIdCacheHash != NULL"), File: "typcache.c", Line: 441, PID: 87325 ExceptionalCondition at assert.c:51:13 lookup_type_cache at typcache.c:444:27 get_sort_group_operators at parse_oper.c:207:13 addTargetToSortList at parse_clause.c:3647:4 transformSortClause at parse_clause.c:2959:14 transformSelectStmt at analyze.c:1806:18 transformStmt at analyze.c:396:15 transformOptionalSelectInto at analyze.c:327:1 transformTopLevelStmt at analyze.c:276:11 parse_analyze_fixedparams at analyze.c:144:10 pg_analyze_and_rewrite_fixedparams at postgres.c:699:10 exec_simple_query at postgres.c:1206:20 PostgresMain at postgres.c:4860:27 BackendInitialize at backend_startup.c:142:1 postmaster_child_launch at launch_backend.c:269:3 BackendStartup at postmaster.c:3627:8 ServerLoop at postmaster.c:1731:10 PostmasterMain at postmaster.c:1415:11 main at main.c:236:2 /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x8b)[0x7b3d5c02a28b] postgres: law regression [local] SELECT(_start+0x25)[0x5944d79e8155] 2026-06-17 07:26:07.914 EEST [85875:6] LOG: client backend (PID 87325) was terminated by signal 6: Aborted Without asserts enables, the server might crash. 2) An issue in GetSnapshotData() The following modification: --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -71,2 +71,3 @@ #include "utils/wait_event.h" +#include "common/pg_prng.h" @@ -2157,3 +2158,3 @@ GetSnapshotData(Snapshot snapshot) Assert(snapshot->subxip == NULL); - snapshot->subxip = (TransactionId *) + snapshot->subxip = (pg_prng_double(&pg_global_prng_state) < 0.01) ? NULL : (TransactionId *) malloc(GetMaxSnapshotSubxidCount() * sizeof(TransactionId)); makes this script (max_prepared_transactions = 2 in postgresql.conf): for i in {1..1000}; do cat << 'EOS' | psql >>psql.log SELECT 1; BEGIN; CREATE TABLE t1(a int); SAVEPOINT sp1; INSERT INTO t1 VALUES (1); ROLLBACK TO sp1; INSERT INTO t1 VALUES (2); PREPARE TRANSACTION 'pt1'; BEGIN; CREATE TABLE t2(a int); ROLLBACK; ROLLBACK PREPARED 'pt1'; EOS grep "terminated by signal" server.log && break; done trigger a segmentation fault: 2026-06-17 07:37:52.619 EEST [108789:3] [unknown] LOG: connection authorized: user=law database=regression application_name=psql 2026-06-17 07:37:52.620 EEST [108789:4] psql LOG: statement: SELECT 1; 2026-06-17 07:37:52.620 EEST [108789:5] psql ERROR: out of memory 2026-06-17 07:37:52.620 EEST [108789:6] psql LOG: statement: BEGIN; 2026-06-17 07:37:52.620 EEST [108789:7] psql LOG: statement: CREATE TABLE t1(a int); 2026-06-17 07:37:52.621 EEST [108789:8] psql LOG: statement: SAVEPOINT sp1; 2026-06-17 07:37:52.621 EEST [108789:9] psql LOG: statement: INSERT INTO t1 VALUES (1); 2026-06-17 07:37:52.621 EEST [108789:10] psql LOG: statement: ROLLBACK TO sp1; 2026-06-17 07:37:52.621 EEST [108789:11] psql LOG: statement: INSERT INTO t1 VALUES (2); 2026-06-17 07:37:52.621 EEST [108789:12] psql LOG: statement: PREPARE TRANSACTION 'pt1'; 2026-06-17 07:37:52.622 EEST [108789:13] psql LOG: statement: BEGIN; 2026-06-17 07:37:52.622 EEST [108789:14] psql LOG: statement: CREATE TABLE t2(a int); 2026-06-17 07:37:52.777 EEST [108710:6] LOG: client backend (PID 108789) was terminated by signal 11: Segmentation fault 2026-06-17 07:37:52.777 EEST [108710:7] DETAIL: Failed process was running: CREATE TABLE t2(a int); Program terminated with signal SIGSEGV, Segmentation fault. #0 __memcpy_avx512_unaligned_erms () at ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:289 (gdb) bt #0 __memcpy_avx512_unaligned_erms () at ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:289 #1 0x00005e857d7dc534 in GetSnapshotData (snapshot=0x5e857df07ae0 <CurrentSnapshotData>) at procarray.c:2297 #2 0x00005e857da9e452 in GetTransactionSnapshot () at snapmgr.c:331 #3 0x00005e857d823117 in PortalRunUtility (portal=0x5e85b337f3b0, pstmt=0x5e85b32fcd58, isTopLevel=true, setHoldSnapshot=false, dest=0x5e85b32fd118, qc=0x7ffe081d5aa0) at pquery.c:1127 #4 0x00005e857d82343b in PortalRunMulti (portal=0x5e85b337f3b0, isTopLevel=true, setHoldSnapshot=false, dest=0x5e85b32fd118, altdest=0x5e85b32fd118, qc=0x7ffe081d5aa0) at pquery.c:1307 #5 0x00005e857d82289a in PortalRun (portal=0x5e85b337f3b0, count=9223372036854775807, isTopLevel=true, dest=0x5e85b32fd118, altdest=0x5e85b32fd118, qc=0x7ffe081d5aa0) at pquery.c:784 (gdb) f 1 #1 0x00005e857d7dc534 in GetSnapshotData (snapshot=0x5e857df07ae0 <CurrentSnapshotData>) at procarray.c:2297 2297 memcpy(snapshot->subxip + subcount, (gdb) p *snapshot $1 = {snapshot_type = SNAPSHOT_MVCC, xmin = 745, xmax = 747, xip = 0x5e85b3329030, xcnt = 0, subxip = 0x0, subxcnt = 0, suboverflowed = false, takenDuringRecovery = false, copied = false, curcid = 3, speculativeToken = 0, vistest = 0x0, active_count = 0, regd_count = 0, ph_node = {first_child = 0x0, next_sibling = 0x0, prev_or_parent = 0x0}, snapXactCompletionCount = 55} 3) An issue in StandbyAcquireAccessExclusiveLock() No modification needed. Please try the attached TAP test on REL_17_STABLE. It fails as below: t/099_out_of_shared_memory.pl .. Bailout called. Further testing stopped: pg_ctl start failed 099_out_of_shared_memory_standby.log contains: 2026-06-17 07:53:03.237 EEST [167771] LOG: database system is ready to accept read-only connections 2026-06-17 07:53:03.240 EEST [167775] LOG: started streaming WAL from primary at 0/3000000 on timeline 1 2026-06-17 07:53:03.269 EEST [167774] FATAL: out of shared memory 2026-06-17 07:53:03.269 EEST [167774] HINT: You might need to increase "max_locks_per_transaction". 2026-06-17 07:53:03.269 EEST [167774] CONTEXT: WAL redo at 0/32218D8 for Standby/LOCK: xid 738 db 5 rel 17839 2026-06-17 07:53:03.269 EEST [167774] WARNING: you don't own a lock of type AccessExclusiveLock 2026-06-17 07:53:03.269 EEST [167774] LOG: RecoveryLockHash contains entry for lock no longer recorded by lock manager: xid 738 database 5 relation 17839 TRAP: failed Assert("false"), File: "standby.c", Line: 1053, PID: 167774 ExceptionalCondition at assert.c:52:13 StandbyReleaseXidEntryLocks at standby.c:1056:8 StandbyReleaseAllLocks at standby.c:1116:3 ShutdownRecoveryTransactionEnvironment at standby.c:178:2 StartupProcExit at startup.c:208:1 shmem_exit at ipc.c:282:9 proc_exit_prepare at ipc.c:201:2 proc_exit at ipc.c:155:2 errfinish at elog.c:593:5 LockAcquireExtended at lock.c:1020:4 LockAcquire at lock.c:763:1 StandbyAcquireAccessExclusiveLock at standby.c:1026:10 standby_redo at standby.c:1175:35 ApplyWalRecord at xlogrecovery.c:2008:13 PerformWalRecovery at xlogrecovery.c:1835:8 StartupXLOG at xlog.c:5803:24 StartupProcessMain at startup.c:264:2 postmaster_child_launch at launch_backend.c:281:9 StartChildProcess at postmaster.c:3918:8 PostmasterMain at postmaster.c:1369:13 startup_hacks at main.c:219:1 /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x8b)[0x71abb4e2a28b] postgres: standby: startup recovering 000000010000000000000003(_start+0x25)[0x64d0286de095] 2026-06-17 07:53:03.279 EEST [167771] LOG: startup process (PID 167774) was terminated by signal 6: Aborted Best regards, Alexander -
Re: Unexpected behavior after OOM errors
Matthias van de Meent <boekewurm+postgres@gmail.com> — 2026-06-17T12:27:25Z
On Wed, 17 Jun 2026 at 08:00, Alexander Lakhin <exclusion@gmail.com> wrote: > > Hello hackers, > > I'd like to share my findings related to OOM error handling. I'm not sure > how large the class of such anomalies is (and if all of these can be > detected and fixed), but please look at a few issues I have discovered so > far: > > 1) An issue in lookup_type_cache() > > The following modification: <snip> > makes this script: <snip> > trigger an assertion failure: <snip> > Without asserts enables, the server might crash. I believe this is caused by partial subsystem initialization. Attached patch 0001 should address this failure without causing the server to restart on OOM. > 2) An issue in GetSnapshotData() > > The following modification: <snip> > makes this script (max_prepared_transactions = 2 in postgresql.conf): <snip> > trigger a segmentation fault: <snip> 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. > 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. Kind regards, Matthias van de Meent Databricks (https://www.databricks.com)
-
Re: Unexpected behavior after OOM errors
Michael Paquier <michael@paquier.xyz> — 2026-06-18T04:37:34Z
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 <exclusion@gmail.com> 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
-
Re: Unexpected behavior after OOM errors
Heikki Linnakangas <hlinnaka@iki.fi> — 2026-06-18T06:42:39Z
On 18/06/2026 07:37, Michael Paquier wrote: > 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 <exclusion@gmail.com> 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. Yeah, this can be solved by ordering. It's a bit fiddly though. I don't know about Matthias's proposal either, but it'd be nice to have a less fiddly system for these. One idea is to have something similar to START_CRIT_SECTION()/END_CRIT_SECTION(), but instead of promoting the ERROR to a PANIC, promote it to FATAL. That way, if any of these one-time allocations fail, the backend exits. If you're so memory-starved that you cannot even initialize the type cache, you won't be able to do anything useful with the connection anyway. Another idea is that instead of having these be singletons in the type cache, initialized on first use, move it to a new TypeCacheInitialize() function that is always called at backend startup, like RelationCacheInitialize(). If an allocation fails at that stage, the backend will just exit. I think that's my favorite alternative so far. BTW, I'm surprised we create the hash tables are created in TopMemoryContext rather than CacheMemoryContext... - Heikki
-
Re: Unexpected behavior after OOM errors
Matthias van de Meent <boekewurm+postgres@gmail.com> — 2026-06-18T09:27:28Z
On Thu, 18 Jun 2026 at 06:37, Michael Paquier <michael@paquier.xyz> wrote: > > 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 <exclusion@gmail.com> 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 don't disagree that there's an ordering problem, but in my view the main problem is the fallible initialization of N components, gated behind a single condition. The question of when to register the callbacks is just one part of many. > 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. I'm not a huge fan of templating if(!global) { init_global(); } all around. But, it works. > 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. This un-fixes one of the unlikely issues that was fixed in my patch - though unrelated to OOM: Each of the calls to CacheRegisterSyscacheCallback/CacheRegisterRelcacheCallback can throw an ERROR when all slots have been used. This would leave the typcache in an invalid state, so I think that must be wrapped in a critical section: neither syscache nor relcache has options to release callbacks, and we can't safely continue without the callbacks installed, so once an error is thrown here this backend can't ever be properly initialized. This is unlike OOMs, whose conditions for failure may (and often do) change as workloads change in other backends. I think Heikki's suggestion for a FATAL critical section option would be a good alternative. It wouldn't always be sufficient, but would fix issues 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. Thanks for committing! Kind regards, Matthias van de Meent Databricks (https://www.databricks.com) -
Re: Unexpected behavior after OOM errors
Matthias van de Meent <boekewurm+postgres@gmail.com> — 2026-06-18T15:27:57Z
On Thu, 18 Jun 2026 at 06:37, Michael Paquier <michael@paquier.xyz> wrote: > >> 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. I found that the attached patch v3 solves that issue. The assert fires because we link the lock into the transaction's exclusive locks ahead of actually having acquired the lock, and when that lock acquisition fails, as part of the error handling we hit StartupProcExit->ShutdownRecoveryTransactionEnvironment->StandbyReleaseAllLocks, which causes this assertion failure because the lock was not taken by this backend. By moving StandbyAcquireAccessExclusiveLock's LockAcquire ahead of when it links the lock to the transaction, the local data structure doesn't know to clean up the lock until after it's acquired, so failure in that process won't make error cleanup try to clean up the lock. Kind regards, Matthias van de Meent Databricks (https://www.databricks.com)
-
Re: Unexpected behavior after OOM errors
Michael Paquier <michael@paquier.xyz> — 2026-06-18T23:29:03Z
On Thu, Jun 18, 2026 at 05:27:57PM +0200, Matthias van de Meent wrote: > By moving StandbyAcquireAccessExclusiveLock's LockAcquire ahead of > when it links the lock to the transaction, the local data structure > doesn't know to clean up the lock until after it's acquired, so > failure in that process won't make error cleanup try to clean up the > lock. Yep, reordering these two actions would take care of the list inconsistency where the startup process goes down following the ERROR promoted to a FATAL. I have been fingering the idea of backpatching this fix for a few minutes, actually, but discarded the idea at the end. It does not require a random pattern to cause the failure, being actionable through a combination of GUCs as Alexander has proved. Still, the only consequence is an extra LOG entry telling that the lock is not being tracked for non-assert builds. Confusing, OK, but not really critical. Comments? -- Michael
-
Re: Unexpected behavior after OOM errors
Michael Paquier <michael@paquier.xyz> — 2026-06-18T23:55:30Z
On Thu, Jun 18, 2026 at 11:27:28AM +0200, Matthias van de Meent wrote: > Each of the calls to > CacheRegisterSyscacheCallback/CacheRegisterRelcacheCallback can throw > an ERROR when all slots have been used. This would leave the typcache > in an invalid state, so I think that must be wrapped in a critical > section: neither syscache nor relcache has options to release > callbacks, and we can't safely continue without the callbacks > installed, so once an error is thrown here this backend can't ever be > properly initialized. This is unlike OOMs, whose conditions for > failure may (and often do) change as workloads change in other > backends. We don't ERROR when failing to register a syscache/relcache callback, we FATAL if we reach one of the thresholds. Reaching these thresholds points to me to a programming error anyway, so these should not matter in the field. The OOM is a random pattern that can happen outside the Postgres realm. Just in case, I have planted a elog(FATAL) triggering randomly in the middle of cache registration callback calls, and the typcache inconsistency does not come in play with the shutdown sequence once these trigger even if we have the tables set but not the callbacks. As a whole, I tend to think that reordering the actions is a solution good enough here. > I think Heikki's suggestion for a FATAL critical section option would > be a good alternative. It wouldn't always be sufficient, but would fix > issues here. That sounds like an interesting idea, potentially reusable for other areas, but I'm not really convinced that we need to add this kind of facility for the case dealt with here. To me, that's also where we could use a TRY/CATCH block and call it a day. If others feel differently about this matter, I'm fine to be outvoted. -- Michael
-
Re: Unexpected behavior after OOM errors
Matthias van de Meent <boekewurm+postgres@gmail.com> — 2026-06-19T07:18:03Z
On Fri, 19 Jun 2026 at 01:55, Michael Paquier <michael@paquier.xyz> wrote: > > On Thu, Jun 18, 2026 at 11:27:28AM +0200, Matthias van de Meent wrote: > > Each of the calls to > > CacheRegisterSyscacheCallback/CacheRegisterRelcacheCallback can throw > > an ERROR when all slots have been used. This would leave the typcache > > in an invalid state, so I think that must be wrapped in a critical > > section: neither syscache nor relcache has options to release > > callbacks, and we can't safely continue without the callbacks > > installed, so once an error is thrown here this backend can't ever be > > properly initialized. This is unlike OOMs, whose conditions for > > failure may (and often do) change as workloads change in other > > backends. > > We don't ERROR when failing to register a syscache/relcache callback, > we FATAL if we reach one of the thresholds. Ah, thanks for correcting me. I'm not sure why I had ERROR in mind, but you're obviously correct. Your patch v2 LGTM. > Reaching these thresholds > points to me to a programming error anyway, so these should not matter > in the field. I don't think that's (necessarily) correct. These callbacks are accessible to extensions, and if you load sufficiently many of those you could still run out of slots even if each extension stayed well within a reasonable threshold. > > I think Heikki's suggestion for a FATAL critical section option would > > be a good alternative. It wouldn't always be sufficient, but would fix > > issues here. > > That sounds like an interesting idea, potentially reusable for other > areas, but I'm not really convinced that we need to add this kind of > facility for the case dealt with here. To me, that's also where we > could use a TRY/CATCH block and call it a day. If others feel > differently about this matter, I'm fine to be outvoted. While TRY/CATCH would work, I'm not so keen on adding those to system-initalizing code; the allocations generally go into contexts that aren't cleaned up nicely during error handling. E.g. a partial hash initialization for any of the cache hashmaps due to OOM will leak its allocations. Failing the connection for that makes sure we complete the right cleanup procedures and not leak those resources (and it adds another item to the multi-threading concerns list). -Matthias
-
Re: Unexpected behavior after OOM errors
Matthias van de Meent <boekewurm+postgres@gmail.com> — 2026-06-19T07:22:28Z
On Fri, 19 Jun 2026 at 01:30, Michael Paquier <michael@paquier.xyz> wrote: > > On Thu, Jun 18, 2026 at 05:27:57PM +0200, Matthias van de Meent wrote: > > By moving StandbyAcquireAccessExclusiveLock's LockAcquire ahead of > > when it links the lock to the transaction, the local data structure > > doesn't know to clean up the lock until after it's acquired, so > > failure in that process won't make error cleanup try to clean up the > > lock. > > Yep, reordering these two actions would take care of the list > inconsistency where the startup process goes down following the ERROR > promoted to a FATAL. > > I have been fingering the idea of backpatching this fix for a few > minutes, actually, but discarded the idea at the end. It does not > require a random pattern to cause the failure, being actionable > through a combination of GUCs as Alexander has proved. Still, the > only consequence is an extra LOG entry telling that the lock is not > being tracked for non-assert builds. Confusing, OK, but not really > critical. > > Comments? Because it fixes an assertion, I'd vote for backpatching; but because the case is handled safely without assertions I also wouldn't be upset if it wasn't backpatched. -Matthias
-
Re: Unexpected behavior after OOM errors
Michael Paquier <michael@paquier.xyz> — 2026-06-19T11:12:47Z
On Fri, Jun 19, 2026 at 09:18:03AM +0200, Matthias van de Meent wrote: > On Fri, 19 Jun 2026 at 01:55, Michael Paquier <michael@paquier.xyz> wrote: >> We don't ERROR when failing to register a syscache/relcache callback, >> we FATAL if we reach one of the thresholds. > > Ah, thanks for correcting me. I'm not sure why I had ERROR in mind, > but you're obviously correct. Your patch v2 LGTM. Cool, thanks. >> Reaching these thresholds >> points to me to a programming error anyway, so these should not matter >> in the field. > > I don't think that's (necessarily) correct. These callbacks are > accessible to extensions, and if you load sufficiently many of those > you could still run out of slots even if each extension stayed well > within a reasonable threshold. Sure, but then the only way to get out of the problem is to patch the backend so there are more slots available. At the end, when it comes to core (and there should be some margin anyway), I am not really worried. -- Michael
-
Re: Unexpected behavior after OOM errors
Michael Paquier <michael@paquier.xyz> — 2026-06-20T06:03:20Z
On Fri, Jun 19, 2026 at 09:22:28AM +0200, Matthias van de Meent wrote: > Because it fixes an assertion, I'd vote for backpatching; but because > the case is handled safely without assertions I also wouldn't be upset > if it wasn't backpatched. With some tweaks to the comments, applied this one on HEAD, without a backpatch. -- Michael
-
Re: Unexpected behavior after OOM errors
Michael Paquier <michael@paquier.xyz> — 2026-06-20T07:45:55Z
On Fri, Jun 19, 2026 at 08:12:47PM +0900, Michael Paquier wrote: > On Fri, Jun 19, 2026 at 09:18:03AM +0200, Matthias van de Meent wrote: >> Ah, thanks for correcting me. I'm not sure why I had ERROR in mind, >> but you're obviously correct. Your patch v2 LGTM. > > Cool, thanks. And done that as well. If we invent a new facility, I'd be curious to see how this would apply here or to other parts of the backend. And perhaps not only for initialization steps? -- Michael
-
Re: Unexpected behavior after OOM errors
Alexander Law <exclusion@gmail.com> — 2026-06-20T08:00:01Z
Hello Michael and Matthias, 20.06.2026 10:45, Michael Paquier wrote: > On Fri, Jun 19, 2026 at 08:12:47PM +0900, Michael Paquier wrote: >> On Fri, Jun 19, 2026 at 09:18:03AM +0200, Matthias van de Meent wrote: >>> Ah, thanks for correcting me. I'm not sure why I had ERROR in mind, >>> but you're obviously correct. Your patch v2 LGTM. >> Cool, thanks. > And done that as well. If we invent a new facility, I'd be curious to > see how this would apply here or to other parts of the backend. And > perhaps not only for initialization steps? Thank you for working on the fixes! Best regards, Alexander