mirror of
https://github.com/postgres/postgres.git
synced 2025-11-12 05:01:15 +03:00
Fix wrong validation of top-parent pointer during page deletion in Btree.
After introducing usage of t_tid of inner or page high key for storing number of attributes of tuple, validation of tuple's ItemPointer with ItemPointerIsValid becomes incorrect, it's need to validate only blocknumber of ItemPointer. Missing this causes a incorrect page deletion, fix that. Test is added. BTW, current contrib/amcheck doesn't fail on index corrupted by this way. Also introduce BTreeTupleGetTopParent/BTreeTupleSetTopParent macroses to improve code readability and to avoid possible confusion with page high key: high key is used to store top-parent link for branch to remove. Bug found by Michael Paquier, but bug doesn't exist in previous versions because t_tid was set to P_HIKEY. Author: Teodor Sigaev Reviewer: Peter Geoghegan Discussion: https://www.postgresql.org/message-id/flat/20180419052436.GA16000%40paquier.xyz
This commit is contained in:
@@ -1602,10 +1602,9 @@ _bt_mark_page_halfdead(Relation rel, Buffer leafbuf, BTStack stack)
|
||||
MemSet(&trunctuple, 0, sizeof(IndexTupleData));
|
||||
trunctuple.t_info = sizeof(IndexTupleData);
|
||||
if (target != leafblkno)
|
||||
ItemPointerSetBlockNumber(&trunctuple.t_tid, target);
|
||||
BTreeTupleSetTopParent(&trunctuple, target);
|
||||
else
|
||||
ItemPointerSetInvalid(&trunctuple.t_tid);
|
||||
BTreeTupleSetNAtts(&trunctuple, 0);
|
||||
BTreeTupleSetTopParent(&trunctuple, InvalidBlockNumber);
|
||||
|
||||
if (PageAddItem(page, (Item) &trunctuple, sizeof(IndexTupleData), P_HIKEY,
|
||||
false, false) == InvalidOffsetNumber)
|
||||
@@ -1690,7 +1689,7 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, bool *rightsib_empty)
|
||||
BTPageOpaque opaque;
|
||||
bool rightsib_is_rightmost;
|
||||
int targetlevel;
|
||||
ItemPointer leafhikey;
|
||||
IndexTuple leafhikey;
|
||||
BlockNumber nextchild;
|
||||
|
||||
page = BufferGetPage(leafbuf);
|
||||
@@ -1702,7 +1701,7 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, bool *rightsib_empty)
|
||||
* Remember some information about the leaf page.
|
||||
*/
|
||||
itemid = PageGetItemId(page, P_HIKEY);
|
||||
leafhikey = &((IndexTuple) PageGetItem(page, itemid))->t_tid;
|
||||
leafhikey = (IndexTuple) PageGetItem(page, itemid);
|
||||
leafleftsib = opaque->btpo_prev;
|
||||
leafrightsib = opaque->btpo_next;
|
||||
|
||||
@@ -1714,9 +1713,10 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, bool *rightsib_empty)
|
||||
* parent in the branch. Set 'target' and 'buf' to reference the page
|
||||
* actually being unlinked.
|
||||
*/
|
||||
if (ItemPointerIsValid(leafhikey))
|
||||
target = BTreeTupleGetTopParent(leafhikey);
|
||||
|
||||
if (target != InvalidBlockNumber)
|
||||
{
|
||||
target = ItemPointerGetBlockNumberNoCheck(leafhikey);
|
||||
Assert(target != leafblkno);
|
||||
|
||||
/* fetch the block number of the topmost parent's left sibling */
|
||||
@@ -1919,12 +1919,7 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, bool *rightsib_empty)
|
||||
* branch.
|
||||
*/
|
||||
if (target != leafblkno)
|
||||
{
|
||||
if (nextchild == InvalidBlockNumber)
|
||||
ItemPointerSetInvalid(leafhikey);
|
||||
else
|
||||
ItemPointerSetBlockNumber(leafhikey, nextchild);
|
||||
}
|
||||
BTreeTupleSetTopParent(leafhikey, nextchild);
|
||||
|
||||
/*
|
||||
* Mark the page itself deleted. It can be recycled when all current
|
||||
|
||||
@@ -800,11 +800,7 @@ btree_xlog_mark_page_halfdead(uint8 info, XLogReaderState *record)
|
||||
*/
|
||||
MemSet(&trunctuple, 0, sizeof(IndexTupleData));
|
||||
trunctuple.t_info = sizeof(IndexTupleData);
|
||||
if (xlrec->topparent != InvalidBlockNumber)
|
||||
ItemPointerSetBlockNumber(&trunctuple.t_tid, xlrec->topparent);
|
||||
else
|
||||
ItemPointerSetInvalid(&trunctuple.t_tid);
|
||||
BTreeTupleSetNAtts(&trunctuple, 0);
|
||||
BTreeTupleSetTopParent(&trunctuple, xlrec->topparent);
|
||||
|
||||
if (PageAddItem(page, (Item) &trunctuple, sizeof(IndexTupleData), P_HIKEY,
|
||||
false, false) == InvalidOffsetNumber)
|
||||
@@ -912,11 +908,7 @@ btree_xlog_unlink_page(uint8 info, XLogReaderState *record)
|
||||
/* Add a dummy hikey item */
|
||||
MemSet(&trunctuple, 0, sizeof(IndexTupleData));
|
||||
trunctuple.t_info = sizeof(IndexTupleData);
|
||||
if (xlrec->topparent != InvalidBlockNumber)
|
||||
ItemPointerSetBlockNumber(&trunctuple.t_tid, xlrec->topparent);
|
||||
else
|
||||
ItemPointerSetInvalid(&trunctuple.t_tid);
|
||||
BTreeTupleSetNAtts(&trunctuple, 0);
|
||||
BTreeTupleSetTopParent(&trunctuple, xlrec->topparent);
|
||||
|
||||
if (PageAddItem(page, (Item) &trunctuple, sizeof(IndexTupleData), P_HIKEY,
|
||||
false, false) == InvalidOffsetNumber)
|
||||
|
||||
Reference in New Issue
Block a user