Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Typedefs | Functions | Variables

buf_internals.h File Reference

#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"
Include dependency graph for buf_internals.h:
This graph shows which files directly or indirectly include this file:

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 BufferDescStrategyGetBuffer (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)
BufferDescLocalBufferAlloc (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 BufferDescBufferDescriptors
BufferDescLocalBufferDescriptors

Define Documentation

#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)
#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)
#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)
#define BM_VALID   (1 << 1)
#define BufferDescriptorGetBuffer (   bdesc  )     ((bdesc)->buf_id + 1)
#define BUFFERTAGS_EQUAL (   a,
  b 
)
Value:
( \
    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  ) 
Value:
( \
    (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 
)
Value:
( \
    (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)
#define UnlockBufHdr (   bufHdr  )     SpinLockRelease(&(bufHdr)->buf_hdr_lock)

Typedef Documentation

typedef struct sbufdesc BufferDesc
typedef struct buftag BufferTag
typedef bits16 BufFlags

Definition at line 44 of file buf_internals.h.


Function Documentation

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 BufTableDelete ( BufferTag tagPtr,
uint32  hashcode 
)

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");
}

uint32 BufTableHashCode ( BufferTag tagPtr  ) 

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);
}

int BufTableInsert ( BufferTag tagPtr,
uint32  hashcode,
int  buf_id 
)

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;
}

int BufTableLookup ( BufferTag tagPtr,
uint32  hashcode 
)

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;
}

int StrategySyncStart ( uint32 complete_passes,
uint32 num_buf_alloc 
)

Variable Documentation