From: Vadim B. Mikheev Date: Wed, 31 Jan 2001 01:08:36 +0000 (+0000) Subject: Couple additional functions to fix tree at runtime. X-Git-Tag: REL7_1~598 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=dca0762efc1b4f84c0185b5464f94f7d66bbe566;p=postgresql Couple additional functions to fix tree at runtime. Need in one more function to handle "my bits moved..." case. FixBTree is still FALSE. --- diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c index 76d2d9ff86..b44b7839de 100644 --- a/src/backend/access/nbtree/nbtinsert.c +++ b/src/backend/access/nbtree/nbtinsert.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.78 2001/01/29 07:28:16 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.79 2001/01/31 01:08:36 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -37,7 +37,9 @@ typedef struct extern bool FixBTree; Buffer _bt_fixroot(Relation rel, Buffer oldrootbuf, bool release); -static void _bt_fixtree(Relation rel, BlockNumber blkno, BTStack stack); +static void _bt_fixtree(Relation rel, BlockNumber blkno); +static BlockNumber _bt_fixlevel(Relation rel, Buffer buf, BlockNumber limit); +static OffsetNumber _bt_getoff(Page page, BlockNumber blkno); static Buffer _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf); @@ -512,7 +514,7 @@ _bt_insertonpg(Relation rel, { blkno = lpageop->btpo_parent; _bt_relbuf(rel, buf, BT_WRITE); - _bt_fixtree(rel, blkno, NULL); + _bt_fixtree(rel, blkno); goto formres; } } @@ -561,6 +563,10 @@ _bt_insertonpg(Relation rel, pbuf = _bt_getstackbuf(rel, stack); + if (pbuf == InvalidBuffer) + elog(ERROR, "_bt_getstackbuf: my bits moved right off the end of the world!" + "\n\tRecreate index %s.", RelationGetRelationName(rel)); + /* Now we can write and unlock the children */ _bt_wrtbuf(rel, rbuf); _bt_wrtbuf(rel, buf); @@ -1172,8 +1178,10 @@ _bt_getstackbuf(Relation rel, BTStack stack) } /* by here, the item we're looking for moved right at least one page */ if (P_RIGHTMOST(opaque)) - elog(FATAL, "_bt_getstackbuf: my bits moved right off the end of the world!" - "\n\tRecreate index %s.", RelationGetRelationName(rel)); + { + _bt_relbuf(rel, buf, BT_WRITE); + return(InvalidBuffer); + } blkno = opaque->btpo_next; _bt_relbuf(rel, buf, BT_WRITE); @@ -1450,6 +1458,7 @@ _bt_fixroot(Relation rel, Buffer oldrootbuf, bool release) /* give up left buffer */ _bt_relbuf(rel, leftbuf, BT_WRITE); + pfree(btitem); leftbuf = rightbuf; leftpage = rightpage; leftopaque = rightopaque; @@ -1477,10 +1486,318 @@ _bt_fixroot(Relation rel, Buffer oldrootbuf, bool release) return(rootbuf); } +/* + * Using blkno of leftmost page on a level inside tree this func + * checks/fixes tree from this level up to the root page. + */ static void -_bt_fixtree(Relation rel, BlockNumber blkno, BTStack stack) +_bt_fixtree(Relation rel, BlockNumber blkno) +{ + Buffer buf; + Page page; + BTPageOpaque opaque; + BlockNumber pblkno; + + elog(ERROR, "bt_fixtree: unimplemented , yet (need to recreate index)"); + + for ( ; ; ) + { + buf = _bt_getbuf(rel, blkno, BT_READ); + page = BufferGetPage(buf); + opaque = (BTPageOpaque) PageGetSpecialPointer(page); + if (! P_LEFTMOST(opaque) || P_ISLEAF(opaque)) + elog(ERROR, "bt_fixtree: invalid start page (need to recreate index)"); + pblkno = opaque->btpo_parent; + + /* check/fix entire level */ + _bt_fixlevel(rel, buf, InvalidBlockNumber); + + /* + * No pins/locks are held here. Re-read start page if its + * btpo_parent pointed to meta page else go up one level. + */ + if (pblkno == BTREE_METAPAGE) + { + buf = _bt_getbuf(rel, blkno, BT_WRITE); + page = BufferGetPage(buf); + opaque = (BTPageOpaque) PageGetSpecialPointer(page); + if (P_ISROOT(opaque)) + { + /* Tree is Ok now */ + _bt_relbuf(rel, buf, BT_WRITE); + return; + } + pblkno = opaque->btpo_parent; + /* Call _bt_fixroot() if there is no upper level */ + if (pblkno == BTREE_METAPAGE) + { + buf = _bt_fixroot(rel, buf, true); + _bt_relbuf(rel, buf, BT_WRITE); + return; + } + /* Have to go up one level */ + _bt_relbuf(rel, buf, BT_WRITE); + blkno = pblkno; + } + } + +} + +/* + * Check/fix level starting from page in buffer buf up to block + * limit on *child* level (or till rightmost child page if limit + * is InvalidBlockNumber). Start buffer must be read locked. + * No pins/locks are held on exit. Returns block number of last + * visited/pointing-to-limit page on *check/fix* level. + */ +static BlockNumber +_bt_fixlevel(Relation rel, Buffer buf, BlockNumber limit) +{ + BlockNumber blkno = BufferGetBlockNumber(buf); + BlockNumber pblkno = blkno; + Page page; + BTPageOpaque opaque; + BlockNumber cblkno[3]; + OffsetNumber coff[3]; + Buffer cbuf[3]; + Page cpage[3]; + BTPageOpaque copaque[3]; + BTItem btitem; + int cidx, i; + bool goodbye = false; + char tbuf[BLCKSZ]; + + page = BufferGetPage(buf); + /* copy page to temp storage */ + memmove(tbuf, page, PageGetPageSize(page)); + _bt_relbuf(rel, buf, BT_READ); + + page = (Page)tbuf; + opaque = (BTPageOpaque) PageGetSpecialPointer(page); + + /* Initialize first child data */ + coff[0] = P_FIRSTDATAKEY(opaque); + if (coff[0] > PageGetMaxOffsetNumber(page)) + elog(ERROR, "bt_fixlevel: invalid maxoff on start page (need to recreate index)"); + btitem = (BTItem) PageGetItem(page, PageGetItemId(page, coff[0])); + cblkno[0] = ItemPointerGetBlockNumber(&(btitem->bti_itup.t_tid)); + cbuf[0] = _bt_getbuf(rel, cblkno[0], BT_READ); + cpage[0] = BufferGetPage(cbuf[0]); + copaque[0] = (BTPageOpaque) PageGetSpecialPointer(cpage[0]); + if (P_LEFTMOST(opaque) && ! P_LEFTMOST(copaque[0])) + elog(ERROR, "bt_fixtlevel: non-leftmost child page of leftmost parent (need to recreate index)"); + /* caller should take care and avoid this */ + if (P_RIGHTMOST(copaque[0])) + elog(ERROR, "bt_fixtlevel: invalid start child (need to recreate index)"); + + for ( ; ; ) + { + /* + * Read up to 2 more child pages and look for pointers + * to them in *saved* parent page + */ + coff[1] = coff[2] = InvalidOffsetNumber; + for (cidx = 0; cidx < 2; ) + { + cidx++; + cblkno[cidx] = (copaque[cidx - 1])->btpo_next; + cbuf[cidx] = _bt_getbuf(rel, cblkno[cidx], BT_READ); + cpage[cidx] = BufferGetPage(cbuf[cidx]); + copaque[cidx] = (BTPageOpaque) PageGetSpecialPointer(cpage[cidx]); + coff[cidx] = _bt_getoff(page, cblkno[cidx]); + + /* sanity check */ + if (coff[cidx] != InvalidOffsetNumber) + { + for (i = cidx - 1; i >= 0; i--) + { + if (coff[i] == InvalidOffsetNumber) + continue; + if (coff[cidx] != coff[i] + 1) + elog(ERROR, "bt_fixlevel: invalid item order(1) (need to recreate index)"); + break; + } + } + + if (P_RIGHTMOST(copaque[cidx])) + break; + } + + /* + * Read parent page and insert missed pointers. + */ + if (coff[1] == InvalidOffsetNumber || + (cidx == 2 && coff[2] == InvalidOffsetNumber)) + { + Buffer newbuf; + Page newpage; + BTPageOpaque newopaque; + BTItem ritem; + Size itemsz; + OffsetNumber newitemoff; + BlockNumber parblk[3]; + BTStackData stack; + + stack.bts_parent = NULL; + stack.bts_blkno = pblkno; + stack.bts_offset = InvalidOffsetNumber; + ItemPointerSet(&(stack.bts_btitem.bti_itup.t_tid), + cblkno[0], P_HIKEY); + + buf = _bt_getstackbuf(rel, &stack); + if (buf == InvalidBuffer) + elog(ERROR, "bt_fixlevel: pointer disappeared (need to recreate index)"); + + page = BufferGetPage(buf); + opaque = (BTPageOpaque) PageGetSpecialPointer(page); + coff[0] = stack.bts_offset; + pblkno = BufferGetBlockNumber(buf); + parblk[0] = pblkno; + if (cblkno[0] == limit) + blkno = pblkno; /* where we have seen pointer to limit */ + + /* Check/insert missed pointers */ + for (i = 1; i <= cidx; i++) + { + coff[i] = _bt_getoff(page, cblkno[i]); + + /* sanity check */ + parblk[i] = BufferGetBlockNumber(buf); + if (coff[i] != InvalidOffsetNumber) + { + if (parblk[i] == parblk[i - 1] && + coff[i] != coff[i - 1] + 1) + elog(ERROR, "bt_fixlevel: invalid item order(2) (need to recreate index)"); + if (cblkno[i] == limit) + blkno = parblk[i]; + continue; + } + /* Have to check next page ? */ + if ((! P_RIGHTMOST(opaque)) && + coff[i - 1] == PageGetMaxOffsetNumber(page)) /* yes */ + { + newbuf = _bt_getbuf(rel, opaque->btpo_next, BT_WRITE); + newpage = BufferGetPage(newbuf); + newopaque = (BTPageOpaque) PageGetSpecialPointer(newpage); + coff[i] = _bt_getoff(newpage, cblkno[i]); + if (coff[i] != InvalidOffsetNumber) /* found ! */ + { + if (coff[i] != P_FIRSTDATAKEY(newopaque)) + elog(ERROR, "bt_fixlevel: invalid item order(3) (need to recreate index)"); + _bt_relbuf(rel, buf, BT_WRITE); + buf = newbuf; + page = newpage; + opaque = newopaque; + pblkno = BufferGetBlockNumber(buf); + parblk[i] = pblkno; + if (cblkno[i] == limit) + blkno = pblkno; + continue; + } + /* unfound - need to insert on current page */ + _bt_relbuf(rel, newbuf, BT_WRITE); + } + /* insert pointer */ + ritem = (BTItem) PageGetItem(cpage[i - 1], + PageGetItemId(cpage[i - 1], P_HIKEY)); + btitem = _bt_formitem(&(ritem->bti_itup)); + ItemPointerSet(&(btitem->bti_itup.t_tid), cblkno[i], P_HIKEY); + itemsz = IndexTupleDSize(btitem->bti_itup) + + (sizeof(BTItemData) - sizeof(IndexTupleData)); + itemsz = MAXALIGN(itemsz); + + newitemoff = coff[i - 1] + 1; + + if (PageGetFreeSpace(page) < itemsz) + { + OffsetNumber firstright; + OffsetNumber itup_off; + BlockNumber itup_blkno; + bool newitemonleft; + + firstright = _bt_findsplitloc(rel, page, + newitemoff, itemsz, &newitemonleft); + newbuf = _bt_split(rel, buf, firstright, + newitemoff, itemsz, btitem, newitemonleft, + &itup_off, &itup_blkno); + /* what buffer we need in ? */ + if (newitemonleft) + _bt_relbuf(rel, newbuf, BT_WRITE); + else + { + _bt_relbuf(rel, buf, BT_WRITE); + buf = newbuf; + page = BufferGetPage(buf); + opaque = (BTPageOpaque) PageGetSpecialPointer(page); + } + pblkno = BufferGetBlockNumber(buf); + coff[i] = itup_off; + } + else + { + _bt_insertuple(rel, buf, itemsz, btitem, newitemoff); + coff[i] = newitemoff; + } + + pfree(btitem); + parblk[i] = pblkno; + if (cblkno[i] == limit) + blkno = pblkno; + } + + /* copy page with pointer to cblkno[cidx] to temp storage */ + memmove(tbuf, page, PageGetPageSize(page)); + _bt_relbuf(rel, buf, BT_WRITE); + page = (Page)tbuf; + opaque = (BTPageOpaque) PageGetSpecialPointer(page); + if (limit == InvalidBlockNumber) + blkno = pblkno; /* last visited page */ + } + + /* Continue if current check/fix level page is rightmost */ + if (P_RIGHTMOST(opaque)) + goodbye = false; + + /* Pointers to child pages are Ok - right end of child level ? */ + _bt_relbuf(rel, cbuf[0], BT_READ); + _bt_relbuf(rel, cbuf[1], BT_READ); + if (cidx == 1 || + (cidx == 2 && (P_RIGHTMOST(copaque[2]) || goodbye))) + { + if (cidx == 2) + _bt_relbuf(rel, cbuf[2], BT_READ); + return(blkno); + } + if (cblkno[0] == limit || cblkno[1] == limit) + goodbye = true; + cblkno[0] = cblkno[2]; + cbuf[0] = cbuf[2]; + cpage[0] = cpage[2]; + copaque[0] = copaque[2]; + coff[0] = coff[2]; + } +} + +static OffsetNumber +_bt_getoff(Page page, BlockNumber blkno) { - elog(ERROR, "bt_fixtree: unimplemented , yet"); + BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page); + OffsetNumber maxoff = PageGetMaxOffsetNumber(page); + OffsetNumber offnum = P_FIRSTDATAKEY(opaque); + BlockNumber curblkno; + ItemId itemid; + BTItem item; + + for ( ; offnum <= maxoff; offnum++) + { + itemid = PageGetItemId(page, offnum); + item = (BTItem) PageGetItem(page, itemid); + curblkno = ItemPointerGetBlockNumber(&(item->bti_itup.t_tid)); + if (curblkno == blkno) + return(offnum); + } + + return(InvalidOffsetNumber); } /*