PostgreSQL Source Code  git master
buf_internals.h File Reference
#include "storage/buf.h"
#include "storage/bufmgr.h"
#include "storage/latch.h"
#include "storage/lwlock.h"
#include "storage/shmem.h"
#include "storage/smgr.h"
#include "port/atomics.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  BufferDesc
 
union  BufferDescPadded
 
struct  PendingWriteback
 
struct  WritebackContext
 
struct  CkptSortItem
 

Macros

#define BUF_REFCOUNT_ONE   1
 
#define BUF_REFCOUNT_MASK   ((1U << 18) - 1)
 
#define BUF_USAGECOUNT_MASK   0x003C0000U
 
#define BUF_USAGECOUNT_ONE   (1U << 18)
 
#define BUF_USAGECOUNT_SHIFT   18
 
#define BUF_FLAG_MASK   0xFFC00000U
 
#define BUF_STATE_GET_REFCOUNT(state)   ((state) & BUF_REFCOUNT_MASK)
 
#define BUF_STATE_GET_USAGECOUNT(state)   (((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT)
 
#define BM_LOCKED   (1U << 22) /* buffer header is locked */
 
#define BM_DIRTY   (1U << 23) /* data needs writing */
 
#define BM_VALID   (1U << 24) /* data is valid */
 
#define BM_TAG_VALID   (1U << 25) /* tag is assigned */
 
#define BM_IO_IN_PROGRESS   (1U << 26) /* read or write in progress */
 
#define BM_IO_ERROR   (1U << 27) /* previous I/O failed */
 
#define BM_JUST_DIRTIED   (1U << 28) /* dirtied since write started */
 
#define BM_PIN_COUNT_WAITER   (1U << 29) /* have waiter for sole pin */
 
#define BM_CHECKPOINT_NEEDED   (1U << 30) /* must write for checkpoint */
 
#define BM_PERMANENT
 
#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)
 
#define BufMappingPartitionLockByIndex(i)   (&MainLWLockArray[BUFFER_MAPPING_LWLOCK_OFFSET + (i)].lock)
 
#define BUFFERDESC_PAD_TO_SIZE   (SIZEOF_VOID_P == 8 ? 64 : 1)
 
#define GetBufferDescriptor(id)   (&BufferDescriptors[(id)].bufferdesc)
 
#define GetLocalBufferDescriptor(id)   (&LocalBufferDescriptors[(id)])
 
#define BufferDescriptorGetBuffer(bdesc)   ((bdesc)->buf_id + 1)
 
#define BufferDescriptorGetIOLock(bdesc)   (&(BufferIOLWLockArray[(bdesc)->buf_id]).lock)
 
#define BufferDescriptorGetContentLock(bdesc)   ((LWLock*) (&(bdesc)->content_lock))
 
#define FREENEXT_END_OF_LIST   (-1)
 
#define FREENEXT_NOT_IN_LIST   (-2)
 
#define UnlockBufHdr(desc, s)
 

Typedefs

typedef struct buftag BufferTag
 
typedef struct BufferDesc BufferDesc
 
typedef union BufferDescPadded BufferDescPadded
 
typedef struct PendingWriteback PendingWriteback
 
typedef struct WritebackContext WritebackContext
 
typedef struct CkptSortItem CkptSortItem
 

Functions

uint32 LockBufHdr (BufferDesc *desc)
 
void WritebackContextInit (WritebackContext *context, int *max_pending)
 
void IssuePendingWritebacks (WritebackContext *context)
 
void ScheduleBufferTagForWriteback (WritebackContext *context, BufferTag *tag)
 
BufferDescStrategyGetBuffer (BufferAccessStrategy strategy, uint32 *buf_state)
 
void StrategyFreeBuffer (BufferDesc *buf)
 
bool StrategyRejectBuffer (BufferAccessStrategy strategy, BufferDesc *buf)
 
int StrategySyncStart (uint32 *complete_passes, uint32 *num_buf_alloc)
 
void StrategyNotifyBgWriter (int bgwprocno)
 
Size StrategyShmemSize (void)
 
void StrategyInitialize (bool init)
 
bool have_free_buffer (void)
 
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 LWLockMinimallyPaddedBufferIOLWLockArray
 
PGDLLIMPORT BufferDescPaddedBufferDescriptors
 
PGDLLIMPORT WritebackContext BackendWritebackContext
 
BufferDescLocalBufferDescriptors
 
CkptSortItemCkptBufferIds
 

Macro Definition Documentation

◆ BM_CHECKPOINT_NEEDED

#define BM_CHECKPOINT_NEEDED   (1U << 30) /* must write for checkpoint */

Definition at line 66 of file buf_internals.h.

Referenced by BufferAlloc(), BufferSync(), and TerminateBufferIO().

◆ BM_DIRTY

◆ BM_IO_ERROR

#define BM_IO_ERROR   (1U << 27) /* previous I/O failed */

Definition at line 63 of file buf_internals.h.

Referenced by AbortBufferIO(), BufferAlloc(), LocalBufferAlloc(), and TerminateBufferIO().

◆ BM_IO_IN_PROGRESS

#define BM_IO_IN_PROGRESS   (1U << 26) /* read or write in progress */

Definition at line 62 of file buf_internals.h.

Referenced by AbortBufferIO(), StartBufferIO(), TerminateBufferIO(), and WaitIO().

◆ BM_JUST_DIRTIED

#define BM_JUST_DIRTIED   (1U << 28) /* dirtied since write started */

◆ BM_LOCKED

#define BM_LOCKED   (1U << 22) /* buffer header is locked */

◆ BM_MAX_USAGE_COUNT

#define BM_MAX_USAGE_COUNT   5

Definition at line 77 of file buf_internals.h.

Referenced by LocalBufferAlloc(), and PinBuffer().

◆ BM_PERMANENT

#define BM_PERMANENT
Value:
(1U << 31) /* permanent buffer (not unlogged,
* or init fork) */

Definition at line 67 of file buf_internals.h.

Referenced by apw_dump_now(), BufferAlloc(), BufferIsPermanent(), BufferSync(), FlushBuffer(), and MarkBufferDirtyHint().

◆ BM_PIN_COUNT_WAITER

#define BM_PIN_COUNT_WAITER   (1U << 29) /* have waiter for sole pin */

Definition at line 65 of file buf_internals.h.

Referenced by LockBufferForCleanup(), UnlockBuffers(), and UnpinBuffer().

◆ BM_TAG_VALID

#define BM_TAG_VALID   (1U << 25) /* tag is assigned */

◆ BM_VALID

◆ BUF_FLAG_MASK

#define BUF_FLAG_MASK   0xFFC00000U

◆ BUF_REFCOUNT_MASK

#define BUF_REFCOUNT_MASK   ((1U << 18) - 1)

Definition at line 42 of file buf_internals.h.

◆ BUF_REFCOUNT_ONE

#define BUF_REFCOUNT_ONE   1

Definition at line 41 of file buf_internals.h.

Referenced by PinBuffer(), PinBuffer_Locked(), and UnpinBuffer().

◆ BUF_STATE_GET_REFCOUNT

◆ BUF_STATE_GET_USAGECOUNT

#define BUF_STATE_GET_USAGECOUNT (   state)    (((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT)

◆ BUF_USAGECOUNT_MASK

#define BUF_USAGECOUNT_MASK   0x003C0000U

◆ BUF_USAGECOUNT_ONE

#define BUF_USAGECOUNT_ONE   (1U << 18)

Definition at line 44 of file buf_internals.h.

Referenced by BufferAlloc(), LocalBufferAlloc(), PinBuffer(), and StrategyGetBuffer().

◆ BUF_USAGECOUNT_SHIFT

#define BUF_USAGECOUNT_SHIFT   18

Definition at line 45 of file buf_internals.h.

