Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 12b5ade

Browse files
Update high level vacuumlazy.c comments.
Update vacuumlazy.c file header comments (as well as comments above the lazy_scan_heap function) that were largely written before the introduction of the HOT optimization, when lazy_scan_heap did far less, and didn't actually prune during its initial heap pass. Since lazy_scan_heap now outsources far more work to lower level functions, it makes sense to introduce the function by talking about the high level invariant that dictates the order in which each phase takes place. Also deemphasize the case where we run out of memory for TIDs, since delaying that discussion makes it easier to talk about issues of central importance. Finally, remove discussion of parallel VACUUM from header comments. These don't add much, and are in the wrong place.
1 parent f744519 commit 12b5ade

File tree

1 file changed

+70
-68
lines changed

1 file changed

+70
-68
lines changed

src/backend/access/heap/vacuumlazy.c

+70-68
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,23 @@
33
* vacuumlazy.c
44
* Concurrent ("lazy") vacuuming.
55
*
6-
*
7-
* The major space usage for LAZY VACUUM is storage for the array of dead tuple
8-
* TIDs. We want to ensure we can vacuum even the very largest relations with
9-
* finite memory space usage. To do that, we set upper bounds on the number of
10-
* tuples we will keep track of at once.
6+
* The major space usage for vacuuming is storage for the array of dead TIDs
7+
* that are to be removed from indexes. We want to ensure we can vacuum even
8+
* the very largest relations with finite memory space usage. To do that, we
9+
* set upper bounds on the number of TIDs we can keep track of at once.
1110
*
1211
* We are willing to use at most maintenance_work_mem (or perhaps
13-
* autovacuum_work_mem) memory space to keep track of dead tuples. We
14-
* initially allocate an array of TIDs of that size, with an upper limit that
15-
* depends on table size (this limit ensures we don't allocate a huge area
16-
* uselessly for vacuuming small tables). If the array threatens to overflow,
17-
* we suspend the heap scan phase and perform a pass of index cleanup and page
18-
* compaction, then resume the heap scan with an empty TID array.
19-
*
20-
* If we're processing a table with no indexes, we can just vacuum each page
21-
* as we go; there's no need to save up multiple tuples to minimize the number
22-
* of index scans performed. So we don't use maintenance_work_mem memory for
23-
* the TID array, just enough to hold as many heap tuples as fit on one page.
12+
* autovacuum_work_mem) memory space to keep track of dead TIDs. We initially
13+
* allocate an array of TIDs of that size, with an upper limit that depends on
14+
* table size (this limit ensures we don't allocate a huge area uselessly for
15+
* vacuuming small tables). If the array threatens to overflow, we must call
16+
* lazy_vacuum to vacuum indexes (and to vacuum the pages that we've pruned).
17+
* This frees up the memory space dedicated to storing dead TIDs.
2418
*
25-
* Lazy vacuum supports parallel execution with parallel worker processes. In
26-
* a parallel vacuum, we perform both index vacuum and index cleanup with
27-
* parallel worker processes. Individual indexes are processed by one vacuum
28-
* process. At the beginning of a lazy vacuum (at lazy_scan_heap) we prepare
29-
* the parallel context and initialize the DSM segment that contains shared
30-
* information as well as the memory space for storing dead tuples. When
31-
* starting either index vacuum or index cleanup, we launch parallel worker
32-
* processes. Once all indexes are processed the parallel worker processes
33-
* exit. After that, the leader process re-initializes the parallel context
34-
* so that it can use the same DSM for multiple passes of index vacuum and
35-
* for performing index cleanup. For updating the index statistics, we need
36-
* to update the system table and since updates are not allowed during
37-
* parallel mode we update the index statistics after exiting from the
38-
* parallel mode.
19+
* In practice VACUUM will often complete its initial pass over the target
20+
* heap relation without ever running out of space to store TIDs. This means
21+
* that there only needs to be one call to lazy_vacuum, after the initial pass
22+
* completes.
3923
*
4024
* Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
4125
* Portions Copyright (c) 1994, Regents of the University of California
@@ -124,13 +108,6 @@
124108
#define VACUUM_FSM_EVERY_PAGES \
125109
((BlockNumber) (((uint64) 8 * 1024 * 1024 * 1024) / BLCKSZ))
126110

127-
/*
128-
* Guesstimation of number of dead tuples per page. This is used to
129-
* provide an upper limit to memory allocated when vacuuming small
130-
* tables.
131-
*/
132-
#define LAZY_ALLOC_TUPLES MaxHeapTuplesPerPage
133-
134111
/*
135112
* Before we consider skipping a page that's marked as clean in
136113
* visibility map, we must've seen at least this many clean pages.
@@ -472,8 +449,9 @@ static void restore_vacuum_error_info(LVRelState *vacrel,
472449
/*
473450
* heap_vacuum_rel() -- perform VACUUM for one heap relation
474451
*
475-
* This routine vacuums a single heap, cleans out its indexes, and
476-
* updates its relpages and reltuples statistics.
452+
* This routine sets things up for and then calls lazy_scan_heap, where
453+
* almost all work actually takes place. Finalizes everything after call
454+
* returns by managing rel truncation and updating pg_class statistics.
477455
*
478456
* At entry, we have already established a transaction and opened
479457
* and locked the relation.
@@ -631,7 +609,10 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
631609
errcallback.previous = error_context_stack;
632610
error_context_stack = &errcallback;
633611

634-
/* Do the vacuuming */
612+
/*
613+
* Call lazy_scan_heap to perform all required heap pruning, index
614+
* vacuuming, and heap vacuuming (plus related processing)
615+
*/
635616
lazy_scan_heap(vacrel, params, aggressive);
636617

637618
/* Done with indexes */
@@ -714,8 +695,8 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
714695
*
715696
* Deliberately avoid telling the stats collector about LP_DEAD items that
716697
* remain in the table due to VACUUM bypassing index and heap vacuuming.
717-
* ANALYZE will consider the remaining LP_DEAD items to be dead tuples. It
718-
* seems like a good idea to err on the side of not vacuuming again too
698+
* ANALYZE will consider the remaining LP_DEAD items to be dead "tuples".
699+
* It seems like a good idea to err on the side of not vacuuming again too
719700
* soon in cases where the failsafe prevented significant amounts of heap
720701
* vacuuming.
721702
*/
@@ -875,20 +856,40 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
875856
}
876857

