From 1e387dbcf45d2c2adce7ec697f0e959e80ef23b7 Mon Sep 17 00:00:00 2001 From: David Christensen Date: Wed, 7 Feb 2024 10:49:31 -0500 Subject: [PATCH v1 2/4] Split MaxHeapTupleSize into runtime and max values --- src/backend/access/heap/heapam.c | 12 +++++----- src/backend/access/heap/hio.c | 6 ++--- src/backend/access/heap/rewriteheap.c | 4 ++-- .../replication/logical/reorderbuffer.c | 2 +- src/backend/storage/freespace/freespace.c | 2 +- src/include/access/heaptoast.h | 2 +- src/include/access/htup_details.h | 22 ++++++++++++++----- src/test/regress/expected/insert.out | 2 +- src/test/regress/sql/insert.sql | 2 +- 9 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index f740d4225e..dcbb926916 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -9231,7 +9231,7 @@ heap_xlog_insert(XLogReaderState *record) union { HeapTupleHeaderData hdr; - char data[MaxHeapTupleSize]; + char data[MaxHeapTupleSizeLimit]; } tbuf; HeapTupleHeader htup; xl_heap_header xlhdr; @@ -9287,7 +9287,7 @@ heap_xlog_insert(XLogReaderState *record) data = XLogRecGetBlockData(record, 0, &datalen); newlen = datalen - SizeOfHeapHeader; - Assert(datalen > SizeOfHeapHeader && newlen <= MaxHeapTupleSize); + Assert(datalen > SizeOfHeapHeader && newlen <= ClusterMaxHeapTupleSize); memcpy((char *) &xlhdr, data, SizeOfHeapHeader); data += SizeOfHeapHeader; @@ -9353,7 +9353,7 @@ heap_xlog_multi_insert(XLogReaderState *record) union { HeapTupleHeaderData hdr; - char data[MaxHeapTupleSize]; + char data[MaxHeapTupleSizeLimit]; } tbuf; HeapTupleHeader htup; uint32 newlen; @@ -9431,7 +9431,7 @@ heap_xlog_multi_insert(XLogReaderState *record) tupdata = ((char *) xlhdr) + SizeOfMultiInsertTuple; newlen = xlhdr->datalen; - Assert(newlen <= MaxHeapTupleSize); + Assert(newlen <= ClusterMaxHeapTupleSize); htup = &tbuf.hdr; MemSet((char *) htup, 0, SizeofHeapTupleHeader); /* PG73FORMAT: get bitmap [+ padding] [+ oid] + data */ @@ -9510,7 +9510,7 @@ heap_xlog_update(XLogReaderState *record, bool hot_update) union { HeapTupleHeaderData hdr; - char data[MaxHeapTupleSize]; + char data[MaxHeapTupleSizeLimit]; } tbuf; xl_heap_header xlhdr; uint32 newlen; @@ -9666,7 +9666,7 @@ heap_xlog_update(XLogReaderState *record, bool hot_update) recdata += SizeOfHeapHeader; tuplen = recdata_end - recdata; - Assert(tuplen <= MaxHeapTupleSize); + Assert(tuplen <= ClusterMaxHeapTupleSize); htup = &tbuf.hdr; MemSet((char *) htup, 0, SizeofHeapTupleHeader); diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c index 58f0a384c8..3e3963503b 100644 --- a/src/backend/access/heap/hio.c +++ b/src/backend/access/heap/hio.c @@ -530,11 +530,11 @@ RelationGetBufferForTuple(Relation relation, Size len, /* * If we're gonna fail for oversize tuple, do it right away */ - if (len > MaxHeapTupleSize) + if (len > ClusterMaxHeapTupleSize) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("row is too big: size %zu, maximum size %zu", - len, MaxHeapTupleSize))); + len, ClusterMaxHeapTupleSize))); /* Compute desired extra freespace due to fillfactor option */ saveFreeSpace = RelationGetTargetPageFreeSpace(relation, @@ -546,7 +546,7 @@ RelationGetBufferForTuple(Relation relation, Size len, * somewhat arbitrary, but it should prevent most unnecessary relation * extensions while inserting large tuples into low-fillfactor tables. */ - nearlyEmptyFreeSpace = MaxHeapTupleSize - + nearlyEmptyFreeSpace = ClusterMaxHeapTupleSize - (ClusterMaxHeapTuplesPerPage / 8 * sizeof(ItemIdData)); if (len + saveFreeSpace > nearlyEmptyFreeSpace) targetFreeSpace = Max(len, nearlyEmptyFreeSpace); diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c index 34107323ff..75e0d1ffe8 100644 --- a/src/backend/access/heap/rewriteheap.c +++ b/src/backend/access/heap/rewriteheap.c @@ -653,11 +653,11 @@ raw_heap_insert(RewriteState state, HeapTuple tup) /* * If we're gonna fail for oversize tuple, do it right away */ - if (len > MaxHeapTupleSize) + if (len > ClusterMaxHeapTupleSize) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("row is too big: size %zu, maximum size %zu", - len, MaxHeapTupleSize))); + len, ClusterMaxHeapTupleSize))); /* Compute desired extra freespace due to fillfactor option */ saveFreeSpace = RelationGetTargetPageFreeSpace(state->rs_new_rel, diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c index bbf0966182..07441d630b 100644 --- a/src/backend/replication/logical/reorderbuffer.c +++ b/src/backend/replication/logical/reorderbuffer.c @@ -4879,7 +4879,7 @@ ReorderBufferToastReplace(ReorderBuffer *rb, ReorderBufferTXN *txn, * the tuplebuf because attrs[] will point back into the current content. */ tmphtup = heap_form_tuple(desc, attrs, isnull); - Assert(newtup->t_len <= MaxHeapTupleSize); + Assert(newtup->t_len <= ClusterMaxHeapTupleSize); Assert(newtup->t_data == (HeapTupleHeader) ((char *) newtup + HEAPTUPLESIZE)); memcpy(newtup->t_data, tmphtup->t_data, tmphtup->t_len); diff --git a/src/backend/storage/freespace/freespace.c b/src/backend/storage/freespace/freespace.c index 15e3a07341..f31edadabf 100644 --- a/src/backend/storage/freespace/freespace.c +++ b/src/backend/storage/freespace/freespace.c @@ -63,7 +63,7 @@ */ #define FSM_CATEGORIES 256 #define FSM_CAT_STEP (BLCKSZ / FSM_CATEGORIES) -#define MaxFSMRequestSize MaxHeapTupleSize +#define MaxFSMRequestSize ClusterMaxHeapTupleSize /* * Depth of the on-disk tree. We need to be able to address 2^32-1 blocks, diff --git a/src/include/access/heaptoast.h b/src/include/access/heaptoast.h index c376dff48d..6fe836f7d1 100644 --- a/src/include/access/heaptoast.h +++ b/src/include/access/heaptoast.h @@ -65,7 +65,7 @@ * compress it (we can't move it out-of-line, however). Note that this * number is per-datum, not per-tuple, for simplicity in index_form_tuple(). */ -#define TOAST_INDEX_TARGET (MaxHeapTupleSize / 16) +#define TOAST_INDEX_TARGET (ClusterMaxHeapTupleSize / 16) /* * When we store an oversize datum externally, we divide it into chunks diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h index 7a35baf4b1..bb5c746b98 100644 --- a/src/include/access/htup_details.h +++ b/src/include/access/htup_details.h @@ -550,17 +550,27 @@ StaticAssertDecl(MaxOffsetNumber < SpecTokenOffsetNumber, #define BITMAPLEN(NATTS) (((int)(NATTS) + 7) / 8) /* - * MaxHeapTupleSize is the maximum allowed size of a heap tuple, including - * header and MAXALIGN alignment padding. Basically it's BLCKSZ minus the - * other stuff that has to be on a disk page. Since heap pages use no - * "special space", there's no deduction for that. + * ClusterMaxHeapTupleSize is a cluster-specific maximum allowed size of a + * heap tuple, including header and MAXALIGN alignment padding. Basically + * it's BLCKSZ minus the other stuff that has to be on a disk page. Since + * heap pages use no "special space", there's no deduction for that. + * + * MaxHeapTuplesSizeLimit is the largest value that ClusterMaxHeapTupleSize + * could be. While these currently evaluate to the same value, these are + * being split out so ClusterMaxHeapTupleSize can become a variable + * instead of a constant. + * + * The CalcMaxHeapTupleSize() macro is used to determine the appropriate + * values, given the usable page space on a given page. * * NOTE: we allow for the ItemId that must point to the tuple, ensuring that * an otherwise-empty page can indeed hold a tuple of this size. Because * ItemIds and tuples have different alignment requirements, don't assume that - * you can, say, fit 2 tuples of size MaxHeapTupleSize/2 on the same page. + * you can, say, fit 2 tuples of size ClusterMaxHeapTupleSize/2 on the same page. */ -#define MaxHeapTupleSize (BLCKSZ - MAXALIGN(SizeOfPageHeaderData + sizeof(ItemIdData))) +#define CalcMaxHeapTupleSize(size) (size - sizeof(ItemIdData)) +#define ClusterMaxHeapTupleSize CalcMaxHeapTupleSize(BLCKSZ - SizeOfPageHeaderData) +#define MaxHeapTupleSizeLimit CalcMaxHeapTupleSize(BLCKSZ - SizeOfPageHeaderData) #define MinHeapTupleSize MAXALIGN(SizeofHeapTupleHeader) /* diff --git a/src/test/regress/expected/insert.out b/src/test/regress/expected/insert.out index dd4354fc7d..eebf3c6d4d 100644 --- a/src/test/regress/expected/insert.out +++ b/src/test/regress/expected/insert.out @@ -86,7 +86,7 @@ drop table inserttest; -- CREATE TABLE large_tuple_test (a int, b text) WITH (fillfactor = 10); ALTER TABLE large_tuple_test ALTER COLUMN b SET STORAGE plain; --- create page w/ free space in range [nearlyEmptyFreeSpace, MaxHeapTupleSize) +-- create page w/ free space in range [nearlyEmptyFreeSpace, ClusterMaxHeapTupleSize) INSERT INTO large_tuple_test (select 1, NULL); -- should still fit on the page INSERT INTO large_tuple_test (select 2, repeat('a', 1000)); diff --git a/src/test/regress/sql/insert.sql b/src/test/regress/sql/insert.sql index bdcffd0314..53f46e7960 100644 --- a/src/test/regress/sql/insert.sql +++ b/src/test/regress/sql/insert.sql @@ -43,7 +43,7 @@ drop table inserttest; CREATE TABLE large_tuple_test (a int, b text) WITH (fillfactor = 10); ALTER TABLE large_tuple_test ALTER COLUMN b SET STORAGE plain; --- create page w/ free space in range [nearlyEmptyFreeSpace, MaxHeapTupleSize) +-- create page w/ free space in range [nearlyEmptyFreeSpace, ClusterMaxHeapTupleSize) INSERT INTO large_tuple_test (select 1, NULL); -- should still fit on the page -- 2.40.1