Re: [HACKERS] Did we forget to unpin buf in function "revmap_physical_extend" ?

2015-09-11 Thread Alvaro Herrera
Jinyu Zhang wrote:
> In function "revmap_physical_extend",  should we add "ReleaseBuffer(buf);" 
> between line 438 and 439 ?
>  422 else
>  423 {
>  424 if (needLock)
>  425 LockRelationForExtension(irel, ExclusiveLock);
>  426 
>  427 buf = ReadBuffer(irel, P_NEW);
>  428 if (BufferGetBlockNumber(buf) != mapBlk)
>  429 {
>  430 /*
>  431  * Very rare corner case: somebody extended the relation
>  432  * concurrently after we read its length.  If this happens, 
> give
>  433  * up and have caller start over.  We will have to evacuate 
> that
>  434  * page from under whoever is using it.
>  435  */
>  436 if (needLock)
>  437 UnlockRelationForExtension(irel, ExclusiveLock);
>  438 LockBuffer(revmap->rm_metaBuf, BUFFER_LOCK_UNLOCK);
>  439 return;
>  440 }

Yeah, clearly there's a missing ReleaseBuffer call there.

There are two callers of this code (brinRevmapExtend calls
revmap_extend_and_get_blkno calls revmap_physical_extend) -- one is
brin_doupdate.  This function is concerned with updating an existing
index tuple, that is, one that already has a revmap entry.  It follows
that the revmap page must already exist.  In other words, this callsite
is dead code.

The other caller is in brin_doinsert, which itself is called from
brinbuild (both directly and via brinbuildCallback) and summarize_range.
In the first case, the index is just being created, and therefore no one
can be trying to extend the relation concurrently.  In the second case,
we always hold ShareUpdateExclusiveLock, and therefore no one can be
also running the same thing.

Another thing to keep in mind is that since the revmap allocates blocks
from the start of the main fork, the pages it wants to use are most of
the time already used by "regular index pages".  The only case where it
actually needs to physically extend the relation is when the index is
new.  I've been trying to think of a case in which the index is created
to an empty relation, and then we try to insert a tuple during a
vacuum-induced summarization, which decides to create a new revmap page,
and then somehow another process needs to insert another index tuple and
allocate a regular index page for it, which happens to get to the
relation extension before the first process.  But I don't think this can
happen either, because every path that inserts regular index tuples
extends the revmap first.

Therefore I think this is dead code and there is no live bug.

All that said, adding the call is simple enough and I don't want to
spend a lot of time constructing a test case to prove that this cannot
happen.

-- 
Álvaro Herrerahttp://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] Did we forget to unpin buf in function "revmap_physical_extend" ?

2015-09-11 Thread Jinyu Zhang
In function "revmap_physical_extend",  should we add "ReleaseBuffer(buf);" 
between line 438 and 439 ?
422 else
 423 {
 424 if (needLock)
 425 LockRelationForExtension(irel, ExclusiveLock);
 426 
 427 buf = ReadBuffer(irel, P_NEW);
 428 if (BufferGetBlockNumber(buf) != mapBlk)
 429 {
 430 /*
 431  * Very rare corner case: somebody extended the relation
 432  * concurrently after we read its length.  If this happens, 
give
 433  * up and have caller start over.  We will have to evacuate 
that
 434  * page from under whoever is using it.
 435  */
 436 if (needLock)
 437 UnlockRelationForExtension(irel, ExclusiveLock);
 438 LockBuffer(revmap->rm_metaBuf, BUFFER_LOCK_UNLOCK);
 439 return;
 440 }
 441 LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
 442 page = BufferGetPage(buf);
 443 
 444 if (needLock)
 445 UnlockRelationForExtension(irel, ExclusiveLock);
 446 }


Jinyu,
regards