On Fri, Jan 24, 2014 at 04:52:55PM -0500, Jaime Casanova wrote: > On Tue, Dec 3, 2013 at 11:25 AM, Bruce Momjian <br...@momjian.us> wrote: > > > > Is everyone else OK with this approach? Updated patch attached. > > > > Hi, > > I started to look at this patch and i found that it fails an assertion > as soon as you run a VACUUM FULL after a lazy VACUUM even if those are > on unrelated relations. For example in an assert-enabled build with > the regression database run: > > VACUUM customer; > [... insert here whatever commands you like or nothing at all ...] > VACUUM FULL customer;
Wow, thanks for the testing. You are right that I had two bugs, both in visibilitymap_set(). First, I made setting heapBuf optional, but forgot to remove the Assert check now that it was optional. Second, I passed InvalidBlockNumber instead of InvalidBuffer when calling visibilitymap_set(). Both are fixed in the attached patch. Thanks for the report. -- Bruce Momjian <br...@momjian.us> http://momjian.us EnterpriseDB http://enterprisedb.com + Everyone has their own god. +
diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c new file mode 100644 index c34ab98..ff275fa *** a/src/backend/access/heap/rewriteheap.c --- b/src/backend/access/heap/rewriteheap.c *************** *** 107,112 **** --- 107,114 ---- #include "access/rewriteheap.h" #include "access/transam.h" #include "access/tuptoaster.h" + #include "access/visibilitymap.h" + #include "commands/vacuum.h" #include "storage/bufmgr.h" #include "storage/smgr.h" #include "utils/memutils.h" *************** typedef OldToNewMappingData *OldToNewMap *** 172,177 **** --- 174,180 ---- /* prototypes for internal functions */ static void raw_heap_insert(RewriteState state, HeapTuple tup); + static void update_page_vm(Relation relation, Page page, BlockNumber blkno); /* *************** end_heap_rewrite(RewriteState state) *** 281,286 **** --- 284,290 ---- true); RelationOpenSmgr(state->rs_new_rel); + update_page_vm(state->rs_new_rel, state->rs_buffer, state->rs_blockno); PageSetChecksumInplace(state->rs_buffer, state->rs_blockno); smgrextend(state->rs_new_rel->rd_smgr, MAIN_FORKNUM, state->rs_blockno, *************** raw_heap_insert(RewriteState state, Heap *** 633,638 **** --- 637,643 ---- */ RelationOpenSmgr(state->rs_new_rel); + update_page_vm(state->rs_new_rel, page, state->rs_blockno); PageSetChecksumInplace(page, state->rs_blockno); smgrextend(state->rs_new_rel->rd_smgr, MAIN_FORKNUM, *************** raw_heap_insert(RewriteState state, Heap *** 678,680 **** --- 683,705 ---- if (heaptup != tup) heap_freetuple(heaptup); } + + static void + update_page_vm(Relation relation, Page page, BlockNumber blkno) + { + Buffer vmbuffer = InvalidBuffer; + TransactionId visibility_cutoff_xid; + + visibilitymap_pin(relation, blkno, &vmbuffer); + Assert(BufferIsValid(vmbuffer)); + + if (!visibilitymap_test(relation, blkno, &vmbuffer) && + heap_page_is_all_visible(relation, InvalidBuffer, page, + &visibility_cutoff_xid)) + { + PageSetAllVisible(page); + visibilitymap_set(relation, blkno, InvalidBuffer, + InvalidXLogRecPtr, vmbuffer, visibility_cutoff_xid); + } + ReleaseBuffer(vmbuffer); + } diff --git a/src/backend/access/heap/visibilitymap.c b/src/backend/access/heap/visibilitymap.c new file mode 100644 index 899ffac..3e7546b *** a/src/backend/access/heap/visibilitymap.c --- b/src/backend/access/heap/visibilitymap.c *************** visibilitymap_set(Relation rel, BlockNum *** 257,263 **** #endif Assert(InRecovery || XLogRecPtrIsInvalid(recptr)); - Assert(InRecovery || BufferIsValid(heapBuf)); /* Check that we have the right heap page pinned, if present */ if (BufferIsValid(heapBuf) && BufferGetBlockNumber(heapBuf) != heapBlk) --- 257,262 ---- *************** visibilitymap_set(Relation rel, BlockNum *** 278,284 **** map[mapByte] |= (1 << mapBit); MarkBufferDirty(vmBuf); ! if (RelationNeedsWAL(rel)) { if (XLogRecPtrIsInvalid(recptr)) { --- 277,283 ---- map[mapByte] |= (1 << mapBit); MarkBufferDirty(vmBuf); ! if (RelationNeedsWAL(rel) && BufferIsValid(heapBuf)) { if (XLogRecPtrIsInvalid(recptr)) { diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c new file mode 100644 index 75e5f15..8d84bef *** a/src/backend/commands/vacuumlazy.c --- b/src/backend/commands/vacuumlazy.c *************** static void lazy_record_dead_tuple(LVRel *** 152,159 **** ItemPointer itemptr); static bool lazy_tid_reaped(ItemPointer itemptr, void *state); static int vac_cmp_itemptr(const void *left, const void *right); - static bool heap_page_is_all_visible(Relation rel, Buffer buf, - TransactionId *visibility_cutoff_xid); /* --- 152,157 ---- *************** lazy_vacuum_page(Relation onerel, BlockN *** 1232,1238 **** * check if the page has become all-visible. */ if (!visibilitymap_test(onerel, blkno, vmbuffer) && ! heap_page_is_all_visible(onerel, buffer, &visibility_cutoff_xid)) { Assert(BufferIsValid(*vmbuffer)); PageSetAllVisible(page); --- 1230,1236 ---- * check if the page has become all-visible. */ if (!visibilitymap_test(onerel, blkno, vmbuffer) && ! heap_page_is_all_visible(onerel, buffer, NULL, &visibility_cutoff_xid)) { Assert(BufferIsValid(*vmbuffer)); PageSetAllVisible(page); *************** vac_cmp_itemptr(const void *left, const *** 1730,1743 **** * transactions. Also return the visibility_cutoff_xid which is the highest * xmin amongst the visible tuples. */ ! static bool ! heap_page_is_all_visible(Relation rel, Buffer buf, TransactionId *visibility_cutoff_xid) { - Page page = BufferGetPage(buf); OffsetNumber offnum, maxoff; bool all_visible = true; *visibility_cutoff_xid = InvalidTransactionId; /* --- 1728,1744 ---- * transactions. Also return the visibility_cutoff_xid which is the highest * xmin amongst the visible tuples. */ ! bool ! heap_page_is_all_visible(Relation rel, Buffer buf, Page page, ! TransactionId *visibility_cutoff_xid) { OffsetNumber offnum, maxoff; bool all_visible = true; + if (BufferIsValid(buf)) + page = BufferGetPage(buf); + *visibility_cutoff_xid = InvalidTransactionId; /* *************** heap_page_is_all_visible(Relation rel, B *** 1758,1764 **** if (!ItemIdIsUsed(itemid) || ItemIdIsRedirected(itemid)) continue; ! ItemPointerSet(&(tuple.t_self), BufferGetBlockNumber(buf), offnum); /* * Dead line pointers can have index pointers pointing to them. So --- 1759,1767 ---- if (!ItemIdIsUsed(itemid) || ItemIdIsRedirected(itemid)) continue; ! /* XXX use 0 or real offset? */ ! ItemPointerSet(&(tuple.t_self), BufferIsValid(buf) ? ! BufferGetBlockNumber(buf) : 0, offnum); /* * Dead line pointers can have index pointers pointing to them. So diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c new file mode 100644 index f626755..b37ecc4 *** a/src/backend/utils/time/tqual.c --- b/src/backend/utils/time/tqual.c *************** static inline void *** 108,113 **** --- 108,117 ---- SetHintBits(HeapTupleHeader tuple, Buffer buffer, uint16 infomask, TransactionId xid) { + /* we might not have a buffer if we are doing raw_heap_insert() */ + if (!BufferIsValid(buffer)) + return; + if (TransactionIdIsValid(xid)) { /* NB: xid must be known committed here! */ diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h new file mode 100644 index 7c36890..1a35f6c *** a/src/include/commands/vacuum.h --- b/src/include/commands/vacuum.h *************** *** 19,24 **** --- 19,25 ---- #include "catalog/pg_type.h" #include "nodes/parsenodes.h" #include "storage/buf.h" + #include "storage/bufpage.h" #include "storage/lock.h" #include "utils/relcache.h" *************** extern void vacuum_delay_point(void); *** 168,173 **** --- 169,176 ---- /* in commands/vacuumlazy.c */ extern void lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt, BufferAccessStrategy bstrategy); + extern bool heap_page_is_all_visible(Relation rel, Buffer buf, Page page, + TransactionId *visibility_cutoff_xid); /* in commands/analyze.c */ extern void analyze_rel(Oid relid, VacuumStmt *vacstmt,
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers