*** a/src/backend/commands/vacuumlazy.c --- b/src/backend/commands/vacuumlazy.c *************** *** 97,102 **** --- 97,109 ---- */ #define SKIP_PAGES_THRESHOLD ((BlockNumber) 32) + /* + * Macro used to specify the number of pages to be prefetched before + * reading the page, used for truncating a relation by verifing the page + * is empty or not. + */ + #define VACUUM_TRUNCATE_PREFETCH 32 + typedef struct LVRelStats { /* hasindex = true means two-pass strategy; false means one-pass */ *************** *** 113,118 **** typedef struct LVRelStats --- 120,126 ---- BlockNumber pages_removed; double tuples_deleted; BlockNumber nonempty_pages; /* actually, last nonempty page + 1 */ + BlockNumber skipped_pages; /* actually, last skipped page + 1 */ /* List of TIDs of tuples we intend to delete */ /* NB: this list is ordered by TID address */ int num_dead_tuples; /* current # of entries */ *************** *** 475,480 **** lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, --- 483,489 ---- vacrelstats->rel_pages = nblocks; vacrelstats->scanned_pages = 0; vacrelstats->nonempty_pages = 0; + vacrelstats->skipped_pages = 0; vacrelstats->latestRemovedXid = InvalidTransactionId; lazy_space_alloc(vacrelstats, nblocks); *************** *** 568,574 **** lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, --- 577,586 ---- { /* Current block is all-visible */ if (skipping_all_visible_blocks && !scan_all) + { + vacrelstats->skipped_pages = blkno + 1; continue; + } all_visible_according_to_vm = true; } *************** *** 1559,1568 **** static BlockNumber --- 1571,1590 ---- count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats) { BlockNumber blkno; + BlockNumber trust_vm; instr_time starttime; + Buffer vmbuffer = InvalidBuffer; /* Initialize the starttime if we check for conflicting lock requests */ INSTR_TIME_SET_CURRENT(starttime); + + /* + * Pages that were inspected and found to be empty by this vacuum run + * must still be empty if the vm bit is still set. Only vacuum sets + * vm bits, and only one vacuum can exist in a table at one time. + */ + trust_vm = vacrelstats->nonempty_pages > vacrelstats->skipped_pages ? + vacrelstats->nonempty_pages : vacrelstats->skipped_pages; /* Strange coding of loop control is needed because blkno is unsigned */ blkno = vacrelstats->rel_pages; *************** *** 1600,1605 **** count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats) --- 1622,1629 ---- RelationGetRelationName(onerel)))); vacrelstats->lock_waiter_detected = true; + if (BufferIsValid(vmbuffer)) + ReleaseBuffer(vmbuffer); return blkno; } starttime = currenttime; *************** *** 1614,1619 **** count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats) --- 1638,1657 ---- CHECK_FOR_INTERRUPTS(); blkno--; + + /* + * Verify the page is empty or not based on visibility map test, instead + * of verifying from the page contents. + */ + if ((blkno >= trust_vm) && visibilitymap_test(onerel, blkno, &vmbuffer)) + continue; + + if ((blkno % VACUUM_TRUNCATE_PREFETCH) == 0 && blkno >= VACUUM_TRUNCATE_PREFETCH) + { + int i; + for (i = -VACUUM_TRUNCATE_PREFETCH; i<0; i++) + PrefetchBuffer(onerel, MAIN_FORKNUM, blkno + i); + } buf = ReadBufferExtended(onerel, MAIN_FORKNUM, blkno, RBM_NORMAL, vac_strategy); *************** *** 1657,1663 **** count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats) --- 1695,1705 ---- /* Done scanning if we found a tuple here */ if (hastup) + { + if (BufferIsValid(vmbuffer)) + ReleaseBuffer(vmbuffer); return blkno + 1; + } } /* *************** *** 1665,1670 **** count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats) --- 1707,1714 ---- * pages still are; we need not bother to look at the last known-nonempty * page. */ + if (BufferIsValid(vmbuffer)) + ReleaseBuffer(vmbuffer); return vacrelstats->nonempty_pages; }