From 2b3d11aaed891958f24aed05bf454524d603b6ea Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Fri, 4 Sep 2026 07:50:46 +0900 Subject: [PATCH] Minimize footprint of TOAST_MAX_CHUNK_SIZE in heap and amcheck code This refactoring eases a little bit a follow-up change to add support for 8-byte TOAST value IDs, as the maximum chunk size allowed for a single chunk of TOASTed data depends on the size of varatt_external, its value ID being part of it. It is worth noting that TOAST_MAX_CHUNK_SIZE resolves as a uintptr_t, so the previous calculations were in 64-bit unsigned arithmetic. These are now done in int32, which still works the same way due to an external TOAST value being bounded to 1GB. Author: Michael Paquier Reviewed-by: Yugo Nagata Reviewed-by: Bharath Rupireddy Discussion: https://postgr.es/m/CALj2ACVnO6jjs5aRx3dSOBy9LV7=iakPBR1eOvoeB8rL8Q47zg@mail.gmail.com --- contrib/amcheck/verify_heapam.c | 13 +++++++++---- src/backend/access/heap/heaptoast.c | 20 ++++++++++++-------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/contrib/amcheck/verify_heapam.c b/contrib/amcheck/verify_heapam.c index 20ff58aa782..6757baee240 100644 --- a/contrib/amcheck/verify_heapam.c +++ b/contrib/amcheck/verify_heapam.c @@ -1558,11 +1558,15 @@ check_toast_tuple(HeapTuple toasttup, HeapCheckContext *ctx, uint32 extsize) { int32 chunk_seq; - int32 last_chunk_seq = (extsize - 1) / TOAST_MAX_CHUNK_SIZE; + int32 last_chunk_seq; Pointer chunk; bool isnull; int32 chunksize; int32 expected_size; + int32 max_chunk_size; + + max_chunk_size = TOAST_MAX_CHUNK_SIZE; + last_chunk_seq = (extsize - 1) / max_chunk_size; /* Sanity-check the sequence number. */ chunk_seq = DatumGetInt32(fastgetattr(toasttup, 2, @@ -1628,8 +1632,8 @@ check_toast_tuple(HeapTuple toasttup, HeapCheckContext *ctx, return; } - expected_size = chunk_seq < last_chunk_seq ? TOAST_MAX_CHUNK_SIZE - : extsize - (last_chunk_seq * TOAST_MAX_CHUNK_SIZE); + expected_size = chunk_seq < last_chunk_seq ? max_chunk_size + : extsize - (last_chunk_seq * max_chunk_size); if (chunksize != expected_size) report_toast_corruption(ctx, ta, @@ -1868,9 +1872,10 @@ check_toasted_attribute(HeapCheckContext *ctx, ToastedAttribute *ta) uint32 extsize; int32 expected_chunk_seq = 0; int32 last_chunk_seq; + int32 max_chunk_size = TOAST_MAX_CHUNK_SIZE; extsize = VARATT_EXTERNAL_GET_EXTSIZE(ta->toast_pointer); - last_chunk_seq = (extsize - 1) / TOAST_MAX_CHUNK_SIZE; + last_chunk_seq = (extsize - 1) / max_chunk_size; /* * Setup a scan key to find chunks in toast table with matching va_valueid diff --git a/src/backend/access/heap/heaptoast.c b/src/backend/access/heap/heaptoast.c index 03f885a25b0..bc4cdd8a3d8 100644 --- a/src/backend/access/heap/heaptoast.c +++ b/src/backend/access/heap/heaptoast.c @@ -634,11 +634,12 @@ heap_fetch_toast_slice(Relation toastrel, Oid valueid, int32 attrsize, SysScanDesc toastscan; HeapTuple ttup; int32 expectedchunk; - int32 totalchunks = ((attrsize - 1) / TOAST_MAX_CHUNK_SIZE) + 1; + int32 totalchunks; int startchunk; int endchunk; int num_indexes; int validIndex; + int32 max_chunk_size; /* Look for the valid index of toast relation */ validIndex = toast_open_indexes(toastrel, @@ -646,8 +647,11 @@ heap_fetch_toast_slice(Relation toastrel, Oid valueid, int32 attrsize, &toastidxs, &num_indexes); - startchunk = sliceoffset / TOAST_MAX_CHUNK_SIZE; - endchunk = (sliceoffset + slicelength - 1) / TOAST_MAX_CHUNK_SIZE; + max_chunk_size = TOAST_MAX_CHUNK_SIZE; + + totalchunks = ((attrsize - 1) / max_chunk_size) + 1; + startchunk = sliceoffset / max_chunk_size; + endchunk = (sliceoffset + slicelength - 1) / max_chunk_size; Assert(endchunk <= totalchunks); /* Set up a scan key to fetch from the index. */ @@ -747,8 +751,8 @@ heap_fetch_toast_slice(Relation toastrel, Oid valueid, int32 attrsize, curchunk, startchunk, endchunk, valueid, RelationGetRelationName(toastrel)))); - expected_size = curchunk < totalchunks - 1 ? TOAST_MAX_CHUNK_SIZE - : attrsize - ((totalchunks - 1) * TOAST_MAX_CHUNK_SIZE); + expected_size = curchunk < totalchunks - 1 ? max_chunk_size + : attrsize - ((totalchunks - 1) * max_chunk_size); if (chunksize != expected_size) ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED), @@ -763,12 +767,12 @@ heap_fetch_toast_slice(Relation toastrel, Oid valueid, int32 attrsize, chcpystrt = 0; chcpyend = chunksize - 1; if (curchunk == startchunk) - chcpystrt = sliceoffset % TOAST_MAX_CHUNK_SIZE; + chcpystrt = sliceoffset % max_chunk_size; if (curchunk == endchunk) - chcpyend = (sliceoffset + slicelength - 1) % TOAST_MAX_CHUNK_SIZE; + chcpyend = (sliceoffset + slicelength - 1) % max_chunk_size; memcpy(VARDATA(result) + - curchunk * TOAST_MAX_CHUNK_SIZE - sliceoffset + chcpystrt, + (curchunk * max_chunk_size - sliceoffset) + chcpystrt, chunkdata + chcpystrt, (chcpyend - chcpystrt) + 1);