On Sun, Dec 15, 2002 at 11:49:57PM -0300, Alvaro Herrera wrote:

> I iterate over the elements of the parent page in a for loop, and the
> upper bound is rarely reached because the item is found.  However
> sometimes the item isn't found, and PageGetItem fails its assertion
> because the item isn't used (LP_USED).  I have found that
> PageGetMaxOffsetNumber (the upper bound) returns a consistent value
> that's far too high (4294967291, 0xFFFFFFFB) and therefore the for loop
> eventually falls out of bounds.

FWIW, the code that is supposed to do this (and appears to work fine on
most cases) is the following.  buf is the page I'm going to free and
pblkno is the BlockNumber of its parent as seen in btpo_parent.

/*
 * Delete the pointer to a child page.  If the parent page is empty after
 * the deletion, delete the pointer from its parent too.
 */
static void
_bt_deletefromparent(Relation rel, BlockNumber pblkno, Buffer buf)
{
        Buffer                  pbuf;
        OffsetNumber    offnum;
        Page                    ppage;
        BTPageOpaque    pop;
        BlockNumber             blkno = BufferGetBlockNumber(buf),
                                        max;

        pbuf = _bt_getbuf(rel, pblkno, BT_WRITE);
        Assert(!BufferIsInvalid(pbuf));

        ppage = BufferGetPage(pbuf);
        pop = (BTPageOpaque) PageGetSpecialPointer(ppage);

        /*
         * Repeat until the correct parent page is found.       Splits may
         * cause the parent page to move right.
         */
        for (;;)
        {
                BlockNumber     next;

                /* Make sure no one else tries to look at the page. */
                LockBuffer(pbuf, BUFFER_LOCK_UNLOCK);
                LockBufferForCleanup(pbuf);
                max = PageGetMaxOffsetNumber(pop);

                /*
                 * Look every offset of the page for the item pointing to the
                 * dead page.
                 */
                for (offnum = FirstOffsetNumber; offnum <= max; offnum++)
                {
                        BTItem                  item;
                        ItemPointer             iptr;

                        item = (BTItem) PageGetItem(ppage, PageGetItemId(ppage, 
offnum));
                        iptr  = &(item->bti_itup.t_tid);
                        if (ItemPointerGetBlockNumber(iptr) == blkno)
                        {
                                /* Ok, we found the page.  Now delete the pointer. */
                                ItemPointer             iptrd = palloc(SizeOfIptrData);

                                ItemPointerSet(iptrd, pblkno, offnum);
                                _bt_itemdel(rel, pbuf, iptrd);
                                _bt_wrtnorelbuf(rel, pbuf);
                                LockBuffer(pbuf, BUFFER_LOCK_UNLOCK);

                                /*
                                 * If the parent page is empty after this deletion,
                                 * mark it dead and free it too.
                                 */
                                if (_bt_pageisempty(ppage))
                                {
                                        pop->btpo_flags |= BTP_DEAD;
                                        _bt_processdead(rel, pbuf);
                                }
                                ReleaseBuffer(pbuf);
                                return;
                        }
                }

                /*
                 * If we just finished scanning the rightmost page of the upper level,
                 * there's some wrong.
                 */
                if (P_RIGHTMOST(pop))
                        elog(ERROR, "Unable to find parent page!");

                /* Oops, the parent was split.  Check its right sibling. */
                next = pop->btpo_next;
                _bt_relbuf(rel, pbuf);
                pbuf = _bt_getbuf(rel, next, BT_WRITE);
                ppage = BufferGetPage(pbuf);
                pop = (BTPageOpaque) PageGetSpecialPointer(ppage);
        }
}

-- 
Alvaro Herrera (<alvherre[a]dcc.uchile.cl>)
"Aprende a avergonzarte mas ante ti que ante los demas" (Democrito)

---------------------------(end of broadcast)---------------------------
TIP 2: you can get off all lists at once with the unregister command
    (send "unregister YourEmailAddressHere" to [EMAIL PROTECTED])

Reply via email to