◆ BUFFERDESC_PAD_TO_SIZE

#define BUFFERDESC_PAD_TO_SIZE   (SIZEOF_VOID_P == 8 ? 64 : 1)

Definition at line 212 of file buf_internals.h.

◆ BufferDescriptorGetBuffer

#define BufferDescriptorGetBuffer (   bdesc)    ((bdesc)->buf_id + 1)

◆ BufferDescriptorGetContentLock

◆ BufferDescriptorGetIOLock

#define BufferDescriptorGetIOLock (   bdesc)    (&(BufferIOLWLockArray[(bdesc)->buf_id]).lock)

◆ BUFFERTAGS_EQUAL

#define BUFFERTAGS_EQUAL (   a,
 
)
Value:
( \
RelFileNodeEquals((a).rnode, (b).rnode) && \
(a).blockNum == (b).blockNum && \
(a).forkNum == (b).forkNum \
)

Definition at line 114 of file buf_internals.h.

Referenced by InvalidateBuffer(), and LocalBufferAlloc().

◆ BufMappingPartitionLock

#define BufMappingPartitionLock (   hashcode)
Value:
BufTableHashPartition(hashcode)].lock)
#define BUFFER_MAPPING_LWLOCK_OFFSET
Definition: lwlock.h:124
LWLock lock
Definition: lwlock.h:79
LWLockPadded * MainLWLockArray
Definition: lwlock.c:125

Definition at line 129 of file buf_internals.h.

Referenced by BufferAlloc(), InvalidateBuffer(), and PrefetchBuffer().

◆ BufMappingPartitionLockByIndex

#define BufMappingPartitionLockByIndex (   i)    (&MainLWLockArray[BUFFER_MAPPING_LWLOCK_OFFSET + (i)].lock)

Definition at line 132 of file buf_internals.h.

◆ BufTableHashPartition

#define BufTableHashPartition (   hashcode)    ((hashcode) % NUM_BUFFER_PARTITIONS)

Definition at line 127 of file buf_internals.h.

◆ CLEAR_BUFFERTAG

#define CLEAR_BUFFERTAG (   a)
Value:
( \
(a).rnode.spcNode = InvalidOid, \
(a).rnode.dbNode = InvalidOid, \
(a).rnode.relNode = InvalidOid, \
(a).forkNum = InvalidForkNumber, \
(a).blockNum = InvalidBlockNumber \
)
#define InvalidOid
Definition: postgres_ext.h:36
#define InvalidBlockNumber
Definition: block.h:33

Definition at line 98 of file buf_internals.h.

Referenced by DropRelFileNodeAllLocalBuffers(), DropRelFileNodeLocalBuffers(), InitBufferPool(), InvalidateBuffer(), and LocalBufferAlloc().

◆ FREENEXT_END_OF_LIST

#define FREENEXT_END_OF_LIST   (-1)

Definition at line 236 of file buf_internals.h.

Referenced by InitBufferPool().

◆ FREENEXT_NOT_IN_LIST

#define FREENEXT_NOT_IN_LIST   (-2)

Definition at line 237 of file buf_internals.h.

Referenced by StrategyFreeBuffer(), and StrategyGetBuffer().

◆ GetBufferDescriptor

◆ GetLocalBufferDescriptor

◆ INIT_BUFFERTAG

#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 107 of file buf_internals.h.

Referenced by BufferAlloc(), LocalBufferAlloc(), LocalPrefetchBuffer(), and PrefetchBuffer().

◆ UnlockBufHdr

Typedef Documentation

◆ BufferDesc

◆ BufferDescPadded

◆ BufferTag

◆ CkptSortItem

◆ PendingWriteback

◆ WritebackContext

Function Documentation

◆ AtEOXact_LocalBuffers()

void AtEOXact_LocalBuffers ( bool  isCommit)

Definition at line 572 of file localbuf.c.

References CheckForLocalBufferLeaks().

Referenced by AtEOXact_Buffers().

573 {
575 }
static void CheckForLocalBufferLeaks(void)
Definition: localbuf.c:543

◆ BufTableDelete()

void BufTableDelete ( BufferTag tagPtr,
uint32  hashcode 
)

Definition at line 150 of file buf_table.c.

References elog, ERROR, HASH_REMOVE, and hash_search_with_hash_value().

Referenced by BufferAlloc(), and InvalidateBuffer().

151 {
152  BufferLookupEnt *result;
153 
154  result = (BufferLookupEnt *)
156  (void *) tagPtr,
157  hashcode,
158  HASH_REMOVE,
159  NULL);
160 
161  if (!result) /* shouldn't happen */
162  elog(ERROR, "shared buffer hash table corrupted");
163 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:915
#define ERROR
Definition: elog.h:43
static HTAB * SharedBufHash
Definition: buf_table.c:35
#define elog
Definition: elog.h:219

◆ BufTableHashCode()

uint32 BufTableHashCode ( BufferTag tagPtr)

Definition at line 80 of file buf_table.c.

References get_hash_value().

Referenced by BufferAlloc(), InvalidateBuffer(), and PrefetchBuffer().

81 {
82  return get_hash_value(SharedBufHash, (void *) tagPtr);
83 }
uint32 get_hash_value(HTAB *hashp, const void *keyPtr)
Definition: dynahash.c:856
static HTAB * SharedBufHash
Definition: buf_table.c:35

◆ BufTableInsert()

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

Definition at line 120 of file buf_table.c.

References Assert, buftag::blockNum, HASH_ENTER, hash_search_with_hash_value(), BufferLookupEnt::id, and P_NEW.

Referenced by BufferAlloc().

121 {
122  BufferLookupEnt *result;
123  bool found;
124 
125  Assert(buf_id >= 0); /* -1 is reserved for not-in-table */
126  Assert(tagPtr->blockNum != P_NEW); /* invalid tag */
127 
128  result = (BufferLookupEnt *)
130  (void *) tagPtr,
131  hashcode,
132  HASH_ENTER,
133  &found);
134 
135  if (found) /* found something already in the table */
136  return result->id;
137 
138  result->id = buf_id;
139 
140  return -1;
141 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:915
#define P_NEW
Definition: bufmgr.h:82
#define Assert(condition)
Definition: c.h:670
static HTAB * SharedBufHash
Definition: buf_table.c:35
BlockNumber blockNum
Definition: buf_internals.h:95

◆ BufTableLookup()

int BufTableLookup ( BufferTag tagPtr,
uint32  hashcode 
)

Definition at line 92 of file buf_table.c.

References HASH_FIND, hash_search_with_hash_value(), and BufferLookupEnt::id.

Referenced by BufferAlloc(), and PrefetchBuffer().

93 {
94  BufferLookupEnt *result;
95 
96  result = (BufferLookupEnt *)
98  (void *) tagPtr,
99  hashcode,
100  HASH_FIND,
101  NULL);
102 
103  if (!result)
104  return -1;
105 
106  return result->id;
107 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:915
static HTAB * SharedBufHash
Definition: buf_table.c:35

◆ BufTableShmemSize()

Size BufTableShmemSize ( int  size)

Definition at line 43 of file buf_table.c.

References hash_estimate_size().

Referenced by StrategyShmemSize().

44 {
45  return hash_estimate_size(size, sizeof(BufferLookupEnt));
46 }
Size hash_estimate_size(long num_entries, Size entrysize)
Definition: dynahash.c:728

◆ DropRelFileNodeAllLocalBuffers()

void DropRelFileNodeAllLocalBuffers ( RelFileNode  rnode)

Definition at line 367 of file localbuf.c.

References buftag::blockNum, BM_TAG_VALID, BUF_FLAG_MASK, BUF_USAGECOUNT_MASK, CLEAR_BUFFERTAG, elog, ERROR, buftag::forkNum, GetLocalBufferDescriptor, HASH_REMOVE, hash_search(), i, LocalRefCount, MyBackendId, NLocBuffer, pg_atomic_read_u32(), pg_atomic_unlocked_write_u32(), RelFileNodeEquals, relpathbackend, buftag::rnode, BufferDesc::state, and BufferDesc::tag.

