Re: PageGetMaxOffsetNumber

From: Alvaro Herrera <alvherre(at)dcc(dot)uchile(dot)cl>
To: Hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: PageGetMaxOffsetNumber
Date: 2002-12-16 03:05:20
Message-ID: 20021216030520.GA30674@dcc.uchile.cl
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

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)

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Greg Copeland 2002-12-16 03:13:29 Re: PQnotifies() in 7.3 broken?
Previous Message Alvaro Herrera 2002-12-16 02:49:57 PageGetMaxOffsetNumber