PostgreSQL Source Code  git master
buf_internals.h File Reference
#include "port/atomics.h"
#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 "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)
 
PrefetchBufferResult PrefetchLocalBuffer (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 65 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 62 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 61 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 76 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 66 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 64 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 41 of file buf_internals.h.

◆ BUF_REFCOUNT_ONE

#define BUF_REFCOUNT_ONE   1

Definition at line 40 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 43 of file buf_internals.h.

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

◆ BUF_USAGECOUNT_SHIFT

#define BUF_USAGECOUNT_SHIFT   18

Definition at line 44 of file buf_internals.h.

◆ BUFFERDESC_PAD_TO_SIZE

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

Definition at line 211 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 113 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:122
LWLock lock
Definition: lwlock.h:78
LWLockPadded * MainLWLockArray
Definition: lwlock.c:200

Definition at line 128 of file buf_internals.h.

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

◆ BufMappingPartitionLockByIndex

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

Definition at line 131 of file buf_internals.h.

◆ BufTableHashPartition

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

Definition at line 126 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 97 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 235 of file buf_internals.h.

Referenced by InitBufferPool().

◆ FREENEXT_NOT_IN_LIST

#define FREENEXT_NOT_IN_LIST   (-2)

Definition at line 236 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 106 of file buf_internals.h.

Referenced by BufferAlloc(), LocalBufferAlloc(), PrefetchLocalBuffer(), and PrefetchSharedBuffer().

◆ UnlockBufHdr

Typedef Documentation

◆ BufferDesc

typedef struct BufferDesc BufferDesc

◆ BufferDescPadded

◆ BufferTag

typedef struct buftag BufferTag

◆ CkptSortItem

typedef struct CkptSortItem CkptSortItem

◆ PendingWriteback

◆ WritebackContext

Function Documentation

◆ AtEOXact_LocalBuffers()

void AtEOXact_LocalBuffers ( bool  isCommit)

Definition at line 578 of file localbuf.c.

References CheckForLocalBufferLeaks().

Referenced by AtEOXact_Buffers().

579 {
581 }
static void CheckForLocalBufferLeaks(void)
Definition: localbuf.c:549

◆ BufTableDelete()

void BufTableDelete ( BufferTag tagPtr,
uint32  hashcode 
)

Definition at line 149 of file buf_table.c.

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

Referenced by BufferAlloc(), and InvalidateBuffer().

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

◆ BufTableHashCode()

uint32 BufTableHashCode ( BufferTag tagPtr)

Definition at line 79 of file buf_table.c.

References get_hash_value().

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

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

◆ BufTableInsert()

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

Definition at line 119 of file buf_table.c.

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

Referenced by BufferAlloc().

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

◆ BufTableLookup()

int BufTableLookup ( BufferTag tagPtr,
uint32  hashcode 
)

Definition at line 91 of file buf_table.c.

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

Referenced by BufferAlloc(), and PrefetchSharedBuffer().

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

◆ BufTableShmemSize()

Size BufTableShmemSize ( int  size)

Definition at line 42 of file buf_table.c.

References hash_estimate_size().

Referenced by StrategyShmemSize().

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

◆ DropRelFileNodeAllLocalBuffers()

void DropRelFileNodeAllLocalBuffers ( RelFileNode  rnode)

Definition at line 373 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().

374 {
375  int i;
376 
377  for (i = 0; i < NLocBuffer; i++)
378  {
380  LocalBufferLookupEnt *hresult;
381  uint32 buf_state;
382 
383  buf_state = pg_atomic_read_u32(&bufHdr->state);
384 
385  if ((buf_state & BM_TAG_VALID) &&
386  RelFileNodeEquals(bufHdr->tag.rnode, rnode))
387  {
388  if (LocalRefCount[i] != 0)
389  elog(ERROR, "block %u of %s is still referenced (local %u)",
390  bufHdr->tag.blockNum,
392  bufHdr->tag.forkNum),
393  LocalRefCount[i]);
394  /* Remove entry from hashtable */
395  hresult = (LocalBufferLookupEnt *)
396  hash_search(LocalBufHash, (void *) &bufHdr->tag,
397  HASH_REMOVE, NULL);
398  if (!hresult) /* shouldn't happen */
399  elog(ERROR, "local buffer hash table corrupted");
400  /* Mark buffer invalid */
401  CLEAR_BUFFERTAG(bufHdr->tag);
402  buf_state &= ~BUF_FLAG_MASK;
403  buf_state &= ~BUF_USAGECOUNT_MASK;
404  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
405  }
406  }
407 }
BackendId MyBackendId
Definition: globals.c:81
#define BM_TAG_VALID
Definition: buf_internals.h:60
ForkNumber forkNum
Definition: buf_internals.h:93
#define GetLocalBufferDescriptor(id)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:927
#define ERROR
Definition: elog.h:43
#define BUF_FLAG_MASK
Definition: buf_internals.h:45
int NLocBuffer
Definition: localbuf.c:41
unsigned int uint32
Definition: c.h:374
#define CLEAR_BUFFERTAG(a)
Definition: buf_internals.h:97
#define BUF_USAGECOUNT_MASK
Definition: buf_internals.h:42
static HTAB * LocalBufHash
Definition: localbuf.c:49
BlockNumber blockNum
Definition: buf_internals.h:94
RelFileNode rnode
Definition: buf_internals.h:92
BufferTag tag
#define elog(elevel,...)
Definition: elog.h:214
int i
static void pg_atomic_unlocked_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition: atomics.h:277
pg_atomic_uint32 state
#define relpathbackend(rnode, backend, forknum)
Definition: relpath.h:78
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:241

