mirror of
https://github.com/postgres/postgres.git
synced 2025-11-12 05:01:15 +03:00
Massive commit to run PGINDENT on all *.c and *.h files.
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* buf_init.c--
|
||||
* buffer manager initialization routines
|
||||
* 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.10 1997/07/28 00:54:33 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.11 1997/09/07 04:48:15 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -35,98 +35,103 @@
|
||||
#include "utils/dynahash.h"
|
||||
#include "utils/hsearch.h"
|
||||
#include "utils/memutils.h"
|
||||
#include "executor/execdebug.h" /* for NDirectFileRead */
|
||||
#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.
|
||||
* 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;
|
||||
bmtrace *TraceBuf;
|
||||
long *CurTraceBuf;
|
||||
|
||||
int NBuffers = NDBUFS; /* NDBUFS defined in miscadmin.h */
|
||||
int Data_Descriptors;
|
||||
int Free_List_Descriptor;
|
||||
int Lookup_List_Descriptor;
|
||||
int Num_Descriptors;
|
||||
#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;
|
||||
|
||||
BufferDesc *BufferDescriptors;
|
||||
BufferBlock BufferBlocks;
|
||||
#ifndef HAS_TEST_AND_SET
|
||||
long *NWaitIOBackendP;
|
||||
long *NWaitIOBackendP;
|
||||
|
||||
#endif
|
||||
|
||||
extern IpcSemaphoreId WaitIOSemId;
|
||||
extern IpcSemaphoreId WaitIOSemId;
|
||||
|
||||
long *PrivateRefCount; /* also used in freelist.c */
|
||||
long *LastRefCount; /* refcounts of last ExecMain level */
|
||||
long *CommitInfoNeedsSave; /* to write buffers where we have filled in */
|
||||
/* t_tmin (or t_tmax) */
|
||||
long *PrivateRefCount;/* also used in freelist.c */
|
||||
long *LastRefCount; /* refcounts of last ExecMain level */
|
||||
long *CommitInfoNeedsSave; /* to write buffers where we have
|
||||
* filled in */
|
||||
|
||||
/* t_tmin (or t_tmax) */
|
||||
|
||||
/*
|
||||
* Data Structures:
|
||||
* buffers live in a freelist and a lookup data structure.
|
||||
*
|
||||
* 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.
|
||||
* 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.
|
||||
* 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.
|
||||
* 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.
|
||||
* 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.
|
||||
* 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.
|
||||
* 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.
|
||||
* 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;
|
||||
SPINLOCK BufMgrLock;
|
||||
|
||||
long int ReadBufferCount;
|
||||
long int ReadLocalBufferCount;
|
||||
long int BufferHitCount;
|
||||
long int LocalBufferHitCount;
|
||||
long int BufferFlushCount;
|
||||
long int LocalBufferFlushCount;
|
||||
long int ReadBufferCount;
|
||||
long int ReadLocalBufferCount;
|
||||
long int BufferHitCount;
|
||||
long int LocalBufferHitCount;
|
||||
long int BufferFlushCount;
|
||||
long int LocalBufferFlushCount;
|
||||
|
||||
|
||||
/*
|
||||
@@ -138,111 +143,121 @@ long int LocalBufferFlushCount;
|
||||
void
|
||||
InitBufferPool(IPCKey key)
|
||||
{
|
||||
bool foundBufs,foundDescs;
|
||||
int i;
|
||||
|
||||
/* check padding of BufferDesc and BufferHdr */
|
||||
/* we need both checks because a sbufdesc_padded > PADDED_SBUFDESC_SIZE
|
||||
will shrink sbufdesc to the required size, which is bad */
|
||||
if (sizeof(struct sbufdesc) != PADDED_SBUFDESC_SIZE ||
|
||||
sizeof(struct sbufdesc_unpadded) > PADDED_SBUFDESC_SIZE)
|
||||
elog(WARN,"Internal error: sbufdesc does not have the proper size, "
|
||||
"contact the Postgres developers");
|
||||
if (sizeof(struct sbufdesc_unpadded) <= PADDED_SBUFDESC_SIZE/2)
|
||||
elog(WARN,"Internal error: sbufdesc is greatly over-sized, "
|
||||
"contact the Postgres developers");
|
||||
bool foundBufs,
|
||||
foundDescs;
|
||||
int i;
|
||||
|
||||
/* check padding of BufferDesc and BufferHdr */
|
||||
|
||||
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.
|
||||
* we need both checks because a sbufdesc_padded >
|
||||
* PADDED_SBUFDESC_SIZE will shrink sbufdesc to the required size,
|
||||
* which is bad
|
||||
*/
|
||||
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));
|
||||
if (sizeof(struct sbufdesc) != PADDED_SBUFDESC_SIZE ||
|
||||
sizeof(struct sbufdesc_unpadded) > PADDED_SBUFDESC_SIZE)
|
||||
elog(WARN, "Internal error: sbufdesc does not have the proper size, "
|
||||
"contact the Postgres developers");
|
||||
if (sizeof(struct sbufdesc_unpadded) <= PADDED_SBUFDESC_SIZE / 2)
|
||||
elog(WARN, "Internal error: sbufdesc is greatly over-sized, "
|
||||
"contact the Postgres developers");
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
|
||||
BufferDescriptors = (BufferDesc *)
|
||||
ShmemInitStruct("Buffer Descriptors",
|
||||
Num_Descriptors * sizeof(BufferDesc), &foundDescs);
|
||||
|
||||
BufferBlocks = (BufferBlock)
|
||||
ShmemInitStruct("Buffer Blocks",
|
||||
NBuffers * BLCKSZ, &foundBufs);
|
||||
|
||||
#ifndef HAS_TEST_AND_SET
|
||||
{
|
||||
int status;
|
||||
WaitIOSemId = IpcSemaphoreCreate(IPCKeyGetWaitIOSemaphoreKey(key),
|
||||
1, IPCProtection, 0, 1, &status);
|
||||
}
|
||||
{
|
||||
bool foundNWaitIO;
|
||||
|
||||
NWaitIOBackendP = (long *) ShmemInitStruct("#Backends Waiting IO",
|
||||
sizeof(long),
|
||||
&foundNWaitIO);
|
||||
if (!foundNWaitIO)
|
||||
*NWaitIOBackendP = 0;
|
||||
}
|
||||
#endif
|
||||
PrivateRefCount = (long *) calloc(NBuffers, sizeof(long));
|
||||
LastRefCount = (long *) calloc(NBuffers, sizeof(long));
|
||||
CommitInfoNeedsSave = (long *) calloc(NBuffers, sizeof(long));
|
||||
|
||||
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));
|
||||
CommitInfoNeedsSave = (long *) calloc(NBuffers, sizeof(long));
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------
|
||||
@@ -255,43 +270,41 @@ InitBufferPool(IPCKey key)
|
||||
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)));
|
||||
|
||||
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);
|
||||
size += (BMT_LIMIT * sizeof(bmtrace)) + sizeof(long);
|
||||
#endif
|
||||
return size;
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* buf_table.c--
|
||||
* routines for finding buffers in the buffer pool.
|
||||
* 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.4 1997/08/19 21:32:34 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_table.c,v 1.5 1997/09/07 04:48:17 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -16,30 +16,31 @@
|
||||
*
|
||||
* Data Structures:
|
||||
*
|
||||
* Buffers are identified by their BufferTag (buf.h). This
|
||||
* 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.
|
||||
*
|
||||
* All routines in this file assume buffer manager spinlock is
|
||||
* held by their caller.
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "storage/bufmgr.h"
|
||||
#include "storage/buf_internals.h" /* where the declarations go */
|
||||
#include "storage/buf_internals.h" /* where the declarations go */
|
||||
#include "storage/shmem.h"
|
||||
#include "storage/spin.h"
|
||||
#include "utils/hsearch.h"
|
||||
|
||||
static HTAB *SharedBufHash;
|
||||
static HTAB *SharedBufHash;
|
||||
|
||||
typedef struct lookup {
|
||||
BufferTag key;
|
||||
Buffer id;
|
||||
} LookupEnt;
|
||||
typedef struct lookup
|
||||
{
|
||||
BufferTag key;
|
||||
Buffer id;
|
||||
} LookupEnt;
|
||||
|
||||
/*
|
||||
* Initialize shmem hash table for mapping buffers
|
||||
@@ -47,109 +48,116 @@ typedef struct lookup {
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
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]));
|
||||
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)
|
||||
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);
|
||||
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)
|
||||
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);
|
||||
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 */
|
||||
@@ -157,8 +165,9 @@ BufTableInsert(BufferDesc *buf)
|
||||
void
|
||||
DBG_LookupListCheck(int nlookup)
|
||||
{
|
||||
nlookup = 10;
|
||||
|
||||
hash_stats("Shared",SharedBufHash);
|
||||
nlookup = 10;
|
||||
|
||||
hash_stats("Shared", SharedBufHash);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,14 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* freelist.c--
|
||||
* routines for manipulating the buffer pool's replacement strategy
|
||||
* freelist.
|
||||
* 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.4 1997/08/19 21:32:44 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/freelist.c,v 1.5 1997/09/07 04:48:22 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -16,23 +16,23 @@
|
||||
* 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.
|
||||
* 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.
|
||||
* semaphore has been acquired by the caller.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "storage/bufmgr.h"
|
||||
#include "storage/buf_internals.h" /* where declarations go */
|
||||
#include "storage/buf_internals.h" /* where declarations go */
|
||||
#include "storage/spin.h"
|
||||
|
||||
|
||||
static BufferDesc *SharedFreeList;
|
||||
static BufferDesc *SharedFreeList;
|
||||
|
||||
/* only actually used in debugging. The lock
|
||||
* should be acquired before calling the freelist manager.
|
||||
@@ -40,40 +40,40 @@ static BufferDesc *SharedFreeList;
|
||||
extern SPINLOCK BufMgrLock;
|
||||
|
||||
#define IsInQueue(bf) \
|
||||
Assert((bf->freeNext != INVALID_DESCRIPTOR));\
|
||||
Assert((bf->freePrev != INVALID_DESCRIPTOR));\
|
||||
Assert((bf->flags & BM_FREE))
|
||||
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))
|
||||
Assert((bf->freeNext == INVALID_DESCRIPTOR));\
|
||||
Assert((bf->freePrev == INVALID_DESCRIPTOR));\
|
||||
Assert(! (bf->flags & BM_FREE))
|
||||
|
||||
|
||||
/*
|
||||
* AddBufferToFreelist --
|
||||
* AddBufferToFreelist --
|
||||
*
|
||||
* In theory, this is the only routine that needs to be changed
|
||||
* if the buffer replacement strategy changes. Just change
|
||||
* 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)
|
||||
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;
|
||||
_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
|
||||
@@ -82,47 +82,52 @@ AddBufferToFreelist(BufferDesc *bf)
|
||||
* PinBuffer -- make buffer unavailable for replacement.
|
||||
*/
|
||||
void
|
||||
PinBuffer(BufferDesc *buf)
|
||||
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]++;
|
||||
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]++;
|
||||
}
|
||||
|
||||
#ifdef NOT_USED
|
||||
void
|
||||
PinBuffer_Debug(char *file, int line, BufferDesc *buf)
|
||||
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, \
|
||||
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);
|
||||
}
|
||||
buffer, buf->sb_relname, buf->tag.blockNum,
|
||||
PrivateRefCount[buffer - 1], file, line);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#undef UnpinBuffer
|
||||
@@ -131,95 +136,102 @@ refcount = %ld, file: %s, line: %d\n",
|
||||
* UnpinBuffer -- make buffer available for replacement.
|
||||
*/
|
||||
void
|
||||
UnpinBuffer(BufferDesc *buf)
|
||||
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 */
|
||||
}
|
||||
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 */
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NOT_USED
|
||||
void
|
||||
UnpinBuffer_Debug(char *file, int line, BufferDesc *buf)
|
||||
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, \
|
||||
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);
|
||||
}
|
||||
buffer, buf->sb_relname, buf->tag.blockNum,
|
||||
PrivateRefCount[buffer - 1], file, line);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* GetFreeBuffer() -- get the 'next' buffer from the freelist.
|
||||
*
|
||||
*/
|
||||
BufferDesc *
|
||||
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);
|
||||
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.
|
||||
* as a freelist head.
|
||||
*
|
||||
* Assume: All of the buffers are already linked in a circular
|
||||
* queue. Only called by postmaster and only during
|
||||
* initialization.
|
||||
* 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -230,67 +242,78 @@ InitFreeList(bool init)
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
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 ((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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if (buf != SharedFreeList) {
|
||||
printf("\tfree list corrupted: %d-th buffer is %d\n",
|
||||
nfree,buf->buf_id);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef NOT_USED
|
||||
/*
|
||||
* PrintBufferFreeList -
|
||||
* prints the buffer free list, for debugging
|
||||
* prints the buffer free list, for debugging
|
||||
*/
|
||||
static void
|
||||
PrintBufferFreeList()
|
||||
{
|
||||
BufferDesc *buf;
|
||||
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;
|
||||
if (SharedFreeList->freeNext == Free_List_Descriptor)
|
||||
{
|
||||
printf("free list is empty.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
buf = &(BufferDescriptors[buf->freeNext]);
|
||||
}
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* localbuf.c--
|
||||
* local buffer manager. Fast buffer manager for temporary tables
|
||||
* or special cases when the operation is not visible to other backends.
|
||||
* 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.
|
||||
* 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.8 1997/07/28 00:54:48 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/localbuf.c,v 1.9 1997/09/07 04:48:23 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -45,252 +45,262 @@
|
||||
#include "utils/hsearch.h"
|
||||
#include "utils/memutils.h"
|
||||
#include "utils/relcache.h"
|
||||
#include "executor/execdebug.h" /* for NDirectFileRead */
|
||||
#include "executor/execdebug.h" /* for NDirectFileRead */
|
||||
#include "catalog/catalog.h"
|
||||
|
||||
extern long int LocalBufferFlushCount;
|
||||
|
||||
int NLocBuffer = 64;
|
||||
BufferDesc *LocalBufferDescriptors = NULL;
|
||||
long *LocalRefCount = NULL;
|
||||
int NLocBuffer = 64;
|
||||
BufferDesc *LocalBufferDescriptors = NULL;
|
||||
long *LocalRefCount = NULL;
|
||||
|
||||
static int nextFreeLocalBuf = 0;
|
||||
static int nextFreeLocalBuf = 0;
|
||||
|
||||
/*#define LBDEBUG*/
|
||||
|
||||
/*
|
||||
* LocalBufferAlloc -
|
||||
* allocate a local buffer. We do round robin allocation for now.
|
||||
* allocate a local buffer. We do round robin allocation for now.
|
||||
*/
|
||||
BufferDesc *
|
||||
LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
|
||||
BufferDesc *
|
||||
LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool * foundPtr)
|
||||
{
|
||||
int i;
|
||||
BufferDesc *bufHdr = (BufferDesc *) NULL;
|
||||
int i;
|
||||
BufferDesc *bufHdr = (BufferDesc *) NULL;
|
||||
|
||||
if (blockNum == P_NEW) {
|
||||
blockNum = reln->rd_nblocks;
|
||||
reln->rd_nblocks++;
|
||||
}
|
||||
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) {
|
||||
/* 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];
|
||||
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;
|
||||
fprintf(stderr, "LB ALLOC (%d,%d) %d\n",
|
||||
reln->rd_id, blockNum, -nextFreeLocalBuf - 1);
|
||||
#endif
|
||||
|
||||
if (LocalRefCount[b]==0) {
|
||||
bufHdr = &LocalBufferDescriptors[b];
|
||||
LocalRefCount[b]++;
|
||||
nextFreeLocalBuf = (b + 1) % NLocBuffer;
|
||||
break;
|
||||
/* 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.");
|
||||
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);
|
||||
/*
|
||||
* 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));
|
||||
LocalBufferFlushCount++;
|
||||
}
|
||||
Assert(bufrel != NULL);
|
||||
|
||||
/*
|
||||
* it's all ours now.
|
||||
*/
|
||||
bufHdr->tag.relId.relId = reln->rd_id;
|
||||
bufHdr->tag.blockNum = blockNum;
|
||||
bufHdr->flags &= ~BM_DIRTY;
|
||||
/* flush this page */
|
||||
smgrwrite(bufrel->rd_rel->relsmgr, bufrel, bufHdr->tag.blockNum,
|
||||
(char *) MAKE_PTR(bufHdr->data));
|
||||
LocalBufferFlushCount++;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
/*
|
||||
* it's all ours now.
|
||||
*/
|
||||
bufHdr->tag.relId.relId = reln->rd_id;
|
||||
bufHdr->tag.blockNum = blockNum;
|
||||
bufHdr->flags &= ~BM_DIRTY;
|
||||
|
||||
bufHdr->data = MAKE_OFFSET(data);
|
||||
}
|
||||
|
||||
*foundPtr = FALSE;
|
||||
return bufHdr;
|
||||
/*
|
||||
* 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
|
||||
* writes out a local buffer
|
||||
*/
|
||||
int
|
||||
WriteLocalBuffer(Buffer buffer, bool release)
|
||||
{
|
||||
int bufid;
|
||||
int bufid;
|
||||
|
||||
Assert(BufferIsLocal(buffer));
|
||||
Assert(BufferIsLocal(buffer));
|
||||
|
||||
#ifdef LBDEBUG
|
||||
fprintf(stderr, "LB WRITE %d\n", buffer);
|
||||
#endif
|
||||
|
||||
bufid = - (buffer + 1);
|
||||
LocalBufferDescriptors[bufid].flags |= BM_DIRTY;
|
||||
fprintf(stderr, "LB WRITE %d\n", buffer);
|
||||
#endif
|
||||
|
||||
if (release) {
|
||||
Assert(LocalRefCount[bufid] > 0);
|
||||
LocalRefCount[bufid]--;
|
||||
}
|
||||
bufid = -(buffer + 1);
|
||||
LocalBufferDescriptors[bufid].flags |= BM_DIRTY;
|
||||
|
||||
return true;
|
||||
if (release)
|
||||
{
|
||||
Assert(LocalRefCount[bufid] > 0);
|
||||
LocalRefCount[bufid]--;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* FlushLocalBuffer -
|
||||
* flushes a local buffer
|
||||
* flushes a local buffer
|
||||
*/
|
||||
int
|
||||
FlushLocalBuffer(Buffer buffer, bool release)
|
||||
{
|
||||
int bufid;
|
||||
Relation bufrel;
|
||||
BufferDesc *bufHdr;
|
||||
int bufid;
|
||||
Relation bufrel;
|
||||
BufferDesc *bufHdr;
|
||||
|
||||
Assert(BufferIsLocal(buffer));
|
||||
Assert(BufferIsLocal(buffer));
|
||||
|
||||
#ifdef LBDEBUG
|
||||
fprintf(stderr, "LB FLUSH %d\n", buffer);
|
||||
#endif
|
||||
fprintf(stderr, "LB FLUSH %d\n", buffer);
|
||||
#endif
|
||||
|
||||
bufid = - (buffer + 1);
|
||||
bufHdr = &LocalBufferDescriptors[bufid];
|
||||
bufHdr->flags &= ~BM_DIRTY;
|
||||
bufrel = RelationIdCacheGetRelation(bufHdr->tag.relId.relId);
|
||||
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));
|
||||
LocalBufferFlushCount++;
|
||||
Assert(bufrel != NULL);
|
||||
smgrflush(bufrel->rd_rel->relsmgr, bufrel, bufHdr->tag.blockNum,
|
||||
(char *) MAKE_PTR(bufHdr->data));
|
||||
LocalBufferFlushCount++;
|
||||
|
||||
Assert(LocalRefCount[bufid] > 0);
|
||||
if ( release )
|
||||
LocalRefCount[bufid]--;
|
||||
|
||||
return true;
|
||||
Assert(LocalRefCount[bufid] > 0);
|
||||
if (release)
|
||||
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.
|
||||
* 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(void)
|
||||
{
|
||||
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];
|
||||
int 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.)
|
||||
* these aren't going away. I'm not gonna use palloc.
|
||||
*/
|
||||
buf->buf_id = - i - 2;
|
||||
}
|
||||
LocalBufferDescriptors =
|
||||
(BufferDesc *) malloc(sizeof(BufferDesc) * NLocBuffer);
|
||||
memset(LocalBufferDescriptors, 0, sizeof(BufferDesc) * NLocBuffer);
|
||||
nextFreeLocalBuf = 0;
|
||||
|
||||
LocalRefCount =
|
||||
(long *)malloc(sizeof(long) * NLocBuffer);
|
||||
memset(LocalRefCount, 0, sizeof(long) * NLocBuffer);
|
||||
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.
|
||||
* 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(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NLocBuffer; i++) {
|
||||
BufferDesc *buf = &LocalBufferDescriptors[i];
|
||||
Relation bufrel;
|
||||
int i;
|
||||
|
||||
if (buf->flags & BM_DIRTY) {
|
||||
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);
|
||||
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));
|
||||
LocalBufferFlushCount++;
|
||||
Assert(bufrel != NULL);
|
||||
|
||||
buf->tag.relId.relId = InvalidOid;
|
||||
buf->flags &= ~BM_DIRTY;
|
||||
smgrwrite(bufrel->rd_rel->relsmgr, bufrel, buf->tag.blockNum,
|
||||
(char *) MAKE_PTR(buf->data));
|
||||
LocalBufferFlushCount++;
|
||||
|
||||
buf->tag.relId.relId = InvalidOid;
|
||||
buf->flags &= ~BM_DIRTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memset(LocalRefCount, 0, sizeof(long) * NLocBuffer);
|
||||
nextFreeLocalBuf = 0;
|
||||
memset(LocalRefCount, 0, sizeof(long) * NLocBuffer);
|
||||
nextFreeLocalBuf = 0;
|
||||
}
|
||||
|
||||
void
|
||||
ResetLocalBufferPool(void)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NLocBuffer; i++)
|
||||
{
|
||||
BufferDesc *buf = &LocalBufferDescriptors[i];
|
||||
for (i = 0; i < NLocBuffer; i++)
|
||||
{
|
||||
BufferDesc *buf = &LocalBufferDescriptors[i];
|
||||
|
||||
buf->tag.relId.relId = InvalidOid;
|
||||
buf->flags &= ~BM_DIRTY;
|
||||
buf->buf_id = - i - 2;
|
||||
}
|
||||
buf->tag.relId.relId = InvalidOid;
|
||||
buf->flags &= ~BM_DIRTY;
|
||||
buf->buf_id = -i - 2;
|
||||
}
|
||||
|
||||
memset(LocalRefCount, 0, sizeof(long) * NLocBuffer);
|
||||
nextFreeLocalBuf = 0;
|
||||
memset(LocalRefCount, 0, sizeof(long) * NLocBuffer);
|
||||
nextFreeLocalBuf = 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user