Referenced by DropRelFileNodesAllBuffers().

368 {
369  int i;
370 
371  for (i = 0; i < NLocBuffer; i++)
372  {
374  LocalBufferLookupEnt *hresult;
375  uint32 buf_state;
376 
377  buf_state = pg_atomic_read_u32(&bufHdr->state);
378 
379  if ((buf_state & BM_TAG_VALID) &&
380  RelFileNodeEquals(bufHdr->tag.rnode, rnode))
381  {
382  if (LocalRefCount[i] != 0)
383  elog(ERROR, "block %u of %s is still referenced (local %u)",
384  bufHdr->tag.blockNum,
386  bufHdr->tag.forkNum),
387  LocalRefCount[i]);
388  /* Remove entry from hashtable */
389  hresult = (LocalBufferLookupEnt *)
390  hash_search(LocalBufHash, (void *) &bufHdr->tag,
391  HASH_REMOVE, NULL);
392  if (!hresult) /* shouldn't happen */
393  elog(ERROR, "local buffer hash table corrupted");
394  /* Mark buffer invalid */
395  CLEAR_BUFFERTAG(bufHdr->tag);
396  buf_state &= ~BUF_FLAG_MASK;
397  buf_state &= ~BUF_USAGECOUNT_MASK;
398  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
399  }
400  }
401 }
BackendId MyBackendId
Definition: globals.c:73
#define BM_TAG_VALID
Definition: buf_internals.h:61
ForkNumber forkNum
Definition: buf_internals.h:94
#define GetLocalBufferDescriptor(id)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:902
#define ERROR
Definition: elog.h:43
#define BUF_FLAG_MASK
Definition: buf_internals.h:46
int NLocBuffer
Definition: localbuf.c:41
unsigned int uint32
Definition: c.h:296
#define CLEAR_BUFFERTAG(a)
Definition: buf_internals.h:98
#define BUF_USAGECOUNT_MASK
Definition: buf_internals.h:43
static HTAB * LocalBufHash
Definition: localbuf.c:49
BlockNumber blockNum
Definition: buf_internals.h:95
RelFileNode rnode
Definition: buf_internals.h:93
BufferTag tag
int i
static void pg_atomic_unlocked_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition: atomics.h:288
pg_atomic_uint32 state
#define elog
Definition: elog.h:219
#define relpathbackend(rnode, backend, forknum)
Definition: relpath.h:62
int32 * LocalRefCount
Definition: localbuf.c:45
#define RelFileNodeEquals(node1, node2)
Definition: relfilenode.h:88
static uint32 pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
Definition: atomics.h:252

◆ DropRelFileNodeLocalBuffers()

void DropRelFileNodeLocalBuffers ( RelFileNode  rnode,
ForkNumber  forkNum,
BlockNumber  firstDelBlock 
)

Definition at line 320 of file localbuf.c.

References buftag::blockNum, BM_TAG_VALID, BUF_FLAG_MASK, BUF_USAGECOUNT_MASK, CLEAR_BUFFERTAG, elog, ERROR, buftag::forkNum, GetLocalBufferDescriptor, HASH_REMOVE, hash_search(), i, LocalRefCount, MyBackendId, NLocBuffer, pg_atomic_read_u32(), pg_atomic_unlocked_write_u32(), RelFileNodeEquals, relpathbackend, buftag::rnode, BufferDesc::state, and BufferDesc::tag.

Referenced by DropRelFileNodeBuffers().

322 {
323  int i;
324 
325  for (i = 0; i < NLocBuffer; i++)
326  {
328  LocalBufferLookupEnt *hresult;
329  uint32 buf_state;
330 
331  buf_state = pg_atomic_read_u32(&bufHdr->state);
332 
333  if ((buf_state & BM_TAG_VALID) &&
334  RelFileNodeEquals(bufHdr->tag.rnode, rnode) &&
335  bufHdr->tag.forkNum == forkNum &&
336  bufHdr->tag.blockNum >= firstDelBlock)
337  {
338  if (LocalRefCount[i] != 0)
339  elog(ERROR, "block %u of %s is still referenced (local %u)",
340  bufHdr->tag.blockNum,
342  bufHdr->tag.forkNum),
343  LocalRefCount[i]);
344  /* Remove entry from hashtable */
345  hresult = (LocalBufferLookupEnt *)
346  hash_search(LocalBufHash, (void *) &bufHdr->tag,
347  HASH_REMOVE, NULL);
348  if (!hresult) /* shouldn't happen */
349  elog(ERROR, "local buffer hash table corrupted");
350  /* Mark buffer invalid */
351  CLEAR_BUFFERTAG(bufHdr->tag);
352  buf_state &= ~BUF_FLAG_MASK;
353  buf_state &= ~BUF_USAGECOUNT_MASK;
354  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
355  }
356  }
357 }
BackendId MyBackendId
Definition: globals.c:73
#define BM_TAG_VALID
Definition: buf_internals.h:61
ForkNumber forkNum
Definition: buf_internals.h:94
#define GetLocalBufferDescriptor(id)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:902
#define ERROR
Definition: elog.h:43
#define BUF_FLAG_MASK
Definition: buf_internals.h:46
int NLocBuffer
Definition: localbuf.c:41
unsigned int uint32
Definition: c.h:296
#define CLEAR_BUFFERTAG(a)
Definition: buf_internals.h:98
#define BUF_USAGECOUNT_MASK
Definition: buf_internals.h:43
static HTAB * LocalBufHash
Definition: localbuf.c:49
BlockNumber blockNum
Definition: buf_internals.h:95
RelFileNode rnode
Definition: buf_internals.h:93
BufferTag tag
int i
static void pg_atomic_unlocked_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition: atomics.h:288
pg_atomic_uint32 state
#define elog
Definition: elog.h:219
#define relpathbackend(rnode, backend, forknum)
Definition: relpath.h:62
int32 * LocalRefCount
Definition: localbuf.c:45
#define RelFileNodeEquals(node1, node2)
Definition: relfilenode.h:88
static uint32 pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
Definition: atomics.h:252

◆ have_free_buffer()

bool have_free_buffer ( void  )

Definition at line 180 of file freelist.c.

References BufferStrategyControl::firstFreeBuffer.

Referenced by apw_load_buffers(), and autoprewarm_database_main().

181 {
183  return true;
184  else
185  return false;
186 }
static BufferStrategyControl * StrategyControl
Definition: freelist.c:64

◆ InitBufTable()

void InitBufTable ( int  size)

Definition at line 53 of file buf_table.c.

References HASHCTL::entrysize, HASH_BLOBS, HASH_ELEM, HASH_PARTITION, HASHCTL::keysize, NUM_BUFFER_PARTITIONS, HASHCTL::num_partitions, and ShmemInitHash().

Referenced by StrategyInitialize().

