#include "storage/buf.h"#include "storage/latch.h"#include "storage/lwlock.h"#include "storage/shmem.h"#include "storage/smgr.h"#include "storage/spin.h"#include "utils/relcache.h"

Go to the source code of this file.
Data Structures | |
| struct | buftag |
| struct | sbufdesc |
Defines | |
| #define | BM_DIRTY (1 << 0) |
| #define | BM_VALID (1 << 1) |
| #define | BM_TAG_VALID (1 << 2) |
| #define | BM_IO_IN_PROGRESS (1 << 3) |
| #define | BM_IO_ERROR (1 << 4) |
| #define | BM_JUST_DIRTIED (1 << 5) |
| #define | BM_PIN_COUNT_WAITER (1 << 6) |
| #define | BM_CHECKPOINT_NEEDED (1 << 7) |
| #define | BM_PERMANENT (1 << 8) |
| #define | BM_MAX_USAGE_COUNT 5 |
| #define | CLEAR_BUFFERTAG(a) |
| #define | INIT_BUFFERTAG(a, xx_rnode, xx_forkNum, xx_blockNum) |
| #define | BUFFERTAGS_EQUAL(a, b) |
| #define | BufTableHashPartition(hashcode) ((hashcode) % NUM_BUFFER_PARTITIONS) |
| #define | BufMappingPartitionLock(hashcode) ((LWLockId) (FirstBufMappingLock + BufTableHashPartition(hashcode))) |
| #define | BufferDescriptorGetBuffer(bdesc) ((bdesc)->buf_id + 1) |
| #define | FREENEXT_END_OF_LIST (-1) |
| #define | FREENEXT_NOT_IN_LIST (-2) |
| #define | LockBufHdr(bufHdr) SpinLockAcquire(&(bufHdr)->buf_hdr_lock) |
| #define | UnlockBufHdr(bufHdr) SpinLockRelease(&(bufHdr)->buf_hdr_lock) |
Typedefs | |
| typedef bits16 | BufFlags |
| typedef struct buftag | BufferTag |
| typedef struct sbufdesc | BufferDesc |
Functions | |
| volatile BufferDesc * | StrategyGetBuffer (BufferAccessStrategy strategy, bool *lock_held) |
| void | StrategyFreeBuffer (volatile BufferDesc *buf) |
| bool | StrategyRejectBuffer (BufferAccessStrategy strategy, volatile BufferDesc *buf) |
| int | StrategySyncStart (uint32 *complete_passes, uint32 *num_buf_alloc) |
| void | StrategyNotifyBgWriter (Latch *bgwriterLatch) |
| Size | StrategyShmemSize (void) |
| void | StrategyInitialize (bool init) |
| Size | BufTableShmemSize (int size) |
| void | InitBufTable (int size) |
| uint32 | BufTableHashCode (BufferTag *tagPtr) |
| int | BufTableLookup (BufferTag *tagPtr, uint32 hashcode) |
| int | BufTableInsert (BufferTag *tagPtr, uint32 hashcode, int buf_id) |
| void | BufTableDelete (BufferTag *tagPtr, uint32 hashcode) |
| void | LocalPrefetchBuffer (SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum) |
| BufferDesc * | LocalBufferAlloc (SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, bool *foundPtr) |
| void | MarkLocalBufferDirty (Buffer buffer) |
| void | DropRelFileNodeLocalBuffers (RelFileNode rnode, ForkNumber forkNum, BlockNumber firstDelBlock) |
| void | DropRelFileNodeAllLocalBuffers (RelFileNode rnode) |
| void | AtEOXact_LocalBuffers (bool isCommit) |
Variables | |
| PGDLLIMPORT BufferDesc * | BufferDescriptors |
| BufferDesc * | LocalBufferDescriptors |
| #define BM_CHECKPOINT_NEEDED (1 << 7) |
Definition at line 40 of file buf_internals.h.
Referenced by BufferAlloc(), BufferSync(), and TerminateBufferIO().
| #define BM_DIRTY (1 << 0) |
Definition at line 33 of file buf_internals.h.
Referenced by AbortBufferIO(), BufferAlloc(), FlushDatabaseBuffers(), FlushRelationBuffers(), LocalBufferAlloc(), MarkBufferDirty(), MarkBufferDirtyHint(), MarkLocalBufferDirty(), pg_buffercache_pages(), StartBufferIO(), SyncOneBuffer(), and TerminateBufferIO().
| #define BM_IO_ERROR (1 << 4) |
Definition at line 37 of file buf_internals.h.
Referenced by AbortBufferIO(), and BufferAlloc().
| #define BM_IO_IN_PROGRESS (1 << 3) |
Definition at line 36 of file buf_internals.h.
Referenced by AbortBufferIO(), StartBufferIO(), TerminateBufferIO(), and WaitIO().
| #define BM_JUST_DIRTIED (1 << 5) |
Definition at line 38 of file buf_internals.h.
Referenced by BufferAlloc(), LocalBufferAlloc(), MarkBufferDirtyHint(), and TerminateBufferIO().
| #define BM_MAX_USAGE_COUNT 5 |
Definition at line 54 of file buf_internals.h.
Referenced by LocalBufferAlloc(), and PinBuffer().
| #define BM_PERMANENT (1 << 8) |
Definition at line 41 of file buf_internals.h.
Referenced by BufferIsPermanent(), FlushBuffer(), and MarkBufferDirtyHint().
| #define BM_PIN_COUNT_WAITER (1 << 6) |
Definition at line 39 of file buf_internals.h.
Referenced by LockBufferForCleanup(), UnlockBuffers(), and UnpinBuffer().
| #define BM_TAG_VALID (1 << 2) |
Definition at line 35 of file buf_internals.h.
Referenced by BufferAlloc(), DropRelFileNodeAllLocalBuffers(), DropRelFileNodeLocalBuffers(), InvalidateBuffer(), LocalBufferAlloc(), and pg_buffercache_pages().
| #define BM_VALID (1 << 1) |
Definition at line 34 of file buf_internals.h.
Referenced by AbortBufferIO(), BufferAlloc(), FlushDatabaseBuffers(), FlushRelationBuffers(), LocalBufferAlloc(), pg_buffercache_pages(), ReadBuffer_common(), StartBufferIO(), and SyncOneBuffer().
| #define BufferDescriptorGetBuffer | ( | bdesc | ) | ((bdesc)->buf_id + 1) |
Definition at line 151 of file buf_internals.h.
Referenced by AddBufferToRing(), LocalBufferAlloc(), pg_buffercache_pages(), PinBuffer(), PinBuffer_Locked(), ReadBuffer_common(), StrategyRejectBuffer(), and UnpinBuffer().
| #define BUFFERTAGS_EQUAL | ( | a, | ||
| b | ||||
| ) |
( \
RelFileNodeEquals((a).rnode, (b).rnode) && \
(a).blockNum == (b).blockNum && \
(a).forkNum == (b).forkNum \
)
Definition at line 91 of file buf_internals.h.
Referenced by InvalidateBuffer(), and LocalBufferAlloc().
| #define BufMappingPartitionLock | ( | hashcode | ) | ((LWLockId) (FirstBufMappingLock + BufTableHashPartition(hashcode))) |
Definition at line 106 of file buf_internals.h.
Referenced by BufferAlloc(), InvalidateBuffer(), and PrefetchBuffer().
| #define BufTableHashPartition | ( | hashcode | ) | ((hashcode) % NUM_BUFFER_PARTITIONS) |
Definition at line 104 of file buf_internals.h.
| #define CLEAR_BUFFERTAG | ( | a | ) |
( \
(a).rnode.spcNode = InvalidOid, \
(a).rnode.dbNode = InvalidOid, \
(a).rnode.relNode = InvalidOid, \
(a).forkNum = InvalidForkNumber, \
(a).blockNum = InvalidBlockNumber \
)
Definition at line 75 of file buf_internals.h.
Referenced by DropRelFileNodeAllLocalBuffers(), DropRelFileNodeLocalBuffers(), InitBufferPool(), InvalidateBuffer(), and LocalBufferAlloc().
| #define FREENEXT_END_OF_LIST (-1) |
Definition at line 157 of file buf_internals.h.
| #define FREENEXT_NOT_IN_LIST (-2) |
Definition at line 158 of file buf_internals.h.
Referenced by StrategyFreeBuffer(), and StrategyGetBuffer().
| #define INIT_BUFFERTAG | ( | a, | ||
| xx_rnode, | ||||
| xx_forkNum, | ||||
| xx_blockNum | ||||
| ) |
( \
(a).rnode = (xx_rnode), \
(a).forkNum = (xx_forkNum), \
(a).blockNum = (xx_blockNum) \
)
Definition at line 84 of file buf_internals.h.
Referenced by BufferAlloc(), LocalBufferAlloc(), LocalPrefetchBuffer(), and PrefetchBuffer().
| #define LockBufHdr | ( | bufHdr | ) | SpinLockAcquire(&(bufHdr)->buf_hdr_lock) |
Definition at line 169 of file buf_internals.h.
Referenced by AbortBufferIO(), BufferAlloc(), BufferGetLSNAtomic(), BufferSync(), ConditionalLockBufferForCleanup(), DropDatabaseBuffers(), DropRelFileNodeBuffers(), DropRelFileNodesAllBuffers(), FlushBuffer(), FlushDatabaseBuffers(), FlushRelationBuffers(), GetBufferFromRing(), InvalidateBuffer(), LockBufferForCleanup(), MarkBufferDirty(), MarkBufferDirtyHint(), pg_buffercache_pages(), PinBuffer(), ReadBuffer_common(), StartBufferIO(), StrategyGetBuffer(), SyncOneBuffer(), TerminateBufferIO(), UnlockBuffers(), UnpinBuffer(), and WaitIO().
| #define UnlockBufHdr | ( | bufHdr | ) | SpinLockRelease(&(bufHdr)->buf_hdr_lock) |
Definition at line 170 of file buf_internals.h.
Referenced by AbortBufferIO(), BufferAlloc(), BufferGetLSNAtomic(), BufferSync(), ConditionalLockBufferForCleanup(), DropDatabaseBuffers(), DropRelFileNodeBuffers(), DropRelFileNodesAllBuffers(), FlushBuffer(), FlushDatabaseBuffers(), FlushRelationBuffers(), GetBufferFromRing(), InvalidateBuffer(), LockBufferForCleanup(), MarkBufferDirty(), MarkBufferDirtyHint(), pg_buffercache_pages(), PinBuffer(), PinBuffer_Locked(), ReadBuffer_common(), StartBufferIO(), StrategyGetBuffer(), SyncOneBuffer(), TerminateBufferIO(), UnlockBuffers(), UnpinBuffer(), and WaitIO().
| typedef struct sbufdesc BufferDesc |
Definition at line 44 of file buf_internals.h.
| void AtEOXact_LocalBuffers | ( | bool | isCommit | ) |
Definition at line 500 of file localbuf.c.
References Assert, assert_enabled, i, LocalRefCount, NLocBuffer, and PrintBufferLeakWarning().
Referenced by AtEOXact_Buffers().
{
#ifdef USE_ASSERT_CHECKING
if (assert_enabled && LocalRefCount)
{
int RefCountErrors = 0;
int i;
for (i = 0; i < NLocBuffer; i++)
{
if (LocalRefCount[i] != 0)
{
Buffer b = -i - 1;
PrintBufferLeakWarning(b);
RefCountErrors++;
}
}
Assert(RefCountErrors == 0);
}
#endif
}
Definition at line 151 of file buf_table.c.
References elog, ERROR, hash_search_with_hash_value(), and among::result.
Referenced by BufferAlloc(), and InvalidateBuffer().
{
BufferLookupEnt *result;
result = (BufferLookupEnt *)
hash_search_with_hash_value(SharedBufHash,
(void *) tagPtr,
hashcode,
HASH_REMOVE,
NULL);
if (!result) /* shouldn't happen */
elog(ERROR, "shared buffer hash table corrupted");
}
Definition at line 81 of file buf_table.c.
References get_hash_value().
Referenced by BufferAlloc(), InvalidateBuffer(), and PrefetchBuffer().
{
return get_hash_value(SharedBufHash, (void *) tagPtr);
}
Definition at line 121 of file buf_table.c.
References Assert, buftag::blockNum, hash_search_with_hash_value(), BufferLookupEnt::id, P_NEW, and among::result.
Referenced by BufferAlloc().
{
BufferLookupEnt *result;
bool found;
Assert(buf_id >= 0); /* -1 is reserved for not-in-table */
Assert(tagPtr->blockNum != P_NEW); /* invalid tag */
result = (BufferLookupEnt *)
hash_search_with_hash_value(SharedBufHash,
(void *) tagPtr,
hashcode,
HASH_ENTER,
&found);
if (found) /* found something already in the table */
return result->id;
result->id = buf_id;
return -1;
}
Definition at line 93 of file buf_table.c.
References hash_search_with_hash_value(), BufferLookupEnt::id, and among::result.
Referenced by BufferAlloc(), and PrefetchBuffer().
{
BufferLookupEnt *result;
result = (BufferLookupEnt *)
hash_search_with_hash_value(SharedBufHash,
(void *) tagPtr,
hashcode,
HASH_FIND,
NULL);
if (!result)
return -1;
return result->id;
}
| Size BufTableShmemSize | ( | int | size | ) |
Definition at line 43 of file buf_table.c.
References hash_estimate_size().
Referenced by StrategyShmemSize().
{
return hash_estimate_size(size, sizeof(BufferLookupEnt));
}
| void DropRelFileNodeAllLocalBuffers | ( | RelFileNode | rnode | ) |
Definition at line 345 of file localbuf.c.
References buftag::blockNum, BM_TAG_VALID, CLEAR_BUFFERTAG, elog, ERROR, sbufdesc::flags, buftag::forkNum, hash_search(), i, LocalRefCount, MyBackendId, NLocBuffer, RelFileNodeEquals, relpathbackend(), buftag::rnode, sbufdesc::tag, and sbufdesc::usage_count.
Referenced by DropRelFileNodesAllBuffers().
{
int i;
for (i = 0; i < NLocBuffer; i++)
{
BufferDesc *bufHdr = &LocalBufferDescriptors[i];
LocalBufferLookupEnt *hresult;
if ((bufHdr->flags & BM_TAG_VALID) &&
RelFileNodeEquals(bufHdr->tag.rnode, rnode))
{
if (LocalRefCount[i] != 0)
elog(ERROR, "block %u of %s is still referenced (local %u)",
bufHdr->tag.blockNum,
relpathbackend(bufHdr->tag.rnode, MyBackendId,
bufHdr->tag.forkNum),
LocalRefCount[i]);
/* Remove entry from hashtable */
hresult = (LocalBufferLookupEnt *)
hash_search(LocalBufHash, (void *) &bufHdr->tag,
HASH_REMOVE, NULL);
if (!hresult) /* shouldn't happen */
elog(ERROR, "local buffer hash table corrupted");
/* Mark buffer invalid */
CLEAR_BUFFERTAG(bufHdr->tag);
bufHdr->flags = 0;
bufHdr->usage_count = 0;
}
}
}
| void DropRelFileNodeLocalBuffers | ( | RelFileNode | rnode, | |
| ForkNumber | forkNum, | |||
| BlockNumber | firstDelBlock | |||
| ) |
Definition at line 302 of file localbuf.c.
References buftag::blockNum, BM_TAG_VALID, CLEAR_BUFFERTAG, elog, ERROR, sbufdesc::flags, buftag::forkNum, hash_search(), i, LocalRefCount, MyBackendId, NLocBuffer, RelFileNodeEquals, relpathbackend(), buftag::rnode, sbufdesc::tag, and sbufdesc::usage_count.
Referenced by DropRelFileNodeBuffers().
{
int i;
for (i = 0; i < NLocBuffer; i++)
{
BufferDesc *bufHdr = &LocalBufferDescriptors[i];
LocalBufferLookupEnt *hresult;
if ((bufHdr->flags & BM_TAG_VALID) &&
RelFileNodeEquals(bufHdr->tag.rnode, rnode) &&
bufHdr->tag.forkNum == forkNum &&
bufHdr->tag.blockNum >= firstDelBlock)
{
if (LocalRefCount[i] != 0)
elog(ERROR, "block %u of %s is still referenced (local %u)",
bufHdr->tag.blockNum,
relpathbackend(bufHdr->tag.rnode, MyBackendId,
bufHdr->tag.forkNum),
LocalRefCount[i]);
/* Remove entry from hashtable */
hresult = (LocalBufferLookupEnt *)
hash_search(LocalBufHash, (void *) &bufHdr->tag,
HASH_REMOVE, NULL);
if (!hresult) /* shouldn't happen */
elog(ERROR, "local buffer hash table corrupted");
/* Mark buffer invalid */
CLEAR_BUFFERTAG(bufHdr->tag);
bufHdr->flags = 0;
bufHdr->usage_count = 0;
}
}
}
| void InitBufTable | ( | int | size | ) |
Definition at line 53 of file buf_table.c.
References HASHCTL::entrysize, HASHCTL::hash, HASH_ELEM, HASH_FUNCTION, HASH_PARTITION, HASHCTL::keysize, HASHCTL::num_partitions, and ShmemInitHash().
Referenced by StrategyInitialize().
{
HASHCTL info;
/* assume no locking is needed yet */
/* BufferTag maps to Buffer */
info.keysize = sizeof(BufferTag);
info.entrysize = sizeof(BufferLookupEnt);
info.hash = tag_hash;
info.num_partitions = NUM_BUFFER_PARTITIONS;
SharedBufHash = ShmemInitHash("Shared Buffer Lookup Table",
size, size,
&info,
HASH_ELEM | HASH_FUNCTION | HASH_PARTITION);
}
| BufferDesc* LocalBufferAlloc | ( | SMgrRelation | smgr, | |
| ForkNumber | forkNum, | |||
| BlockNumber | blockNum, | |||
| bool * | foundPtr | |||
| ) |
Definition at line 103 of file localbuf.c.
References Assert, buftag::blockNum, BM_DIRTY, BM_JUST_DIRTIED, BM_MAX_USAGE_COUNT, BM_TAG_VALID, BM_VALID, BufferDescriptorGetBuffer, BUFFERTAGS_EQUAL, CLEAR_BUFFERTAG, CurrentResourceOwner, elog, ereport, errcode(), errmsg(), ERROR, sbufdesc::flags, buftag::forkNum, GetLocalBufferStorage(), hash_search(), LocalBufferLookupEnt::id, INIT_BUFFERTAG, InitLocalBuffers(), BufferUsage::local_blks_written, LocalBufHdrGetBlock, LocalRefCount, MyBackendId, nextFreeLocalBuf, NLocBuffer, RelFileNodeBackend::node, NULL, PageSetChecksumInplace(), pgBufferUsage, RelFileNode::relNode, ResourceOwnerRememberBuffer(), buftag::rnode, SMgrRelationData::smgr_rnode, smgropen(), smgrwrite(), sbufdesc::tag, and sbufdesc::usage_count.
Referenced by ReadBuffer_common().
{
BufferTag newTag; /* identity of requested block */
LocalBufferLookupEnt *hresult;
BufferDesc *bufHdr;
int b;
int trycounter;
bool found;
INIT_BUFFERTAG(newTag, smgr->smgr_rnode.node, forkNum, blockNum);
/* Initialize local buffers if first request in this session */
if (LocalBufHash == NULL)
InitLocalBuffers();
/* See if the desired buffer already exists */
hresult = (LocalBufferLookupEnt *)
hash_search(LocalBufHash, (void *) &newTag, HASH_FIND, NULL);
if (hresult)
{
b = hresult->id;
bufHdr = &LocalBufferDescriptors[b];
Assert(BUFFERTAGS_EQUAL(bufHdr->tag, newTag));
#ifdef LBDEBUG
fprintf(stderr, "LB ALLOC (%u,%d,%d) %d\n",
smgr->smgr_rnode.node.relNode, forkNum, blockNum, -b - 1);
#endif
/* this part is equivalent to PinBuffer for a shared buffer */
if (LocalRefCount[b] == 0)
{
if (bufHdr->usage_count < BM_MAX_USAGE_COUNT)
bufHdr->usage_count++;
}
LocalRefCount[b]++;
ResourceOwnerRememberBuffer(CurrentResourceOwner,
BufferDescriptorGetBuffer(bufHdr));
if (bufHdr->flags & BM_VALID)
*foundPtr = TRUE;
else
{
/* Previous read attempt must have failed; try again */
*foundPtr = FALSE;
}
return bufHdr;
}
#ifdef LBDEBUG
fprintf(stderr, "LB ALLOC (%u,%d,%d) %d\n",
smgr->smgr_rnode.node.relNode, forkNum, blockNum,
-nextFreeLocalBuf - 1);
#endif
/*
* Need to get a new buffer. We use a clock sweep algorithm (essentially
* the same as what freelist.c does now...)
*/
trycounter = NLocBuffer;
for (;;)
{
b = nextFreeLocalBuf;
if (++nextFreeLocalBuf >= NLocBuffer)
nextFreeLocalBuf = 0;
bufHdr = &LocalBufferDescriptors[b];
if (LocalRefCount[b] == 0)
{
if (bufHdr->usage_count > 0)
{
bufHdr->usage_count--;
trycounter = NLocBuffer;
}
else
{
/* Found a usable buffer */
LocalRefCount[b]++;
ResourceOwnerRememberBuffer(CurrentResourceOwner,
BufferDescriptorGetBuffer(bufHdr));
break;
}
}
else if (--trycounter == 0)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_RESOURCES),
errmsg("no empty local buffer available")));
}
/*
* this buffer is not referenced but it might still be dirty. if that's
* the case, write it out before reusing it!
*/
if (bufHdr->flags & BM_DIRTY)
{
SMgrRelation oreln;
Page localpage = (char *) LocalBufHdrGetBlock(bufHdr);
/* Find smgr relation for buffer */
oreln = smgropen(bufHdr->tag.rnode, MyBackendId);
PageSetChecksumInplace(localpage, bufHdr->tag.blockNum);
/* And write... */
smgrwrite(oreln,
bufHdr->tag.forkNum,
bufHdr->tag.blockNum,
localpage,
false);
/* Mark not-dirty now in case we error out below */
bufHdr->flags &= ~BM_DIRTY;
pgBufferUsage.local_blks_written++;
}
/*
* lazy memory allocation: allocate space on first use of a buffer.
*/
if (LocalBufHdrGetBlock(bufHdr) == NULL)
{
/* Set pointer for use by BufferGetBlock() macro */
LocalBufHdrGetBlock(bufHdr) = GetLocalBufferStorage();
}
/*
* Update the hash table: remove old entry, if any, and make new one.
*/
if (bufHdr->flags & BM_TAG_VALID)
{
hresult = (LocalBufferLookupEnt *)
hash_search(LocalBufHash, (void *) &bufHdr->tag,
HASH_REMOVE, NULL);
if (!hresult) /* shouldn't happen */
elog(ERROR, "local buffer hash table corrupted");
/* mark buffer invalid just in case hash insert fails */
CLEAR_BUFFERTAG(bufHdr->tag);
bufHdr->flags &= ~(BM_VALID | BM_TAG_VALID);
}
hresult = (LocalBufferLookupEnt *)
hash_search(LocalBufHash, (void *) &newTag, HASH_ENTER, &found);
if (found) /* shouldn't happen */
elog(ERROR, "local buffer hash table corrupted");
hresult->id = b;
/*
* it's all ours now.
*/
bufHdr->tag = newTag;
bufHdr->flags &= ~(BM_VALID | BM_DIRTY | BM_JUST_DIRTIED | BM_IO_ERROR);
bufHdr->flags |= BM_TAG_VALID;
bufHdr->usage_count = 1;
*foundPtr = FALSE;
return bufHdr;
}
| void LocalPrefetchBuffer | ( | SMgrRelation | smgr, | |
| ForkNumber | forkNum, | |||
| BlockNumber | blockNum | |||
| ) |
Definition at line 64 of file localbuf.c.
References hash_search(), INIT_BUFFERTAG, InitLocalBuffers(), RelFileNodeBackend::node, NULL, SMgrRelationData::smgr_rnode, and smgrprefetch().
Referenced by PrefetchBuffer().
{
#ifdef USE_PREFETCH
BufferTag newTag; /* identity of requested block */
LocalBufferLookupEnt *hresult;
INIT_BUFFERTAG(newTag, smgr->smgr_rnode.node, forkNum, blockNum);
/* Initialize local buffers if first request in this session */
if (LocalBufHash == NULL)
InitLocalBuffers();
/* See if the desired buffer already exists */
hresult = (LocalBufferLookupEnt *)
hash_search(LocalBufHash, (void *) &newTag, HASH_FIND, NULL);
if (hresult)
{
/* Yes, so nothing to do */
return;
}
/* Not in buffers, so initiate prefetch */
smgrprefetch(smgr, forkNum, blockNum);
#endif /* USE_PREFETCH */
}
| void MarkLocalBufferDirty | ( | Buffer | buffer | ) |
Definition at line 267 of file localbuf.c.
References Assert, BM_DIRTY, BufferIsLocal, sbufdesc::flags, BufferUsage::local_blks_dirtied, LocalRefCount, and pgBufferUsage.
Referenced by MarkBufferDirty(), and MarkBufferDirtyHint().
{
int bufid;
BufferDesc *bufHdr;
Assert(BufferIsLocal(buffer));
#ifdef LBDEBUG
fprintf(stderr, "LB DIRTY %d\n", buffer);
#endif
bufid = -(buffer + 1);
Assert(LocalRefCount[bufid] > 0);
bufHdr = &LocalBufferDescriptors[bufid];
if (!(bufHdr->flags & BM_DIRTY))
pgBufferUsage.local_blks_dirtied++;
bufHdr->flags |= BM_DIRTY;
}
| void StrategyFreeBuffer | ( | volatile BufferDesc * | buf | ) |
Definition at line 242 of file freelist.c.
References sbufdesc::buf_id, BufFreelistLock, BufferStrategyControl::firstFreeBuffer, sbufdesc::freeNext, FREENEXT_NOT_IN_LIST, BufferStrategyControl::lastFreeBuffer, LW_EXCLUSIVE, LWLockAcquire(), and LWLockRelease().
Referenced by InvalidateBuffer().
{
LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE);
/*
* It is possible that we are told to put something in the freelist that
* is already in it; don't screw up the list if so.
*/
if (buf->freeNext == FREENEXT_NOT_IN_LIST)
{
buf->freeNext = StrategyControl->firstFreeBuffer;
if (buf->freeNext < 0)
StrategyControl->lastFreeBuffer = buf->buf_id;
StrategyControl->firstFreeBuffer = buf->buf_id;
}
LWLockRelease(BufFreelistLock);
}
| volatile BufferDesc* StrategyGetBuffer | ( | BufferAccessStrategy | strategy, | |
| bool * | lock_held | |||
| ) |
Definition at line 112 of file freelist.c.
References AddBufferToRing(), Assert, BufferStrategyControl::bgwriterLatch, buf, BufferDescriptors, BufFreelistLock, BufferStrategyControl::completePasses, elog, ERROR, BufferStrategyControl::firstFreeBuffer, sbufdesc::freeNext, FREENEXT_NOT_IN_LIST, GetBufferFromRing(), LockBufHdr, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), NBuffers, BufferStrategyControl::nextVictimBuffer, NULL, BufferStrategyControl::numBufferAllocs, sbufdesc::refcount, SetLatch(), UnlockBufHdr, and sbufdesc::usage_count.
Referenced by BufferAlloc().
{
volatile BufferDesc *buf;
Latch *bgwriterLatch;
int trycounter;
/*
* If given a strategy object, see whether it can select a buffer. We
* assume strategy objects don't need the BufFreelistLock.
*/
if (strategy != NULL)
{
buf = GetBufferFromRing(strategy);
if (buf != NULL)
{
*lock_held = false;
return buf;
}
}
/* Nope, so lock the freelist */
*lock_held = true;
LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE);
/*
* We count buffer allocation requests so that the bgwriter can estimate
* the rate of buffer consumption. Note that buffers recycled by a
* strategy object are intentionally not counted here.
*/
StrategyControl->numBufferAllocs++;
/*
* If bgwriterLatch is set, we need to waken the bgwriter, but we should
* not do so while holding BufFreelistLock; so release and re-grab. This
* is annoyingly tedious, but it happens at most once per bgwriter cycle,
* so the performance hit is minimal.
*/
bgwriterLatch = StrategyControl->bgwriterLatch;
if (bgwriterLatch)
{
StrategyControl->bgwriterLatch = NULL;
LWLockRelease(BufFreelistLock);
SetLatch(bgwriterLatch);
LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE);
}
/*
* Try to get a buffer from the freelist. Note that the freeNext fields
* are considered to be protected by the BufFreelistLock not the
* individual buffer spinlocks, so it's OK to manipulate them without
* holding the spinlock.
*/
while (StrategyControl->firstFreeBuffer >= 0)
{
buf = &BufferDescriptors[StrategyControl->firstFreeBuffer];
Assert(buf->freeNext != FREENEXT_NOT_IN_LIST);
/* Unconditionally remove buffer from freelist */
StrategyControl->firstFreeBuffer = buf->freeNext;
buf->freeNext = FREENEXT_NOT_IN_LIST;
/*
* If the buffer is pinned or has a nonzero usage_count, we cannot use
* it; discard it and retry. (This can only happen if VACUUM put a
* valid buffer in the freelist and then someone else used it before
* we got to it. It's probably impossible altogether as of 8.3, but
* we'd better check anyway.)
*/
LockBufHdr(buf);
if (buf->refcount == 0 && buf->usage_count == 0)
{
if (strategy != NULL)
AddBufferToRing(strategy, buf);
return buf;
}
UnlockBufHdr(buf);
}
/* Nothing on the freelist, so run the "clock sweep" algorithm */
trycounter = NBuffers;
for (;;)
{
buf = &BufferDescriptors[StrategyControl->nextVictimBuffer];
if (++StrategyControl->nextVictimBuffer >= NBuffers)
{
StrategyControl->nextVictimBuffer = 0;
StrategyControl->completePasses++;
}
/*
* If the buffer is pinned or has a nonzero usage_count, we cannot use
* it; decrement the usage_count (unless pinned) and keep scanning.
*/
LockBufHdr(buf);
if (buf->refcount == 0)
{
if (buf->usage_count > 0)
{
buf->usage_count--;
trycounter = NBuffers;
}
else
{
/* Found a usable buffer */
if (strategy != NULL)
AddBufferToRing(strategy, buf);
return buf;
}
}
else if (--trycounter == 0)
{
/*
* We've scanned all the buffers without making any state changes,
* so all the buffers are pinned (or were when we looked at them).
* We could hope that someone will free one eventually, but it's
* probably better to fail than to risk getting stuck in an
* infinite loop.
*/
UnlockBufHdr(buf);
elog(ERROR, "no unpinned buffers available");
}
UnlockBufHdr(buf);
}
}
| void StrategyInitialize | ( | bool | init | ) |
Definition at line 342 of file freelist.c.
References Assert, BufferStrategyControl::bgwriterLatch, BufferStrategyControl::completePasses, BufferStrategyControl::firstFreeBuffer, InitBufTable(), BufferStrategyControl::lastFreeBuffer, NBuffers, BufferStrategyControl::nextVictimBuffer, NUM_BUFFER_PARTITIONS, BufferStrategyControl::numBufferAllocs, and ShmemInitStruct().
Referenced by InitBufferPool().
{
bool found;
/*
* Initialize the shared buffer lookup hashtable.
*
* Since we can't tolerate running out of lookup table entries, we must be
* sure to specify an adequate table size here. The maximum steady-state
* usage is of course NBuffers entries, but BufferAlloc() tries to insert
* a new entry before deleting the old. In principle this could be
* happening in each partition concurrently, so we could need as many as
* NBuffers + NUM_BUFFER_PARTITIONS entries.
*/
InitBufTable(NBuffers + NUM_BUFFER_PARTITIONS);
/*
* Get or create the shared strategy control block
*/
StrategyControl = (BufferStrategyControl *)
ShmemInitStruct("Buffer Strategy Status",
sizeof(BufferStrategyControl),
&found);
if (!found)
{
/*
* Only done once, usually in postmaster
*/
Assert(init);
/*
* Grab the whole linked list of free buffers for our strategy. We
* assume it was previously set up by InitBufferPool().
*/
StrategyControl->firstFreeBuffer = 0;
StrategyControl->lastFreeBuffer = NBuffers - 1;
/* Initialize the clock sweep pointer */
StrategyControl->nextVictimBuffer = 0;
/* Clear statistics */
StrategyControl->completePasses = 0;
StrategyControl->numBufferAllocs = 0;
/* No pending notification */
StrategyControl->bgwriterLatch = NULL;
}
else
Assert(!init);
}
| void StrategyNotifyBgWriter | ( | Latch * | bgwriterLatch | ) |
Definition at line 299 of file freelist.c.
References BufferStrategyControl::bgwriterLatch, BufFreelistLock, LW_EXCLUSIVE, LWLockAcquire(), and LWLockRelease().
Referenced by BackgroundWriterMain().
{
/*
* We acquire the BufFreelistLock just to ensure that the store appears
* atomic to StrategyGetBuffer. The bgwriter should call this rather
* infrequently, so there's no performance penalty from being safe.
*/
LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE);
StrategyControl->bgwriterLatch = bgwriterLatch;
LWLockRelease(BufFreelistLock);
}
| bool StrategyRejectBuffer | ( | BufferAccessStrategy | strategy, | |
| volatile BufferDesc * | buf | |||
| ) |
Definition at line 547 of file freelist.c.
References BAS_BULKREAD, BufferAccessStrategyData::btype, BufferDescriptorGetBuffer, BufferAccessStrategyData::buffers, BufferAccessStrategyData::current, and BufferAccessStrategyData::current_was_in_ring.
Referenced by BufferAlloc().
{
/* We only do this in bulkread mode */
if (strategy->btype != BAS_BULKREAD)
return false;
/* Don't muck with behavior of normal buffer-replacement strategy */
if (!strategy->current_was_in_ring ||
strategy->buffers[strategy->current] != BufferDescriptorGetBuffer(buf))
return false;
/*
* Remove the dirty buffer from the ring; necessary to prevent infinite
* loop if all ring members are dirty.
*/
strategy->buffers[strategy->current] = InvalidBuffer;
return true;
}
| Size StrategyShmemSize | ( | void | ) |
Definition at line 321 of file freelist.c.
References add_size(), BufTableShmemSize(), MAXALIGN, NBuffers, and NUM_BUFFER_PARTITIONS.
Referenced by BufferShmemSize().
{
Size size = 0;
/* size of lookup hash table ... see comment in StrategyInitialize */
size = add_size(size, BufTableShmemSize(NBuffers + NUM_BUFFER_PARTITIONS));
/* size of the shared replacement strategy control block */
size = add_size(size, MAXALIGN(sizeof(BufferStrategyControl)));
return size;
}
Definition at line 273 of file freelist.c.
References BufFreelistLock, BufferStrategyControl::completePasses, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), BufferStrategyControl::nextVictimBuffer, and BufferStrategyControl::numBufferAllocs.
Referenced by BgBufferSync(), and BufferSync().
{
int result;
LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE);
result = StrategyControl->nextVictimBuffer;
if (complete_passes)
*complete_passes = StrategyControl->completePasses;
if (num_buf_alloc)
{
*num_buf_alloc = StrategyControl->numBufferAllocs;
StrategyControl->numBufferAllocs = 0;
}
LWLockRelease(BufFreelistLock);
return result;
}
| PGDLLIMPORT BufferDesc* BufferDescriptors |
Definition at line 21 of file buf_init.c.
Referenced by BufferAlloc(), BufferGetBlockNumber(), BufferGetLSNAtomic(), BufferGetTag(), BufferIsPermanent(), BufferSync(), ConditionalLockBuffer(), ConditionalLockBufferForCleanup(), DropDatabaseBuffers(), DropRelFileNodeBuffers(), DropRelFileNodesAllBuffers(), FlushDatabaseBuffers(), FlushRelationBuffers(), GetBufferFromRing(), LockBuffer(), LockBufferForCleanup(), MarkBufferDirty(), MarkBufferDirtyHint(), pg_buffercache_pages(), PrintBufferLeakWarning(), ReleaseAndReadBuffer(), ReleaseBuffer(), StrategyGetBuffer(), and SyncOneBuffer().
Definition at line 43 of file localbuf.c.
Referenced by BufferGetBlockNumber(), BufferGetTag(), FlushRelationBuffers(), PrintBufferLeakWarning(), and ReleaseAndReadBuffer().
1.7.1