1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-12 05:01:15 +03:00

Postgres95 1.01 Distribution - Virgin Sources

This commit is contained in:
Marc G. Fournier
1996-07-09 06:22:35 +00:00
commit d31084e9d1
868 changed files with 242656 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
#-------------------------------------------------------------------------
#
# Makefile.inc--
# Makefile for storage/buffer
#
# Copyright (c) 1994, Regents of the University of California
#
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/Makefile.inc,v 1.1.1.1 1996/07/09 06:21:53 scrappy Exp $
#
#-------------------------------------------------------------------------
SUBSRCS+= buf_table.c buf_init.c bufmgr.c freelist.c localbuf.c
SRCS_SITEMGR+= buf_table.c buf_init.c freelist.c

View File

@@ -0,0 +1,280 @@
/*-------------------------------------------------------------------------
*
* buf_init.c--
* buffer manager initialization routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.1.1.1 1996/07/09 06:21:53 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <sys/file.h>
#include <stdio.h>
#include <math.h>
#include <signal.h>
/* declarations split between these three files */
#include "storage/buf.h"
#include "storage/buf_internals.h"
#include "storage/bufmgr.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/shmem.h"
#include "storage/spin.h"
#include "storage/smgr.h"
#include "storage/lmgr.h"
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/hsearch.h"
#include "utils/elog.h"
#include "utils/memutils.h"
#include "executor/execdebug.h" /* for NDirectFileRead */
#include "catalog/catalog.h"
/*
* if BMTRACE is defined, we trace the last 200 buffer allocations and
* deallocations in a circular buffer in shared memory.
*/
#ifdef BMTRACE
bmtrace *TraceBuf;
long *CurTraceBuf;
#define BMT_LIMIT 200
#endif /* BMTRACE */
int ShowPinTrace = 0;
int NBuffers = NDBUFS; /* NDBUFS defined in miscadmin.h */
int Data_Descriptors;
int Free_List_Descriptor;
int Lookup_List_Descriptor;
int Num_Descriptors;
BufferDesc *BufferDescriptors;
BufferBlock BufferBlocks;
#ifndef HAS_TEST_AND_SET
long *NWaitIOBackendP;
#endif
extern IpcSemaphoreId WaitIOSemId;
long *PrivateRefCount; /* also used in freelist.c */
long *LastRefCount; /* refcounts of last ExecMain level */
/*
* Data Structures:
* buffers live in a freelist and a lookup data structure.
*
*
* Buffer Lookup:
* Two important notes. First, the buffer has to be
* available for lookup BEFORE an IO begins. Otherwise
* a second process trying to read the buffer will
* allocate its own copy and the buffeer pool will
* become inconsistent.
*
* Buffer Replacement:
* see freelist.c. A buffer cannot be replaced while in
* use either by data manager or during IO.
*
* WriteBufferBack:
* currently, a buffer is only written back at the time
* it is selected for replacement. It should
* be done sooner if possible to reduce latency of
* BufferAlloc(). Maybe there should be a daemon process.
*
* Synchronization/Locking:
*
* BufMgrLock lock -- must be acquired before manipulating the
* buffer queues (lookup/freelist). Must be released
* before exit and before doing any IO.
*
* IO_IN_PROGRESS -- this is a flag in the buffer descriptor.
* It must be set when an IO is initiated and cleared at
* the end of the IO. It is there to make sure that one
* process doesn't start to use a buffer while another is
* faulting it in. see IOWait/IOSignal.
*
* refcount -- A buffer is pinned during IO and immediately
* after a BufferAlloc(). A buffer is always either pinned
* or on the freelist but never both. The buffer must be
* released, written, or flushed before the end of
* transaction.
*
* PrivateRefCount -- Each buffer also has a private refcount the keeps
* track of the number of times the buffer is pinned in the current
* processes. This is used for two purposes, first, if we pin a
* a buffer more than once, we only need to change the shared refcount
* once, thus only lock the buffer pool once, second, when a transaction
* aborts, it should only unpin the buffers exactly the number of times it
* has pinned them, so that it will not blow away buffers of another
* backend.
*
*/
SPINLOCK BufMgrLock;
/* delayed write: TRUE on, FALSE off */
int LateWrite = TRUE;
int ReadBufferCount;
int BufferHitCount;
int BufferFlushCount;
/*
* Initialize module:
*
* should calculate size of pool dynamically based on the
* amount of available memory.
*/
void
InitBufferPool(IPCKey key)
{
bool foundBufs,foundDescs;
int i;
Data_Descriptors = NBuffers;
Free_List_Descriptor = Data_Descriptors;
Lookup_List_Descriptor = Data_Descriptors + 1;
Num_Descriptors = Data_Descriptors + 1;
SpinAcquire(BufMgrLock);
#ifdef BMTRACE
CurTraceBuf = (long *) ShmemInitStruct("Buffer trace",
(BMT_LIMIT * sizeof(bmtrace)) + sizeof(long),
&foundDescs);
if (!foundDescs)
memset(CurTraceBuf, 0, (BMT_LIMIT * sizeof(bmtrace)) + sizeof(long));
TraceBuf = (bmtrace *) &(CurTraceBuf[1]);
#endif
BufferDescriptors = (BufferDesc *)
ShmemInitStruct("Buffer Descriptors",
Num_Descriptors*sizeof(BufferDesc),&foundDescs);
BufferBlocks = (BufferBlock)
ShmemInitStruct("Buffer Blocks",
NBuffers*BLCKSZ,&foundBufs);
#ifndef HAS_TEST_AND_SET
{
bool foundNWaitIO;
NWaitIOBackendP = (long *)ShmemInitStruct("#Backends Waiting IO",
sizeof(long),
&foundNWaitIO);
if (!foundNWaitIO)
*NWaitIOBackendP = 0;
}
#endif
if (foundDescs || foundBufs) {
/* both should be present or neither */
Assert(foundDescs && foundBufs);
} else {
BufferDesc *buf;
unsigned long block;
buf = BufferDescriptors;
block = (unsigned long) BufferBlocks;
/*
* link the buffers into a circular, doubly-linked list to
* initialize free list. Still don't know anything about
* replacement strategy in this file.
*/
for (i = 0; i < Data_Descriptors; block+=BLCKSZ,buf++,i++) {
Assert(ShmemIsValid((unsigned long)block));
buf->freeNext = i+1;
buf->freePrev = i-1;
CLEAR_BUFFERTAG(&(buf->tag));
buf->data = MAKE_OFFSET(block);
buf->flags = (BM_DELETED | BM_FREE | BM_VALID);
buf->refcount = 0;
buf->buf_id = i;
#ifdef HAS_TEST_AND_SET
S_INIT_LOCK(&(buf->io_in_progress_lock));
#endif
}
/* close the circular queue */
BufferDescriptors[0].freePrev = Data_Descriptors-1;
BufferDescriptors[Data_Descriptors-1].freeNext = 0;
}
/* Init the rest of the module */
InitBufTable();
InitFreeList(!foundDescs);
SpinRelease(BufMgrLock);
#ifndef HAS_TEST_AND_SET
{
int status;
WaitIOSemId = IpcSemaphoreCreate(IPCKeyGetWaitIOSemaphoreKey(key),
1, IPCProtection, 0, 1, &status);
}
#endif
PrivateRefCount = (long *) calloc(NBuffers, sizeof(long));
LastRefCount = (long *) calloc(NBuffers, sizeof(long));
}
/* -----------------------------------------------------
* BufferShmemSize
*
* compute the size of shared memory for the buffer pool including
* data pages, buffer descriptors, hash tables, etc.
* ----------------------------------------------------
*/
int
BufferShmemSize()
{
int size = 0;
int nbuckets;
int nsegs;
int tmp;
nbuckets = 1 << (int)my_log2((NBuffers - 1) / DEF_FFACTOR + 1);
nsegs = 1 << (int)my_log2((nbuckets - 1) / DEF_SEGSIZE + 1);
/* size of shmem binding table */
size += MAXALIGN(my_log2(BTABLE_SIZE) * sizeof(void *)); /* HTAB->dir */
size += MAXALIGN(sizeof(HHDR)); /* HTAB->hctl */
size += MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT));
size += BUCKET_ALLOC_INCR *
(MAXALIGN(sizeof(BUCKET_INDEX)) +
MAXALIGN(BTABLE_KEYSIZE) +
MAXALIGN(BTABLE_DATASIZE));
/* size of buffer descriptors */
size += MAXALIGN((NBuffers + 1) * sizeof(BufferDesc));
/* size of data pages */
size += NBuffers * MAXALIGN(BLCKSZ);
/* size of buffer hash table */
size += MAXALIGN(my_log2(NBuffers) * sizeof(void *)); /* HTAB->dir */
size += MAXALIGN(sizeof(HHDR)); /* HTAB->hctl */
size += nsegs * MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT));
tmp = (int)ceil((double)NBuffers/BUCKET_ALLOC_INCR);
size += tmp * BUCKET_ALLOC_INCR *
(MAXALIGN(sizeof(BUCKET_INDEX)) +
MAXALIGN(sizeof(BufferTag)) +
MAXALIGN(sizeof(Buffer)));
#ifdef BMTRACE
size += (BMT_LIMIT * sizeof(bmtrace)) + sizeof(long);
#endif
return size;
}

