📄 nbtxlog.c
字号:
if (!BufferIsValid(buffer)) return; page = (Page) BufferGetPage(buffer); if (XLByteLE(lsn, PageGetLSN(page))) { UnlockReleaseBuffer(buffer); return; } if (record->xl_len > SizeOfBtreeDelete) { OffsetNumber *unused; OffsetNumber *unend; unused = (OffsetNumber *) ((char *) xlrec + SizeOfBtreeDelete); unend = (OffsetNumber *) ((char *) xlrec + record->xl_len); PageIndexMultiDelete(page, unused, unend - unused); } /* * Mark the page as not containing any LP_DEAD items --- see comments in * _bt_delitems(). */ opaque = (BTPageOpaque) PageGetSpecialPointer(page); opaque->btpo_flags &= ~BTP_HAS_GARBAGE; PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); UnlockReleaseBuffer(buffer);}static voidbtree_xlog_delete_page(uint8 info, XLogRecPtr lsn, XLogRecord *record){ xl_btree_delete_page *xlrec = (xl_btree_delete_page *) XLogRecGetData(record); Relation reln; BlockNumber parent; BlockNumber target; BlockNumber leftsib; BlockNumber rightsib; Buffer buffer; Page page; BTPageOpaque pageop; reln = XLogOpenRelation(xlrec->target.node); parent = ItemPointerGetBlockNumber(&(xlrec->target.tid)); target = xlrec->deadblk; leftsib = xlrec->leftblk; rightsib = xlrec->rightblk; /* parent page */ if (!(record->xl_info & XLR_BKP_BLOCK_1)) { buffer = XLogReadBuffer(reln, parent, false); if (BufferIsValid(buffer)) { page = (Page) BufferGetPage(buffer); pageop = (BTPageOpaque) PageGetSpecialPointer(page); if (XLByteLE(lsn, PageGetLSN(page))) { UnlockReleaseBuffer(buffer); } else { OffsetNumber poffset; poffset = ItemPointerGetOffsetNumber(&(xlrec->target.tid)); if (poffset >= PageGetMaxOffsetNumber(page)) { Assert(info == XLOG_BTREE_DELETE_PAGE_HALF); Assert(poffset == P_FIRSTDATAKEY(pageop)); PageIndexTupleDelete(page, poffset); pageop->btpo_flags |= BTP_HALF_DEAD; } else { ItemId itemid; IndexTuple itup; OffsetNumber nextoffset; Assert(info != XLOG_BTREE_DELETE_PAGE_HALF); itemid = PageGetItemId(page, poffset); itup = (IndexTuple) PageGetItem(page, itemid); ItemPointerSet(&(itup->t_tid), rightsib, P_HIKEY); nextoffset = OffsetNumberNext(poffset); PageIndexTupleDelete(page, nextoffset); } PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); UnlockReleaseBuffer(buffer); } } } /* Fix left-link of right sibling */ if (!(record->xl_info & XLR_BKP_BLOCK_2)) { buffer = XLogReadBuffer(reln, rightsib, false); if (BufferIsValid(buffer)) { page = (Page) BufferGetPage(buffer); if (XLByteLE(lsn, PageGetLSN(page))) { UnlockReleaseBuffer(buffer); } else { pageop = (BTPageOpaque) PageGetSpecialPointer(page); pageop->btpo_prev = leftsib; PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); UnlockReleaseBuffer(buffer); } } } /* Fix right-link of left sibling, if any */ if (!(record->xl_info & XLR_BKP_BLOCK_3)) { if (leftsib != P_NONE) { buffer = XLogReadBuffer(reln, leftsib, false); if (BufferIsValid(buffer)) { page = (Page) BufferGetPage(buffer); if (XLByteLE(lsn, PageGetLSN(page))) { UnlockReleaseBuffer(buffer); } else { pageop = (BTPageOpaque) PageGetSpecialPointer(page); pageop->btpo_next = rightsib; PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); UnlockReleaseBuffer(buffer); } } } } /* Rewrite target page as empty deleted page */ buffer = XLogReadBuffer(reln, target, true); Assert(BufferIsValid(buffer)); page = (Page) BufferGetPage(buffer); _bt_pageinit(page, BufferGetPageSize(buffer)); pageop = (BTPageOpaque) PageGetSpecialPointer(page); pageop->btpo_prev = leftsib; pageop->btpo_next = rightsib; pageop->btpo.xact = FrozenTransactionId; pageop->btpo_flags = BTP_DELETED; pageop->btpo_cycleid = 0; PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); UnlockReleaseBuffer(buffer); /* Update metapage if needed */ if (info == XLOG_BTREE_DELETE_PAGE_META) { xl_btree_metadata md; memcpy(&md, (char *) xlrec + SizeOfBtreeDeletePage, sizeof(xl_btree_metadata)); _bt_restore_meta(reln, lsn, md.root, md.level, md.fastroot, md.fastlevel); } /* Forget any completed deletion */ forget_matching_deletion(xlrec->target.node, target); /* If parent became half-dead, remember it for deletion */ if (info == XLOG_BTREE_DELETE_PAGE_HALF) log_incomplete_deletion(xlrec->target.node, parent);}static voidbtree_xlog_newroot(XLogRecPtr lsn, XLogRecord *record){ xl_btree_newroot *xlrec = (xl_btree_newroot *) XLogRecGetData(record); Relation reln; Buffer buffer; Page page; BTPageOpaque pageop; BlockNumber downlink = 0; reln = XLogOpenRelation(xlrec->node); buffer = XLogReadBuffer(reln, xlrec->rootblk, true); Assert(BufferIsValid(buffer)); page = (Page) BufferGetPage(buffer); _bt_pageinit(page, BufferGetPageSize(buffer)); pageop = (BTPageOpaque) PageGetSpecialPointer(page); pageop->btpo_flags = BTP_ROOT; pageop->btpo_prev = pageop->btpo_next = P_NONE; pageop->btpo.level = xlrec->level; if (xlrec->level == 0) pageop->btpo_flags |= BTP_LEAF; pageop->btpo_cycleid = 0; if (record->xl_len > SizeOfBtreeNewroot) { IndexTuple itup; _bt_restore_page(page, (char *) xlrec + SizeOfBtreeNewroot, record->xl_len - SizeOfBtreeNewroot); /* extract downlink to the right-hand split page */ itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, P_FIRSTKEY)); downlink = ItemPointerGetBlockNumber(&(itup->t_tid)); Assert(ItemPointerGetOffsetNumber(&(itup->t_tid)) == P_HIKEY); } PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); UnlockReleaseBuffer(buffer); _bt_restore_meta(reln, lsn, xlrec->rootblk, xlrec->level, xlrec->rootblk, xlrec->level); /* Check to see if this satisfies any incomplete insertions */ if (record->xl_len > SizeOfBtreeNewroot) forget_matching_split(xlrec->node, downlink, true);}voidbtree_redo(XLogRecPtr lsn, XLogRecord *record){ uint8 info = record->xl_info & ~XLR_INFO_MASK; switch (info) { case XLOG_BTREE_INSERT_LEAF: btree_xlog_insert(true, false, lsn, record); break; case XLOG_BTREE_INSERT_UPPER: btree_xlog_insert(false, false, lsn, record); break; case XLOG_BTREE_INSERT_META: btree_xlog_insert(false, true, lsn, record); break; case XLOG_BTREE_SPLIT_L: btree_xlog_split(true, false, lsn, record); break; case XLOG_BTREE_SPLIT_R: btree_xlog_split(false, false, lsn, record); break; case XLOG_BTREE_SPLIT_L_ROOT: btree_xlog_split(true, true, lsn, record); break; case XLOG_BTREE_SPLIT_R_ROOT: btree_xlog_split(false, true, lsn, record); break; case XLOG_BTREE_DELETE: btree_xlog_delete(lsn, record); break; case XLOG_BTREE_DELETE_PAGE: case XLOG_BTREE_DELETE_PAGE_META: case XLOG_BTREE_DELETE_PAGE_HALF: btree_xlog_delete_page(info, lsn, record); break; case XLOG_BTREE_NEWROOT: btree_xlog_newroot(lsn, record); break; default: elog(PANIC, "btree_redo: unknown op code %u", info); }}static voidout_target(StringInfo buf, xl_btreetid *target){ appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u", target->node.spcNode, target->node.dbNode, target->node.relNode, ItemPointerGetBlockNumber(&(target->tid)), ItemPointerGetOffsetNumber(&(target->tid)));}voidbtree_desc(StringInfo buf, uint8 xl_info, char *rec){ uint8 info = xl_info & ~XLR_INFO_MASK; switch (info) { case XLOG_BTREE_INSERT_LEAF: { xl_btree_insert *xlrec = (xl_btree_insert *) rec; appendStringInfo(buf, "insert: "); out_target(buf, &(xlrec->target)); break; } case XLOG_BTREE_INSERT_UPPER: { xl_btree_insert *xlrec = (xl_btree_insert *) rec; appendStringInfo(buf, "insert_upper: "); out_target(buf, &(xlrec->target)); break; } case XLOG_BTREE_INSERT_META: { xl_btree_insert *xlrec = (xl_btree_insert *) rec; appendStringInfo(buf, "insert_meta: "); out_target(buf, &(xlrec->target)); break; } case XLOG_BTREE_SPLIT_L: { xl_btree_split *xlrec = (xl_btree_split *) rec; appendStringInfo(buf, "split_l: rel %u/%u/%u ", xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode); appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d", xlrec->leftsib, xlrec->rightsib, xlrec->rnext, xlrec->level, xlrec->firstright); break; } case XLOG_BTREE_SPLIT_R: { xl_btree_split *xlrec = (xl_btree_split *) rec; appendStringInfo(buf, "split_r: rel %u/%u/%u ", xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode); appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d", xlrec->leftsib, xlrec->rightsib, xlrec->rnext, xlrec->level, xlrec->firstright); break; } case XLOG_BTREE_SPLIT_L_ROOT: { xl_btree_split *xlrec = (xl_btree_split *) rec; appendStringInfo(buf, "split_l_root: rel %u/%u/%u ", xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode); appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d", xlrec->leftsib, xlrec->rightsib, xlrec->rnext, xlrec->level, xlrec->firstright); break; } case XLOG_BTREE_SPLIT_R_ROOT: { xl_btree_split *xlrec = (xl_btree_split *) rec; appendStringInfo(buf, "split_r_root: rel %u/%u/%u ", xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode); appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d", xlrec->leftsib, xlrec->rightsib, xlrec->rnext, xlrec->level, xlrec->firstright); break; } case XLOG_BTREE_DELETE: { xl_btree_delete *xlrec = (xl_btree_delete *) rec; appendStringInfo(buf, "delete: rel %u/%u/%u; blk %u", xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode, xlrec->block); break; } case XLOG_BTREE_DELETE_PAGE: case XLOG_BTREE_DELETE_PAGE_META: case XLOG_BTREE_DELETE_PAGE_HALF: { xl_btree_delete_page *xlrec = (xl_btree_delete_page *) rec; appendStringInfo(buf, "delete_page: "); out_target(buf, &(xlrec->target)); appendStringInfo(buf, "; dead %u; left %u; right %u", xlrec->deadblk, xlrec->leftblk, xlrec->rightblk); break; } case XLOG_BTREE_NEWROOT: { xl_btree_newroot *xlrec = (xl_btree_newroot *) rec; appendStringInfo(buf, "newroot: rel %u/%u/%u; root %u lev %u", xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode, xlrec->rootblk, xlrec->level); break; } default: appendStringInfo(buf, "UNKNOWN"); break; }}voidbtree_xlog_startup(void){ incomplete_actions = NIL;}voidbtree_xlog_cleanup(void){ ListCell *l; foreach(l, incomplete_actions) { bt_incomplete_action *action = (bt_incomplete_action *) lfirst(l); Relation reln; reln = XLogOpenRelation(action->node); if (action->is_split) { /* finish an incomplete split */ Buffer lbuf, rbuf; Page lpage, rpage; BTPageOpaque lpageop, rpageop; bool is_only; lbuf = XLogReadBuffer(reln, action->leftblk, false); /* failure is impossible because we wrote this page earlier */ if (!BufferIsValid(lbuf)) elog(PANIC, "btree_xlog_cleanup: left block unfound"); lpage = (Page) BufferGetPage(lbuf); lpageop = (BTPageOpaque) PageGetSpecialPointer(lpage); rbuf = XLogReadBuffer(reln, action->rightblk, false); /* failure is impossible because we wrote this page earlier */ if (!BufferIsValid(rbuf)) elog(PANIC, "btree_xlog_cleanup: right block unfound"); rpage = (Page) BufferGetPage(rbuf); rpageop = (BTPageOpaque) PageGetSpecialPointer(rpage); /* if the pages are all of their level, it's a only-page split */ is_only = P_LEFTMOST(lpageop) && P_RIGHTMOST(rpageop); _bt_insert_parent(reln, lbuf, rbuf, NULL, action->is_root, is_only); } else { /* finish an incomplete deletion (of a half-dead page) */ Buffer buf; buf = XLogReadBuffer(reln, action->delblk, false); if (BufferIsValid(buf)) if (_bt_pagedel(reln, buf, NULL, true) == 0) elog(PANIC, "btree_xlog_cleanup: _bt_pagdel failed"); } } incomplete_actions = NIL;}boolbtree_safe_restartpoint(void){ if (incomplete_actions) return false; return true;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -