0002-Vacuum-do-a-partial-FSM-vacuum-at-the-beginning-v5.patch
text/x-patch
Filename: 0002-Vacuum-do-a-partial-FSM-vacuum-at-the-beginning-v5.patch
Type: text/x-patch
Part: 1
Patch
Format: format-patch
Series: patch v5-0002
Subject: Vacuum: do a partial FSM vacuum at the beginning
| File | + | − |
|---|---|---|
| src/backend/access/brin/brin.c | 1 | 1 |
| src/backend/access/brin/brin_pageops.c | 5 | 5 |
| src/backend/commands/vacuumlazy.c | 24 | 1 |
| src/backend/storage/freespace/freespace.c | 20 | 6 |
| src/backend/storage/freespace/indexfsm.c | 1 | 1 |
| src/include/storage/freespace.h | 1 | 1 |
From 6cb766385fa27c7de6e9419a7eee13994d47edf5 Mon Sep 17 00:00:00 2001
From: Claudio Freire <klaussfreire@gmail.com>
Date: Mon, 26 Mar 2018 13:12:22 -0300
Subject: [PATCH 2/4] Vacuum: do a partial FSM vacuum at the beginning
A partial FSM vacuum right at the start of the vacuum process
helps ameliorate issues with cancelled autovacuums never updating
the FSM.
---
src/backend/access/brin/brin.c | 2 +-
src/backend/access/brin/brin_pageops.c | 10 +++++-----
src/backend/commands/vacuumlazy.c | 25 ++++++++++++++++++++++++-
src/backend/storage/freespace/freespace.c | 26 ++++++++++++++++++++------
src/backend/storage/freespace/indexfsm.c | 2 +-
src/include/storage/freespace.h | 2 +-
6 files changed, 52 insertions(+), 15 deletions(-)
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
index 0e5849e..292bd11 100644
--- a/src/backend/access/brin/brin.c
+++ b/src/backend/access/brin/brin.c
@@ -1471,5 +1471,5 @@ brin_vacuum_scan(Relation idxrel, BufferAccessStrategy strategy)
* the way to the top.
*/
if (vacuum_fsm)
- FreeSpaceMapVacuum(idxrel);
+ FreeSpaceMapVacuum(idxrel, 0);
}
diff --git a/src/backend/access/brin/brin_pageops.c b/src/backend/access/brin/brin_pageops.c
index 60a7025..d4c7a87 100644
--- a/src/backend/access/brin/brin_pageops.c
+++ b/src/backend/access/brin/brin_pageops.c
@@ -136,7 +136,7 @@ brin_doupdate(Relation idxrel, BlockNumber pagesPerRange,
brin_initialize_empty_new_buffer(idxrel, newbuf);
UnlockReleaseBuffer(newbuf);
if (extended)
- FreeSpaceMapVacuum(idxrel);
+ FreeSpaceMapVacuum(idxrel, 0);
}
return false;
}
@@ -156,7 +156,7 @@ brin_doupdate(Relation idxrel, BlockNumber pagesPerRange,
brin_initialize_empty_new_buffer(idxrel, newbuf);
UnlockReleaseBuffer(newbuf);
if (extended)
- FreeSpaceMapVacuum(idxrel);
+ FreeSpaceMapVacuum(idxrel, 0);
}
return false;
}
@@ -211,7 +211,7 @@ brin_doupdate(Relation idxrel, BlockNumber pagesPerRange,
LockBuffer(oldbuf, BUFFER_LOCK_UNLOCK);
if (extended)
- FreeSpaceMapVacuum(idxrel);
+ FreeSpaceMapVacuum(idxrel, 0);
return true;
}
@@ -313,7 +313,7 @@ brin_doupdate(Relation idxrel, BlockNumber pagesPerRange,
{
Assert(BlockNumberIsValid(newblk));
RecordPageWithFreeSpace(idxrel, newblk, freespace);
- FreeSpaceMapVacuum(idxrel);
+ FreeSpaceMapVacuum(idxrel, 0);
}
return true;
@@ -457,7 +457,7 @@ brin_doinsert(Relation idxrel, BlockNumber pagesPerRange,
LockBuffer(revmapbuf, BUFFER_LOCK_UNLOCK);
if (extended)
- FreeSpaceMapVacuum(idxrel);
+ FreeSpaceMapVacuum(idxrel, 0);
return off;
}
diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c
index c44996f..ff807a3 100644
--- a/src/backend/commands/vacuumlazy.c
+++ b/src/backend/commands/vacuumlazy.c
@@ -116,6 +116,18 @@
*/
#define PREFETCH_SIZE ((BlockNumber) 32)
+/*
+ * If autovacuums get regularly cancelled, the FSM may never be
+ * vacuumed. To work around that, we perform an initial partial
+ * FSM vacuum at the beginning of the vacuum process, to quickly
+ * make existing unmarked free space visible. To avoid useless
+ * redundant work, however, we avoid recursing into branches
+ * that already have a set amount of free space, we only try
+ * to discover unmarked free space. This value controls how
+ * much free space is enough free space in that context.
+ */
+#define INITIAL_PARTIAL_FSM_VACUUM_THRESHOLD ((Size) BLCKSZ/4)
+
typedef struct LVRelStats
{
/* hasindex = true means two-pass strategy; false means one-pass */
@@ -262,6 +274,17 @@ lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params,
vacrelstats->pages_removed = 0;
vacrelstats->lock_waiter_detected = false;
+ /*
+ * Vacuum the Free Space Map partially before we start.
+ * If an earlier vacuum was canceled, and that's likely in
+ * highly contended tables, we may need to finish up. If we do
+ * it now, we make the space visible to other backends regardless
+ * of whether we succeed in finishing this time around.
+ * Don't bother checking branches that already have usable space,
+ * though.
+ */
+ FreeSpaceMapVacuum(onerel, INITIAL_PARTIAL_FSM_VACUUM_THRESHOLD);
+
/* Open all indexes of the relation */
vac_open_indexes(onerel, RowExclusiveLock, &nindexes, &Irel);
vacrelstats->hasindex = (nindexes > 0);
@@ -299,7 +322,7 @@ lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params,
PROGRESS_VACUUM_PHASE_FINAL_CLEANUP);
/* Vacuum the Free Space Map */
- FreeSpaceMapVacuum(onerel);
+ FreeSpaceMapVacuum(onerel, 0);
/*
* Update statistics in pg_class.
diff --git a/src/backend/storage/freespace/freespace.c b/src/backend/storage/freespace/freespace.c
index 6fce3ab..2f48092 100644
--- a/src/backend/storage/freespace/freespace.c
+++ b/src/backend/storage/freespace/freespace.c
@@ -108,7 +108,7 @@ static Size fsm_space_cat_to_avail(uint8 cat);
static int fsm_set_and_search(Relation rel, FSMAddress addr, uint16 slot,
uint8 newValue, uint8 minValue);
static BlockNumber fsm_search(Relation rel, uint8 min_cat);
-static uint8 fsm_vacuum_page(Relation rel, FSMAddress addr, bool *eof,
+static uint8 fsm_vacuum_page(Relation rel, FSMAddress addr, uint8 threshold, bool *eof,
BlockNumber start, BlockNumber end);
static BlockNumber fsm_get_lastblckno(Relation rel, FSMAddress addr);
static void fsm_update_recursive(Relation rel, FSMAddress addr, uint8 new_cat);
@@ -375,9 +375,15 @@ FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks)
/*
* FreeSpaceMapVacuum - scan and fix any inconsistencies in the FSM
+ *
+ * If threshold is nonzero, a partial scan is made, skipping branches
+ * that already contain that much free space. Such a can be faster
+ * if many branches can be skipped, but it can't guarantee all
+ * inconsistencies will be fixed, only those under branches with less
+ * free space recorded than the threshold.
*/
void
-FreeSpaceMapVacuum(Relation rel)
+FreeSpaceMapVacuum(Relation rel, Size threshold)
{
bool dummy;
@@ -385,7 +391,7 @@ FreeSpaceMapVacuum(Relation rel)
* Traverse the tree in depth-first order. The tree is stored physically
* in depth-first order, so this should be pretty I/O efficient.
*/
- fsm_vacuum_page(rel, FSM_ROOT_ADDRESS, &dummy,
+ fsm_vacuum_page(rel, FSM_ROOT_ADDRESS, fsm_space_avail_to_cat(threshold), &dummy,
(BlockNumber) 0, MaxBlockNumber);
}
@@ -403,7 +409,7 @@ FreeSpaceMapVacuumRange(Relation rel, BlockNumber start, BlockNumber end)
* Traverse the tree in depth-first order. The tree is stored physically
* in depth-first order, so this should be pretty I/O efficient.
*/
- fsm_vacuum_page(rel, FSM_ROOT_ADDRESS, &dummy, start, end);
+ fsm_vacuum_page(rel, FSM_ROOT_ADDRESS, 0, &dummy, start, end);
}
/******** Internal routines ********/
@@ -807,7 +813,7 @@ fsm_search(Relation rel, uint8 min_cat)
* that already contain that much free space recorded.
*/
static uint8
-fsm_vacuum_page(Relation rel, FSMAddress addr, bool *eof_p,
+fsm_vacuum_page(Relation rel, FSMAddress addr, uint8 threshold, bool *eof_p,
BlockNumber start, BlockNumber end)
{
Buffer buf;
@@ -870,11 +876,19 @@ fsm_vacuum_page(Relation rel, FSMAddress addr, bool *eof_p,
{
int child_avail;
+ /* Tree pruning for partial vacuums */
+ if (threshold)
+ {
+ child_avail = fsm_get_avail(page, slot);
+ if (child_avail >= threshold)
+ continue;
+ }
+
CHECK_FOR_INTERRUPTS();
/* After we hit end-of-file, just clear the rest of the slots */
if (!eof)
- child_avail = fsm_vacuum_page(rel, fsm_get_child(addr, slot), &eof,
+ child_avail = fsm_vacuum_page(rel, fsm_get_child(addr, slot), threshold, &eof,
start, end);
else
child_avail = 0;
diff --git a/src/backend/storage/freespace/indexfsm.c b/src/backend/storage/freespace/indexfsm.c
index e21047b..dd77a16 100644
--- a/src/backend/storage/freespace/indexfsm.c
+++ b/src/backend/storage/freespace/indexfsm.c
@@ -70,5 +70,5 @@ RecordUsedIndexPage(Relation rel, BlockNumber usedBlock)
void
IndexFreeSpaceMapVacuum(Relation rel)
{
- FreeSpaceMapVacuum(rel);
+ FreeSpaceMapVacuum(rel, 0);
}
diff --git a/src/include/storage/freespace.h b/src/include/storage/freespace.h
index 13f6380..f9fe2e4 100644
--- a/src/include/storage/freespace.h
+++ b/src/include/storage/freespace.h
@@ -31,7 +31,7 @@ extern void XLogRecordPageWithFreeSpace(RelFileNode rnode, BlockNumber heapBlk,
Size spaceAvail);
extern void FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks);
-extern void FreeSpaceMapVacuum(Relation rel);
+extern void FreeSpaceMapVacuum(Relation rel, Size threshold);
extern void FreeSpaceMapVacuumRange(Relation rel, BlockNumber start,
BlockNumber end);
extern void UpdateFreeSpaceMap(Relation rel,
--
1.8.4.5