0001-a-use-huge-allocations.patch

text/x-patch

Filename: 0001-a-use-huge-allocations.patch
Type: text/x-patch
Part: 0
Message: Re: PG18 GIN parallel index build crash - invalid memory alloc request size

Patch

Format: format-patch
Series: patch 0001
Subject: a: use huge allocations
File+
src/backend/access/gin/gininsert.c 75 6
From be3417e947a1f17e5fa4137481668779be532bc5 Mon Sep 17 00:00:00 2001
From: Tomas Vondra <tomas@vondra.me>
Date: Sun, 26 Oct 2025 21:14:44 +0100
Subject: [PATCH 1/3] a: use huge allocations

---
 src/backend/access/gin/gininsert.c | 81 +++++++++++++++++++++++++++---
 1 file changed, 75 insertions(+), 6 deletions(-)

diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c
index 3d71b442aa9..085c85718cc 100644
--- a/src/backend/access/gin/gininsert.c
+++ b/src/backend/access/gin/gininsert.c
@@ -198,6 +198,10 @@ static GinTuple *_gin_build_tuple(OffsetNumber attrnum, unsigned char category,
 								  ItemPointerData *items, uint32 nitems,
 								  Size *len);
 
+static ItemPointer mergeItemPointers(ItemPointerData *a, uint32 na,
+									 ItemPointerData *b, uint32 nb,
+									 int *nmerged);
+
 /*
  * Adds array of item pointers to tuple's posting list, or
  * creates posting tree and tuple pointing to tree in case
@@ -1496,14 +1500,15 @@ GinBufferStoreTuple(GinBuffer *buffer, GinTuple *tup)
 		 * still pass 0 as number of elements in that array though.
 		 */
 		if (buffer->items == NULL)
-			buffer->items = palloc((buffer->nitems + tup->nitems) * sizeof(ItemPointerData));
+			buffer->items = MemoryContextAllocHuge(CurrentMemoryContext,
+												   (buffer->nitems + tup->nitems) * sizeof(ItemPointerData));
 		else
-			buffer->items = repalloc(buffer->items,
-									 (buffer->nitems + tup->nitems) * sizeof(ItemPointerData));
+			buffer->items = repalloc_huge(buffer->items,
+										  (buffer->nitems + tup->nitems) * sizeof(ItemPointerData));
 
-		new = ginMergeItemPointers(&buffer->items[buffer->nfrozen], /* first unfrozen */
-								   (buffer->nitems - buffer->nfrozen),	/* num of unfrozen */
-								   items, tup->nitems, &nnew);
+		new = mergeItemPointers(&buffer->items[buffer->nfrozen], /* first unfrozen */
+								(buffer->nitems - buffer->nfrozen),	/* num of unfrozen */
+								items, tup->nitems, &nnew);
 
 		Assert(nnew == (tup->nitems + (buffer->nitems - buffer->nfrozen)));
 
@@ -2441,3 +2446,67 @@ _gin_compare_tuples(GinTuple *a, GinTuple *b, SortSupport ssup)
 	return ItemPointerCompare(GinTupleGetFirst(a),
 							  GinTupleGetFirst(b));
 }
+
+
+/*
+ * local copy, doing palloc_huge
+ */
+static ItemPointer
+mergeItemPointers(ItemPointerData *a, uint32 na,
+				  ItemPointerData *b, uint32 nb,
+				  int *nmerged)
+{
+	ItemPointerData *dst;
+
+	dst = (ItemPointer) MemoryContextAllocHuge(CurrentMemoryContext,
+											   (na + nb) * sizeof(ItemPointerData));
+
+	/*
+	 * If the argument arrays don't overlap, we can just append them to each
+	 * other.
+	 */
+	if (na == 0 || nb == 0 || ginCompareItemPointers(&a[na - 1], &b[0]) < 0)
+	{
+		memcpy(dst, a, na * sizeof(ItemPointerData));
+		memcpy(&dst[na], b, nb * sizeof(ItemPointerData));
+		*nmerged = na + nb;
+	}
+	else if (ginCompareItemPointers(&b[nb - 1], &a[0]) < 0)
+	{
+		memcpy(dst, b, nb * sizeof(ItemPointerData));
+		memcpy(&dst[nb], a, na * sizeof(ItemPointerData));
+		*nmerged = na + nb;
+	}
+	else
+	{
+		ItemPointerData *dptr = dst;
+		ItemPointerData *aptr = a;
+		ItemPointerData *bptr = b;
+
+		while (aptr - a < na && bptr - b < nb)
+		{
+			int			cmp = ginCompareItemPointers(aptr, bptr);
+
+			if (cmp > 0)
+				*dptr++ = *bptr++;
+			else if (cmp == 0)
+			{
+				/* only keep one copy of the identical items */
+				*dptr++ = *bptr++;
+				aptr++;
+			}
+			else
+				*dptr++ = *aptr++;
+		}
+
+		while (aptr - a < na)
+			*dptr++ = *aptr++;
+
+		while (bptr - b < nb)
+			*dptr++ = *bptr++;
+
+		*nmerged = dptr - dst;
+	}
+
+	return dst;
+}
-- 
2.51.0