On Fri, Jul 17, 2026 at 12:00:01PM +0300, Alexander Lakhin wrote: > (Assuming the attached OOM injection patch applied.) > 1) An issue in generate_partition_qual(): > --- a/src/backend/utils/cache/partcache.c > +++ b/src/backend/utils/cache/partcache.c > @@ -419,3 +419,5 @@ generate_partition_qual(Relation rel) > oldcxt = MemoryContextSwitchTo(rel->rd_partcheckcxt); > +oom_prob = 0.1; > rel->rd_partcheck = copyObject(result); > +oom_prob = 0; > MemoryContextSwitchTo(oldcxt);
This one is again an ordering problem: let's assign rd_partcheckcxt
and rd_partcheck once we are sure that all the allocations have
succeeded, so as we don't finish with a semi-allocated transient
state.
> 2) lookup_type_cache():
> --- a/src/backend/utils/cache/typcache.c
> +++ b/src/backend/utils/cache/typcache.c
> @@ -463,8 +463,10 @@ lookup_type_cache(Oid type_id, int flags)
> in_progress_list[in_progress_offset] = type_id;
>
> +oom_prob = 0.1;
> /* Try to look up an existing entry */
> typentry = (TypeCacheEntry *) hash_search(TypeCacheHash,
> &type_id,
> HASH_FIND, NULL);
> +oom_prob = 0;
>
> triggers
> TRAP: failed Assert("cache->cc_tupdesc != NULL"), File:
> "catcache.c", Line: 1112, PID: 43932
This one is tricky. That's obviously due to the fact that we store a
type ID in the in_progress_list and on OOM we finish with a stale
entry in the list, no cleaned up. My first impression was: could we
delay the registration of the type ID in the in_progress_list? But
the answer to that is no; we want it from the point where we to the
lookups in the typcache hash table to protect from concurrent
invalidation. So I am not sure what to do here yet.
> 3) pgstat_prep_pending_entry() / pgstat_write_statsfiles():
> --- a/src/backend/utils/activity/pgstat.c
> +++ b/src/backend/utils/activity/pgstat.c
> @@ -1333,3 +1333,5 @@ pgstat_prep_pending_entry(PgStat_Kind kind, Oid dboid,
> uint64 objid, bool *creat
>
> +oom_prob = 0.005;
> entry_ref->pending = MemoryContextAllocZero(pgStatPendingContext,
> entrysize);
> +oom_prob = 0;
> dlist_push_tail(&pgStatPending, &entry_ref->pending_node);
>
> triggers
> TRAP: failed Assert("!ps->dropped"), File: "pgstat.c", Line: 1730, PID: 844901
> maybe this Assert can be removed, because there is no corresponding
Yes, perhaps we should do that. I am not completely sure if this is
the best thing to do, though.
> 4) make_new_heap():
> --- a/src/backend/commands/repack.c
> +++ b/src/backend/commands/repack.c
> @@ -1255,3 +1255,5 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, Oid
> NewAccessMethod,
> */
> +oom_prob = 0.01;
> CommandCounterIncrement();
> +oom_prob = 0;
>
> triggers:
> TRAP: failed Assert("ItemIdIsNormal(lp)"), File: "heapam.c", Line: 2813, PID:
> 943626
> also:
> ERROR: attempted to delete invisible tuple
I'll let Alvaro comment on this one. It deserves an open item.
For now, I have 1 out of 4, the partcache one. 25% is still better
than 0%. :p
--
Michael
diff --git a/src/backend/utils/cache/partcache.c
b/src/backend/utils/cache/partcache.c
index 3107075c9ad6..b25751b3793f 100644
--- a/src/backend/utils/cache/partcache.c
+++ b/src/backend/utils/cache/partcache.c
@@ -404,21 +404,28 @@ generate_partition_qual(Relation rel)
/*
* Save a copy in the relcache. The order of these operations is fairly
* critical to avoid memory leaks and ensure that we don't leave a
corrupt
- * relcache entry if we fail partway through copyObject.
+ * relcache entry if we fail partway through copyObject.
rd_partcheckcxt
+ * and rd_partcheck are assigned last, after copyObject() succeeds.
*
* If, as is definitely possible, the partcheck list is NIL, then we do
* not need to make a context to hold it.
*/
if (result != NIL)
{
- rel->rd_partcheckcxt = AllocSetContextCreate(CacheMemoryContext,
-
"partition constraint",
-
ALLOCSET_SMALL_SIZES);
- MemoryContextCopyAndSetIdentifier(rel->rd_partcheckcxt,
+ MemoryContext partcheckcxt;
+ List *partcheck;
+
+ partcheckcxt = AllocSetContextCreate(CacheMemoryContext,
+
"partition constraint",
+
ALLOCSET_SMALL_SIZES);
+ MemoryContextCopyAndSetIdentifier(partcheckcxt,
RelationGetRelationName(rel));
- oldcxt = MemoryContextSwitchTo(rel->rd_partcheckcxt);
- rel->rd_partcheck = copyObject(result);
+ oldcxt = MemoryContextSwitchTo(partcheckcxt);
+ partcheck = copyObject(result);
MemoryContextSwitchTo(oldcxt);
+
+ rel->rd_partcheckcxt = partcheckcxt;
+ rel->rd_partcheck = partcheck;
}
else
rel->rd_partcheck = NIL;
signature.asc
Description: PGP signature
