diff options
Diffstat (limited to 'src/backend/access/nbtree/nbtpage.c')
-rw-r--r-- | src/backend/access/nbtree/nbtpage.c | 76 |
1 files changed, 56 insertions, 20 deletions
diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c index 5e9e7b9270..58f47e7b64 100644 --- a/src/backend/access/nbtree/nbtpage.c +++ b/src/backend/access/nbtree/nbtpage.c @@ -4,12 +4,12 @@ * BTree-specific page management code for the Postgres btree access * method. * - * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtpage.c,v 1.123 2010/07/06 19:18:55 momjian Exp $ + * src/backend/access/nbtree/nbtpage.c * * NOTES * Postgres btree pages look like ordinary relation pages. The opaque @@ -29,6 +29,7 @@ #include "storage/freespace.h" #include "storage/indexfsm.h" #include "storage/lmgr.h" +#include "storage/predicate.h" #include "utils/inval.h" #include "utils/snapmgr.h" @@ -224,7 +225,7 @@ _bt_getroot(Relation rel, int access) MarkBufferDirty(metabuf); /* XLOG stuff */ - if (!rel->rd_istemp) + if (RelationNeedsWAL(rel)) { xl_btree_newroot xlrec; XLogRecPtr recptr; @@ -452,7 +453,7 @@ _bt_checkpage(Relation rel, Buffer buf) static void _bt_log_reuse_page(Relation rel, BlockNumber blkno, TransactionId latestRemovedXid) { - if (rel->rd_istemp) + if (!RelationNeedsWAL(rel)) return; /* No ereport(ERROR) until changes are logged */ @@ -465,7 +466,6 @@ _bt_log_reuse_page(Relation rel, BlockNumber blkno, TransactionId latestRemovedX /* XLOG stuff */ { - XLogRecPtr recptr; XLogRecData rdata[1]; xl_btree_reuse_page xlrec_reuse; @@ -477,7 +477,7 @@ _bt_log_reuse_page(Relation rel, BlockNumber blkno, TransactionId latestRemovedX rdata[0].buffer = InvalidBuffer; rdata[0].next = NULL; - recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_REUSE_PAGE, rdata); + XLogInsert(RM_BTREE_ID, XLOG_BTREE_REUSE_PAGE, rdata); /* * We don't do PageSetLSN or PageSetTLI here because we're about @@ -751,7 +751,7 @@ _bt_delitems_vacuum(Relation rel, Buffer buf, MarkBufferDirty(buf); /* XLOG stuff */ - if (!rel->rd_istemp) + if (RelationNeedsWAL(rel)) { XLogRecPtr recptr; XLogRecData rdata[2]; @@ -829,7 +829,7 @@ _bt_delitems_delete(Relation rel, Buffer buf, MarkBufferDirty(buf); /* XLOG stuff */ - if (!rel->rd_istemp) + if (RelationNeedsWAL(rel)) { XLogRecPtr recptr; XLogRecData rdata[3]; @@ -1175,6 +1175,19 @@ _bt_pagedel(Relation rel, Buffer buf, BTStack stack) */ rightsib = opaque->btpo_next; rbuf = _bt_getbuf(rel, rightsib, BT_WRITE); + page = BufferGetPage(rbuf); + opaque = (BTPageOpaque) PageGetSpecialPointer(page); + if (opaque->btpo_prev != target) + elog(ERROR, "right sibling's left-link doesn't match: " + "block %u links to %u instead of expected %u in index \"%s\"", + rightsib, opaque->btpo_prev, target, + RelationGetRelationName(rel)); + + /* + * Any insert which would have gone on the target block will now go to the + * right sibling block. + */ + PredicateLockPageCombine(rel, target, rightsib); /* * Next find and write-lock the current parent of the target page. This is @@ -1253,6 +1266,38 @@ _bt_pagedel(Relation rel, Buffer buf, BTStack stack) } /* + * Check that the parent-page index items we're about to delete/overwrite + * contain what we expect. This can fail if the index has become corrupt + * for some reason. We want to throw any error before entering the + * critical section --- otherwise it'd be a PANIC. + * + * The test on the target item is just an Assert because _bt_getstackbuf + * should have guaranteed it has the expected contents. The test on the + * next-child downlink is known to sometimes fail in the field, though. + */ + page = BufferGetPage(pbuf); + opaque = (BTPageOpaque) PageGetSpecialPointer(page); + +#ifdef USE_ASSERT_CHECKING + itemid = PageGetItemId(page, poffset); + itup = (IndexTuple) PageGetItem(page, itemid); + Assert(ItemPointerGetBlockNumber(&(itup->t_tid)) == target); +#endif + + if (!parent_half_dead) + { + OffsetNumber nextoffset; + + nextoffset = OffsetNumberNext(poffset); + itemid = PageGetItemId(page, nextoffset); + itup = (IndexTuple) PageGetItem(page, itemid); + if (ItemPointerGetBlockNumber(&(itup->t_tid)) != rightsib) + elog(ERROR, "right sibling %u of block %u is not next child %u of block %u in index \"%s\"", + rightsib, target, ItemPointerGetBlockNumber(&(itup->t_tid)), + parent, RelationGetRelationName(rel)); + } + + /* * Here we begin doing the deletion. */ @@ -1265,8 +1310,6 @@ _bt_pagedel(Relation rel, Buffer buf, BTStack stack) * to copy the right sibling's downlink over the target downlink, and then * delete the following item. */ - page = BufferGetPage(pbuf); - opaque = (BTPageOpaque) PageGetSpecialPointer(page); if (parent_half_dead) { PageIndexTupleDelete(page, poffset); @@ -1278,23 +1321,16 @@ _bt_pagedel(Relation rel, Buffer buf, BTStack stack) itemid = PageGetItemId(page, poffset); itup = (IndexTuple) PageGetItem(page, itemid); - Assert(ItemPointerGetBlockNumber(&(itup->t_tid)) == target); ItemPointerSet(&(itup->t_tid), rightsib, P_HIKEY); nextoffset = OffsetNumberNext(poffset); - /* This part is just for double-checking */ - itemid = PageGetItemId(page, nextoffset); - itup = (IndexTuple) PageGetItem(page, itemid); - if (ItemPointerGetBlockNumber(&(itup->t_tid)) != rightsib) - elog(PANIC, "right sibling %u of block %u is not next child of %u in index \"%s\"", - rightsib, target, BufferGetBlockNumber(pbuf), - RelationGetRelationName(rel)); PageIndexTupleDelete(page, nextoffset); } /* * Update siblings' side-links. Note the target page's side-links will - * continue to point to the siblings. + * continue to point to the siblings. Asserts here are just rechecking + * things we already verified above. */ if (BufferIsValid(lbuf)) { @@ -1335,7 +1371,7 @@ _bt_pagedel(Relation rel, Buffer buf, BTStack stack) MarkBufferDirty(lbuf); /* XLOG stuff */ - if (!rel->rd_istemp) + if (RelationNeedsWAL(rel)) { xl_btree_delete_page xlrec; xl_btree_metadata xlmeta; |