View File

@@ -0,0 +1,162 @@
/*-------------------------------------------------------------------------
*
* buf_table.c--
* routines for finding buffers in the buffer pool.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_table.c,v 1.1.1.1 1996/07/09 06:21:53 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
/*
* OLD COMMENTS
*
* Data Structures:
*
* Buffers are identified by their BufferTag (buf.h). This
* file contains routines for allocating a shmem hash table to
* map buffer tags to buffer descriptors.
*
* Synchronization:
*
* All routines in this file assume buffer manager spinlock is
* held by their caller.
*/
#include "storage/bufmgr.h"
#include "storage/buf_internals.h" /* where the declarations go */
#include "storage/shmem.h"
#include "storage/spin.h"
#include "utils/hsearch.h"
#include "utils/elog.h"
static HTAB *SharedBufHash;
extern HTAB *ShmemInitHash();
typedef struct lookup {
BufferTag key;
Buffer id;
} LookupEnt;
/*
* Initialize shmem hash table for mapping buffers
*/
void
InitBufTable()
{
HASHCTL info;
int hash_flags;
/* assume lock is held */
/* BufferTag maps to Buffer */
info.keysize = sizeof(BufferTag);
info.datasize = sizeof(Buffer);
info.hash = tag_hash;
hash_flags = (HASH_ELEM | HASH_FUNCTION);
SharedBufHash = (HTAB *) ShmemInitHash("Shared Buf Lookup Table",
NBuffers,NBuffers,
&info,hash_flags);
if (! SharedBufHash) {
elog(FATAL,"couldn't initialize shared buffer pool Hash Tbl");
exit(1);
}
}
BufferDesc *
BufTableLookup(BufferTag *tagPtr)
{
LookupEnt * result;
bool found;
if (tagPtr->blockNum == P_NEW)
return(NULL);
result = (LookupEnt *)
hash_search(SharedBufHash,(char *) tagPtr,HASH_FIND,&found);
if (! result){
elog(WARN,"BufTableLookup: BufferLookup table corrupted");
return(NULL);
}
if (! found) {
return(NULL);
}
return(&(BufferDescriptors[result->id]));
}
/*
* BufTableDelete
*/
bool
BufTableDelete(BufferDesc *buf)
{
LookupEnt * result;
bool found;
/* buffer not initialized or has been removed from
* table already. BM_DELETED keeps us from removing
* buffer twice.
*/
if (buf->flags & BM_DELETED) {
return(TRUE);
}
buf->flags |= BM_DELETED;
result = (LookupEnt *)
hash_search(SharedBufHash,(char *) &(buf->tag),HASH_REMOVE,&found);
if (! (result && found)) {
elog(WARN,"BufTableDelete: BufferLookup table corrupted");
return(FALSE);
}
return(TRUE);
}
bool
BufTableInsert(BufferDesc *buf)
{
LookupEnt * result;
bool found;
/* cannot insert it twice */
Assert (buf->flags & BM_DELETED);
buf->flags &= ~(BM_DELETED);
result = (LookupEnt *)
hash_search(SharedBufHash,(char *) &(buf->tag),HASH_ENTER,&found);
if (! result) {
Assert(0);
elog(WARN,"BufTableInsert: BufferLookup table corrupted");
return(FALSE);
}
/* found something else in the table ! */
if (found) {
Assert(0);
elog(WARN,"BufTableInsert: BufferLookup table corrupted");
return(FALSE);
}
result->id = buf->buf_id;
return(TRUE);
}
/* prints out collision stats for the buf table */
void
DBG_LookupListCheck(int nlookup)
{
nlookup = 10;
hash_stats("Shared",SharedBufHash);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,285 @@
/*-------------------------------------------------------------------------
*
* freelist.c--
* routines for manipulating the buffer pool's replacement strategy
* freelist.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/freelist.c,v 1.1.1.1 1996/07/09 06:21:54 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
/*
* OLD COMMENTS
*
* Data Structures:
* SharedFreeList is a circular queue. Notice that this
* is a shared memory queue so the next/prev "ptrs" are
* buffer ids, not addresses.
*
* Sync: all routines in this file assume that the buffer
* semaphore has been acquired by the caller.
*/
#include <stdio.h>
#include "storage/bufmgr.h"
#include "storage/buf_internals.h" /* where declarations go */
#include "storage/spin.h"
#include "utils/elog.h"
static BufferDesc *SharedFreeList;
/* only actually used in debugging. The lock
* should be acquired before calling the freelist manager.
*/
extern SPINLOCK BufMgrLock;
#define IsInQueue(bf) \
Assert((bf->freeNext != INVALID_DESCRIPTOR));\
Assert((bf->freePrev != INVALID_DESCRIPTOR));\
Assert((bf->flags & BM_FREE))
#define NotInQueue(bf) \
Assert((bf->freeNext == INVALID_DESCRIPTOR));\
Assert((bf->freePrev == INVALID_DESCRIPTOR));\
Assert(! (bf->flags & BM_FREE))
/*
* AddBufferToFreelist --
*
* In theory, this is the only routine that needs to be changed
* if the buffer replacement strategy changes. Just change
* the manner in which buffers are added to the freelist queue.
* Currently, they are added on an LRU basis.
*/
void
AddBufferToFreelist(BufferDesc *bf)
{
#ifdef BMTRACE
_bm_trace(bf->tag.relId.dbId, bf->tag.relId.relId, bf->tag.blockNum,
BufferDescriptorGetBuffer(bf), BMT_DEALLOC);
#endif /* BMTRACE */
NotInQueue(bf);
/* change bf so it points to inFrontOfNew and its successor */
bf->freePrev = SharedFreeList->freePrev;
bf->freeNext = Free_List_Descriptor;
/* insert new into chain */
BufferDescriptors[bf->freeNext].freePrev = bf->buf_id;
BufferDescriptors[bf->freePrev].freeNext = bf->buf_id;
}
#undef PinBuffer
/*
* PinBuffer -- make buffer unavailable for replacement.
*/
void
PinBuffer(BufferDesc *buf)
{
long b;
/* Assert (buf->refcount < 25); */
if (buf->refcount == 0) {
IsInQueue(buf);
/* remove from freelist queue */
BufferDescriptors[buf->freeNext].freePrev = buf->freePrev;
BufferDescriptors[buf->freePrev].freeNext = buf->freeNext;
buf->freeNext = buf->freePrev = INVALID_DESCRIPTOR;
/* mark buffer as no longer free */
buf->flags &= ~BM_FREE;
} else {
NotInQueue(buf);
}
b = BufferDescriptorGetBuffer(buf) - 1;
Assert(PrivateRefCount[b] >= 0);
if (PrivateRefCount[b] == 0 && LastRefCount[b] == 0)
buf->refcount++;
PrivateRefCount[b]++;
}
void
PinBuffer_Debug(char *file, int line, BufferDesc *buf)
{
PinBuffer(buf);
if (ShowPinTrace) {
Buffer buffer = BufferDescriptorGetBuffer(buf);
fprintf(stderr, "PIN(Pin) %ld relname = %s, blockNum = %d, \
refcount = %ld, file: %s, line: %d\n",
buffer, buf->sb_relname, buf->tag.blockNum,
PrivateRefCount[buffer - 1], file, line);
}
}
#undef UnpinBuffer
/*
* UnpinBuffer -- make buffer available for replacement.
*/
void
UnpinBuffer(BufferDesc *buf)
{
long b = BufferDescriptorGetBuffer(buf) - 1;
Assert(buf->refcount);
Assert(PrivateRefCount[b] > 0);
PrivateRefCount[b]--;
if (PrivateRefCount[b] == 0 && LastRefCount[b] == 0)
buf->refcount--;
NotInQueue(buf);
if (buf->refcount == 0) {
AddBufferToFreelist(buf);
buf->flags |= BM_FREE;
} else {
/* do nothing */
}
}
void
UnpinBuffer_Debug(char *file, int line, BufferDesc *buf)
{
UnpinBuffer(buf);
if (ShowPinTrace) {
Buffer buffer = BufferDescriptorGetBuffer(buf);
fprintf(stderr, "UNPIN(Unpin) %ld relname = %s, blockNum = %d, \
refcount = %ld, file: %s, line: %d\n",
buffer, buf->sb_relname, buf->tag.blockNum,
PrivateRefCount[buffer - 1], file, line);
}
}
/*
* GetFreeBuffer() -- get the 'next' buffer from the freelist.
*
*/
BufferDesc *
GetFreeBuffer()
{
BufferDesc *buf;
if (Free_List_Descriptor == SharedFreeList->freeNext) {
/* queue is empty. All buffers in the buffer pool are pinned. */
elog(WARN,"out of free buffers: time to abort !\n");
return(NULL);
}
buf = &(BufferDescriptors[SharedFreeList->freeNext]);
/* remove from freelist queue */
BufferDescriptors[buf->freeNext].freePrev = buf->freePrev;
BufferDescriptors[buf->freePrev].freeNext = buf->freeNext;
buf->freeNext = buf->freePrev = INVALID_DESCRIPTOR;
buf->flags &= ~(BM_FREE);
return(buf);
}
/*
* InitFreeList -- initialize the dummy buffer descriptor used
* as a freelist head.
*
* Assume: All of the buffers are already linked in a circular
* queue. Only called by postmaster and only during
* initialization.
*/
void
InitFreeList(bool init)
{
SharedFreeList = &(BufferDescriptors[Free_List_Descriptor]);
if (init) {
/* we only do this once, normally the postmaster */
SharedFreeList->data = INVALID_OFFSET;
SharedFreeList->flags = 0;
SharedFreeList->flags &= ~(BM_VALID | BM_DELETED | BM_FREE);
SharedFreeList->buf_id = Free_List_Descriptor;
/* insert it into a random spot in the circular queue */
SharedFreeList->freeNext = BufferDescriptors[0].freeNext;
SharedFreeList->freePrev = 0;
BufferDescriptors[SharedFreeList->freeNext].freePrev =
BufferDescriptors[SharedFreeList->freePrev].freeNext =
Free_List_Descriptor;
}
}
/*
* print out the free list and check for breaks.
*/
void
DBG_FreeListCheck(int nfree)
{
int i;
BufferDesc *buf;
buf = &(BufferDescriptors[SharedFreeList->freeNext]);
for (i=0;i<nfree;i++,buf = &(BufferDescriptors[buf->freeNext])) {
if (! (buf->flags & (BM_FREE))){
if (buf != SharedFreeList) {
printf("\tfree list corrupted: %d flags %x\n",
buf->buf_id,buf->flags);
} else {
printf("\tfree list corrupted: too short -- %d not %d\n",
i,nfree);
}
}
if ((BufferDescriptors[buf->freeNext].freePrev != buf->buf_id) ||
(BufferDescriptors[buf->freePrev].freeNext != buf->buf_id)) {
printf("\tfree list links corrupted: %d %ld %ld\n",
buf->buf_id,buf->freePrev,buf->freeNext);
}
}
if (buf != SharedFreeList) {
printf("\tfree list corrupted: %d-th buffer is %d\n",
nfree,buf->buf_id);
}
}
/*
* PrintBufferFreeList -
* prints the buffer free list, for debugging
*/
void
PrintBufferFreeList()
{
BufferDesc *buf;
if (SharedFreeList->freeNext == Free_List_Descriptor) {
printf("free list is empty.\n");
return;
}
buf = &(BufferDescriptors[SharedFreeList->freeNext]);
for (;;) {
int i = (buf - BufferDescriptors);
printf("[%-2d] (%s, %d) flags=0x%x, refcnt=%d %ld, nxt=%ld prv=%ld)\n",
i, buf->sb_relname, buf->tag.blockNum,
buf->flags, buf->refcount, PrivateRefCount[i],
buf->freeNext, buf->freePrev);
if (buf->freeNext == Free_List_Descriptor)
break;
buf = &(BufferDescriptors[buf->freeNext]);
}
}

View File

@@ -0,0 +1,284 @@
/*-------------------------------------------------------------------------
*
* localbuf.c--
* local buffer manager. Fast buffer manager for temporary tables
* or special cases when the operation is not visible to other backends.
*
* When a relation is being created, the descriptor will have rd_islocal
* set to indicate that the local buffer manager should be used. During
* the same transaction the relation is being created, any inserts or
* selects from the newly created relation will use the local buffer
* pool. rd_islocal is reset at the end of a transaction (commit/abort).
* This is useful for queries like SELECT INTO TABLE and create index.
*
* Copyright (c) 1994-5, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/localbuf.c,v 1.1.1.1 1996/07/09 06:21:54 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <sys/file.h>
#include <stdio.h>
#include <math.h>
#include <signal.h>
/* declarations split between these three files */
#include "storage/buf.h"
#include "storage/buf_internals.h"
#include "storage/bufmgr.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/shmem.h"
#include "storage/spin.h"
#include "storage/smgr.h"
#include "storage/lmgr.h"
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/hsearch.h"
#include "utils/elog.h"
#include "utils/memutils.h"
#include "executor/execdebug.h" /* for NDirectFileRead */
#include "catalog/catalog.h"
int NLocBuffer = 64;
BufferDesc *LocalBufferDescriptors = NULL;
long *LocalRefCount = NULL;
static int nextFreeLocalBuf = 0;
/*#define LBDEBUG*/
/*
* LocalBufferAlloc -
* allocate a local buffer. We do round robin allocation for now.
*/
BufferDesc *
LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
{
int i;
BufferDesc *bufHdr = (BufferDesc *) NULL;
if (blockNum == P_NEW) {
blockNum = reln->rd_nblocks;
reln->rd_nblocks++;
}
/* a low tech search for now -- not optimized for scans */
for (i=0; i < NLocBuffer; i++) {
if (LocalBufferDescriptors[i].tag.relId.relId == reln->rd_id &&
LocalBufferDescriptors[i].tag.blockNum == blockNum) {
#ifdef LBDEBUG
fprintf(stderr, "LB ALLOC (%d,%d) %d\n",
reln->rd_id, blockNum, -i-1);
#endif
LocalRefCount[i]++;
*foundPtr = TRUE;
return &LocalBufferDescriptors[i];
}
}
#ifdef LBDEBUG
fprintf(stderr, "LB ALLOC (%d,%d) %d\n",
reln->rd_id, blockNum, -nextFreeLocalBuf-1);
#endif
/* need to get a new buffer (round robin for now) */
for(i=0; i < NLocBuffer; i++) {
int b = (nextFreeLocalBuf + i) % NLocBuffer;
if (LocalRefCount[b]==0) {
bufHdr = &LocalBufferDescriptors[b];
LocalRefCount[b]++;
nextFreeLocalBuf = (b + 1) % NLocBuffer;
break;
}
}
if (bufHdr==NULL)
elog(WARN, "no empty local buffer.");
/*
* this buffer is not referenced but it might still be dirty (the
* last transaction to touch it doesn't need its contents but has
* not flushed it). if that's the case, write it out before
* reusing it!
*/
if (bufHdr->flags & BM_DIRTY) {
Relation bufrel = RelationIdCacheGetRelation(bufHdr->tag.relId.relId);
Assert(bufrel != NULL);
/* flush this page */
smgrwrite(bufrel->rd_rel->relsmgr, bufrel, bufHdr->tag.blockNum,
(char *) MAKE_PTR(bufHdr->data));
}
/*
* it's all ours now.
*/
bufHdr->tag.relId.relId = reln->rd_id;
bufHdr->tag.blockNum = blockNum;
bufHdr->flags &= ~BM_DIRTY;
/*
* lazy memory allocation. (see MAKE_PTR for why we need to do
* MAKE_OFFSET.)
*/
if (bufHdr->data == (SHMEM_OFFSET)0) {
char *data = (char *)malloc(BLCKSZ);
bufHdr->data = MAKE_OFFSET(data);
}
*foundPtr = FALSE;
return bufHdr;
}
/*
* WriteLocalBuffer -
* writes out a local buffer
*/
int
WriteLocalBuffer(Buffer buffer, bool release)
{
int bufid;
Assert(BufferIsLocal(buffer));
#ifdef LBDEBUG
fprintf(stderr, "LB WRITE %d\n", buffer);
#endif
bufid = - (buffer + 1);
LocalBufferDescriptors[bufid].flags |= BM_DIRTY;
if (release) {
Assert(LocalRefCount[bufid] > 0);
LocalRefCount[bufid]--;
}
return true;
}
/*
* FlushLocalBuffer -
* flushes a local buffer
*/
int
FlushLocalBuffer(Buffer buffer)
{
int bufid;
Relation bufrel;
BufferDesc *bufHdr;
Assert(BufferIsLocal(buffer));
#ifdef LBDEBUG
fprintf(stderr, "LB FLUSH %d\n", buffer);
#endif
bufid = - (buffer + 1);
bufHdr = &LocalBufferDescriptors[bufid];
bufHdr->flags &= ~BM_DIRTY;
bufrel = RelationIdCacheGetRelation(bufHdr->tag.relId.relId);
Assert(bufrel != NULL);
smgrflush(bufrel->rd_rel->relsmgr, bufrel, bufHdr->tag.blockNum,
(char *) MAKE_PTR(bufHdr->data));
Assert(LocalRefCount[bufid] > 0);
LocalRefCount[bufid]--;
return true;
}
/*
* InitLocalBuffer -
* init the local buffer cache. Since most queries (esp. multi-user ones)
* don't involve local buffers, we delay allocating memory for actual the
* buffer until we need it.
*/
void
InitLocalBuffer()
{
int i;
/*
* these aren't going away. I'm not gonna use palloc.
*/
LocalBufferDescriptors =
(BufferDesc *)malloc(sizeof(BufferDesc) * NLocBuffer);
memset(LocalBufferDescriptors, 0, sizeof(BufferDesc) * NLocBuffer);
nextFreeLocalBuf = 0;
for (i = 0; i < NLocBuffer; 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;
}
LocalRefCount =
(long *)malloc(sizeof(long) * NLocBuffer);
memset(LocalRefCount, 0, sizeof(long) * NLocBuffer);
}
/*
* LocalBufferSync -
* flush all dirty buffers in the local buffer cache. Since the buffer
* cache is only used for keeping relations visible during a transaction,
* we will not need these buffers again.
*/
void
LocalBufferSync()
{
int i;
for (i = 0; i < NLocBuffer; i++) {
BufferDesc *buf = &LocalBufferDescriptors[i];
Relation bufrel;
if (buf->flags & BM_DIRTY) {
#ifdef LBDEBUG
fprintf(stderr, "LB SYNC %d\n", -i-1);
#endif
bufrel = RelationIdCacheGetRelation(buf->tag.relId.relId);
Assert(bufrel != NULL);
smgrwrite(bufrel->rd_rel->relsmgr, bufrel, buf->tag.blockNum,
(char *) MAKE_PTR(buf->data));
buf->tag.relId.relId = InvalidOid;
buf->flags &= ~BM_DIRTY;
}
}
memset(LocalRefCount, 0, sizeof(long) * NLocBuffer);
}
void
ResetLocalBufferPool()
{
int i;
memset(LocalBufferDescriptors, 0, sizeof(BufferDesc) * NLocBuffer);
nextFreeLocalBuf = 0;
for (i = 0; i < NLocBuffer; i++) {
BufferDesc *buf = &LocalBufferDescriptors[i];
/* just like InitLocalBuffer() */
buf->buf_id = - i - 2;
}
memset(LocalRefCount, 0, sizeof(long) * NLocBuffer);
}