54 {
55  HASHCTL info;
56 
57  /* assume no locking is needed yet */
58 
59  /* BufferTag maps to Buffer */
60  info.keysize = sizeof(BufferTag);
61  info.entrysize = sizeof(BufferLookupEnt);
63 
64  SharedBufHash = ShmemInitHash("Shared Buffer Lookup Table",
65  size, size,
66  &info,
68 }
#define HASH_ELEM
Definition: hsearch.h:87
Size entrysize
Definition: hsearch.h:73
struct buftag BufferTag
#define HASH_PARTITION
Definition: hsearch.h:83
long num_partitions
Definition: hsearch.h:67
#define NUM_BUFFER_PARTITIONS
Definition: lwlock.h:113
#define HASH_BLOBS
Definition: hsearch.h:88
Size keysize
Definition: hsearch.h:72
static HTAB * SharedBufHash
Definition: buf_table.c:35
HTAB * ShmemInitHash(const char *name, long init_size, long max_size, HASHCTL *infoP, int hash_flags)
Definition: shmem.c:317

◆ IssuePendingWritebacks()

void IssuePendingWritebacks ( WritebackContext context)

Definition at line 4276 of file bufmgr.c.

References buftag::blockNum, buffertag_comparator(), cur, buftag::forkNum, i, InvalidBackendId, next, WritebackContext::nr_pending, WritebackContext::pending_writebacks, qsort, RelFileNodeEquals, buftag::rnode, smgropen(), smgrwriteback(), and PendingWriteback::tag.

Referenced by BufferSync(), and ScheduleBufferTagForWriteback().

4277 {
4278  int i;
4279 
4280  if (context->nr_pending == 0)
4281  return;
4282 
4283  /*
4284  * Executing the writes in-order can make them a lot faster, and allows to
4285  * merge writeback requests to consecutive blocks into larger writebacks.
4286  */
4287  qsort(&context->pending_writebacks, context->nr_pending,
4289 
4290  /*
4291  * Coalesce neighbouring writes, but nothing else. For that we iterate
4292  * through the, now sorted, array of pending flushes, and look forward to
4293  * find all neighbouring (or identical) writes.
4294  */
4295  for (i = 0; i < context->nr_pending; i++)
4296  {
4299  SMgrRelation reln;
4300  int ahead;
4301  BufferTag tag;
4302  Size nblocks = 1;
4303 
4304  cur = &context->pending_writebacks[i];
4305  tag = cur->tag;
4306 
4307  /*
4308  * Peek ahead, into following writeback requests, to see if they can
4309  * be combined with the current one.
4310  */
4311  for (ahead = 0; i + ahead + 1 < context->nr_pending; ahead++)
4312  {
4313  next = &context->pending_writebacks[i + ahead + 1];
4314 
4315  /* different file, stop */
4316  if (!RelFileNodeEquals(cur->tag.rnode, next->tag.rnode) ||
4317  cur->tag.forkNum != next->tag.forkNum)
4318  break;
4319 
4320  /* ok, block queued twice, skip */
4321  if (cur->tag.blockNum == next->tag.blockNum)
4322  continue;
4323 
4324  /* only merge consecutive writes */
4325  if (cur->tag.blockNum + 1 != next->tag.blockNum)
4326  break;
4327 
4328  nblocks++;
4329  cur = next;
4330  }
4331 
4332  i += ahead;
4333 
4334  /* and finally tell the kernel to write the data to storage */
4335  reln = smgropen(tag.rnode, InvalidBackendId);
4336  smgrwriteback(reln, tag.forkNum, tag.blockNum, nblocks);
4337  }
4338 
4339  context->nr_pending = 0;
4340 }
static int32 next
Definition: blutils.c:210
ForkNumber forkNum
Definition: buf_internals.h:94
struct cursor * cur
Definition: ecpg.c:28
PendingWriteback pending_writebacks[WRITEBACK_MAX_PENDING_FLUSHES]
void smgrwriteback(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, BlockNumber nblocks)
Definition: smgr.c:660
static int buffertag_comparator(const void *p1, const void *p2)
Definition: bufmgr.c:4144
SMgrRelation smgropen(RelFileNode rnode, BackendId backend)
Definition: smgr.c:137
#define InvalidBackendId
Definition: backendid.h:23
size_t Size
Definition: c.h:404
BlockNumber blockNum
Definition: buf_internals.h:95
RelFileNode rnode
Definition: buf_internals.h:93
int i
#define qsort(a, b, c, d)
Definition: port.h:408
#define RelFileNodeEquals(node1, node2)
Definition: relfilenode.h:88

◆ LocalBufferAlloc()

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_IO_ERROR, BM_JUST_DIRTIED, BM_MAX_USAGE_COUNT, BM_TAG_VALID, BM_VALID, BUF_STATE_GET_USAGECOUNT, BUF_USAGECOUNT_MASK, BUF_USAGECOUNT_ONE, BufferDescriptorGetBuffer, BUFFERTAGS_EQUAL, CLEAR_BUFFERTAG, CurrentResourceOwner, elog, ereport, errcode(), errmsg(), ERROR, buftag::forkNum, GetLocalBufferDescriptor, GetLocalBufferStorage(), HASH_ENTER, HASH_FIND, HASH_REMOVE, hash_search(), LocalBufferLookupEnt::id, INIT_BUFFERTAG, InitLocalBuffers(), BufferUsage::local_blks_written, LocalBufHdrGetBlock, LocalRefCount, MyBackendId, nextFreeLocalBuf, NLocBuffer, RelFileNodeBackend::node, PageSetChecksumInplace(), pg_atomic_read_u32(), pg_atomic_unlocked_write_u32(), pgBufferUsage, RelFileNode::relNode, ResourceOwnerRememberBuffer(), buftag::rnode, SMgrRelationData::smgr_rnode, smgropen(), smgrwrite(), BufferDesc::state, and BufferDesc::tag.

Referenced by ReadBuffer_common().

105 {
106  BufferTag newTag; /* identity of requested block */
107  LocalBufferLookupEnt *hresult;
108  BufferDesc *bufHdr;
109  int b;
110  int trycounter;
111  bool found;
112  uint32 buf_state;
113 
114  INIT_BUFFERTAG(newTag, smgr->smgr_rnode.node, forkNum, blockNum);
115 
116  /* Initialize local buffers if first request in this session */
117  if (LocalBufHash == NULL)
119 
120  /* See if the desired buffer already exists */
121  hresult = (LocalBufferLookupEnt *)
122  hash_search(LocalBufHash, (void *) &newTag, HASH_FIND, NULL);
123 
124  if (hresult)
125  {
126  b = hresult->id;
127  bufHdr = GetLocalBufferDescriptor(b);
128  Assert(BUFFERTAGS_EQUAL(bufHdr->tag, newTag));
129 #ifdef LBDEBUG
130  fprintf(stderr, "LB ALLOC (%u,%d,%d) %d\n",
131  smgr->smgr_rnode.node.relNode, forkNum, blockNum, -b - 1);
132 #endif
133  buf_state = pg_atomic_read_u32(&bufHdr->state);
134 
135  /* this part is equivalent to PinBuffer for a shared buffer */
136  if (LocalRefCount[b] == 0)
137  {
139  {
140  buf_state += BUF_USAGECOUNT_ONE;
141  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
142  }
143  }
144  LocalRefCount[b]++;
146  BufferDescriptorGetBuffer(bufHdr));
147  if (buf_state & BM_VALID)
148  *foundPtr = true;
149  else
150  {
151  /* Previous read attempt must have failed; try again */
152  *foundPtr = false;
153  }
154  return bufHdr;
155  }
156 
157 #ifdef LBDEBUG
158  fprintf(stderr, "LB ALLOC (%u,%d,%d) %d\n",
159  smgr->smgr_rnode.node.relNode, forkNum, blockNum,
160  -nextFreeLocalBuf - 1);
161 #endif
162 
163  /*
164  * Need to get a new buffer. We use a clock sweep algorithm (essentially
165  * the same as what freelist.c does now...)
166  */
167  trycounter = NLocBuffer;
168  for (;;)
169  {
170  b = nextFreeLocalBuf;
171 
172  if (++nextFreeLocalBuf >= NLocBuffer)
173  nextFreeLocalBuf = 0;
174 
175  bufHdr = GetLocalBufferDescriptor(b);
176 
177  if (LocalRefCount[b] == 0)
178  {
179  buf_state = pg_atomic_read_u32(&bufHdr->state);
180 
181  if (BUF_STATE_GET_USAGECOUNT(buf_state) > 0)
182  {
183  buf_state -= BUF_USAGECOUNT_ONE;
184  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
185  trycounter = NLocBuffer;
186  }
187  else
188  {
189  /* Found a usable buffer */
190  LocalRefCount[b]++;
192  BufferDescriptorGetBuffer(bufHdr));
193  break;
194  }
195  }
196  else if (--trycounter == 0)
197  ereport(ERROR,
198  (errcode(ERRCODE_INSUFFICIENT_RESOURCES),
199  errmsg("no empty local buffer available")));
200  }
201 
202  /*
203  * this buffer is not referenced but it might still be dirty. if that's
204  * the case, write it out before reusing it!
205  */
206  if (buf_state & BM_DIRTY)
207  {
208  SMgrRelation oreln;
209  Page localpage = (char *) LocalBufHdrGetBlock(bufHdr);
210 
211  /* Find smgr relation for buffer */
212  oreln = smgropen(bufHdr->tag.rnode, MyBackendId);
213 
214  PageSetChecksumInplace(localpage, bufHdr->tag.blockNum);
215 
216  /* And write... */
217  smgrwrite(oreln,
218  bufHdr->tag.forkNum,
219  bufHdr->tag.blockNum,
220  localpage,
221  false);
222 
223  /* Mark not-dirty now in case we error out below */
224  buf_state &= ~BM_DIRTY;
225  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
226 
228  }
229 
230  /*
231  * lazy memory allocation: allocate space on first use of a buffer.
232  */
233  if (LocalBufHdrGetBlock(bufHdr) == NULL)
234  {
235  /* Set pointer for use by BufferGetBlock() macro */
237  }
238 
239  /*
240  * Update the hash table: remove old entry, if any, and make new one.
241  */
242  if (buf_state & BM_TAG_VALID)
243  {
244  hresult = (LocalBufferLookupEnt *)
245  hash_search(LocalBufHash, (void *) &bufHdr->tag,
246  HASH_REMOVE, NULL);
247  if (!hresult) /* shouldn't happen */
248  elog(ERROR, "local buffer hash table corrupted");
249  /* mark buffer invalid just in case hash insert fails */
250  CLEAR_BUFFERTAG(bufHdr->tag);
251  buf_state &= ~(BM_VALID | BM_TAG_VALID);
252  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
253  }
254 
255  hresult = (LocalBufferLookupEnt *)
256  hash_search(LocalBufHash, (void *) &newTag, HASH_ENTER, &found);
257  if (found) /* shouldn't happen */
258  elog(ERROR, "local buffer hash table corrupted");
259  hresult->id = b;
260 
261  /*
262  * it's all ours now.
263  */
264  bufHdr->tag = newTag;
265  buf_state &= ~(BM_VALID | BM_DIRTY | BM_JUST_DIRTIED | BM_IO_ERROR);
266  buf_state |= BM_TAG_VALID;
267  buf_state &= ~BUF_USAGECOUNT_MASK;
268  buf_state += BUF_USAGECOUNT_ONE;
269  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
270 
271  *foundPtr = false;
272  return bufHdr;
273 }
BackendId MyBackendId
Definition: globals.c:73
#define BM_TAG_VALID
Definition: buf_internals.h:61
ForkNumber forkNum
Definition: buf_internals.h:94
static int nextFreeLocalBuf
Definition: localbuf.c:47
ResourceOwner CurrentResourceOwner
Definition: resowner.c:138
#define GetLocalBufferDescriptor(id)
int errcode(int sqlerrcode)
Definition: elog.c:575
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:902
#define BM_DIRTY
Definition: buf_internals.h:59
void ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer)
Definition: resowner.c:841
#define LocalBufHdrGetBlock(bufHdr)
Definition: localbuf.c:38
#define ERROR
Definition: elog.h:43
int NLocBuffer
Definition: localbuf.c:41
RelFileNodeBackend smgr_rnode
Definition: smgr.h:43
static void InitLocalBuffers(void)
Definition: localbuf.c:410
void smgrwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, bool skipFsync)
Definition: smgr.c:647
#define BUF_USAGECOUNT_ONE
Definition: buf_internals.h:44
#define BM_JUST_DIRTIED
Definition: buf_internals.h:64
unsigned int uint32
Definition: c.h:296
#define ereport(elevel, rest)
Definition: elog.h:122
#define BUFFERTAGS_EQUAL(a, b)
SMgrRelation smgropen(RelFileNode rnode, BackendId backend)
Definition: smgr.c:137
#define BM_VALID
Definition: buf_internals.h:60
RelFileNode node
Definition: relfilenode.h:74
#define Assert(condition)
Definition: c.h:670
#define CLEAR_BUFFERTAG(a)
Definition: buf_internals.h:98
#define INIT_BUFFERTAG(a, xx_rnode, xx_forkNum, xx_blockNum)
#define BUF_USAGECOUNT_MASK
Definition: buf_internals.h:43
static HTAB * LocalBufHash
Definition: localbuf.c:49
#define BufferDescriptorGetBuffer(bdesc)
void PageSetChecksumInplace(Page page, BlockNumber blkno)
Definition: bufpage.c:1195
BlockNumber blockNum
Definition: buf_internals.h:95
RelFileNode rnode
Definition: buf_internals.h:93
static Block GetLocalBufferStorage(void)
Definition: localbuf.c:488
#define BM_MAX_USAGE_COUNT
Definition: buf_internals.h:77
#define BM_IO_ERROR
Definition: buf_internals.h:63
BufferTag tag
int errmsg(const char *fmt,...)
Definition: elog.c:797
long local_blks_written
Definition: instrument.h:28
static void pg_atomic_unlocked_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition: atomics.h:288
pg_atomic_uint32 state
#define elog
Definition: elog.h:219
#define BUF_STATE_GET_USAGECOUNT(state)
Definition: buf_internals.h:50
int32 * LocalRefCount
Definition: localbuf.c:45
Pointer Page
Definition: bufpage.h:74
BufferUsage pgBufferUsage
Definition: instrument.c:20
static uint32 pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
Definition: atomics.h:252

