#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().