|
8 | 8 | *
|
9 | 9 | *
|
10 | 10 | * IDENTIFICATION
|
11 |
| - * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.78 2001/01/29 07:28:16 vadim Exp $ |
| 11 | + * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.79 2001/01/31 01:08:36 vadim Exp $ |
12 | 12 | *
|
13 | 13 | *-------------------------------------------------------------------------
|
14 | 14 | */
|
@@ -37,7 +37,9 @@ typedef struct
|
37 | 37 | extern bool FixBTree;
|
38 | 38 |
|
39 | 39 | Buffer _bt_fixroot(Relation rel, Buffer oldrootbuf, bool release);
|
40 |
| -static void _bt_fixtree(Relation rel, BlockNumber blkno, BTStack stack); |
| 40 | +static void _bt_fixtree(Relation rel, BlockNumber blkno); |
| 41 | +static BlockNumber _bt_fixlevel(Relation rel, Buffer buf, BlockNumber limit); |
| 42 | +static OffsetNumber _bt_getoff(Page page, BlockNumber blkno); |
41 | 43 |
|
42 | 44 | static Buffer _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf);
|
43 | 45 |
|
@@ -512,7 +514,7 @@ _bt_insertonpg(Relation rel,
|
512 | 514 | {
|
513 | 515 | blkno = lpageop->btpo_parent;
|
514 | 516 | _bt_relbuf(rel, buf, BT_WRITE);
|
515 |
| - _bt_fixtree(rel, blkno, NULL); |
| 517 | + _bt_fixtree(rel, blkno); |
516 | 518 | goto formres;
|
517 | 519 | }
|
518 | 520 | }
|
@@ -561,6 +563,10 @@ _bt_insertonpg(Relation rel,
|
561 | 563 |
|
562 | 564 | pbuf = _bt_getstackbuf(rel, stack);
|
563 | 565 |
|
| 566 | + if (pbuf == InvalidBuffer) |
| 567 | + elog(ERROR, "_bt_getstackbuf: my bits moved right off the end of the world!" |
| 568 | + "\n\tRecreate index %s.", RelationGetRelationName(rel)); |
| 569 | + |
564 | 570 | /* Now we can write and unlock the children */
|
565 | 571 | _bt_wrtbuf(rel, rbuf);
|
566 | 572 | _bt_wrtbuf(rel, buf);
|
@@ -1172,8 +1178,10 @@ _bt_getstackbuf(Relation rel, BTStack stack)
|
1172 | 1178 | }
|
1173 | 1179 | /* by here, the item we're looking for moved right at least one page */
|
1174 | 1180 | if (P_RIGHTMOST(opaque))
|
1175 |
| - elog(FATAL, "_bt_getstackbuf: my bits moved right off the end of the world!" |
1176 |
| - "\n\tRecreate index %s.", RelationGetRelationName(rel)); |
| 1181 | + { |
| 1182 | + _bt_relbuf(rel, buf, BT_WRITE); |
| 1183 | + return(InvalidBuffer); |
| 1184 | + } |
1177 | 1185 |
|
1178 | 1186 | blkno = opaque->btpo_next;
|
1179 | 1187 | _bt_relbuf(rel, buf, BT_WRITE);
|
@@ -1450,6 +1458,7 @@ _bt_fixroot(Relation rel, Buffer oldrootbuf, bool release)
|
1450 | 1458 |
|
1451 | 1459 | /* give up left buffer */
|
1452 | 1460 | _bt_relbuf(rel, leftbuf, BT_WRITE);
|
| 1461 | + pfree(btitem); |
1453 | 1462 | leftbuf = rightbuf;
|
1454 | 1463 | leftpage = rightpage;
|
1455 | 1464 | leftopaque = rightopaque;
|
@@ -1477,10 +1486,318 @@ _bt_fixroot(Relation rel, Buffer oldrootbuf, bool release)
|
1477 | 1486 | return(rootbuf);
|
1478 | 1487 | }
|
1479 | 1488 |
|
| 1489 | +/* |
| 1490 | + * Using blkno of leftmost page on a level inside tree this func |
| 1491 | + * checks/fixes tree from this level up to the root page. |
| 1492 | + */ |
1480 | 1493 | static void
|
1481 |
| -_bt_fixtree(Relation rel, BlockNumber blkno, BTStack stack) |
| 1494 | +_bt_fixtree(Relation rel, BlockNumber blkno) |
| 1495 | +{ |
| 1496 | + Buffer buf; |
| 1497 | + Page page; |
| 1498 | + BTPageOpaque opaque; |
| 1499 | + BlockNumber pblkno; |
| 1500 | + |
| 1501 | + elog(ERROR, "bt_fixtree: unimplemented , yet (need to recreate index)"); |
| 1502 | + |
| 1503 | + for ( ; ; ) |
| 1504 | + { |
| 1505 | + buf = _bt_getbuf(rel, blkno, BT_READ); |
| 1506 | + page = BufferGetPage(buf); |
| 1507 | + opaque = (BTPageOpaque) PageGetSpecialPointer(page); |
| 1508 | + if (! P_LEFTMOST(opaque) || P_ISLEAF(opaque)) |
| 1509 | + elog(ERROR, "bt_fixtree: invalid start page (need to recreate index)"); |
| 1510 | + pblkno = opaque->btpo_parent; |
| 1511 | + |
| 1512 | + /* check/fix entire level */ |
| 1513 | + _bt_fixlevel(rel, buf, InvalidBlockNumber); |
| 1514 | + |
| 1515 | + /* |
| 1516 | + * No pins/locks are held here. Re-read start page if its |
| 1517 | + * btpo_parent pointed to meta page else go up one level. |
| 1518 | + */ |
| 1519 | + if (pblkno == BTREE_METAPAGE) |
| 1520 | + { |
| 1521 | + buf = _bt_getbuf(rel, blkno, BT_WRITE); |
| 1522 | + page = BufferGetPage(buf); |
| 1523 | + opaque = (BTPageOpaque) PageGetSpecialPointer(page); |
| 1524 | + if (P_ISROOT(opaque)) |
| 1525 | + { |
| 1526 | + /* Tree is Ok now */ |
| 1527 | + _bt_relbuf(rel, buf, BT_WRITE); |
| 1528 | + return; |
| 1529 | + } |
| 1530 | + pblkno = opaque->btpo_parent; |
| 1531 | + /* Call _bt_fixroot() if there is no upper level */ |
| 1532 | + if (pblkno == BTREE_METAPAGE) |
| 1533 | + { |
| 1534 | + buf = _bt_fixroot(rel, buf, true); |
| 1535 | + _bt_relbuf(rel, buf, BT_WRITE); |
| 1536 | + return; |
| 1537 | + } |
| 1538 | + /* Have to go up one level */ |
| 1539 | + _bt_relbuf(rel, buf, BT_WRITE); |
| 1540 | + blkno = pblkno; |
| 1541 | + } |
| 1542 | + } |
| 1543 | + |
| 1544 | +} |
| 1545 | + |
| 1546 | +/* |
| 1547 | + * Check/fix level starting from page in buffer buf up to block |
| 1548 | + * limit on *child* level (or till rightmost child page if limit |
| 1549 | + * is InvalidBlockNumber). Start buffer must be read locked. |
| 1550 | + * No pins/locks are held on exit. Returns block number of last |
| 1551 | + * visited/pointing-to-limit page on *check/fix* level. |
| 1552 | + */ |
| 1553 | +static BlockNumber |
| 1554 | +_bt_fixlevel(Relation rel, Buffer buf, BlockNumber limit) |
| 1555 | +{ |
| 1556 | + BlockNumber blkno = BufferGetBlockNumber(buf); |
| 1557 | + BlockNumber pblkno = blkno; |
| 1558 | + Page page; |
| 1559 | + BTPageOpaque opaque; |
| 1560 | + BlockNumber cblkno[3]; |
| 1561 | + OffsetNumber coff[3]; |
| 1562 | + Buffer cbuf[3]; |
| 1563 | + Page cpage[3]; |
| 1564 | + BTPageOpaque copaque[3]; |
| 1565 | + BTItem btitem; |
| 1566 | + int cidx, i; |
| 1567 | + bool goodbye = false; |
| 1568 | + char tbuf[BLCKSZ]; |
| 1569 | + |
| 1570 | + page = BufferGetPage(buf); |
| 1571 | + /* copy page to temp storage */ |
| 1572 | + memmove(tbuf, page, PageGetPageSize(page)); |
| 1573 | + _bt_relbuf(rel, buf, BT_READ); |
| 1574 | + |
| 1575 | + page = (Page)tbuf; |
| 1576 | + opaque = (BTPageOpaque) PageGetSpecialPointer(page); |
| 1577 | + |
| 1578 | + /* Initialize first child data */ |
| 1579 | + coff[0] = P_FIRSTDATAKEY(opaque); |
| 1580 | + if (coff[0] > PageGetMaxOffsetNumber(page)) |
| 1581 | + elog(ERROR, "bt_fixlevel: invalid maxoff on start page (need to recreate index)"); |
| 1582 | + btitem = (BTItem) PageGetItem(page, PageGetItemId(page, coff[0])); |
| 1583 | + cblkno[0] = ItemPointerGetBlockNumber(&(btitem->bti_itup.t_tid)); |
| 1584 | + cbuf[0] = _bt_getbuf(rel, cblkno[0], BT_READ); |
| 1585 | + cpage[0] = BufferGetPage(cbuf[0]); |
| 1586 | + copaque[0] = (BTPageOpaque) PageGetSpecialPointer(cpage[0]); |
| 1587 | + if (P_LEFTMOST(opaque) && ! P_LEFTMOST(copaque[0])) |
| 1588 | + elog(ERROR, "bt_fixtlevel: non-leftmost child page of leftmost parent (need to recreate index)"); |
| 1589 | + /* caller should take care and avoid this */ |
| 1590 | + if (P_RIGHTMOST(copaque[0])) |
| 1591 | + elog(ERROR, "bt_fixtlevel: invalid start child (need to recreate index)"); |
| 1592 | + |
| 1593 | + for ( ; ; ) |
| 1594 | + { |
| 1595 | + /* |
| 1596 | + * Read up to 2 more child pages and look for pointers |
| 1597 | + * to them in *saved* parent page |
| 1598 | + */ |
| 1599 | + coff[1] = coff[2] = InvalidOffsetNumber; |
| 1600 | + for (cidx = 0; cidx < 2; ) |
| 1601 | + { |
| 1602 | + cidx++; |
| 1603 | + cblkno[cidx] = (copaque[cidx - 1])->btpo_next; |
| 1604 | + cbuf[cidx] = _bt_getbuf(rel, cblkno[cidx], BT_READ); |
| 1605 | + cpage[cidx] = BufferGetPage(cbuf[cidx]); |
| 1606 | + copaque[cidx] = (BTPageOpaque) PageGetSpecialPointer(cpage[cidx]); |
| 1607 | + coff[cidx] = _bt_getoff(page, cblkno[cidx]); |
| 1608 | + |
| 1609 | + /* sanity check */ |
| 1610 | + if (coff[cidx] != InvalidOffsetNumber) |
| 1611 | + { |
| 1612 | + for (i = cidx - 1; i >= 0; i--) |
| 1613 | + { |
| 1614 | + if (coff[i] == InvalidOffsetNumber) |
| 1615 | + continue; |
| 1616 | + if (coff[cidx] != coff[i] + 1) |
| 1617 | + elog(ERROR, "bt_fixlevel: invalid item order(1) (need to recreate index)"); |
| 1618 | + break; |
| 1619 | + } |
| 1620 | + } |
| 1621 | + |
| 1622 | + if (P_RIGHTMOST(copaque[cidx])) |
| 1623 | + break; |
| 1624 | + } |
| 1625 | + |
| 1626 | + /* |
| 1627 | + * Read parent page and insert missed pointers. |
| 1628 | + */ |
| 1629 | + if (coff[1] == InvalidOffsetNumber || |
| 1630 | + (cidx == 2 && coff[2] == InvalidOffsetNumber)) |
| 1631 | + { |
| 1632 | + Buffer newbuf; |
| 1633 | + Page newpage; |
| 1634 | + BTPageOpaque newopaque; |
| 1635 | + BTItem ritem; |
| 1636 | + Size itemsz; |
| 1637 | + OffsetNumber newitemoff; |
| 1638 | + BlockNumber parblk[3]; |
| 1639 | + BTStackData stack; |
| 1640 | + |
| 1641 | + stack.bts_parent = NULL; |
| 1642 | + stack.bts_blkno = pblkno; |
| 1643 | + stack.bts_offset = InvalidOffsetNumber; |
| 1644 | + ItemPointerSet(&(stack.bts_btitem.bti_itup.t_tid), |
| 1645 | + cblkno[0], P_HIKEY); |
| 1646 | + |
| 1647 | + buf = _bt_getstackbuf(rel, &stack); |
| 1648 | + if (buf == InvalidBuffer) |
| 1649 | + elog(ERROR, "bt_fixlevel: pointer disappeared (need to recreate index)"); |
| 1650 | + |
| 1651 | + page = BufferGetPage(buf); |
| 1652 | + opaque = (BTPageOpaque) PageGetSpecialPointer(page); |
| 1653 | + coff[0] = stack.bts_offset; |
| 1654 | + pblkno = BufferGetBlockNumber(buf); |
| 1655 | + parblk[0] = pblkno; |
| 1656 | + if (cblkno[0] == limit) |
| 1657 | + blkno = pblkno; /* where we have seen pointer to limit */ |
| 1658 | + |
| 1659 | + /* Check/insert missed pointers */ |
| 1660 | + for (i = 1; i <= cidx; i++) |
| 1661 | + { |
| 1662 | + coff[i] = _bt_getoff(page, cblkno[i]); |
| 1663 | + |
| 1664 | + /* sanity check */ |
| 1665 | + parblk[i] = BufferGetBlockNumber(buf); |
| 1666 | + if (coff[i] != InvalidOffsetNumber) |
| 1667 | + { |
| 1668 | + if (parblk[i] == parblk[i - 1] && |
| 1669 | + coff[i] != coff[i - 1] + 1) |
| 1670 | + elog(ERROR, "bt_fixlevel: invalid item order(2) (need to recreate index)"); |
| 1671 | + if (cblkno[i] == limit) |
| 1672 | + blkno = parblk[i]; |
| 1673 | + continue; |
| 1674 | + } |
| 1675 | + /* Have to check next page ? */ |
| 1676 | + if ((! P_RIGHTMOST(opaque)) && |
| 1677 | + coff[i - 1] == PageGetMaxOffsetNumber(page)) /* yes */ |
| 1678 | + { |
| 1679 | + newbuf = _bt_getbuf(rel, opaque->btpo_next, BT_WRITE); |
| 1680 | + newpage = BufferGetPage(newbuf); |
| 1681 | + newopaque = (BTPageOpaque) PageGetSpecialPointer(newpage); |
| 1682 | + coff[i] = _bt_getoff(newpage, cblkno[i]); |
| 1683 | + if (coff[i] != InvalidOffsetNumber) /* found ! */ |
| 1684 | + { |
| 1685 | + if (coff[i] != P_FIRSTDATAKEY(newopaque)) |
| 1686 | + elog(ERROR, "bt_fixlevel: invalid item order(3) (need to recreate index)"); |
| 1687 | + _bt_relbuf(rel, buf, BT_WRITE); |
| 1688 | + buf = newbuf; |
| 1689 | + page = newpage; |
| 1690 | + opaque = newopaque; |
| 1691 | + pblkno = BufferGetBlockNumber(buf); |
| 1692 | + parblk[i] = pblkno; |
| 1693 | + if (cblkno[i] == limit) |
| 1694 | + blkno = pblkno; |
| 1695 | + continue; |
| 1696 | + } |
| 1697 | + /* unfound - need to insert on current page */ |
| 1698 | + _bt_relbuf(rel, newbuf, BT_WRITE); |
| 1699 | + } |
| 1700 | + /* insert pointer */ |
| 1701 | + ritem = (BTItem) PageGetItem(cpage[i - 1], |
| 1702 | + PageGetItemId(cpage[i - 1], P_HIKEY)); |
| 1703 | + btitem = _bt_formitem(&(ritem->bti_itup)); |
| 1704 | + ItemPointerSet(&(btitem->bti_itup.t_tid), cblkno[i], P_HIKEY); |
| 1705 | + itemsz = IndexTupleDSize(btitem->bti_itup) |
| 1706 | + + (sizeof(BTItemData) - sizeof(IndexTupleData)); |
| 1707 | + itemsz = MAXALIGN(itemsz); |
| 1708 | + |
| 1709 | + newitemoff = coff[i - 1] + 1; |
| 1710 | + |
| 1711 | + if (PageGetFreeSpace(page) < itemsz) |
| 1712 | + { |
| 1713 | + OffsetNumber firstright; |
| 1714 | + OffsetNumber itup_off; |
| 1715 | + BlockNumber itup_blkno; |
| 1716 | + bool newitemonleft; |
| 1717 | + |
| 1718 | + firstright = _bt_findsplitloc(rel, page, |
| 1719 | + newitemoff, itemsz, &newitemonleft); |
| 1720 | + newbuf = _bt_split(rel, buf, firstright, |
| 1721 | + newitemoff, itemsz, btitem, newitemonleft, |
| 1722 | + &itup_off, &itup_blkno); |
| 1723 | + /* what buffer we need in ? */ |
| 1724 | + if (newitemonleft) |
| 1725 | + _bt_relbuf(rel, newbuf, BT_WRITE); |
| 1726 | + else |
| 1727 | + { |
| 1728 | + _bt_relbuf(rel, buf, BT_WRITE); |
| 1729 | + buf = newbuf; |
| 1730 | + page = BufferGetPage(buf); |
| 1731 | + opaque = (BTPageOpaque) PageGetSpecialPointer(page); |
| 1732 | + } |
| 1733 | + pblkno = BufferGetBlockNumber(buf); |
| 1734 | + coff[i] = itup_off; |
| 1735 | + } |
| 1736 | + else |
| 1737 | + { |
| 1738 | + _bt_insertuple(rel, buf, itemsz, btitem, newitemoff); |
| 1739 | + coff[i] = newitemoff; |
| 1740 | + } |
| 1741 | + |
| 1742 | + pfree(btitem); |
| 1743 | + parblk[i] = pblkno; |
| 1744 | + if (cblkno[i] == limit) |
| 1745 | + blkno = pblkno; |
| 1746 | + } |
| 1747 | + |
| 1748 | + /* copy page with pointer to cblkno[cidx] to temp storage */ |
| 1749 | + memmove(tbuf, page, PageGetPageSize(page)); |
| 1750 | + _bt_relbuf(rel, buf, BT_WRITE); |
| 1751 | + page = (Page)tbuf; |
| 1752 | + opaque = (BTPageOpaque) PageGetSpecialPointer(page); |
| 1753 | + if (limit == InvalidBlockNumber) |
| 1754 | + blkno = pblkno; /* last visited page */ |
| 1755 | + } |
| 1756 | + |
| 1757 | + /* Continue if current check/fix level page is rightmost */ |
| 1758 | + if (P_RIGHTMOST(opaque)) |
| 1759 | + goodbye = false; |
| 1760 | + |
| 1761 | + /* Pointers to child pages are Ok - right end of child level ? */ |
| 1762 | + _bt_relbuf(rel, cbuf[0], BT_READ); |
| 1763 | + _bt_relbuf(rel, cbuf[1], BT_READ); |
| 1764 | + if (cidx == 1 || |
| 1765 | + (cidx == 2 && (P_RIGHTMOST(copaque[2]) || goodbye))) |
| 1766 | + { |
| 1767 | + if (cidx == 2) |
| 1768 | + _bt_relbuf(rel, cbuf[2], BT_READ); |
| 1769 | + return(blkno); |
| 1770 | + } |
| 1771 | + if (cblkno[0] == limit || cblkno[1] == limit) |
| 1772 | + goodbye = true; |
| 1773 | + cblkno[0] = cblkno[2]; |
| 1774 | + cbuf[0] = cbuf[2]; |
| 1775 | + cpage[0] = cpage[2]; |
| 1776 | + copaque[0] = copaque[2]; |
| 1777 | + coff[0] = coff[2]; |
| 1778 | + } |
| 1779 | +} |
| 1780 | + |
| 1781 | +static OffsetNumber |
| 1782 | +_bt_getoff(Page page, BlockNumber blkno) |
1482 | 1783 | {
|
1483 |
| - elog(ERROR, "bt_fixtree: unimplemented , yet"); |
| 1784 | + BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page); |
| 1785 | + OffsetNumber maxoff = PageGetMaxOffsetNumber(page); |
| 1786 | + OffsetNumber offnum = P_FIRSTDATAKEY(opaque); |
| 1787 | + BlockNumber curblkno; |
| 1788 | + ItemId itemid; |
| 1789 | + BTItem item; |
| 1790 | + |
| 1791 | + for ( ; offnum <= maxoff; offnum++) |
| 1792 | + { |
| 1793 | + itemid = PageGetItemId(page, offnum); |
| 1794 | + item = (BTItem) PageGetItem(page, itemid); |
| 1795 | + curblkno = ItemPointerGetBlockNumber(&(item->bti_itup.t_tid)); |
| 1796 | + if (curblkno == blkno) |
| 1797 | + return(offnum); |
| 1798 | + } |
| 1799 | + |
| 1800 | + return(InvalidOffsetNumber); |
1484 | 1801 | }
|
1485 | 1802 |
|
1486 | 1803 | /*
|
|
0 commit comments