◆ LocalPrefetchBuffer()

void LocalPrefetchBuffer ( SMgrRelation  smgr,
ForkNumber  forkNum,
BlockNumber  blockNum 
)

Definition at line 64 of file localbuf.c.

References HASH_FIND, hash_search(), INIT_BUFFERTAG, InitLocalBuffers(), RelFileNodeBackend::node, SMgrRelationData::smgr_rnode, and smgrprefetch().

Referenced by PrefetchBuffer().

66 {
67 #ifdef USE_PREFETCH
68  BufferTag newTag; /* identity of requested block */
69  LocalBufferLookupEnt *hresult;
70 
71  INIT_BUFFERTAG(newTag, smgr->smgr_rnode.node, forkNum, blockNum);
72 
73  /* Initialize local buffers if first request in this session */
74  if (LocalBufHash == NULL)
76 
77  /* See if the desired buffer already exists */
78  hresult = (LocalBufferLookupEnt *)
79  hash_search(LocalBufHash, (void *) &newTag, HASH_FIND, NULL);
80 
81  if (hresult)
82  {
83  /* Yes, so nothing to do */
84  return;
85  }
86 
87  /* Not in buffers, so initiate prefetch */
88  smgrprefetch(smgr, forkNum, blockNum);
89 #endif /* USE_PREFETCH */
90 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:902
RelFileNodeBackend smgr_rnode
Definition: smgr.h:43
static void InitLocalBuffers(void)
Definition: localbuf.c:410
RelFileNode node
Definition: relfilenode.h:74
#define INIT_BUFFERTAG(a, xx_rnode, xx_forkNum, xx_blockNum)
static HTAB * LocalBufHash
Definition: localbuf.c:49
void smgrprefetch(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum)
Definition: smgr.c:611

◆ LockBufHdr()

uint32 LockBufHdr ( BufferDesc desc)

Definition at line 4092 of file bufmgr.c.

References BM_LOCKED, finish_spin_delay(), init_local_spin_delay, perform_spin_delay(), pg_atomic_fetch_or_u32(), and BufferDesc::state.

Referenced by AbortBufferIO(), apw_dump_now(), BufferAlloc(), BufferGetLSNAtomic(), BufferSync(), ConditionalLockBufferForCleanup(), DropDatabaseBuffers(), DropRelFileNodeBuffers(), DropRelFileNodesAllBuffers(), FlushBuffer(), FlushDatabaseBuffers(), FlushRelationBuffers(), GetBufferFromRing(), InvalidateBuffer(), IsBufferCleanupOK(), LockBufferForCleanup(), MarkBufferDirtyHint(), pg_buffercache_pages(), ReadBuffer_common(), StartBufferIO(), StrategyGetBuffer(), SyncOneBuffer(), TerminateBufferIO(), UnlockBuffers(), UnpinBuffer(), and WaitIO().

4093 {
4094  SpinDelayStatus delayStatus;
4095  uint32 old_buf_state;
4096 
4097  init_local_spin_delay(&delayStatus);
4098 
4099  while (true)
4100  {
4101  /* set BM_LOCKED flag */
4102  old_buf_state = pg_atomic_fetch_or_u32(&desc->state, BM_LOCKED);
4103  /* if it wasn't set before we're OK */
4104  if (!(old_buf_state & BM_LOCKED))
4105  break;
4106  perform_spin_delay(&delayStatus);
4107  }
4108  finish_spin_delay(&delayStatus);
4109  return old_buf_state | BM_LOCKED;
4110 }
#define init_local_spin_delay(status)
Definition: s_lock.h:1021
void finish_spin_delay(SpinDelayStatus *status)
Definition: s_lock.c:175
unsigned int uint32
Definition: c.h:296
#define BM_LOCKED
Definition: buf_internals.h:58
pg_atomic_uint32 state
static uint32 pg_atomic_fetch_or_u32(volatile pg_atomic_uint32 *ptr, uint32 or_)
Definition: atomics.h:383
void perform_spin_delay(SpinDelayStatus *status)
Definition: s_lock.c:125

◆ MarkLocalBufferDirty()

void MarkLocalBufferDirty ( Buffer  buffer)

Definition at line 280 of file localbuf.c.

References Assert, BM_DIRTY, BufferIsLocal, GetLocalBufferDescriptor, BufferUsage::local_blks_dirtied, LocalRefCount, pg_atomic_read_u32(), pg_atomic_unlocked_write_u32(), pgBufferUsage, and BufferDesc::state.

Referenced by MarkBufferDirty(), and MarkBufferDirtyHint().

281 {
282  int bufid;
283  BufferDesc *bufHdr;
284  uint32 buf_state;
285 
287 
288 #ifdef LBDEBUG
289  fprintf(stderr, "LB DIRTY %d\n", buffer);
290 #endif
291 
292  bufid = -(buffer + 1);
293 
294  Assert(LocalRefCount[bufid] > 0);
295 
296  bufHdr = GetLocalBufferDescriptor(bufid);
297 
298  buf_state = pg_atomic_read_u32(&bufHdr->state);
299 
300  if (!(buf_state & BM_DIRTY))
302 
303  buf_state |= BM_DIRTY;
304 
305  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
306 }
long local_blks_dirtied
Definition: instrument.h:27
#define GetLocalBufferDescriptor(id)
#define BM_DIRTY
Definition: buf_internals.h:59
unsigned int uint32
Definition: c.h:296
#define Assert(condition)
Definition: c.h:670
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
#define BufferIsLocal(buffer)
Definition: buf.h:37
static void pg_atomic_unlocked_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition: atomics.h:288
pg_atomic_uint32 state
int32 * LocalRefCount
Definition: localbuf.c:45
BufferUsage pgBufferUsage
Definition: instrument.c:20
static uint32 pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
Definition: atomics.h:252

◆ ScheduleBufferTagForWriteback()

void ScheduleBufferTagForWriteback ( WritebackContext context,
BufferTag tag 
)

Definition at line 4242 of file bufmgr.c.

References Assert, IssuePendingWritebacks(), WritebackContext::max_pending, WritebackContext::nr_pending, WritebackContext::pending_writebacks, PendingWriteback::tag, and WRITEBACK_MAX_PENDING_FLUSHES.

Referenced by BufferAlloc(), and SyncOneBuffer().

4243 {
4244  PendingWriteback *pending;
4245 
4246  /*
4247  * Add buffer to the pending writeback array, unless writeback control is
4248  * disabled.
4249  */
4250  if (*context->max_pending > 0)
4251  {
4253 
4254  pending = &context->pending_writebacks[context->nr_pending++];
4255 
4256  pending->tag = *tag;
4257  }
4258 
4259  /*
4260  * Perform pending flushes if the writeback limit is exceeded. This
4261  * includes the case where previously an item has been added, but control
4262  * is now disabled.
4263  */
4264  if (context->nr_pending >= *context->max_pending)
4265  IssuePendingWritebacks(context);
4266 }
void IssuePendingWritebacks(WritebackContext *context)
Definition: bufmgr.c:4276
PendingWriteback pending_writebacks[WRITEBACK_MAX_PENDING_FLUSHES]
#define Assert(condition)
Definition: c.h:670
#define WRITEBACK_MAX_PENDING_FLUSHES

◆ StrategyFreeBuffer()

void StrategyFreeBuffer ( BufferDesc buf)

Definition at line 364 of file freelist.c.

References BufferDesc::buf_id, BufferStrategyControl::buffer_strategy_lock, BufferStrategyControl::firstFreeBuffer, BufferDesc::freeNext, FREENEXT_NOT_IN_LIST, BufferStrategyControl::lastFreeBuffer, SpinLockAcquire, and SpinLockRelease.

Referenced by InvalidateBuffer().

365 {
367 
368  /*
369  * It is possible that we are told to put something in the freelist that
370  * is already in it; don't screw up the list if so.
371  */
372  if (buf->freeNext == FREENEXT_NOT_IN_LIST)
373  {
375  if (buf->freeNext < 0)
378  }
379 
381 }
#define SpinLockAcquire(lock)
Definition: spin.h:62
#define FREENEXT_NOT_IN_LIST
slock_t buffer_strategy_lock
Definition: freelist.c:32
#define SpinLockRelease(lock)
Definition: spin.h:64
static BufferStrategyControl * StrategyControl
Definition: freelist.c:64

◆ StrategyGetBuffer()

BufferDesc* StrategyGetBuffer ( BufferAccessStrategy  strategy,
uint32 buf_state 
)

Definition at line 201 of file freelist.c.

References AddBufferToRing(), PROC_HDR::allProcs, Assert, BufferStrategyControl::bgwprocno, buf, BUF_STATE_GET_REFCOUNT, BUF_STATE_GET_USAGECOUNT, BUF_USAGECOUNT_ONE, BufferStrategyControl::buffer_strategy_lock, ClockSweepTick(), elog, ERROR, BufferStrategyControl::firstFreeBuffer, BufferDesc::freeNext, FREENEXT_NOT_IN_LIST, GetBufferDescriptor, GetBufferFromRing(), INT_ACCESS_ONCE, LockBufHdr(), NBuffers, BufferStrategyControl::numBufferAllocs, pg_atomic_fetch_add_u32(), ProcGlobal, PGPROC::procLatch, SetLatch(), SpinLockAcquire, SpinLockRelease, and UnlockBufHdr.

Referenced by BufferAlloc().

202 {
203  BufferDesc *buf;
204  int bgwprocno;
205  int trycounter;
206  uint32 local_buf_state; /* to avoid repeated (de-)referencing */
207 
208  /*
209  * If given a strategy object, see whether it can select a buffer. We
210  * assume strategy objects don't need buffer_strategy_lock.
211  */
212  if (strategy != NULL)
213  {
214  buf = GetBufferFromRing(strategy, buf_state);
215  if (buf != NULL)
216  return buf;
217  }
218 
219  /*
220  * If asked, we need to waken the bgwriter. Since we don't want to rely on
221  * a spinlock for this we force a read from shared memory once, and then
222  * set the latch based on that value. We need to go through that length
223  * because otherwise bgprocno might be reset while/after we check because
224  * the compiler might just reread from memory.
225  *
226  * This can possibly set the latch of the wrong process if the bgwriter
227  * dies in the wrong moment. But since PGPROC->procLatch is never
228  * deallocated the worst consequence of that is that we set the latch of
229  * some arbitrary process.
230  */
232  if (bgwprocno != -1)
233  {
234  /* reset bgwprocno first, before setting the latch */
236 
237  /*
238  * Not acquiring ProcArrayLock here which is slightly icky. It's
239  * actually fine because procLatch isn't ever freed, so we just can
240  * potentially set the wrong process' (or no process') latch.
241  */
242  SetLatch(&ProcGlobal->allProcs[bgwprocno].procLatch);
243  }
244 
245  /*
246  * We count buffer allocation requests so that the bgwriter can estimate
247  * the rate of buffer consumption. Note that buffers recycled by a
248  * strategy object are intentionally not counted here.
249  */
251 
252  /*
253  * First check, without acquiring the lock, whether there's buffers in the
254  * freelist. Since we otherwise don't require the spinlock in every
255  * StrategyGetBuffer() invocation, it'd be sad to acquire it here -
256  * uselessly in most cases. That obviously leaves a race where a buffer is
257  * put on the freelist but we don't see the store yet - but that's pretty
258  * harmless, it'll just get used during the next buffer acquisition.
259  *
260  * If there's buffers on the freelist, acquire the spinlock to pop one
261  * buffer of the freelist. Then check whether that buffer is usable and
262  * repeat if not.
263  *
264  * Note that the freeNext fields are considered to be protected by the
265  * buffer_strategy_lock not the individual buffer spinlocks, so it's OK to
266  * manipulate them without holding the spinlock.
267  */
269  {
270  while (true)
271  {
272  /* Acquire the spinlock to remove element from the freelist */
274 
276  {
278  break;
279  }
280 
283 
284  /* Unconditionally remove buffer from freelist */
287 
288  /*
289  * Release the lock so someone else can access the freelist while
290  * we check out this buffer.
291  */
293 
294  /*
295  * If the buffer is pinned or has a nonzero usage_count, we cannot
296  * use it; discard it and retry. (This can only happen if VACUUM
297  * put a valid buffer in the freelist and then someone else used
298  * it before we got to it. It's probably impossible altogether as
299  * of 8.3, but we'd better check anyway.)
300  */
301  local_buf_state = LockBufHdr(buf);
302  if (BUF_STATE_GET_REFCOUNT(local_buf_state) == 0
303  && BUF_STATE_GET_USAGECOUNT(local_buf_state) == 0)
304  {
305  if (strategy != NULL)
306  AddBufferToRing(strategy, buf);
307  *buf_state = local_buf_state;
308  return buf;
309  }
310  UnlockBufHdr(buf, local_buf_state);
311 
312  }
313  }
314 
315  /* Nothing on the freelist, so run the "clock sweep" algorithm */
316  trycounter = NBuffers;
317  for (;;)
318  {
320 
321  /*
322  * If the buffer is pinned or has a nonzero usage_count, we cannot use
323  * it; decrement the usage_count (unless pinned) and keep scanning.
324  */
325  local_buf_state = LockBufHdr(buf);
326 
327  if (BUF_STATE_GET_REFCOUNT(local_buf_state) == 0)
328  {
329  if (BUF_STATE_GET_USAGECOUNT(local_buf_state) != 0)
330  {
331  local_buf_state -= BUF_USAGECOUNT_ONE;
332 
333  trycounter = NBuffers;
334  }
335  else
336  {
337  /* Found a usable buffer */
338  if (strategy != NULL)
339  AddBufferToRing(strategy, buf);
340  *buf_state = local_buf_state;
341  return buf;
342  }
343  }
344  else if (--trycounter == 0)
345  {
346  /*
347  * We've scanned all the buffers without making any state changes,
348  * so all the buffers are pinned (or were when we looked at them).
349  * We could hope that someone will free one eventually, but it's
350  * probably better to fail than to risk getting stuck in an
351  * infinite loop.
352  */
353  UnlockBufHdr(buf, local_buf_state);
354  elog(ERROR, "no unpinned buffers available");
355  }
356  UnlockBufHdr(buf, local_buf_state);
357  }
358 }
static uint32 ClockSweepTick(void)
Definition: freelist.c:113
PROC_HDR * ProcGlobal
Definition: proc.c:80
Latch procLatch
Definition: proc.h:104
#define SpinLockAcquire(lock)
Definition: spin.h:62
#define FREENEXT_NOT_IN_LIST
#define ERROR
Definition: elog.h:43
static BufferDesc * GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state)
Definition: freelist.c:611
static char * buf
Definition: pg_test_fsync.c:67
#define BUF_USAGECOUNT_ONE
Definition: buf_internals.h:44
#define GetBufferDescriptor(id)
unsigned int uint32
Definition: c.h:296
slock_t buffer_strategy_lock
Definition: freelist.c:32
#define INT_ACCESS_ONCE(var)
Definition: freelist.c:23
#define SpinLockRelease(lock)
Definition: spin.h:64
pg_atomic_uint32 numBufferAllocs
Definition: freelist.c:54
static void AddBufferToRing(BufferAccessStrategy strategy, BufferDesc *buf)
Definition: freelist.c:669
static uint32 pg_atomic_fetch_add_u32(volatile pg_atomic_uint32 *ptr, int32 add_)
Definition: atomics.h:339
void SetLatch(volatile Latch *latch)
Definition: latch.c:414
uint32 LockBufHdr(BufferDesc *desc)
Definition: bufmgr.c:4092
#define Assert(condition)
Definition: c.h:670
#define UnlockBufHdr(desc, s)
int NBuffers
Definition: globals.c:122
PGPROC * allProcs
Definition: proc.h:244
#define elog
Definition: elog.h:219
#define BUF_STATE_GET_USAGECOUNT(state)
Definition: buf_internals.h:50
static BufferStrategyControl * StrategyControl
Definition: freelist.c:64
#define BUF_STATE_GET_REFCOUNT(state)
Definition: buf_internals.h:49