◆ DropRelFileNodeLocalBuffers()

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

Definition at line 326 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().

328 {
329  int i;
330 
331  for (i = 0; i < NLocBuffer; i++)
332  {
334  LocalBufferLookupEnt *hresult;
335  uint32 buf_state;
336 
337  buf_state = pg_atomic_read_u32(&bufHdr->state);
338 
339  if ((buf_state & BM_TAG_VALID) &&
340  RelFileNodeEquals(bufHdr->tag.rnode, rnode) &&
341  bufHdr->tag.forkNum == forkNum &&
342  bufHdr->tag.blockNum >= firstDelBlock)
343  {
344  if (LocalRefCount[i] != 0)
345  elog(ERROR, "block %u of %s is still referenced (local %u)",
346  bufHdr->tag.blockNum,
348  bufHdr->tag.forkNum),
349  LocalRefCount[i]);
350  /* Remove entry from hashtable */
351  hresult = (LocalBufferLookupEnt *)
352  hash_search(LocalBufHash, (void *) &bufHdr->tag,
353  HASH_REMOVE, NULL);
354  if (!hresult) /* shouldn't happen */
355  elog(ERROR, "local buffer hash table corrupted");
356  /* Mark buffer invalid */
357  CLEAR_BUFFERTAG(bufHdr->tag);
358  buf_state &= ~BUF_FLAG_MASK;
359  buf_state &= ~BUF_USAGECOUNT_MASK;
360  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
361  }
362  }
363 }
BackendId MyBackendId
Definition: globals.c:81
#define BM_TAG_VALID
Definition: buf_internals.h:60
ForkNumber forkNum
Definition: buf_internals.h:93
#define GetLocalBufferDescriptor(id)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:927
#define ERROR
Definition: elog.h:43
#define BUF_FLAG_MASK
Definition: buf_internals.h:45
int NLocBuffer
Definition: localbuf.c:41
unsigned int uint32
Definition: c.h:374
#define CLEAR_BUFFERTAG(a)
Definition: buf_internals.h:97
#define BUF_USAGECOUNT_MASK
Definition: buf_internals.h:42
static HTAB * LocalBufHash
Definition: localbuf.c:49
BlockNumber blockNum
Definition: buf_internals.h:94
RelFileNode rnode
Definition: buf_internals.h:92
BufferTag tag
#define elog(elevel,...)
Definition: elog.h:214
int i
static void pg_atomic_unlocked_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition: atomics.h:277
pg_atomic_uint32 state
#define relpathbackend(rnode, backend, forknum)
Definition: relpath.h:78
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:241

◆ 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 52 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().