877858
/*
878-
* lazy_scan_heap() -- scan an open heap relation
859+
* lazy_scan_heap() -- workhorse function for VACUUM
860+
*
861+
* This routine prunes each page in the heap, and considers the need to
862+
* freeze remaining tuples with storage (not including pages that can be
863+
* skipped using the visibility map). Also performs related maintenance
864+
* of the FSM and visibility map. These steps all take place during an
865+
* initial pass over the target heap relation.
866+
*
867+
* Also invokes lazy_vacuum_all_indexes to vacuum indexes, which largely
868+
* consists of deleting index tuples that point to LP_DEAD items left in
869+
* heap pages following pruning. Earlier initial pass over the heap will
870+
* have collected the TIDs whose index tuples need to be removed.
879871
*
880-
* This routine prunes each page in the heap, which will among other
881-
* things truncate dead tuples to dead line pointers, defragment the
882-
* page, and set commit status bits (see heap_page_prune). It also builds
883-
* lists of dead tuples and pages with free space, calculates statistics
884-
* on the number of live tuples in the heap, and marks pages as
885-
* all-visible if appropriate. When done, or when we run low on space
886-
* for dead-tuple TIDs, invoke lazy_vacuum to vacuum indexes and vacuum
887-
* heap relation during its own second pass over the heap.
872+
* Finally, invokes lazy_vacuum_heap_rel to vacuum heap pages, which
873+
* largely consists of marking LP_DEAD items (from collected TID array)
874+
* as LP_UNUSED. This has to happen in a second, final pass over the
875+
* heap, to preserve a basic invariant that all index AMs rely on: no
876+
* extant index tuple can ever be allowed to contain a TID that points to
877+
* an LP_UNUSED line pointer in the heap. We must disallow premature
878+
* recycling of line pointers to avoid index scans that get confused
879+
* about which TID points to which tuple immediately after recycling.
880+
* (Actually, this isn't a concern when target heap relation happens to
881+
* have no indexes, which allows us to safely apply the one-pass strategy
882+
* as an optimization).
888883
*
889-
* If there are no indexes then we can reclaim line pointers on the fly;
890-
* dead line pointers need only be retained until all index pointers that
891-
* reference them have been killed.
884+
* In practice we often have enough space to fit all TIDs, and so won't
885+
* need to call lazy_vacuum more than once, after our initial pass over
886+
* the heap has totally finished. Otherwise things are slightly more
887+
* complicated: our "initial pass" over the heap applies only to those
888+
* pages that were pruned before we needed to call lazy_vacuum, and our
889+
* "final pass" over the heap only vacuums these same heap pages.
890+
* However, we process indexes in full every time lazy_vacuum is called,
891+
* which makes index processing very inefficient when memory is in short
892+
* supply.
892893
*/
893894
static void
894895
lazy_scan_heap(LVRelState *vacrel, VacuumParams *params, bool aggressive)
@@ -1173,7 +1174,7 @@ lazy_scan_heap(LVRelState *vacrel, VacuumParams *params, bool aggressive)
11731174
vmbuffer = InvalidBuffer;
11741175
}
11751176