◆ StrategyInitialize()

void StrategyInitialize ( bool  init)

Definition at line 475 of file freelist.c.

References Assert, BufferStrategyControl::bgwprocno, BufferStrategyControl::buffer_strategy_lock, BufferStrategyControl::completePasses, BufferStrategyControl::firstFreeBuffer, InitBufTable(), BufferStrategyControl::lastFreeBuffer, NBuffers, BufferStrategyControl::nextVictimBuffer, NUM_BUFFER_PARTITIONS, BufferStrategyControl::numBufferAllocs, pg_atomic_init_u32(), ShmemInitStruct(), and SpinLockInit.

Referenced by InitBufferPool().

476 {
477  bool found;
478 
479  /*
480  * Initialize the shared buffer lookup hashtable.
481  *
482  * Since we can't tolerate running out of lookup table entries, we must be
483  * sure to specify an adequate table size here. The maximum steady-state
484  * usage is of course NBuffers entries, but BufferAlloc() tries to insert
485  * a new entry before deleting the old. In principle this could be
486  * happening in each partition concurrently, so we could need as many as
487  * NBuffers + NUM_BUFFER_PARTITIONS entries.
488  */
490 
491  /*
492  * Get or create the shared strategy control block
493  */
495  ShmemInitStruct("Buffer Strategy Status",
496  sizeof(BufferStrategyControl),
497  &found);
498 
499  if (!found)
500  {
501  /*
502  * Only done once, usually in postmaster
503  */
504  Assert(init);
505 
507 
508  /*
509  * Grab the whole linked list of free buffers for our strategy. We
510  * assume it was previously set up by InitBufferPool().
511  */
514 
515  /* Initialize the clock sweep pointer */
517 
518  /* Clear statistics */
521 
522  /* No pending notification */
524  }
525  else
526  Assert(!init);
527 }
pg_atomic_uint32 nextVictimBuffer
Definition: freelist.c:39
#define SpinLockInit(lock)
Definition: spin.h:60
void InitBufTable(int size)
Definition: buf_table.c:53
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:372
#define NUM_BUFFER_PARTITIONS
Definition: lwlock.h:113
slock_t buffer_strategy_lock
Definition: freelist.c:32
pg_atomic_uint32 numBufferAllocs
Definition: freelist.c:54
#define Assert(condition)
Definition: c.h:670
int NBuffers
Definition: globals.c:122
static void pg_atomic_init_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition: atomics.h:234
static BufferStrategyControl * StrategyControl
Definition: freelist.c:64

