inter.diff
text/x-diff
Filename: inter.diff
Type: text/x-diff
Part: 1
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| contrib/pgstattuple/pgstatbloat.c | 52 | 5 |
diff --git a/contrib/pgstattuple/pgstatbloat.c b/contrib/pgstattuple/pgstatbloat.c
index 2dd1900..b19459a 100644
--- a/contrib/pgstattuple/pgstatbloat.c
+++ b/contrib/pgstattuple/pgstatbloat.c
@@ -193,6 +193,12 @@ pgstatbloat(PG_FUNCTION_ARGS)
}
/*
+ * Before we consider skipping a page that's marked as clean in
+ * visibility map, we must've seen at least this many clean pages.
+ */
+#define SKIP_PAGES_THRESHOLD ((BlockNumber) 32)
+
+/*
* This function takes an already open relation and scans its pages,
* skipping those that have the corresponding visibility map bit set.
* For pages we skip, we find the free space from the free space map
@@ -213,6 +219,8 @@ pgstatbloat_heap(Relation rel, FunctionCallInfo fcinfo)
pgstatbloat_output_type stat = {0};
BufferAccessStrategy bstrategy;
TransactionId OldestXmin;
+ BlockNumber next_not_all_visible_block;
+ bool skipping_all_visible_blocks;
OldestXmin = GetOldestXmin(rel, true);
bstrategy = GetAccessStrategy(BAS_BULKREAD);
@@ -220,6 +228,24 @@ pgstatbloat_heap(Relation rel, FunctionCallInfo fcinfo)
scanned = 0;
nblocks = RelationGetNumberOfBlocks(rel);
+ /*
+ * We use the visibility map to skip over SKIP_PAGES_THRESHOLD or
+ * more contiguous all-visible pages. See the explanation in
+ * lazy_scan_heap for the rationale.
+ */
+
+ for (next_not_all_visible_block = 0;
+ next_not_all_visible_block < nblocks;
+ next_not_all_visible_block++)
+ {
+ if (!visibilitymap_test(rel, next_not_all_visible_block, &vmbuffer))
+ break;
+ }
+ if (next_not_all_visible_block >= SKIP_PAGES_THRESHOLD)
+ skipping_all_visible_blocks = true;
+ else
+ skipping_all_visible_blocks = false;
+
for (blkno = 0; blkno < nblocks; blkno++)
{
Buffer buf;
@@ -230,13 +256,34 @@ pgstatbloat_heap(Relation rel, FunctionCallInfo fcinfo)
CHECK_FOR_INTERRUPTS();
- /*
- * If the page has only visible tuples, then we can find out the
- * free space from the FSM and move on.
- */
+ if (blkno == next_not_all_visible_block)
+ {
+ /* Time to advance next_not_all_visible_block */
+ for (next_not_all_visible_block++;
+ next_not_all_visible_block < nblocks;
+ next_not_all_visible_block++)
+ {
+ if (!visibilitymap_test(rel, next_not_all_visible_block,
+ &vmbuffer))
+ break;
+ }
- if (visibilitymap_test(rel, blkno, &vmbuffer))
+ /*
+ * We know we can't skip the current block. But set up
+ * skipping_all_visible_blocks to do the right thing at the
+ * following blocks.
+ */
+ if (next_not_all_visible_block - blkno > SKIP_PAGES_THRESHOLD)
+ skipping_all_visible_blocks = true;
+ else
+ skipping_all_visible_blocks = false;
+ }
+ else if (skipping_all_visible_blocks)
{
+ /*
+ * We can skip this all-visible page, so we just find out
+ * the free space from the FSM.
+ */
freespace = GetRecordedFreeSpace(rel, blkno);
stat.tuple_len += BLCKSZ - freespace;
stat.free_space += freespace;