1176-
/* Remove the collected garbage tuples from table and indexes */
1177+
/* Perform a round of index and heap vacuuming */
11771178
vacrel->consider_bypass_optimization = false;
11781179
lazy_vacuum(vacrel);
11791180

@@ -1490,12 +1491,12 @@ lazy_scan_heap(LVRelState *vacrel, VacuumParams *params, bool aggressive)
14901491
* visible to everyone yet actually are, and the PD_ALL_VISIBLE flag
14911492
* is correct.
14921493
*
1493-
* There should never be dead tuples on a page with PD_ALL_VISIBLE
1494+
* There should never be LP_DEAD items on a page with PD_ALL_VISIBLE
14941495
* set, however.
14951496
*/
14961497
else if (prunestate.has_lpdead_items && PageIsAllVisible(page))
14971498
{
1498-
elog(WARNING, "page containing dead tuples is marked as all-visible in relation \"%s\" page %u",
1499+
elog(WARNING, "page containing LP_DEAD items is marked as all-visible in relation \"%s\" page %u",
14991500
vacrel->relname, blkno);
15001501
PageClearAllVisible(page);
15011502
MarkBufferDirty(buf);
@@ -1585,7 +1586,7 @@ lazy_scan_heap(LVRelState *vacrel, VacuumParams *params, bool aggressive)
15851586
vmbuffer = InvalidBuffer;
15861587
}
15871588

1588-
/* If any tuples need to be deleted, perform final vacuum cycle */
1589+
/* Perform a final round of index and heap vacuuming */
15891590
if (dead_tuples->num_tuples > 0)
15901591
lazy_vacuum(vacrel);
15911592

@@ -1816,13 +1817,14 @@ lazy_scan_prune(LVRelState *vacrel,
18161817
* VACUUM can't run inside a transaction block, which makes some cases
18171818
* impossible (e.g. in-progress insert from the same transaction).
18181819
*
1819-
* We treat LP_DEAD items a little differently, too -- we don't count
1820-
* them as dead_tuples at all (we only consider new_dead_tuples). The
1821-
* outcome is no different because we assume that any LP_DEAD items we
1822-
* encounter here will become LP_UNUSED inside lazy_vacuum_heap_page()
1823-
* before we report anything to the stats collector. (Cases where we
1824-
* bypass index vacuuming will violate our assumption, but the overall
1825-
* impact of that should be negligible.)
1820+
* We treat LP_DEAD items (which are the closest thing to DEAD tuples
1821+
* that might be seen here) differently, too: we assume that they'll
1822+
* become LP_UNUSED before VACUUM finishes. This difference is only
1823+
* superficial. VACUUM effectively agrees with ANALYZE about DEAD
1824+
* items, in the end. VACUUM won't remember LP_DEAD items, but only
1825+
* because they're not supposed to be left behind when it is done.
1826+
* (Cases where we bypass index vacuuming will violate this optimistic
1827+
* assumption, but the overall impact of that should be negligible.)
18261828
*/
18271829
switch (res)
18281830
{
@@ -2169,7 +2171,7 @@ lazy_vacuum(LVRelState *vacrel)
21692171
/*
21702172
* Failsafe case.
21712173
*
2172-
* we attempted index vacuuming, but didn't finish a full round/full
2174+
* We attempted index vacuuming, but didn't finish a full round/full
21732175
* index scan. This happens when relfrozenxid or relminmxid is too
21742176
* far in the past.
21752177
*
@@ -3448,8 +3450,8 @@ compute_max_dead_tuples(BlockNumber relblocks, bool hasindex)
34483450
maxtuples = Min(maxtuples, MAXDEADTUPLES(MaxAllocSize));
34493451

34503452
/* curious coding here to ensure the multiplication can't overflow */
3451-
if ((BlockNumber) (maxtuples / LAZY_ALLOC_TUPLES) > relblocks)
3452-
maxtuples = relblocks * LAZY_ALLOC_TUPLES;
3453+
if ((BlockNumber) (maxtuples / MaxHeapTuplesPerPage) > relblocks)
3454+
maxtuples = relblocks * MaxHeapTuplesPerPage;
34533455

34543456
/* stay sane if small maintenance_work_mem */
34553457
maxtuples = Max(maxtuples, MaxHeapTuplesPerPage);

0 commit comments

Comments
 (0)