1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-16 06:01:02 +03:00

Further work on connecting the free space map (which is still just a

stub) into the rest of the system.  Adopt a cleaner approach to preventing
deadlock in concurrent heap_updates: allow RelationGetBufferForTuple to
select any page of the rel, and put the onus on it to lock both buffers
in a consistent order.  Remove no-longer-needed isExtend hack from
API of ReleaseAndReadBuffer.
This commit is contained in:
Tom Lane
2001-06-29 21:08:25 +00:00
parent 0eab92c0e6
commit af5ced9cfd
12 changed files with 381 additions and 233 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.113 2001/06/22 19:16:22 wieck Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.114 2001/06/29 21:08:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -91,7 +91,7 @@ extern void AbortBufferIO(void);
#define BUFFER_IS_BROKEN(buf) ((buf->flags & BM_IO_ERROR) && !(buf->flags & BM_DIRTY))
static Buffer ReadBufferInternal(Relation reln, BlockNumber blockNum,
bool isExtend, bool bufferLockHeld);
bool bufferLockHeld);
static BufferDesc *BufferAlloc(Relation reln, BlockNumber blockNum,
bool *foundPtr);
static int ReleaseBufferWithBufferLock(Buffer buffer);
@ -103,7 +103,9 @@ void PrintBufferDescs(void);
* ReadBuffer -- returns a buffer containing the requested
* block of the requested relation. If the blknum
* requested is P_NEW, extend the relation file and
* allocate a new block.
* allocate a new block. (Caller is responsible for
* ensuring that only one backend tries to extend a
* relation at the same time!)
*
* Returns: the buffer number for the buffer containing
* the block read, or NULL on an error. If successful,
@ -111,6 +113,8 @@ void PrintBufferDescs(void);
*
* Assume when this function is called, that reln has been
* opened already.
*
* Note: a side effect of a P_NEW call is to update reln->rd_nblocks.
*/
#undef ReadBuffer /* conflicts with macro when BUFMGR_DEBUG
@ -122,28 +126,26 @@ void PrintBufferDescs(void);
Buffer
ReadBuffer(Relation reln, BlockNumber blockNum)
{
return ReadBufferInternal(reln, blockNum, false, false);
return ReadBufferInternal(reln, blockNum, false);
}
/*
* ReadBufferInternal -- internal version of ReadBuffer with more options
*
* isExtend: if true, assume that we are extending the file and the caller
* is passing the current EOF block number (ie, caller already called
* smgrnblocks()).
*
* bufferLockHeld: if true, caller already acquired the bufmgr spinlock.
* (This is assumed never to be true if dealing with a local buffer!)
*/
static Buffer
ReadBufferInternal(Relation reln, BlockNumber blockNum,
bool isExtend, bool bufferLockHeld)
bool bufferLockHeld)
{
BufferDesc *bufHdr;
int status;
bool found;
bool isExtend;
bool isLocalBuf;
isExtend = (blockNum == P_NEW);
isLocalBuf = reln->rd_myxactonly;
if (isLocalBuf)
@ -151,11 +153,10 @@ ReadBufferInternal(Relation reln, BlockNumber blockNum,
ReadLocalBufferCount++;
pgstat_count_buffer_read(&reln->pgstat_info, reln);
/* Substitute proper block number if caller asked for P_NEW */
if (blockNum == P_NEW)
if (isExtend)
{
blockNum = reln->rd_nblocks;
reln->rd_nblocks++;
isExtend = true;
}
bufHdr = LocalBufferAlloc(reln, blockNum, &found);
if (found)
@ -169,10 +170,11 @@ ReadBufferInternal(Relation reln, BlockNumber blockNum,
ReadBufferCount++;
pgstat_count_buffer_read(&reln->pgstat_info, reln);
/* Substitute proper block number if caller asked for P_NEW */
if (blockNum == P_NEW)
if (isExtend)
{
blockNum = smgrnblocks(DEFAULT_SMGR, reln);
isExtend = true;
/* must be sure we have accurate file length! */
blockNum = reln->rd_nblocks = smgrnblocks(DEFAULT_SMGR, reln);
reln->rd_nblocks++;
}
/*
* lookup the buffer. IO_IN_PROGRESS is set if the requested
@ -649,26 +651,24 @@ WriteNoReleaseBuffer(Buffer buffer)
* ReleaseAndReadBuffer -- combine ReleaseBuffer() and ReadBuffer()
* to save a spinlock release/acquire.
*
* An additional frammish of this routine is that the caller may perform
* file extension (as if blockNum = P_NEW) by passing the actual current
* EOF block number as blockNum and setting isExtend true. This hack
* allows us to avoid calling smgrnblocks() again when the caller has
* already done it.
*
* Note: it is OK to pass buffer = InvalidBuffer, indicating that no old
* buffer actually needs to be released. This case is the same as ReadBuffer
* except for the isExtend option.
*
* Also, if the passed buffer is valid and already contains the desired block
* number, we simply return it without ever acquiring the spinlock at all.
* Since the passed buffer must be pinned, it's OK to examine its block
* number without getting the lock first.
*
* Note: it is OK to pass buffer = InvalidBuffer, indicating that no old
* buffer actually needs to be released. This case is the same as ReadBuffer,
* but can save some tests in the caller.
*
* Also note: while it will work to call this routine with blockNum == P_NEW,
* it's best to avoid doing so, since that would result in calling
* smgrnblocks() while holding the bufmgr spinlock, hence some loss of
* concurrency.
*/
Buffer
ReleaseAndReadBuffer(Buffer buffer,
Relation relation,
BlockNumber blockNum,
bool isExtend)
BlockNumber blockNum)
{
BufferDesc *bufHdr;
@ -703,14 +703,12 @@ ReleaseAndReadBuffer(Buffer buffer,
AddBufferToFreelist(bufHdr);
bufHdr->flags |= BM_FREE;
}
return ReadBufferInternal(relation, blockNum,
isExtend, true);
return ReadBufferInternal(relation, blockNum, true);
}
}
}
return ReadBufferInternal(relation, blockNum,
isExtend, false);
return ReadBufferInternal(relation, blockNum, false);
}
/*
@ -1738,14 +1736,13 @@ ReleaseAndReadBuffer_Debug(char *file,
int line,
Buffer buffer,
Relation relation,
BlockNumber blockNum,
bool isExtend)
BlockNumber blockNum)
{
bool bufferValid;
Buffer b;
bufferValid = BufferIsValid(buffer);
b = ReleaseAndReadBuffer(buffer, relation, blockNum, isExtend);
b = ReleaseAndReadBuffer(buffer, relation, blockNum);
if (ShowPinTrace && bufferValid && BufferIsLocal(buffer)
&& is_userbuffer(buffer))
{