◆ StrategyNotifyBgWriter()

void StrategyNotifyBgWriter ( int  bgwprocno)

Definition at line 432 of file freelist.c.

References BufferStrategyControl::bgwprocno, BufferStrategyControl::buffer_strategy_lock, SpinLockAcquire, and SpinLockRelease.

Referenced by BackgroundWriterMain().

433 {
434  /*
435  * We acquire buffer_strategy_lock just to ensure that the store appears
436  * atomic to StrategyGetBuffer. The bgwriter should call this rather
437  * infrequently, so there's no performance penalty from being safe.
438  */
440  StrategyControl->bgwprocno = bgwprocno;
442 }
#define SpinLockAcquire(lock)
Definition: spin.h:62
slock_t buffer_strategy_lock
Definition: freelist.c:32
#define SpinLockRelease(lock)
Definition: spin.h:64
static BufferStrategyControl * StrategyControl
Definition: freelist.c:64

◆ StrategyRejectBuffer()

bool StrategyRejectBuffer ( BufferAccessStrategy  strategy,
BufferDesc buf 
)

Definition at line 686 of file freelist.c.

References BAS_BULKREAD, BufferAccessStrategyData::btype, BufferDescriptorGetBuffer, BufferAccessStrategyData::buffers, BufferAccessStrategyData::current, BufferAccessStrategyData::current_was_in_ring, and InvalidBuffer.

