From d008b684394efdf1aff5e49b6034e5a5830f4a2b Mon Sep 17 00:00:00 2001 From: Jingtang Zhang Date: Wed, 28 Oct 2026 18:43:31 +0800 Subject: [PATCH v4] Use maintenance I/O concurrency for index builds and table rewrites Heap scans for index builds and table rewrites currently use ordinary query I/O concurrency even though these operations perform maintenance work. Propagate the maintenance context so their read streams use the maintenance setting, including tablespace overrides. Cover serial and parallel index builds, BRIN range summarization, and the sequential heap scans used by VACUUM FULL, CLUSTER, and REPACK. Preserve the existing scan options and interfaces. The separate heap validation scan during concurrent index creation is unchanged. --- src/backend/access/brin/brin.c | 2 +- src/backend/access/gin/gininsert.c | 2 +- src/backend/access/heap/heapam.c | 7 +++++-- src/backend/access/heap/heapam_handler.c | 21 ++++++++++++++------- src/backend/access/nbtree/nbtsort.c | 2 +- src/include/access/tableam.h | 3 +++ 6 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 5059da8dce7..b6f3f87d768 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -2845,7 +2845,7 @@ _brin_parallel_scan_and_build(BrinBuildState *state, scan = table_beginscan_parallel(heap, ParallelTableScanFromBrinShared(brinshared), - SO_NONE); + SO_MAINTENANCE); reltuples = table_index_build_scan(heap, index, indexInfo, true, true, brinbuildCallbackParallel, state, scan); diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c index 564b1509f1b..b2c554dbbef 100644 --- a/src/backend/access/gin/gininsert.c +++ b/src/backend/access/gin/gininsert.c @@ -2063,7 +2063,7 @@ _gin_parallel_scan_and_build(GinBuildState *state, scan = table_beginscan_parallel(heap, ParallelTableScanFromGinBuildShared(ginshared), - SO_NONE); + SO_MAINTENANCE); reltuples = table_index_build_scan(heap, index, indexInfo, true, progress, ginBuildCallbackParallel, state, scan); diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 6a09a1a1517..800ac470e2e 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -1283,6 +1283,10 @@ heap_beginscan(Relation relation, Snapshot snapshot, scan->rs_base.rs_flags & SO_TYPE_TIDRANGESCAN) { ReadStreamBlockNumberCB cb; + int stream_flags = READ_STREAM_SEQUENTIAL | READ_STREAM_USE_BATCHING; + + if (scan->rs_base.rs_flags & SO_MAINTENANCE) + stream_flags |= READ_STREAM_MAINTENANCE; if (scan->rs_base.rs_parallel) cb = heap_scan_stream_read_next_parallel; @@ -1296,8 +1300,7 @@ heap_beginscan(Relation relation, Snapshot snapshot, * - in the parallel case, only spinlocks and atomics are used * --- */ - scan->rs_read_stream = read_stream_begin_relation(READ_STREAM_SEQUENTIAL | - READ_STREAM_USE_BATCHING, + scan->rs_read_stream = read_stream_begin_relation(stream_flags, scan->rs_strategy, scan->rs_base.rs_rd, MAIN_FORKNUM, diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index 05a81e4557a..a2619875cda 100644 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@ -680,7 +680,7 @@ heapam_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap, tableScan = table_beginscan(OldHeap, snapshot ? snapshot : SnapshotAny, 0, (ScanKey) NULL, - SO_NONE); + SO_MAINTENANCE); heapScan = (HeapScanDesc) tableScan; indexScan = NULL; @@ -1204,6 +1204,9 @@ heapam_index_build_range_scan(Relation heapRelation, if (!scan) { + uint32 internal_flags = SO_TYPE_SEQSCAN | + SO_ALLOW_PAGEMODE | SO_ALLOW_STRAT; + /* * Serial index build. * @@ -1218,12 +1221,16 @@ heapam_index_build_range_scan(Relation heapRelation, else snapshot = SnapshotAny; - scan = table_beginscan_strat(heapRelation, /* relation */ - snapshot, /* snapshot */ - 0, /* number of keys */ - NULL, /* scan key */ - true, /* buffer access strategy OK */ - allow_sync); /* syncscan OK? */ + if (allow_sync) + internal_flags |= SO_ALLOW_SYNC; + + scan = table_beginscan_common(heapRelation, /* relation */ + snapshot, /* snapshot */ + 0, /* number of keys */ + NULL, /* scan key */ + NULL, /* serial scan */ + internal_flags, + SO_MAINTENANCE); } else { diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c index 756dfa3dcf4..ff5ed01718c 100644 --- a/src/backend/access/nbtree/nbtsort.c +++ b/src/backend/access/nbtree/nbtsort.c @@ -1929,7 +1929,7 @@ _bt_parallel_scan_and_sort(BTSpool *btspool, BTSpool *btspool2, indexInfo->ii_Concurrent = btshared->isconcurrent; scan = table_beginscan_parallel(btspool->heap, ParallelTableScanFromBTShared(btshared), - SO_NONE); + SO_MAINTENANCE); reltuples = table_index_build_scan(btspool->heap, btspool->index, indexInfo, true, progress, _bt_build_callback, &buildstate, scan); diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h index ea3f2a6be99..ae312fd8b5e 100644 --- a/src/include/access/tableam.h +++ b/src/include/access/tableam.h @@ -73,6 +73,9 @@ typedef enum ScanOptions /* collect scan instrumentation */ SO_SCAN_INSTRUMENT = 1 << 11, + + /* use maintenance I/O concurrency */ + SO_MAINTENANCE = 1 << 12, } ScanOptions; /* -- 2.43.7