53 {
54  HASHCTL info;
55 
56  /* assume no locking is needed yet */
57 
58  /* BufferTag maps to Buffer */
59  info.keysize = sizeof(BufferTag);
60  info.entrysize = sizeof(BufferLookupEnt);
62 
63  SharedBufHash = ShmemInitHash("Shared Buffer Lookup Table",
64  size, size,
65  &info,
67 }
#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:111
#define HASH_BLOBS
Definition: hsearch.h:88
Size keysize
Definition: hsearch.h:72
static HTAB * SharedBufHash
Definition: buf_table.c:34
HTAB * ShmemInitHash(const char *name, long init_size, long max_size, HASHCTL *infoP, int hash_flags)
Definition: shmem.c:337

◆ IssuePendingWritebacks()

void IssuePendingWritebacks ( WritebackContext context)

Definition at line 4511 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().

4512 {
4513  int i;
4514 
4515  if (context->nr_pending == 0)
4516  return;
4517 
4518  /*
4519  * Executing the writes in-order can make them a lot faster, and allows to
4520  * merge writeback requests to consecutive blocks into larger writebacks.
4521  */
4522  qsort(&context->pending_writebacks, context->nr_pending,
4524 
4525  /*
4526  * Coalesce neighbouring writes, but nothing else. For that we iterate
4527  * through the, now sorted, array of pending flushes, and look forward to
4528  * find all neighbouring (or identical) writes.
4529  */
4530  for (i = 0; i < context->nr_pending; i++)
4531  {
4534  SMgrRelation reln;
4535  int ahead;
4536  BufferTag tag;
4537  Size nblocks = 1;
4538 
4539  cur = &context->pending_writebacks[i];
4540  tag = cur->tag;
4541 
4542  /*
4543  * Peek ahead, into following writeback requests, to see if they can
4544  * be combined with the current one.
4545  */
4546  for (ahead = 0; i + ahead + 1 < context->nr_pending; ahead++)
4547  {
4548  next = &context->pending_writebacks[i + ahead + 1];
4549 
4550  /* different file, stop */
4551  if (!RelFileNodeEquals(cur->tag.rnode, next->tag.rnode) ||
4552  cur->tag.forkNum != next->tag.forkNum)
4553  break;
4554 
4555  /* ok, block queued twice, skip */
4556  if (cur->tag.blockNum == next->tag.blockNum)
4557  continue;
4558 
4559  /* only merge consecutive writes */
4560  if (cur->tag.blockNum + 1 != next->tag.blockNum)
4561  break;
4562 
4563  nblocks++;
4564  cur = next;
4565  }
4566 
4567  i += ahead;
4568 
4569  /* and finally tell the kernel to write the data to storage */
4570  reln = smgropen(tag.rnode, InvalidBackendId);
4571  smgrwriteback(reln, tag.forkNum, tag.blockNum, nblocks);
4572  }
4573 
4574  context->nr_pending = 0;
4575 }
static int32 next
Definition: blutils.c:219
ForkNumber forkNum
Definition: buf_internals.h:93
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:537
static int buffertag_comparator(const void *p1, const void *p2)
Definition: bufmgr.c:4377
SMgrRelation smgropen(RelFileNode rnode, BackendId backend)
Definition: smgr.c:146
#define InvalidBackendId
Definition: backendid.h:23
size_t Size
Definition: c.h:473
BlockNumber blockNum
Definition: buf_internals.h:94
RelFileNode rnode
Definition: buf_internals.h:92
int i
#define qsort(a, b, c, d)
Definition: port.h:479
#define RelFileNodeEquals(node1, node2)
Definition: relfilenode.h:88

◆ LocalBufferAlloc()

BufferDesc* LocalBufferAlloc ( SMgrRelation  smgr,
ForkNumber  forkNum,
BlockNumber  blockNum,
bool foundPtr 
)

Definition at line 109 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, fprintf, 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().

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

◆ LockBufHdr()

uint32 LockBufHdr ( BufferDesc desc)

Definition at line 4325 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(), FlushRelationsAllBuffers(), GetBufferFromRing(), InvalidateBuffer(), IsBufferCleanupOK(), LockBufferForCleanup(), MarkBufferDirtyHint(), pg_buffercache_pages(), ReadBuffer_common(), StartBufferIO(), StrategyGetBuffer(), SyncOneBuffer(), TerminateBufferIO(), UnlockBuffers(), UnpinBuffer(), and WaitIO().

4326 {
4327  SpinDelayStatus delayStatus;
4328  uint32 old_buf_state;
4329 
4330  init_local_spin_delay(&delayStatus);
4331 
4332  while (true)
4333  {
4334  /* set BM_LOCKED flag */
4335  old_buf_state = pg_atomic_fetch_or_u32(&desc->state, BM_LOCKED);
4336  /* if it wasn't set before we're OK */
4337  if (!(old_buf_state & BM_LOCKED))
4338  break;
4339  perform_spin_delay(&delayStatus);
4340  }
4341  finish_spin_delay(&delayStatus);
4342  return old_buf_state | BM_LOCKED;
4343 }
#define init_local_spin_delay(status)
Definition: s_lock.h:1043
void finish_spin_delay(SpinDelayStatus *status)
Definition: s_lock.c:174
unsigned int uint32
Definition: c.h:374
#define BM_LOCKED
Definition: buf_internals.h:57
pg_atomic_uint32 state
static uint32 pg_atomic_fetch_or_u32(volatile pg_atomic_uint32 *ptr, uint32 or_)
Definition: atomics.h:372
void perform_spin_delay(SpinDelayStatus *status)
Definition: s_lock.c:124

◆ MarkLocalBufferDirty()

void MarkLocalBufferDirty ( Buffer  buffer)

Definition at line 286 of file localbuf.c.

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

Referenced by MarkBufferDirty(), and MarkBufferDirtyHint().

287 {
288  int bufid;
289  BufferDesc *bufHdr;
290  uint32 buf_state;
291 
292  Assert(BufferIsLocal(buffer));
293 
294 #ifdef LBDEBUG
295  fprintf(stderr, "LB DIRTY %d\n", buffer);
296 #endif
297 
298  bufid = -(buffer + 1);
299 
300  Assert(LocalRefCount[bufid] > 0);
301 
302  bufHdr = GetLocalBufferDescriptor(bufid);
303 
304  buf_state = pg_atomic_read_u32(&bufHdr->state);
305 
306  if (!(buf_state & BM_DIRTY))
308 
309  buf_state |= BM_DIRTY;
310 
311  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
312 }
long local_blks_dirtied
Definition: instrument.h:27
#define GetLocalBufferDescriptor(id)
#define BM_DIRTY
Definition: buf_internals.h:58
#define fprintf
Definition: port.h:197
unsigned int uint32
Definition: c.h:374
#define Assert(condition)
Definition: c.h:745
#define BufferIsLocal(buffer)
Definition: buf.h:37
static void pg_atomic_unlocked_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition: atomics.h:277
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:241

◆ PrefetchLocalBuffer()

PrefetchBufferResult PrefetchLocalBuffer ( SMgrRelation  smgr,
ForkNumber  forkNum,
BlockNumber  blockNum 
)

Definition at line 64 of file localbuf.c.

References HASH_FIND, hash_search(), LocalBufferLookupEnt::id, INIT_BUFFERTAG, PrefetchBufferResult::initiated_io, InitLocalBuffers(), InvalidBuffer, RelFileNodeBackend::node, PrefetchBufferResult::recent_buffer, SMgrRelationData::smgr_rnode, and smgrprefetch().

Referenced by PrefetchBuffer().

66 {
67  PrefetchBufferResult result = {InvalidBuffer, false};
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  result.recent_buffer = -hresult->id - 1;
85  }
86  else
87  {
88 #ifdef USE_PREFETCH
89  /* Not in buffers, so initiate prefetch */
90  smgrprefetch(smgr, forkNum, blockNum);
91  result.initiated_io = true;
92 #endif /* USE_PREFETCH */
93  }
94 
95  return result;
96 }
#define InvalidBuffer
Definition: buf.h:25
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:927
Buffer recent_buffer
Definition: bufmgr.h:54
RelFileNodeBackend smgr_rnode
Definition: smgr.h:42
static void InitLocalBuffers(void)
Definition: localbuf.c:416
RelFileNode node
Definition: relfilenode.h:74
#define INIT_BUFFERTAG(a, xx_rnode, xx_forkNum, xx_blockNum)
static HTAB * LocalBufHash
Definition: localbuf.c:49
bool smgrprefetch(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum)
Definition: smgr.c:488

◆ ScheduleBufferTagForWriteback()

void ScheduleBufferTagForWriteback ( WritebackContext context,
BufferTag tag 
)

Definition at line 4477 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().

4478 {
4479  PendingWriteback *pending;
4480 
4481  /*
4482  * Add buffer to the pending writeback array, unless writeback control is
4483  * disabled.
4484  */
4485  if (*context->max_pending > 0)
4486  {
4488 
4489  pending = &context->pending_writebacks[context->nr_pending++];
4490 
4491  pending->tag = *tag;
4492  }
4493 
4494  /*
4495  * Perform pending flushes if the writeback limit is exceeded. This
4496  * includes the case where previously an item has been added, but control
4497  * is now disabled.
4498  */
4499  if (context->nr_pending >= *context->max_pending)
4500  IssuePendingWritebacks(context);
4501 }
void IssuePendingWritebacks(WritebackContext *context)
Definition: bufmgr.c:4511
PendingWriteback pending_writebacks[WRITEBACK_MAX_PENDING_FLUSHES]
#define Assert(condition)
Definition: c.h:745
#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 bgwprocno 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
void SetLatch(Latch *latch)
Definition: latch.c:505
Latch procLatch
Definition: proc.h:110
#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:43
#define GetBufferDescriptor(id)
unsigned int uint32
Definition: c.h:374
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:328
uint32 LockBufHdr(BufferDesc *desc)
Definition: bufmgr.c:4325
#define Assert(condition)
Definition: c.h:745
#define UnlockBufHdr(desc, s)
#define elog(elevel,...)
Definition: elog.h:214
int NBuffers
Definition: globals.c:132
PGPROC * allProcs
Definition: proc.h:251
#define BUF_STATE_GET_USAGECOUNT(state)
Definition: buf_internals.h:49
static BufferStrategyControl * StrategyControl
Definition: freelist.c:64
#define BUF_STATE_GET_REFCOUNT(state)
Definition: buf_internals.h:48

◆ 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:52
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:392
#define NUM_BUFFER_PARTITIONS
Definition: lwlock.h:111
#define init()
slock_t buffer_strategy_lock
Definition: freelist.c:32
pg_atomic_uint32 numBufferAllocs
Definition: freelist.c:54
#define Assert(condition)
Definition: c.h:745
int NBuffers
Definition: globals.c:132
static void pg_atomic_init_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition: atomics.h:223
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:111
Size add_size(Size s1, Size s2)
Definition: shmem.c:498
size_t Size
Definition: c.h:473
#define MAXALIGN(LEN)
Definition: c.h:698
int NBuffers
Definition: globals.c:132
Size BufTableShmemSize(int size)
Definition: buf_table.c:42

◆ 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:292
#define SpinLockAcquire(lock)
Definition: spin.h:62
unsigned int uint32
Definition: c.h:374
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:132
static BufferStrategyControl * StrategyControl
Definition: freelist.c:64
static uint32 pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
Definition: atomics.h:241

◆ WritebackContextInit()

void WritebackContextInit ( WritebackContext context,
int *  max_pending 
)

Definition at line 4465 of file bufmgr.c.

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

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

4466 {
4467  Assert(*max_pending <= WRITEBACK_MAX_PENDING_FLUSHES);
4468 
4469  context->max_pending = max_pending;
4470  context->nr_pending = 0;
4471 }
#define Assert(condition)
Definition: c.h:745
#define WRITEBACK_MAX_PENDING_FLUSHES

Variable Documentation

◆ BackendWritebackContext

PGDLLIMPORT WritebackContext BackendWritebackContext

Definition at line 23 of file buf_init.c.

Referenced by BufferAlloc().

◆ BufferDescriptors

PGDLLIMPORT BufferDescPadded* BufferDescriptors

Definition at line 20 of file buf_init.c.

◆ BufferIOLWLockArray

PGDLLIMPORT LWLockMinimallyPadded* BufferIOLWLockArray

Definition at line 22 of file buf_init.c.

◆ CkptBufferIds

CkptSortItem* CkptBufferIds

Definition at line 24 of file buf_init.c.

Referenced by BufferSync().

◆ LocalBufferDescriptors

BufferDesc* LocalBufferDescriptors

Definition at line 43 of file localbuf.c.