#include "postgres.h"#include "catalog/catalog.h"#include "common/relpath.h"#include "executor/instrument.h"#include "storage/buf_internals.h"#include "storage/bufmgr.h"#include "utils/guc.h"#include "utils/memutils.h"#include "utils/resowner_private.h"
Go to the source code of this file.
Data Structures | |
| struct | LocalBufferLookupEnt |
Defines | |
| #define | LocalBufHdrGetBlock(bufHdr) LocalBufferBlockPointers[-((bufHdr)->buf_id + 2)] |
Functions | |
| static void | InitLocalBuffers (void) |
| static Block | GetLocalBufferStorage (void) |
| 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) |
| void | AtProcExit_LocalBuffers (void) |
Variables | |
| int | NLocBuffer = 0 |
| BufferDesc * | LocalBufferDescriptors = NULL |
| Block * | LocalBufferBlockPointers = NULL |
| int32 * | LocalRefCount = NULL |
| static int | nextFreeLocalBuf = 0 |
| static HTAB * | LocalBufHash = NULL |
| #define LocalBufHdrGetBlock | ( | bufHdr | ) | LocalBufferBlockPointers[-((bufHdr)->buf_id + 2)] |
Definition at line 38 of file localbuf.c.
Referenced by LocalBufferAlloc().
| 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
}
| void AtProcExit_LocalBuffers | ( | void | ) |
Definition at line 532 of file localbuf.c.
References Assert, assert_enabled, i, LocalRefCount, NLocBuffer, and PrintBufferLeakWarning().
Referenced by AtProcExit_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
}
| 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;
}
}
}
| static Block GetLocalBufferStorage | ( | void | ) | [static] |
Definition at line 443 of file localbuf.c.
References ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), Assert, Max, MaxAllocSize, MemoryContextAlloc(), Min, NLocBuffer, NULL, and TopMemoryContext.
Referenced by LocalBufferAlloc().
{
static char *cur_block = NULL;
static int next_buf_in_block = 0;
static int num_bufs_in_block = 0;
static int total_bufs_allocated = 0;
static MemoryContext LocalBufferContext = NULL;
char *this_buf;
Assert(total_bufs_allocated < NLocBuffer);
if (next_buf_in_block >= num_bufs_in_block)
{
/* Need to make a new request to memmgr */
int num_bufs;
/*
* We allocate local buffers in a context of their own, so that the
* space eaten for them is easily recognizable in MemoryContextStats
* output. Create the context on first use.
*/
if (LocalBufferContext == NULL)
LocalBufferContext =
AllocSetContextCreate(TopMemoryContext,
"LocalBufferContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
/* Start with a 16-buffer request; subsequent ones double each time */
num_bufs = Max(num_bufs_in_block * 2, 16);
/* But not more than what we need for all remaining local bufs */
num_bufs = Min(num_bufs, NLocBuffer - total_bufs_allocated);
/* And don't overflow MaxAllocSize, either */
num_bufs = Min(num_bufs, MaxAllocSize / BLCKSZ);
cur_block = (char *) MemoryContextAlloc(LocalBufferContext,
num_bufs * BLCKSZ);
next_buf_in_block = 0;
num_bufs_in_block = num_bufs;
}
/* Allocate next buffer in current memory block */
this_buf = cur_block + next_buf_in_block * BLCKSZ;
next_buf_in_block++;
total_bufs_allocated++;
return (Block) this_buf;
}
| static void InitLocalBuffers | ( | void | ) | [static] |
Definition at line 384 of file localbuf.c.
References buf, sbufdesc::buf_id, calloc, elog, HASHCTL::entrysize, ereport, errcode(), errmsg(), ERROR, FATAL, HASHCTL::hash, hash_create(), HASH_ELEM, HASH_FUNCTION, i, HASHCTL::keysize, LocalBufferBlockPointers, LocalRefCount, MemSet, nextFreeLocalBuf, NLocBuffer, and num_temp_buffers.
Referenced by LocalBufferAlloc(), and LocalPrefetchBuffer().
{
int nbufs = num_temp_buffers;
HASHCTL info;
int i;
/* Allocate and zero buffer headers and auxiliary arrays */
LocalBufferDescriptors = (BufferDesc *) calloc(nbufs, sizeof(BufferDesc));
LocalBufferBlockPointers = (Block *) calloc(nbufs, sizeof(Block));
LocalRefCount = (int32 *) calloc(nbufs, sizeof(int32));
if (!LocalBufferDescriptors || !LocalBufferBlockPointers || !LocalRefCount)
ereport(FATAL,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory")));
nextFreeLocalBuf = 0;
/* initialize fields that need to start off nonzero */
for (i = 0; i < nbufs; i++)
{
BufferDesc *buf = &LocalBufferDescriptors[i];
/*
* negative to indicate local buffer. This is tricky: shared buffers
* start with 0. We have to start with -2. (Note that the routine
* BufferDescriptorGetBuffer adds 1 to buf_id so our first buffer id
* is -1.)
*/
buf->buf_id = -i - 2;
}
/* Create the lookup hash table */
MemSet(&info, 0, sizeof(info));
info.keysize = sizeof(BufferTag);
info.entrysize = sizeof(LocalBufferLookupEnt);
info.hash = tag_hash;
LocalBufHash = hash_create("Local Buffer Lookup Table",
nbufs,
&info,
HASH_ELEM | HASH_FUNCTION);
if (!LocalBufHash)
elog(ERROR, "could not initialize local buffer hash table");
/* Initialization done, mark buffers allocated */
NLocBuffer = nbufs;
}
| 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;
}
| Block* LocalBufferBlockPointers = NULL |
Definition at line 44 of file localbuf.c.
Referenced by InitLocalBuffers().
| BufferDesc* LocalBufferDescriptors = NULL |
Definition at line 43 of file localbuf.c.
Referenced by BufferGetBlockNumber(), BufferGetTag(), FlushRelationBuffers(), PrintBufferLeakWarning(), and ReleaseAndReadBuffer().
HTAB* LocalBufHash = NULL [static] |
Definition at line 49 of file localbuf.c.
| int32* LocalRefCount = NULL |
Definition at line 45 of file localbuf.c.
Referenced by AtEOXact_LocalBuffers(), AtProcExit_LocalBuffers(), ConditionalLockBufferForCleanup(), DropRelFileNodeAllLocalBuffers(), DropRelFileNodeLocalBuffers(), IncrBufferRefCount(), InitLocalBuffers(), LocalBufferAlloc(), LockBufferForCleanup(), MarkLocalBufferDirty(), PrintBufferLeakWarning(), ReleaseAndReadBuffer(), and ReleaseBuffer().
int nextFreeLocalBuf = 0 [static] |
Definition at line 47 of file localbuf.c.
Referenced by InitLocalBuffers(), and LocalBufferAlloc().
| int NLocBuffer = 0 |
Definition at line 41 of file localbuf.c.
Referenced by AtEOXact_LocalBuffers(), AtProcExit_LocalBuffers(), check_temp_buffers(), DropRelFileNodeAllLocalBuffers(), DropRelFileNodeLocalBuffers(), FlushRelationBuffers(), GetLocalBufferStorage(), InitLocalBuffers(), and LocalBufferAlloc().
1.7.1