|
|
@ -85,7 +85,7 @@ |
|
|
|
* relation is visible yet (its xact may have started before the xact that |
|
|
|
* relation is visible yet (its xact may have started before the xact that |
|
|
|
* created the rel). The storage manager must be able to cope anyway. |
|
|
|
* created the rel). The storage manager must be able to cope anyway. |
|
|
|
* |
|
|
|
* |
|
|
|
* Note: if there's any pad bytes in the struct, INIT_BUFFERTAG will have |
|
|
|
* Note: if there's any pad bytes in the struct, InitBufferTag will have |
|
|
|
* to be fixed to zero them, since this struct is used as a hash key. |
|
|
|
* to be fixed to zero them, since this struct is used as a hash key. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
typedef struct buftag |
|
|
|
typedef struct buftag |
|
|
@ -95,28 +95,32 @@ typedef struct buftag |
|
|
|
BlockNumber blockNum; /* blknum relative to begin of reln */ |
|
|
|
BlockNumber blockNum; /* blknum relative to begin of reln */ |
|
|
|
} BufferTag; |
|
|
|
} BufferTag; |
|
|
|
|
|
|
|
|
|
|
|
#define CLEAR_BUFFERTAG(a) \ |
|
|
|
static inline void |
|
|
|
( \
|
|
|
|
ClearBufferTag(BufferTag *tag) |
|
|
|
(a).rlocator.spcOid = InvalidOid, \
|
|
|
|
{ |
|
|
|
(a).rlocator.dbOid = InvalidOid, \
|
|
|
|
tag->rlocator.spcOid = InvalidOid; |
|
|
|
(a).rlocator.relNumber = InvalidRelFileNumber, \
|
|
|
|
tag->rlocator.dbOid = InvalidOid; |
|
|
|
(a).forkNum = InvalidForkNumber, \
|
|
|
|
tag->rlocator.relNumber = InvalidRelFileNumber; |
|
|
|
(a).blockNum = InvalidBlockNumber \
|
|
|
|
tag->forkNum = InvalidForkNumber; |
|
|
|
) |
|
|
|
tag->blockNum = InvalidBlockNumber; |
|
|
|
|
|
|
|
} |
|
|
|
#define INIT_BUFFERTAG(a,xx_rlocator,xx_forkNum,xx_blockNum) \ |
|
|
|
|
|
|
|
( \
|
|
|
|
static inline void |
|
|
|
(a).rlocator = (xx_rlocator), \
|
|
|
|
InitBufferTag(BufferTag *tag, const RelFileLocator *rlocator, |
|
|
|
(a).forkNum = (xx_forkNum), \
|
|
|
|
ForkNumber forkNum, BlockNumber blockNum) |
|
|
|
(a).blockNum = (xx_blockNum) \
|
|
|
|
{ |
|
|
|
) |
|
|
|
tag->rlocator = *rlocator; |
|
|
|
|
|
|
|
tag->forkNum = forkNum; |
|
|
|
#define BUFFERTAGS_EQUAL(a,b) \ |
|
|
|
tag->blockNum = blockNum; |
|
|
|
( \
|
|
|
|
} |
|
|
|
RelFileLocatorEquals((a).rlocator, (b).rlocator) && \
|
|
|
|
|
|
|
|
(a).blockNum == (b).blockNum && \
|
|
|
|
static inline bool |
|
|
|
(a).forkNum == (b).forkNum \
|
|
|
|
BufferTagsEqual(const BufferTag *tag1, const BufferTag *tag2) |
|
|
|
) |
|
|
|
{ |
|
|
|
|
|
|
|
return RelFileLocatorEquals(tag1->rlocator, tag2->rlocator) && |
|
|
|
|
|
|
|
(tag1->blockNum == tag2->blockNum) && |
|
|
|
|
|
|
|
(tag1->forkNum == tag2->forkNum); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* The shared buffer mapping table is partitioned to reduce contention. |
|
|
|
* The shared buffer mapping table is partitioned to reduce contention. |
|
|
@ -124,13 +128,24 @@ typedef struct buftag |
|
|
|
* hash code with BufTableHashCode(), then apply BufMappingPartitionLock(). |
|
|
|
* hash code with BufTableHashCode(), then apply BufMappingPartitionLock(). |
|
|
|
* NB: NUM_BUFFER_PARTITIONS must be a power of 2! |
|
|
|
* NB: NUM_BUFFER_PARTITIONS must be a power of 2! |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
#define BufTableHashPartition(hashcode) \ |
|
|
|
static inline uint32 |
|
|
|
((hashcode) % NUM_BUFFER_PARTITIONS) |
|
|
|
BufTableHashPartition(uint32 hashcode) |
|
|
|
#define BufMappingPartitionLock(hashcode) \ |
|
|
|
{ |
|
|
|
(&MainLWLockArray[BUFFER_MAPPING_LWLOCK_OFFSET + \
|
|
|
|
return hashcode % NUM_BUFFER_PARTITIONS; |
|
|
|
BufTableHashPartition(hashcode)].lock) |
|
|
|
} |
|
|
|
#define BufMappingPartitionLockByIndex(i) \ |
|
|
|
|
|
|
|
(&MainLWLockArray[BUFFER_MAPPING_LWLOCK_OFFSET + (i)].lock) |
|
|
|
static inline LWLock * |
|
|
|
|
|
|
|
BufMappingPartitionLock(uint32 hashcode) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return &MainLWLockArray[BUFFER_MAPPING_LWLOCK_OFFSET + |
|
|
|
|
|
|
|
BufTableHashPartition(hashcode)].lock; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static inline LWLock * |
|
|
|
|
|
|
|
BufMappingPartitionLockByIndex(uint32 index) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return &MainLWLockArray[BUFFER_MAPPING_LWLOCK_OFFSET + index].lock; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* BufferDesc -- shared descriptor/state data for a single shared buffer. |
|
|
|
* BufferDesc -- shared descriptor/state data for a single shared buffer. |
|
|
@ -220,37 +235,6 @@ typedef union BufferDescPadded |
|
|
|
char pad[BUFFERDESC_PAD_TO_SIZE]; |
|
|
|
char pad[BUFFERDESC_PAD_TO_SIZE]; |
|
|
|
} BufferDescPadded; |
|
|
|
} BufferDescPadded; |
|
|
|
|
|
|
|
|
|
|
|
#define GetBufferDescriptor(id) (&BufferDescriptors[(id)].bufferdesc) |
|
|
|
|
|
|
|
#define GetLocalBufferDescriptor(id) (&LocalBufferDescriptors[(id)]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define BufferDescriptorGetBuffer(bdesc) ((bdesc)->buf_id + 1) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define BufferDescriptorGetIOCV(bdesc) \ |
|
|
|
|
|
|
|
(&(BufferIOCVArray[(bdesc)->buf_id]).cv) |
|
|
|
|
|
|
|
#define BufferDescriptorGetContentLock(bdesc) \ |
|
|
|
|
|
|
|
((LWLock*) (&(bdesc)->content_lock)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extern PGDLLIMPORT ConditionVariableMinimallyPadded *BufferIOCVArray; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* The freeNext field is either the index of the next freelist entry, |
|
|
|
|
|
|
|
* or one of these special values: |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
#define FREENEXT_END_OF_LIST (-1) |
|
|
|
|
|
|
|
#define FREENEXT_NOT_IN_LIST (-2) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* Functions for acquiring/releasing a shared buffer header's spinlock. Do |
|
|
|
|
|
|
|
* not apply these to local buffers! |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
extern uint32 LockBufHdr(BufferDesc *desc); |
|
|
|
|
|
|
|
#define UnlockBufHdr(desc, s) \ |
|
|
|
|
|
|
|
do { \
|
|
|
|
|
|
|
|
pg_write_barrier(); \
|
|
|
|
|
|
|
|
pg_atomic_write_u32(&(desc)->state, (s) & (~BM_LOCKED)); \
|
|
|
|
|
|
|
|
} while (0) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* The PendingWriteback & WritebackContext structure are used to keep |
|
|
|
* The PendingWriteback & WritebackContext structure are used to keep |
|
|
|
* information about pending flush requests to be issued to the OS. |
|
|
|
* information about pending flush requests to be issued to the OS. |
|
|
@ -276,11 +260,63 @@ typedef struct WritebackContext |
|
|
|
|
|
|
|
|
|
|
|
/* in buf_init.c */ |
|
|
|
/* in buf_init.c */ |
|
|
|
extern PGDLLIMPORT BufferDescPadded *BufferDescriptors; |
|
|
|
extern PGDLLIMPORT BufferDescPadded *BufferDescriptors; |
|
|
|
|
|
|
|
extern PGDLLIMPORT ConditionVariableMinimallyPadded *BufferIOCVArray; |
|
|
|
extern PGDLLIMPORT WritebackContext BackendWritebackContext; |
|
|
|
extern PGDLLIMPORT WritebackContext BackendWritebackContext; |
|
|
|
|
|
|
|
|
|
|
|
/* in localbuf.c */ |
|
|
|
/* in localbuf.c */ |
|
|
|
extern PGDLLIMPORT BufferDesc *LocalBufferDescriptors; |
|
|
|
extern PGDLLIMPORT BufferDesc *LocalBufferDescriptors; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static inline BufferDesc * |
|
|
|
|
|
|
|
GetBufferDescriptor(uint32 id) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return &(BufferDescriptors[id]).bufferdesc; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static inline BufferDesc * |
|
|
|
|
|
|
|
GetLocalBufferDescriptor(uint32 id) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return &LocalBufferDescriptors[id]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static inline Buffer |
|
|
|
|
|
|
|
BufferDescriptorGetBuffer(const BufferDesc *bdesc) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return (Buffer) (bdesc->buf_id + 1); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static inline ConditionVariable * |
|
|
|
|
|
|
|
BufferDescriptorGetIOCV(const BufferDesc *bdesc) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return &(BufferIOCVArray[bdesc->buf_id]).cv; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static inline LWLock * |
|
|
|
|
|
|
|
BufferDescriptorGetContentLock(const BufferDesc *bdesc) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return (LWLock *) (&bdesc->content_lock); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* The freeNext field is either the index of the next freelist entry, |
|
|
|
|
|
|
|
* or one of these special values: |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
#define FREENEXT_END_OF_LIST (-1) |
|
|
|
|
|
|
|
#define FREENEXT_NOT_IN_LIST (-2) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* Functions for acquiring/releasing a shared buffer header's spinlock. Do |
|
|
|
|
|
|
|
* not apply these to local buffers! |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
extern uint32 LockBufHdr(BufferDesc *desc); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static inline void |
|
|
|
|
|
|
|
UnlockBufHdr(BufferDesc *desc, uint32 buf_state) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
pg_write_barrier(); |
|
|
|
|
|
|
|
pg_atomic_write_u32(&desc->state, buf_state & (~BM_LOCKED)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* in bufmgr.c */ |
|
|
|
/* in bufmgr.c */ |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|