Referenced by BufferAlloc().

687 {
688  /* We only do this in bulkread mode */
689  if (strategy->btype != BAS_BULKREAD)
690  return false;
691 
692  /* Don't muck with behavior of normal buffer-replacement strategy */
693  if (!strategy->current_was_in_ring ||
694  strategy->buffers[strategy->current] != BufferDescriptorGetBuffer(buf))
695  return false;
696 
697  /*
698  * Remove the dirty buffer from the ring; necessary to prevent infinite
699  * loop if all ring members are dirty.
700  */
701  strategy->buffers[strategy->current] = InvalidBuffer;
702 
703  return true;
704 }
#define InvalidBuffer
Definition: buf.h:25
Buffer buffers[FLEXIBLE_ARRAY_MEMBER]
Definition: freelist.c:96
BufferAccessStrategyType btype
Definition: freelist.c:74
#define BufferDescriptorGetBuffer(bdesc)

◆ StrategyShmemSize()

Size StrategyShmemSize ( void  )

Definition at line 454 of file freelist.c.

References add_size(), BufTableShmemSize(), MAXALIGN, NBuffers, and NUM_BUFFER_PARTITIONS.

Referenced by BufferShmemSize().

455 {
456  Size size = 0;
457 
458  /* size of lookup hash table ... see comment in StrategyInitialize */
460 
461  /* size of the shared replacement strategy control block */
462  size = add_size(size, MAXALIGN(sizeof(BufferStrategyControl)));
463 
464  return size;
465 }
#define NUM_BUFFER_PARTITIONS
Definition: lwlock.h:113
Size add_size(Size s1, Size s2)
Definition: shmem.c:475
size_t Size
Definition: c.h:404
#define MAXALIGN(LEN)
Definition: c.h:623
int NBuffers
Definition: globals.c:122
Size BufTableShmemSize(int size)
Definition: buf_table.c:43

◆ StrategySyncStart()

int StrategySyncStart ( uint32 complete_passes,
uint32 num_buf_alloc 
)

Definition at line 395 of file freelist.c.

References BufferStrategyControl::buffer_strategy_lock, BufferStrategyControl::completePasses, NBuffers, BufferStrategyControl::nextVictimBuffer, BufferStrategyControl::numBufferAllocs, pg_atomic_exchange_u32(), pg_atomic_read_u32(), SpinLockAcquire, and SpinLockRelease.

Referenced by BgBufferSync().

396 {
397  uint32 nextVictimBuffer;
398  int result;
399 
402  result = nextVictimBuffer % NBuffers;
403 
404  if (complete_passes)
405  {
406  *complete_passes = StrategyControl->completePasses;
407 
408  /*
409  * Additionally add the number of wraparounds that happened before
410  * completePasses could be incremented. C.f. ClockSweepTick().
411  */
412  *complete_passes += nextVictimBuffer / NBuffers;
413  }
414 
415  if (num_buf_alloc)
416  {
418  }
420  return result;
421 }
pg_atomic_uint32 nextVictimBuffer
Definition: freelist.c:39
static uint32 pg_atomic_exchange_u32(volatile pg_atomic_uint32 *ptr, uint32 newval)
Definition: atomics.h:303
#define SpinLockAcquire(lock)
Definition: spin.h:62
unsigned int uint32
Definition: c.h:296
slock_t buffer_strategy_lock
Definition: freelist.c:32
#define SpinLockRelease(lock)
Definition: spin.h:64
pg_atomic_uint32 numBufferAllocs
Definition: freelist.c:54
int NBuffers
Definition: globals.c:122
static BufferStrategyControl * StrategyControl
Definition: freelist.c:64
static uint32 pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
Definition: atomics.h:252

◆ WritebackContextInit()

void WritebackContextInit ( WritebackContext context,
int *  max_pending 
)

Definition at line 4230 of file bufmgr.c.

References Assert, WritebackContext::max_pending, WritebackContext::nr_pending, and WRITEBACK_MAX_PENDING_FLUSHES.

Referenced by BackgroundWriterMain(), BufferSync(), and InitBufferPool().

4231 {
4232  Assert(*max_pending <= WRITEBACK_MAX_PENDING_FLUSHES);
4233 
4234  context->max_pending = max_pending;
4235  context->nr_pending = 0;
4236 }
#define Assert(condition)
Definition: c.h:670
#define WRITEBACK_MAX_PENDING_FLUSHES

Variable Documentation

◆ BackendWritebackContext

PGDLLIMPORT WritebackContext BackendWritebackContext

Definition at line 24 of file buf_init.c.

Referenced by BufferAlloc().

◆ BufferDescriptors

PGDLLIMPORT BufferDescPadded* BufferDescriptors

Definition at line 21 of file buf_init.c.

◆ BufferIOLWLockArray

PGDLLIMPORT LWLockMinimallyPadded* BufferIOLWLockArray

Definition at line 23 of file buf_init.c.

◆ CkptBufferIds

CkptSortItem* CkptBufferIds

Definition at line 25 of file buf_init.c.

Referenced by BufferSync().

◆ LocalBufferDescriptors

BufferDesc* LocalBufferDescriptors

Definition at line 43 of file localbuf.c.