71 #define REL_TRUNCATE_MINIMUM 1000 72 #define REL_TRUNCATE_FRACTION 16 81 #define VACUUM_TRUNCATE_LOCK_CHECK_INTERVAL 20 82 #define VACUUM_TRUNCATE_LOCK_WAIT_INTERVAL 50 83 #define VACUUM_TRUNCATE_LOCK_TIMEOUT 5000 91 #define VACUUM_FSM_EVERY_PAGES \ 92 ((BlockNumber) (((uint64) 8 * 1024 * 1024 * 1024) / BLCKSZ)) 99 #define LAZY_ALLOC_TUPLES MaxHeapTuplesPerPage 105 #define SKIP_PAGES_THRESHOLD ((BlockNumber) 32) 111 #define PREFETCH_SIZE ((BlockNumber) 32) 203 bool scanned_all_unfrozen;
235 vac_strategy = bstrategy;
267 (
errmsg(
"skipping redundant vacuum to prevent wraparound of table \"%s.%s.%s\"",
285 vacrelstats->
useindex = (nindexes > 0 &&
289 lazy_scan_heap(onerel, params, vacrelstats, Irel, nindexes, aggressive);
305 scanned_all_unfrozen =
false;
308 scanned_all_unfrozen =
true;
350 if (new_rel_allvisible > new_rel_pages)
351 new_rel_allvisible = new_rel_pages;
367 onerel->
rd_rel->relisshared,
388 if ((secs > 0) || (usecs > 0))
391 (secs + usecs / 1000000.0);
393 (secs + usecs / 1000000.0);
405 msgfmt =
_(
"automatic aggressive vacuum to prevent wraparound of table \"%s.%s.%s\": index scans: %d\n");
410 msgfmt =
_(
"automatic aggressive vacuum of table \"%s.%s.%s\": index scans: %d\n");
412 msgfmt =
_(
"automatic vacuum of table \"%s.%s.%s\": index scans: %d\n");
419 appendStringInfo(&buf,
_(
"pages: %u removed, %u remain, %u skipped due to pins, %u skipped frozen\n"),
425 _(
"tuples: %.0f removed, %.0f remain, %.0f are dead but not yet removable, oldest xmin: %u\n"),
431 _(
"buffer usage: %d hits, %d misses, %d dirtied\n"),
435 appendStringInfo(&buf,
_(
"avg read rate: %.3f MB/s, avg write rate: %.3f MB/s\n"),
436 read_rate, write_rate);
497 Relation *Irel,
int nindexes,
bool aggressive)
507 next_fsm_block_to_vacuum;
518 bool skipping_blocks;
521 const int initprog_index[] = {
526 int64 initprog_val[3];
533 (
errmsg(
"aggressively vacuuming \"%s.%s\"",
538 (
errmsg(
"vacuuming \"%s.%s\"",
542 empty_pages = vacuumed_pages = 0;
544 num_tuples = live_tuples = tups_vacuumed = nkeep = nunused = 0;
561 initprog_val[1] = nblocks;
609 next_unskippable_block = 0;
612 while (next_unskippable_block < nblocks)
629 next_unskippable_block++;
634 skipping_blocks =
true;
636 skipping_blocks =
false;
638 for (blkno = 0; blkno < nblocks; blkno++)
649 bool all_visible_according_to_vm =
false;
651 bool all_frozen =
true;
652 bool has_dead_tuples;
656 #define FORCE_CHECK_PAGE() \ 657 (blkno == nblocks - 1 && should_attempt_truncation(params, vacrelstats)) 661 if (blkno == next_unskippable_block)
664 next_unskippable_block++;
667 while (next_unskippable_block < nblocks)
672 next_unskippable_block,
685 next_unskippable_block++;
694 skipping_blocks =
true;
696 skipping_blocks =
false;
704 all_visible_according_to_vm =
true;
731 all_visible_according_to_vm =
true;
743 const int hvp_index[] = {
769 for (i = 0; i < nindexes; i++)
800 next_fsm_block_to_vacuum = blkno;
985 has_dead_tuples =
false;
1028 all_visible =
false;
1087 all_visible =
false;
1112 all_visible =
false;
1123 all_visible =
false;
1129 visibility_cutoff_xid = xmin;
1139 all_visible =
false;
1153 all_visible =
false;
1157 all_visible =
false;
1167 elog(
ERROR,
"unexpected HeapTupleSatisfiesVacuum result");
1177 has_dead_tuples =
true;
1181 bool tuple_totally_frozen;
1191 relfrozenxid, relminmxid,
1194 &tuple_totally_frozen))
1195 frozen[nfrozen++].
offset = offnum;
1197 if (!tuple_totally_frozen)
1214 for (i = 0; i < nfrozen; i++)
1250 has_dead_tuples =
false;
1284 next_fsm_block_to_vacuum = blkno;
1291 if (all_visible && !all_visible_according_to_vm)
1314 vmbuffer, visibility_cutoff_xid, flags);
1327 elog(
WARNING,
"page is not marked all-visible but visibility map bit is set in relation \"%s\" page %u",
1348 elog(
WARNING,
"page containing dead tuples is marked as all-visible in relation \"%s\" page %u",
1361 else if (all_visible_according_to_vm && all_visible && all_frozen &&
1423 const int hvp_index[] = {
1437 for (i = 0; i < nindexes; i++)
1458 if (blkno > next_fsm_block_to_vacuum)
1469 for (i = 0; i < nindexes; i++)
1476 (
errmsg(
"\"%s\": removed %.0f row versions in %u pages",
1478 tups_vacuumed, vacuumed_pages)));
1486 _(
"%.0f dead row versions cannot be removed yet, oldest xmin: %u\n"),
1491 "Skipped %u pages due to buffer pins, ",
1495 "%u frozen pages.\n",
1499 "%u pages are entirely empty.\n",
1505 (
errmsg(
"\"%s\": found %.0f removable, %.0f nonremovable row versions in %u out of %u pages",
1507 tups_vacuumed, num_tuples,
1574 (
errmsg(
"\"%s\": removed %d row versions in %d pages",
1616 unused[uncnt++] = toff;
1675 *vmbuffer, visibility_cutoff_xid, flags);
1751 ivinfo.
index = indrel;
1765 (
errmsg(
"scanned index \"%s\" to remove %d row versions",
1767 vacrelstats->num_dead_tuples),
1784 ivinfo.
index = indrel;
1818 (
errmsg(
"index \"%s\" now contains %.0f row versions in %u pages",
1822 errdetail(
"%.0f index row versions were removed.\n" 1823 "%u index pages have been deleted, %u are currently reusable.\n" 1860 if (possibly_freeable > 0 &&
1920 (
errmsg(
"\"%s\": stopping truncate due to conflicting lock request",
1934 if (new_rel_pages != old_rel_pages)
1955 if (new_rel_pages >= old_rel_pages)
1981 vacrelstats->
pages_removed += old_rel_pages - new_rel_pages;
1985 (
errmsg(
"\"%s\": truncated %u to %u pages",
1987 old_rel_pages, new_rel_pages),
1990 old_rel_pages = new_rel_pages;
2018 "prefetch size must be power of 2");
2036 if ((blkno % 32) == 0)
2042 elapsed = currenttime;
2050 (
errmsg(
"\"%s\": suspending truncate due to conflicting lock request",
2056 starttime = currenttime;
2070 if (prefetchedUntil > blkno)
2076 for (pblkno = prefetchStart; pblkno <= blkno; pblkno++)
2081 prefetchedUntil = prefetchStart;
2152 maxtuples =
Min(maxtuples, INT_MAX);
2213 return (res != NULL);
2261 bool all_visible =
true;
2272 offnum <= maxoff && all_visible;
2292 all_visible =
false;
2293 *all_frozen =
false;
2312 all_visible =
false;
2313 *all_frozen =
false;
2324 all_visible =
false;
2325 *all_frozen =
false;
2331 *visibility_cutoff_xid = xmin;
2334 if (all_visible && *all_frozen &&
2336 *all_frozen =
false;
2345 all_visible =
false;
2346 *all_frozen =
false;
2350 elog(
ERROR,
"unexpected HeapTupleSatisfiesVacuum result");
void HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple, TransactionId *latestRemovedXid)
XLogRecPtr log_heap_cleanup_info(RelFileNode rnode, TransactionId latestRemovedXid)
int multixact_freeze_table_age
void vac_close_indexes(int nindexes, Relation *Irel, LOCKMODE lockmode)
#define BUFFER_LOCK_UNLOCK
static int lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer, int tupindex, LVRelStats *vacrelstats, Buffer *vmbuffer)
int heap_page_prune(Relation relation, Buffer buffer, TransactionId OldestXmin, bool report_stats, TransactionId *latestRemovedXid)
void LockBufferForCleanup(Buffer buffer)
XLogRecPtr log_heap_freeze(Relation reln, Buffer buffer, TransactionId cutoff_xid, xl_heap_freeze_tuple *tuples, int ntuples)
#define PROGRESS_VACUUM_HEAP_BLKS_VACUUMED
#define InvalidXLogRecPtr
#define PageIsEmpty(page)
static BlockNumber count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats)
XLogRecPtr log_newpage_buffer(Buffer buffer, bool page_std)
double vac_estimate_reltuples(Relation relation, BlockNumber total_pages, BlockNumber scanned_pages, double scanned_tuples)
static void lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats)
static bool lazy_tid_reaped(ItemPointer itemptr, void *state)
#define ItemIdIsRedirected(itemId)
static void lazy_record_dead_tuple(LVRelStats *vacrelstats, ItemPointer itemptr)
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
#define PageIsAllVisible(page)
void UnlockRelation(Relation relation, LOCKMODE lockmode)
void RecordPageWithFreeSpace(Relation rel, BlockNumber heapBlk, Size spaceAvail)
void pgstat_progress_start_command(ProgressCommandType cmdtype, Oid relid)
#define PROGRESS_VACUUM_MAX_DEAD_TUPLES
#define PROGRESS_VACUUM_PHASE_VACUUM_INDEX
void visibilitymap_pin(Relation rel, BlockNumber heapBlk, Buffer *buf)
TimestampTz GetCurrentTimestamp(void)
void visibilitymap_set(Relation rel, BlockNumber heapBlk, Buffer heapBuf, XLogRecPtr recptr, Buffer vmBuf, TransactionId cutoff_xid, uint8 flags)
void MarkBufferDirty(Buffer buffer)
HeapTupleHeaderData * HeapTupleHeader
void pgstat_progress_update_param(int index, int64 val)
#define VISIBILITYMAP_ALL_FROZEN
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
struct timeval instr_time
BlockNumber tupcount_pages
#define END_CRIT_SECTION()
BufferAccessStrategy strategy
#define ItemIdIsUsed(itemId)
#define MaxHeapTuplesPerPage
#define VM_ALL_FROZEN(r, b, v)
#define PROGRESS_VACUUM_HEAP_BLKS_SCANNED
static void lazy_cleanup_index(Relation indrel, IndexBulkDeleteResult *stats, LVRelStats *vacrelstats)
#define PROGRESS_VACUUM_TOTAL_HEAP_BLKS
#define START_CRIT_SECTION()
BlockNumber scanned_pages
#define VACUUM_TRUNCATE_LOCK_TIMEOUT
void vacuum_set_xid_limits(Relation rel, int freeze_min_age, int freeze_table_age, int multixact_freeze_min_age, int multixact_freeze_table_age, TransactionId *oldestXmin, TransactionId *freezeLimit, TransactionId *xidFullScanLimit, MultiXactId *multiXactCutoff, MultiXactId *mxactFullScanLimit)
void ReleaseBuffer(Buffer buffer)
BlockNumber pinskipped_pages
void visibilitymap_count(Relation rel, BlockNumber *all_visible, BlockNumber *all_frozen)
#define SizeOfPageHeaderData
#define ItemIdIsDead(itemId)
bool TimestampDifferenceExceeds(TimestampTz start_time, TimestampTz stop_time, int msec)
#define PageGetMaxOffsetNumber(page)
int errdetail_internal(const char *fmt,...)
ItemPointerData * ItemPointer
#define VISIBILITYMAP_VALID_BITS
void pg_rusage_init(PGRUsage *ru0)
bool heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId relfrozenxid, TransactionId relminmxid, TransactionId cutoff_xid, TransactionId cutoff_multi, xl_heap_freeze_tuple *frz, bool *totally_frozen_p)
#define FORCE_CHECK_PAGE()
#define PROGRESS_VACUUM_PHASE_TRUNCATE
#define HeapTupleIsHotUpdated(tuple)
#define StaticAssertStmt(condition, errmessage)
BlockNumber old_rel_pages
void pg_usleep(long microsec)
bool heap_tuple_needs_eventual_freeze(HeapTupleHeader tuple)
#define ItemIdGetLength(itemId)
void pfree(void *pointer)
void appendStringInfo(StringInfo str, const char *fmt,...)
bool visibilitymap_clear(Relation rel, BlockNumber heapBlk, Buffer buf, uint8 flags)
#define VACUUM_FSM_EVERY_PAGES
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
void UnlockReleaseBuffer(Buffer buffer)
bool ConditionalLockBufferForCleanup(Buffer buffer)
#define REL_TRUNCATE_MINIMUM
Size PageGetHeapFreeSpace(Page page)
#define INSTR_TIME_SUBTRACT(x, y)
char * get_database_name(Oid dbid)
#define HeapTupleHeaderXminCommitted(tup)
static TransactionId FreezeLimit
void heap_execute_freeze_tuple(HeapTupleHeader tuple, xl_heap_freeze_tuple *frz)
char * get_namespace_name(Oid nspid)
#define PageSetAllVisible(page)
#define FirstOffsetNumber
int errdetail(const char *fmt,...)
static MultiXactId MultiXactCutoff
const char * pg_rusage_show(const PGRUsage *ru0)
bool ConditionalLockRelation(Relation relation, LOCKMODE lockmode)
#define InvalidTransactionId
#define RelationGetRelationName(relation)
static TransactionId OldestXmin
#define MultiXactIdIsValid(multi)
BlockNumber pages_deleted
#define BufferGetPage(buffer)
HTSV_Result HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin, Buffer buffer)
bool IsAutoVacuumWorkerProcess(void)
#define ereport(elevel, rest)
bool heap_tuple_needs_freeze(HeapTupleHeader tuple, TransactionId cutoff_xid, MultiXactId cutoff_multi, Buffer buf)
#define PROGRESS_VACUUM_NUM_DEAD_TUPLES
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
VacOptTernaryValue index_cleanup
static bool heap_page_is_all_visible(Relation rel, Buffer buf, TransactionId *visibility_cutoff_xid, bool *all_frozen)
#define SKIP_PAGES_THRESHOLD
#define VACUUM_TRUNCATE_LOCK_WAIT_INTERVAL
void initStringInfo(StringInfo str)
void vac_open_indexes(Relation relation, LOCKMODE lockmode, int *nindexes, Relation **Irel)
#define PageGetItemId(page, offsetNumber)
#define ngettext(s, p, n)
Size GetRecordedFreeSpace(Relation rel, BlockNumber heapBlk)
void * palloc0(Size size)
#define VACUUM_TRUNCATE_LOCK_CHECK_INTERVAL
void pgstat_progress_end_command(void)
IndexBulkDeleteResult * index_bulk_delete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
void heap_vacuum_rel(Relation onerel, VacuumParams *params, BufferAccessStrategy bstrategy)
#define BufferGetPageSize(buffer)
void LockBuffer(Buffer buffer, int mode)
#define InvalidMultiXactId
#define RelationGetNumberOfBlocks(reln)
static bool should_attempt_truncation(VacuumParams *params, LVRelStats *vacrelstats)
VacOptTernaryValue truncate
#define PROGRESS_VACUUM_PHASE_FINAL_CLEANUP
void PrefetchBuffer(Relation reln, ForkNumber forkNum, BlockNumber blockNum)
bool LockHasWaitersRelation(Relation relation, LOCKMODE lockmode)
static void vacuum_log_cleanup_info(Relation rel, LVRelStats *vacrelstats)
TransactionId MultiXactId
int errmsg_internal(const char *fmt,...)
static BufferAccessStrategy vac_strategy
#define PageClearAllVisible(page)
#define HeapTupleIsHeapOnly(tuple)
#define Assert(condition)
TransactionId latestRemovedXid
#define ItemIdIsNormal(itemId)
#define INSTR_TIME_GET_MICROSEC(t)
static void lazy_vacuum_index(Relation indrel, IndexBulkDeleteResult **stats, LVRelStats *vacrelstats)
#define PROGRESS_VACUUM_PHASE_INDEX_CLEANUP
#define HeapTupleHeaderGetXmin(tup)
#define VM_ALL_VISIBLE(r, b, v)
void pgstat_progress_update_multi_param(int nparam, const int *index, const int64 *val)
#define OffsetNumberNext(offsetNumber)
#define PROGRESS_VACUUM_NUM_INDEX_VACUUMS
#define PROGRESS_VACUUM_PHASE_SCAN_HEAP
#define PROGRESS_VACUUM_PHASE
#define InvalidBlockNumber
XLogRecPtr log_heap_clean(Relation reln, Buffer buffer, OffsetNumber *redirected, int nredirected, OffsetNumber *nowdead, int ndead, OffsetNumber *nowunused, int nunused, TransactionId latestRemovedXid)
#define BufferIsValid(bufnum)
#define ItemPointerGetOffsetNumber(pointer)
#define RelationNeedsWAL(relation)
IndexBulkDeleteResult * index_vacuum_cleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
#define VISIBILITYMAP_ALL_VISIBLE
struct LVRelStats LVRelStats
#define INSTR_TIME_SET_CURRENT(t)
void pgstat_report_vacuum(Oid tableoid, bool shared, PgStat_Counter livetuples, PgStat_Counter deadtuples)
#define AccessExclusiveLock
BlockNumber BufferGetBlockNumber(Buffer buffer)
BlockNumber pages_removed
BlockNumber nonempty_pages
void PageRepairFragmentation(Page page)
int errmsg(const char *fmt,...)
static void lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats, Relation *Irel, int nindexes, bool aggressive)
uint8 visibilitymap_get_status(Relation rel, BlockNumber heapBlk, Buffer *buf)
BlockNumber frozenskipped_pages
TransactionId relfrozenxid
int old_snapshot_threshold
bool MultiXactIdPrecedesOrEquals(MultiXactId multi1, MultiXactId multi2)
#define BUFFER_LOCK_SHARE
static bool lazy_check_needs_freeze(Buffer buf, bool *hastup)
#define CHECK_FOR_INTERRUPTS()
#define ItemPointerGetBlockNumber(pointer)
#define TransactionIdIsValid(xid)
#define ItemIdSetUnused(itemId)
static int vac_cmp_itemptr(const void *left, const void *right)
void vacuum_delay_point(void)
void TimestampDifference(TimestampTz start_time, TimestampTz stop_time, long *secs, int *microsecs)
#define TransactionIdIsNormal(xid)
void vac_update_relstats(Relation relation, BlockNumber num_pages, double num_tuples, BlockNumber num_all_visible_pages, bool hasindex, TransactionId frozenxid, MultiXactId minmulti, bool in_outer_xact)
#define PageSetLSN(page, lsn)
#define LAZY_ALLOC_TUPLES
#define RelationGetRelid(relation)
int multixact_freeze_min_age
void FreeSpaceMapVacuumRange(Relation rel, BlockNumber start, BlockNumber end)
static void lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
#define PROGRESS_VACUUM_PHASE_VACUUM_HEAP
#define REL_TRUNCATE_FRACTION
#define PageGetItem(page, itemId)
#define ItemPointerSet(pointer, blockNumber, offNum)
static void lazy_space_alloc(LVRelStats *vacrelstats, BlockNumber relblocks)
void RelationTruncate(Relation rel, BlockNumber nblocks)
#define RelationGetNamespace(relation)
bool lock_waiter_detected