v1-0001-Turn-back-the-block-level-API-for-relation-analyz.patch
application/octet-stream
Filename: v1-0001-Turn-back-the-block-level-API-for-relation-analyz.patch
Type: application/octet-stream
Part: 0
Message:
Re: Table AM Interface Enhancements
Patch
Format: format-patch
Series: patch v1-0001
Subject: Turn back the block-level API for relation analyze
| File | + | − |
|---|---|---|
| src/backend/access/heap/heapam_handler.c | 8 | 21 |
| src/backend/access/table/tableamapi.c | 3 | 0 |
| src/backend/commands/analyze.c | 23 | 12 |
| src/include/access/heapam.h | 0 | 9 |
| src/include/access/tableam.h | 89 | 2 |
| src/include/commands/vacuum.h | 2 | 3 |
From 010df6f6c3f9ab07061ee13e2126b2aa4ca128bd Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <akorotkov@postgresql.org>
Date: Mon, 8 Apr 2024 02:02:18 +0300
Subject: [PATCH v1] Turn back the block-level API for relation analyze
And keep the new API as well.
---
src/backend/access/heap/heapam_handler.c | 29 +++-----
src/backend/access/table/tableamapi.c | 3 +
src/backend/commands/analyze.c | 35 +++++----
src/include/access/heapam.h | 9 ---
src/include/access/tableam.h | 91 +++++++++++++++++++++++-
src/include/commands/vacuum.h | 5 +-
6 files changed, 125 insertions(+), 47 deletions(-)
diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c
index 58de2c82a70..088da910a11 100644
--- a/src/backend/access/heap/heapam_handler.c
+++ b/src/backend/access/heap/heapam_handler.c
@@ -51,6 +51,7 @@ static TM_Result heapam_tuple_lock(Relation relation, ItemPointer tid,
CommandId cid, LockTupleMode mode,
LockWaitPolicy wait_policy, uint8 flags,
TM_FailureData *tmfd);
+
static void reform_and_rewrite_tuple(HeapTuple tuple,
Relation OldHeap, Relation NewHeap,
Datum *values, bool *isnull, RewriteState rwstate);
@@ -1054,15 +1055,7 @@ heapam_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap,
pfree(isnull);
}
-/*
- * Prepare to analyze block `blockno` of `scan`. The scan has been started
- * with SO_TYPE_ANALYZE option.
- *
- * This routine holds a buffer pin and lock on the heap page. They are held
- * until heapam_scan_analyze_next_tuple() returns false. That is until all the
- * items of the heap page are analyzed.
- */
-void
+static bool
heapam_scan_analyze_next_block(TableScanDesc scan, BlockNumber blockno,
BufferAccessStrategy bstrategy)
{
@@ -1082,19 +1075,12 @@ heapam_scan_analyze_next_block(TableScanDesc scan, BlockNumber blockno,
hscan->rs_cbuf = ReadBufferExtended(scan->rs_rd, MAIN_FORKNUM,
blockno, RBM_NORMAL, bstrategy);
LockBuffer(hscan->rs_cbuf, BUFFER_LOCK_SHARE);
+
+ /* in heap all blocks can contain tuples, so always return true */
+ return true;
}
-/*
- * Iterate over tuples in the block selected with
- * heapam_scan_analyze_next_block(). If a tuple that's suitable for sampling
- * is found, true is returned and a tuple is stored in `slot`. When no more
- * tuples for sampling, false is returned and the pin and lock acquired by
- * heapam_scan_analyze_next_block() are released.
- *
- * *liverows and *deadrows are incremented according to the encountered
- * tuples.
- */
-bool
+static bool
heapam_scan_analyze_next_tuple(TableScanDesc scan, TransactionId OldestXmin,
double *liverows, double *deadrows,
TupleTableSlot *slot)
@@ -2698,9 +2684,10 @@ static const TableAmRoutine heapam_methods = {
.relation_copy_data = heapam_relation_copy_data,
.relation_copy_for_cluster = heapam_relation_copy_for_cluster,
.relation_vacuum = heap_vacuum_rel,
+ .scan_analyze_next_block = heapam_scan_analyze_next_block,
+ .scan_analyze_next_tuple = heapam_scan_analyze_next_tuple,
.index_build_range_scan = heapam_index_build_range_scan,
.index_validate_scan = heapam_index_validate_scan,
- .relation_analyze = heapam_analyze,
.free_rd_amcache = NULL,
.relation_size = table_block_relation_size,
diff --git a/src/backend/access/table/tableamapi.c b/src/backend/access/table/tableamapi.c
index 55b8caeadf2..4aefdc3c385 100644
--- a/src/backend/access/table/tableamapi.c
+++ b/src/backend/access/table/tableamapi.c
@@ -81,6 +81,9 @@ GetTableAmRoutine(Oid amhandler)
Assert(routine->relation_copy_data != NULL);
Assert(routine->relation_copy_for_cluster != NULL);
Assert(routine->relation_vacuum != NULL);
+ Assert(routine->relation_analyze != NULL ||
+ (routine->scan_analyze_next_block != NULL &&
+ routine->scan_analyze_next_tuple != NULL));
Assert(routine->index_build_range_scan != NULL);
Assert(routine->index_validate_scan != NULL);
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index 2fb39f3ede1..6e3be0d491d 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -1103,15 +1103,15 @@ examine_attribute(Relation onerel, int attnum, Node *index_expr)
}
/*
- * acquire_sample_rows -- acquire a random sample of rows from the heap
+ * acquire_sample_rows -- acquire a random sample of rows from the table
*
* Selected rows are returned in the caller-allocated array rows[], which
* must have at least targrows entries.
* The actual number of rows selected is returned as the function result.
- * We also estimate the total numbers of live and dead rows in the heap,
+ * We also estimate the total numbers of live and dead rows in the table,
* and return them into *totalrows and *totaldeadrows, respectively.
*
- * The returned list of tuples is in order by physical position in the heap.
+ * The returned list of tuples is in order by physical position in the table.
* (We will rely on this later to derive correlation estimates.)
*
* As of May 2004 we use a new two-stage method: Stage one selects up
@@ -1133,7 +1133,7 @@ examine_attribute(Relation onerel, int attnum, Node *index_expr)
* look at a statistically unbiased set of blocks, we should get
* unbiased estimates of the average numbers of live and dead rows per
* block. The previous sampling method put too much credence in the row
- * density near the start of the heap.
+ * density near the start of the table.
*/
static int
acquire_sample_rows(Relation onerel, int elevel,
@@ -1184,7 +1184,7 @@ acquire_sample_rows(Relation onerel, int elevel,
/* Prepare for sampling rows */
reservoir_init_selection_state(&rstate, targrows);
- scan = heap_beginscan(onerel, NULL, 0, NULL, NULL, SO_TYPE_ANALYZE);
+ scan = table_beginscan_analyze(onerel);
slot = table_slot_create(onerel, NULL);
#ifdef USE_PREFETCH
@@ -1214,6 +1214,7 @@ acquire_sample_rows(Relation onerel, int elevel,
/* Outer loop over blocks to sample */
while (BlockSampler_HasMore(&bs))
{
+ bool block_accepted;
BlockNumber targblock = BlockSampler_Next(&bs);
#ifdef USE_PREFETCH
BlockNumber prefetch_targblock = InvalidBlockNumber;
@@ -1229,19 +1230,29 @@ acquire_sample_rows(Relation onerel, int elevel,
vacuum_delay_point();
- heapam_scan_analyze_next_block(scan, targblock, vac_strategy);
+ block_accepted = table_scan_analyze_next_block(scan, targblock, vac_strategy);
#ifdef USE_PREFETCH
/*
* When pre-fetching, after we get a block, tell the kernel about the
* next one we will want, if there's any left.
+ *
+ * We want to do this even if the table_scan_analyze_next_block() call
+ * above decides against analyzing the block it picked.
*/
if (prefetch_maximum && prefetch_targblock != InvalidBlockNumber)
PrefetchBuffer(scan->rs_rd, MAIN_FORKNUM, prefetch_targblock);
#endif
- while (heapam_scan_analyze_next_tuple(scan, OldestXmin, &liverows, &deadrows, slot))
+ /*
+ * Don't analyze if table_scan_analyze_next_block() indicated this
+ * block is unsuitable for analyzing.
+ */
+ if (!block_accepted)
+ continue;
+
+ while (table_scan_analyze_next_tuple(scan, OldestXmin, &liverows, &deadrows, slot))
{
/*
* The first targrows sample rows are simply copied into the
@@ -1291,7 +1302,7 @@ acquire_sample_rows(Relation onerel, int elevel,
}
ExecDropSingleTupleTableSlot(slot);
- heap_endscan(scan);
+ table_endscan(scan);
/*
* If we didn't find as many tuples as we wanted then we're done. No sort
@@ -1363,12 +1374,12 @@ compare_rows(const void *a, const void *b, void *arg)
}
/*
- * heapam_analyze -- implementation of relation_analyze() table access method
- * callback for heap
+ * default_analyze -- implementation of relation_analyze() table access method
+ * callback for block table access methods
*/
void
-heapam_analyze(Relation relation, AcquireSampleRowsFunc *func,
- BlockNumber *totalpages, BufferAccessStrategy bstrategy)
+default_analyze(Relation relation, AcquireSampleRowsFunc *func,
+ BlockNumber *totalpages, BufferAccessStrategy bstrategy)
{
*func = acquire_sample_rows;
*totalpages = RelationGetNumberOfBlocks(relation);
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index 48936826bcc..be630620d0d 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.h
@@ -412,15 +412,6 @@ extern bool HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple);
extern bool HeapTupleIsSurelyDead(HeapTuple htup,
struct GlobalVisState *vistest);
-/* in heap/heapam_handler.c*/
-extern void heapam_scan_analyze_next_block(TableScanDesc scan,
- BlockNumber blockno,
- BufferAccessStrategy bstrategy);
-extern bool heapam_scan_analyze_next_tuple(TableScanDesc scan,
- TransactionId OldestXmin,
- double *liverows, double *deadrows,
- TupleTableSlot *slot);
-
/*
* To avoid leaking too much knowledge about reorderbuffer implementation
* details this is implemented in reorderbuffer.c not heapam_visibility.c
diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h
index be198fa3158..09aa2c119af 100644
--- a/src/include/access/tableam.h
+++ b/src/include/access/tableam.h
@@ -668,6 +668,41 @@ typedef struct TableAmRoutine
struct VacuumParams *params,
BufferAccessStrategy bstrategy);
+ /*
+ * Prepare to analyze block `blockno` of `scan`. The scan has been started
+ * with table_beginscan_analyze(). See also
+ * table_scan_analyze_next_block().
+ *
+ * The callback may acquire resources like locks that are held until
+ * table_scan_analyze_next_tuple() returns false. It e.g. can make sense
+ * to hold a lock until all tuples on a block have been analyzed by
+ * scan_analyze_next_tuple.
+ *
+ * The callback can return false if the block is not suitable for
+ * sampling, e.g. because it's a metapage that could never contain tuples.
+ *
+ * XXX: This obviously is primarily suited for block-based AMs. It's not
+ * clear what a good interface for non block based AMs would be, so there
+ * isn't one yet.
+ */
+ bool (*scan_analyze_next_block) (TableScanDesc scan,
+ BlockNumber blockno,
+ BufferAccessStrategy bstrategy);
+
+ /*
+ * See table_scan_analyze_next_tuple().
+ *
+ * Not every AM might have a meaningful concept of dead rows, in which
+ * case it's OK to not increment *deadrows - but note that that may
+ * influence autovacuum scheduling (see comment for relation_vacuum
+ * callback).
+ */
+ bool (*scan_analyze_next_tuple) (TableScanDesc scan,
+ TransactionId OldestXmin,
+ double *liverows,
+ double *deadrows,
+ TupleTableSlot *slot);
+
/* see table_index_build_range_scan for reference about parameters */
double (*index_build_range_scan) (Relation table_rel,
Relation index_rel,
@@ -992,6 +1027,19 @@ table_beginscan_tid(Relation rel, Snapshot snapshot)
return rel->rd_tableam->scan_begin(rel, snapshot, 0, NULL, NULL, flags);
}
+/*
+ * table_beginscan_analyze is an alternative entry point for setting up a
+ * TableScanDesc for an ANALYZE scan. As with bitmap scans, it's worth using
+ * the same data structure although the behavior is rather different.
+ */
+static inline TableScanDesc
+table_beginscan_analyze(Relation rel)
+{
+ uint32 flags = SO_TYPE_ANALYZE;
+
+ return rel->rd_tableam->scan_begin(rel, NULL, 0, NULL, NULL, flags);
+}
+
/*
* End relation scan.
*/
@@ -1725,6 +1773,42 @@ table_relation_vacuum(Relation rel, struct VacuumParams *params,
rel->rd_tableam->relation_vacuum(rel, params, bstrategy);
}
+/*
+ * Prepare to analyze block `blockno` of `scan`. The scan needs to have been
+ * started with table_beginscan_analyze(). Note that this routine might
+ * acquire resources like locks that are held until
+ * table_scan_analyze_next_tuple() returns false.
+ *
+ * Returns false if block is unsuitable for sampling, true otherwise.
+ */
+static inline bool
+table_scan_analyze_next_block(TableScanDesc scan, BlockNumber blockno,
+ BufferAccessStrategy bstrategy)
+{
+ return scan->rs_rd->rd_tableam->scan_analyze_next_block(scan, blockno,
+ bstrategy);
+}
+
+/*
+ * Iterate over tuples in the block selected with
+ * table_scan_analyze_next_block() (which needs to have returned true, and
+ * this routine may not have returned false for the same block before). If a
+ * tuple that's suitable for sampling is found, true is returned and a tuple
+ * is stored in `slot`.
+ *
+ * *liverows and *deadrows are incremented according to the encountered
+ * tuples.
+ */
+static inline bool
+table_scan_analyze_next_tuple(TableScanDesc scan, TransactionId OldestXmin,
+ double *liverows, double *deadrows,
+ TupleTableSlot *slot)
+{
+ return scan->rs_rd->rd_tableam->scan_analyze_next_tuple(scan, OldestXmin,
+ liverows, deadrows,
+ slot);
+}
+
/*
* table_index_build_scan - scan the table to find tuples to be indexed
*
@@ -1842,8 +1926,11 @@ static inline void
table_relation_analyze(Relation relation, AcquireSampleRowsFunc *func,
BlockNumber *totalpages, BufferAccessStrategy bstrategy)
{
- relation->rd_tableam->relation_analyze(relation, func,
- totalpages, bstrategy);
+ if (relation->rd_tableam->relation_analyze)
+ relation->rd_tableam->relation_analyze(relation, func,
+ totalpages, bstrategy);
+ else
+ default_analyze(relation, func, totalpages, bstrategy);
}
/* ----------------------------------------------------------------------------
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 9514f8b2fd8..d00f3c19abf 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -393,9 +393,8 @@ extern void parallel_vacuum_main(dsm_segment *seg, shm_toc *toc);
extern void analyze_rel(Oid relid, RangeVar *relation,
VacuumParams *params, List *va_cols, bool in_outer_xact,
BufferAccessStrategy bstrategy);
-extern void heapam_analyze(Relation relation, AcquireSampleRowsFunc *func,
- BlockNumber *totalpages,
- BufferAccessStrategy bstrategy);
+extern void default_analyze(Relation relation, AcquireSampleRowsFunc *func,
+ BlockNumber *totalpages, BufferAccessStrategy bstrategy);
extern bool std_typanalyze(VacAttrStats *stats);
--
2.39.3 (Apple Git-145)