PostgreSQL Source Code git master
Loading...
Searching...
No Matches
bufmgr.c File Reference
#include "postgres.h"
#include <sys/file.h>
#include <unistd.h>
#include "access/tableam.h"
#include "access/xloginsert.h"
#include "access/xlogutils.h"
#include "catalog/storage.h"
#include "catalog/storage_xlog.h"
#include "common/hashfn.h"
#include "executor/instrument.h"
#include "lib/binaryheap.h"
#include "miscadmin.h"
#include "pg_trace.h"
#include "pgstat.h"
#include "postmaster/bgwriter.h"
#include "storage/aio.h"
#include "storage/buf_internals.h"
#include "storage/bufmgr.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/lmgr.h"
#include "storage/proc.h"
#include "storage/proclist.h"
#include "storage/procsignal.h"
#include "storage/read_stream.h"
#include "storage/smgr.h"
#include "storage/standby.h"
#include "utils/memdebug.h"
#include "utils/ps_status.h"
#include "utils/rel.h"
#include "utils/resowner.h"
#include "utils/timestamp.h"
#include "utils/wait_event.h"
#include "lib/simplehash.h"
#include "lib/sort_template.h"
Include dependency graph for bufmgr.c:

Go to the source code of this file.

Data Structures

struct  PrivateRefCountData
 
struct  PrivateRefCountEntry
 
struct  CkptTsStatus
 
struct  SMgrSortArray
 

Macros

#define BufHdrGetBlock(bufHdr)   ((Block) (BufferBlocks + ((Size) (bufHdr)->buf_id) * BLCKSZ))
 
#define BufferGetLSN(bufHdr)   (PageGetLSN(BufHdrGetBlock(bufHdr)))
 
#define LocalBufHdrGetBlock(bufHdr)    LocalBufferBlockPointers[-((bufHdr)->buf_id + 2)]
 
#define BUF_WRITTEN   0x01
 
#define BUF_REUSABLE   0x02
 
#define RELS_BSEARCH_THRESHOLD   20
 
#define BUF_DROP_FULL_SCAN_THRESHOLD   (uint64) (NBuffers / 32)
 
#define SH_PREFIX   refcount
 
#define SH_ELEMENT_TYPE   PrivateRefCountEntry
 
#define SH_KEY_TYPE   Buffer
 
#define SH_KEY   buffer
 
#define SH_HASH_KEY(tb, key)   murmurhash32((uint32) (key))
 
#define SH_EQUAL(tb, a, b)   ((a) == (b))
 
#define SH_SCOPE   static inline
 
#define SH_DECLARE
 
#define SH_DEFINE
 
#define REFCOUNT_ARRAY_ENTRIES   8
 
#define BufferIsPinned(bufnum)
 
#define ST_SORT   sort_checkpoint_bufferids
 
#define ST_ELEMENT_TYPE   CkptSortItem
 
#define ST_COMPARE(a, b)   ckpt_buforder_comparator(a, b)
 
#define ST_SCOPE   static
 
#define ST_DEFINE
 
#define ST_SORT   sort_pending_writebacks
 
#define ST_ELEMENT_TYPE   PendingWriteback
 
#define ST_COMPARE(a, b)   buffertag_comparator(&a->tag, &b->tag)
 
#define ST_SCOPE   static
 
#define ST_DEFINE
 
#define READV_COUNT_BITS   7
 
#define READV_COUNT_MASK   ((1 << READV_COUNT_BITS) - 1)
 

Typedefs

typedef struct PrivateRefCountData PrivateRefCountData
 
typedef struct PrivateRefCountEntry PrivateRefCountEntry
 
typedef struct CkptTsStatus CkptTsStatus
 
typedef struct SMgrSortArray SMgrSortArray
 

Functions

static void ReservePrivateRefCountEntry (void)
 
static PrivateRefCountEntryNewPrivateRefCountEntry (Buffer buffer)
 
static PrivateRefCountEntryGetPrivateRefCountEntry (Buffer buffer, bool do_move)
 
static int32 GetPrivateRefCount (Buffer buffer)
 
static void ForgetPrivateRefCountEntry (PrivateRefCountEntry *ref)
 
static void ResOwnerReleaseBufferIO (Datum res)
 
static charResOwnerPrintBufferIO (Datum res)
 
static void ResOwnerReleaseBuffer (Datum res)
 
static charResOwnerPrintBuffer (Datum res)
 
static pg_noinline PrivateRefCountEntryGetPrivateRefCountEntrySlow (Buffer buffer, bool do_move)
 
static Buffer ReadBuffer_common (Relation rel, SMgrRelation smgr, char smgr_persistence, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
 
static BlockNumber ExtendBufferedRelCommon (BufferManagerRelation bmr, ForkNumber fork, BufferAccessStrategy strategy, uint32 flags, uint32 extend_by, BlockNumber extend_upto, Buffer *buffers, uint32 *extended_by)
 
static BlockNumber ExtendBufferedRelShared (BufferManagerRelation bmr, ForkNumber fork, BufferAccessStrategy strategy, uint32 flags, uint32 extend_by, BlockNumber extend_upto, Buffer *buffers, uint32 *extended_by)
 
static bool PinBuffer (BufferDesc *buf, BufferAccessStrategy strategy, bool skip_if_not_valid)
 
static void PinBuffer_Locked (BufferDesc *buf)
 
static void UnpinBuffer (BufferDesc *buf)
 
static void UnpinBufferNoOwner (BufferDesc *buf)
 
static void BufferSync (int flags)
 
static int SyncOneBuffer (int buf_id, bool skip_recently_used, WritebackContext *wb_context)
 
static void WaitIO (BufferDesc *buf)
 
static void AbortBufferIO (Buffer buffer)
 
static void shared_buffer_write_error_callback (void *arg)
 
static void local_buffer_write_error_callback (void *arg)
 
static BufferDescBufferAlloc (SMgrRelation smgr, char relpersistence, ForkNumber forkNum, BlockNumber blockNum, BufferAccessStrategy strategy, bool *foundPtr, IOContext io_context)
 
static bool AsyncReadBuffers (ReadBuffersOperation *operation, int *nblocks_progress)
 
static void CheckReadBuffersOperation (ReadBuffersOperation *operation, bool is_complete)
 
static pg_attribute_always_inline void TrackBufferHit (IOObject io_object, IOContext io_context, Relation rel, char persistence, SMgrRelation smgr, ForkNumber forknum, BlockNumber blocknum)
 
static Buffer GetVictimBuffer (BufferAccessStrategy strategy, IOContext io_context)
 
static void FlushUnlockedBuffer (BufferDesc *buf, SMgrRelation reln, IOObject io_object, IOContext io_context)
 
static void FlushBuffer (BufferDesc *buf, SMgrRelation reln, IOObject io_object, IOContext io_context)
 
static void FindAndDropRelationBuffers (RelFileLocator rlocator, ForkNumber forkNum, BlockNumber nForkBlock, BlockNumber firstDelBlock)
 
static void RelationCopyStorageUsingBuffer (RelFileLocator srclocator, RelFileLocator dstlocator, ForkNumber forkNum, bool permanent)
 
static void AtProcExit_Buffers (int code, Datum arg)
 
static void CheckForBufferLeaks (void)
 
static int rlocator_comparator (const void *p1, const void *p2)
 
static int buffertag_comparator (const BufferTag *ba, const BufferTag *bb)
 
static int ckpt_buforder_comparator (const CkptSortItem *a, const CkptSortItem *b)
 
static int ts_ckpt_progress_comparator (Datum a, Datum b, void *arg)
 
static void BufferLockAcquire (Buffer buffer, BufferDesc *buf_hdr, BufferLockMode mode)
 
static void BufferLockUnlock (Buffer buffer, BufferDesc *buf_hdr)
 
static bool BufferLockConditional (Buffer buffer, BufferDesc *buf_hdr, BufferLockMode mode)
 
static bool BufferLockHeldByMeInMode (BufferDesc *buf_hdr, BufferLockMode mode)
 
static bool BufferLockHeldByMe (BufferDesc *buf_hdr)
 
static void BufferLockDisown (Buffer buffer, BufferDesc *buf_hdr)
 
static int BufferLockDisownInternal (Buffer buffer, BufferDesc *buf_hdr)
 
static bool BufferLockAttempt (BufferDesc *buf_hdr, BufferLockMode mode)
 
static void BufferLockQueueSelf (BufferDesc *buf_hdr, BufferLockMode mode)
 
static void BufferLockDequeueSelf (BufferDesc *buf_hdr)
 
static void BufferLockWakeup (BufferDesc *buf_hdr, bool wake_exclusive)
 
static void BufferLockProcessRelease (BufferDesc *buf_hdr, BufferLockMode mode, uint64 lockstate)
 
static uint64 BufferLockReleaseSub (BufferLockMode mode)
 
PrefetchBufferResult PrefetchSharedBuffer (SMgrRelation smgr_reln, ForkNumber forkNum, BlockNumber blockNum)
 
PrefetchBufferResult PrefetchBuffer (Relation reln, ForkNumber forkNum, BlockNumber blockNum)
 
bool ReadRecentBuffer (RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockNum, Buffer recent_buffer)
 
Buffer ReadBuffer (Relation reln, BlockNumber blockNum)
 
Buffer ReadBufferExtended (Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
 
Buffer ReadBufferWithoutRelcache (RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy, bool permanent)
 
Buffer ExtendBufferedRel (BufferManagerRelation bmr, ForkNumber forkNum, BufferAccessStrategy strategy, uint32 flags)
 
BlockNumber ExtendBufferedRelBy (BufferManagerRelation bmr, ForkNumber fork, BufferAccessStrategy strategy, uint32 flags, uint32 extend_by, Buffer *buffers, uint32 *extended_by)
 
Buffer ExtendBufferedRelTo (BufferManagerRelation bmr, ForkNumber fork, BufferAccessStrategy strategy, uint32 flags, BlockNumber extend_to, ReadBufferMode mode)
 
static void ZeroAndLockBuffer (Buffer buffer, ReadBufferMode mode, bool already_valid)
 
static pg_attribute_always_inline Buffer PinBufferForBlock (Relation rel, SMgrRelation smgr, char persistence, ForkNumber forkNum, BlockNumber blockNum, BufferAccessStrategy strategy, IOObject io_object, IOContext io_context, bool *foundPtr)
 
static pg_attribute_always_inline bool StartReadBuffersImpl (ReadBuffersOperation *operation, Buffer *buffers, BlockNumber blockNum, int *nblocks, int flags, bool allow_forwarding)
 
bool StartReadBuffers (ReadBuffersOperation *operation, Buffer *buffers, BlockNumber blockNum, int *nblocks, int flags)
 
bool StartReadBuffer (ReadBuffersOperation *operation, Buffer *buffer, BlockNumber blocknum, int flags)
 
static void ProcessReadBuffersResult (ReadBuffersOperation *operation)
 
bool WaitReadBuffers (ReadBuffersOperation *operation)
 
static void InvalidateBuffer (BufferDesc *buf)
 
static bool InvalidateVictimBuffer (BufferDesc *buf_hdr)
 
uint32 GetPinLimit (void)
 
uint32 GetAdditionalPinLimit (void)
 
void LimitAdditionalPins (uint32 *additional_pins)
 
bool BufferIsLockedByMe (Buffer buffer)
 
bool BufferIsLockedByMeInMode (Buffer buffer, BufferLockMode mode)
 
bool BufferIsDirty (Buffer buffer)
 
void MarkBufferDirty (Buffer buffer)
 
Buffer ReleaseAndReadBuffer (Buffer buffer, Relation relation, BlockNumber blockNum)
 
static void WakePinCountWaiter (BufferDesc *buf)
 
void TrackNewBufferPin (Buffer buf)
 
bool BgBufferSync (WritebackContext *wb_context)
 
void AtEOXact_Buffers (bool isCommit)
 
void InitBufferManagerAccess (void)
 
charDebugPrintBufferRefcount (Buffer buffer)
 
void CheckPointBuffers (int flags)
 
BlockNumber BufferGetBlockNumber (Buffer buffer)
 
void BufferGetTag (Buffer buffer, RelFileLocator *rlocator, ForkNumber *forknum, BlockNumber *blknum)
 
BlockNumber RelationGetNumberOfBlocksInFork (Relation relation, ForkNumber forkNum)
 
bool BufferIsPermanent (Buffer buffer)
 
XLogRecPtr BufferGetLSNAtomic (Buffer buffer)
 
void DropRelationBuffers (SMgrRelation smgr_reln, ForkNumber *forkNum, int nforks, BlockNumber *firstDelBlock)
 
void DropRelationsAllBuffers (SMgrRelation *smgr_reln, int nlocators)
 
void DropDatabaseBuffers (Oid dbid)
 
void FlushRelationBuffers (Relation rel)
 
void FlushRelationsAllBuffers (SMgrRelation *smgrs, int nrels)
 
void CreateAndCopyRelationData (RelFileLocator src_rlocator, RelFileLocator dst_rlocator, bool permanent)
 
void FlushDatabaseBuffers (Oid dbid)
 
void FlushOneBuffer (Buffer buffer)
 
void ReleaseBuffer (Buffer buffer)
 
void UnlockReleaseBuffer (Buffer buffer)
 
void IncrBufferRefCount (Buffer buffer)
 
static void MarkSharedBufferDirtyHint (Buffer buffer, BufferDesc *bufHdr, uint64 lockstate, bool buffer_std)
 
void MarkBufferDirtyHint (Buffer buffer, bool buffer_std)
 
void UnlockBuffers (void)
 
void UnlockBuffer (Buffer buffer)
 
void LockBufferInternal (Buffer buffer, BufferLockMode mode)
 
bool ConditionalLockBuffer (Buffer buffer)
 
void CheckBufferIsPinnedOnce (Buffer buffer)
 
void LockBufferForCleanup (Buffer buffer)
 
bool HoldingBufferPinThatDelaysRecovery (void)
 
bool ConditionalLockBufferForCleanup (Buffer buffer)
 
bool IsBufferCleanupOK (Buffer buffer)
 
static bool SharedBufferBeginSetHintBits (Buffer buffer, BufferDesc *buf_hdr, uint64 *lockstate)
 
bool BufferBeginSetHintBits (Buffer buffer)
 
void BufferFinishSetHintBits (Buffer buffer, bool mark_dirty, bool buffer_std)
 
bool BufferSetHintBits16 (uint16 *ptr, uint16 val, Buffer buffer)
 
StartBufferIOResult StartSharedBufferIO (BufferDesc *buf, bool forInput, bool wait, PgAioWaitRef *io_wref)
 
StartBufferIOResult StartBufferIO (Buffer buffer, bool forInput, bool wait, PgAioWaitRef *io_wref)
 
void TerminateBufferIO (BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits, bool forget_owner, bool release_aio)
 
uint64 LockBufHdr (BufferDesc *desc)
 
pg_noinline uint64 WaitBufHdrUnlocked (BufferDesc *buf)
 
void WritebackContextInit (WritebackContext *context, int *max_pending)
 
void ScheduleBufferTagForWriteback (WritebackContext *wb_context, IOContext io_context, BufferTag *tag)
 
void IssuePendingWritebacks (WritebackContext *wb_context, IOContext io_context)
 
static bool EvictUnpinnedBufferInternal (BufferDesc *desc, bool *buffer_flushed)
 
bool EvictUnpinnedBuffer (Buffer buf, bool *buffer_flushed)
 
void EvictAllUnpinnedBuffers (int32 *buffers_evicted, int32 *buffers_flushed, int32 *buffers_skipped)
 
void EvictRelUnpinnedBuffers (Relation rel, int32 *buffers_evicted, int32 *buffers_flushed, int32 *buffers_skipped)
 
static bool MarkDirtyUnpinnedBufferInternal (Buffer buf, BufferDesc *desc, bool *buffer_already_dirty)
 
bool MarkDirtyUnpinnedBuffer (Buffer buf, bool *buffer_already_dirty)
 
void MarkDirtyRelUnpinnedBuffers (Relation rel, int32 *buffers_dirtied, int32 *buffers_already_dirty, int32 *buffers_skipped)
 
void MarkDirtyAllUnpinnedBuffers (int32 *buffers_dirtied, int32 *buffers_already_dirty, int32 *buffers_skipped)
 
static pg_attribute_always_inline void buffer_stage_common (PgAioHandle *ioh, bool is_write, bool is_temp)
 
static void buffer_readv_decode_error (PgAioResult result, bool *zeroed_any, bool *ignored_any, uint8 *zeroed_or_error_count, uint8 *checkfail_count, uint8 *first_off)
 
static void buffer_readv_encode_error (PgAioResult *result, bool is_temp, bool zeroed_any, bool ignored_any, uint8 error_count, uint8 zeroed_count, uint8 checkfail_count, uint8 first_error_off, uint8 first_zeroed_off, uint8 first_ignored_off)
 
static pg_attribute_always_inline void buffer_readv_complete_one (PgAioTargetData *td, uint8 buf_off, Buffer buffer, uint8 flags, bool failed, bool is_temp, bool *buffer_invalid, bool *failed_checksum, bool *ignored_checksum, bool *zeroed_buffer)
 
static pg_attribute_always_inline PgAioResult buffer_readv_complete (PgAioHandle *ioh, PgAioResult prior_result, uint8 cb_data, bool is_temp)
 
static void buffer_readv_report (PgAioResult result, const PgAioTargetData *td, int elevel)
 
static void shared_buffer_readv_stage (PgAioHandle *ioh, uint8 cb_data)
 
static PgAioResult shared_buffer_readv_complete (PgAioHandle *ioh, PgAioResult prior_result, uint8 cb_data)
 
static PgAioResult shared_buffer_readv_complete_local (PgAioHandle *ioh, PgAioResult prior_result, uint8 cb_data)
 
static void local_buffer_readv_stage (PgAioHandle *ioh, uint8 cb_data)
 
static PgAioResult local_buffer_readv_complete (PgAioHandle *ioh, PgAioResult prior_result, uint8 cb_data)
 

Variables

bool zero_damaged_pages = false
 
int bgwriter_lru_maxpages = 100
 
double bgwriter_lru_multiplier = 2.0
 
bool track_io_timing = false
 
int effective_io_concurrency = DEFAULT_EFFECTIVE_IO_CONCURRENCY
 
int maintenance_io_concurrency = DEFAULT_MAINTENANCE_IO_CONCURRENCY
 
int io_combine_limit = DEFAULT_IO_COMBINE_LIMIT
 
int io_combine_limit_guc = DEFAULT_IO_COMBINE_LIMIT
 
int io_max_combine_limit = DEFAULT_IO_COMBINE_LIMIT
 
int checkpoint_flush_after = DEFAULT_CHECKPOINT_FLUSH_AFTER
 
int bgwriter_flush_after = DEFAULT_BGWRITER_FLUSH_AFTER
 
int backend_flush_after = DEFAULT_BACKEND_FLUSH_AFTER
 
static BufferDescPinCountWaitBuf = NULL
 
static Buffer PrivateRefCountArrayKeys [REFCOUNT_ARRAY_ENTRIES]
 
static struct PrivateRefCountEntry PrivateRefCountArray [REFCOUNT_ARRAY_ENTRIES]
 
static refcount_hashPrivateRefCountHash = NULL
 
static int32 PrivateRefCountOverflowed = 0
 
static uint32 PrivateRefCountClock = 0
 
static int ReservedRefCountSlot = -1
 
static int PrivateRefCountEntryLast = -1
 
static uint32 MaxProportionalPins
 
const ResourceOwnerDesc buffer_io_resowner_desc
 
const ResourceOwnerDesc buffer_resowner_desc
 
const PgAioHandleCallbacks aio_shared_buffer_readv_cb
 
const PgAioHandleCallbacks aio_local_buffer_readv_cb
 

Macro Definition Documentation

◆ BUF_DROP_FULL_SCAN_THRESHOLD

#define BUF_DROP_FULL_SCAN_THRESHOLD   (uint64) (NBuffers / 32)

Definition at line 95 of file bufmgr.c.

◆ BUF_REUSABLE

#define BUF_REUSABLE   0x02

Definition at line 85 of file bufmgr.c.

◆ BUF_WRITTEN

#define BUF_WRITTEN   0x01

Definition at line 84 of file bufmgr.c.

◆ BufferGetLSN

#define BufferGetLSN (   bufHdr)    (PageGetLSN(BufHdrGetBlock(bufHdr)))

Definition at line 77 of file bufmgr.c.

◆ BufferIsPinned

#define BufferIsPinned (   bufnum)
Value:
( \
false \
: \
(LocalRefCount[-(bufnum) - 1] > 0) \
: \
)
static int32 GetPrivateRefCount(Buffer buffer)
Definition bufmgr.c:542
static bool BufferIsValid(Buffer bufnum)
Definition bufmgr.h:419
int32 * LocalRefCount
Definition localbuf.c:49
static int fb(int x)

Definition at line 599 of file bufmgr.c.

603 : \
605 (LocalRefCount[-(bufnum) - 1] > 0) \
606 : \
608)

◆ BufHdrGetBlock

#define BufHdrGetBlock (   bufHdr)    ((Block) (BufferBlocks + ((Size) (bufHdr)->buf_id) * BLCKSZ))

Definition at line 76 of file bufmgr.c.

◆ LocalBufHdrGetBlock

#define LocalBufHdrGetBlock (   bufHdr)     LocalBufferBlockPointers[-((bufHdr)->buf_id + 2)]

Definition at line 80 of file bufmgr.c.

◆ READV_COUNT_BITS

#define READV_COUNT_BITS   7

◆ READV_COUNT_MASK

#define READV_COUNT_MASK   ((1 << READV_COUNT_BITS) - 1)

◆ REFCOUNT_ARRAY_ENTRIES

#define REFCOUNT_ARRAY_ENTRIES   8

Definition at line 145 of file bufmgr.c.

◆ RELS_BSEARCH_THRESHOLD

#define RELS_BSEARCH_THRESHOLD   20

Definition at line 87 of file bufmgr.c.

◆ SH_DECLARE

#define SH_DECLARE

Definition at line 140 of file bufmgr.c.

◆ SH_DEFINE

#define SH_DEFINE

Definition at line 141 of file bufmgr.c.

◆ SH_ELEMENT_TYPE

#define SH_ELEMENT_TYPE   PrivateRefCountEntry

Definition at line 134 of file bufmgr.c.

◆ SH_EQUAL

#define SH_EQUAL (   tb,
  a,
  b 
)    ((a) == (b))

Definition at line 138 of file bufmgr.c.

◆ SH_HASH_KEY

#define SH_HASH_KEY (   tb,
  key 
)    murmurhash32((uint32) (key))

Definition at line 137 of file bufmgr.c.

◆ SH_KEY

#define SH_KEY   buffer

Definition at line 136 of file bufmgr.c.

◆ SH_KEY_TYPE

#define SH_KEY_TYPE   Buffer

Definition at line 135 of file bufmgr.c.

◆ SH_PREFIX

#define SH_PREFIX   refcount

Definition at line 133 of file bufmgr.c.

◆ SH_SCOPE

#define SH_SCOPE   static inline

Definition at line 139 of file bufmgr.c.

◆ ST_COMPARE [1/2]

#define ST_COMPARE (   a,
  b 
)    ckpt_buforder_comparator(a, b)

Definition at line 3559 of file bufmgr.c.

◆ ST_COMPARE [2/2]

#define ST_COMPARE (   a,
  b 
)    buffertag_comparator(&a->tag, &b->tag)

Definition at line 3559 of file bufmgr.c.

◆ ST_DEFINE [1/2]

#define ST_DEFINE

Definition at line 3561 of file bufmgr.c.

◆ ST_DEFINE [2/2]

#define ST_DEFINE

Definition at line 3561 of file bufmgr.c.

◆ ST_ELEMENT_TYPE [1/2]

#define ST_ELEMENT_TYPE   CkptSortItem

Definition at line 3558 of file bufmgr.c.

◆ ST_ELEMENT_TYPE [2/2]

#define ST_ELEMENT_TYPE   PendingWriteback

Definition at line 3558 of file bufmgr.c.

◆ ST_SCOPE [1/2]

#define ST_SCOPE   static

Definition at line 3560 of file bufmgr.c.

◆ ST_SCOPE [2/2]

#define ST_SCOPE   static

Definition at line 3560 of file bufmgr.c.

◆ ST_SORT [1/2]

Definition at line 3557 of file bufmgr.c.

◆ ST_SORT [2/2]

Definition at line 3557 of file bufmgr.c.

Typedef Documentation

◆ CkptTsStatus

◆ PrivateRefCountData

◆ PrivateRefCountEntry

◆ SMgrSortArray

Function Documentation

◆ AbortBufferIO()

static void AbortBufferIO ( Buffer  buffer)
static

Definition at line 7469 of file bufmgr.c.

7470{
7471 BufferDesc *buf_hdr = GetBufferDescriptor(buffer - 1);
7473
7476
7477 if (!(buf_state & BM_VALID))
7478 {
7481 }
7482 else
7483 {
7486
7487 /* Issue notice if this is not the first failure... */
7488 if (buf_state & BM_IO_ERROR)
7489 {
7490 /* Buffer is pinned, so we can read tag without spinlock */
7493 errmsg("could not write block %u of %s",
7494 buf_hdr->tag.blockNum,
7496 BufTagGetForkNum(&buf_hdr->tag)).str),
7497 errdetail("Multiple failures --- write error might be permanent.")));
7498 }
7499 }
7500
7501 TerminateBufferIO(buf_hdr, false, BM_IO_ERROR, false, false);
7502}
#define BM_TAG_VALID
static ForkNumber BufTagGetForkNum(const BufferTag *tag)
static void UnlockBufHdr(BufferDesc *desc)
#define BM_DIRTY
#define BM_IO_IN_PROGRESS
static RelFileLocator BufTagGetRelFileLocator(const BufferTag *tag)
#define BM_VALID
#define BM_IO_ERROR
static BufferDesc * GetBufferDescriptor(int id)
uint64 LockBufHdr(BufferDesc *desc)
Definition bufmgr.c:7567
void TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits, bool forget_owner, bool release_aio)
Definition bufmgr.c:7407
#define Assert(condition)
Definition c.h:1002
uint64_t uint64
Definition c.h:684
int errcode(int sqlerrcode)
Definition elog.c:875
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define WARNING
Definition elog.h:37
#define ereport(elevel,...)
Definition elog.h:152
static char * errmsg
#define relpathperm(rlocator, forknum)
Definition relpath.h:146

References Assert, BM_DIRTY, BM_IO_ERROR, BM_IO_IN_PROGRESS, BM_TAG_VALID, BM_VALID, PrivateRefCountEntry::buffer, BufTagGetForkNum(), BufTagGetRelFileLocator(), ereport, errcode(), errdetail(), errmsg, fb(), GetBufferDescriptor(), LockBufHdr(), relpathperm, TerminateBufferIO(), UnlockBufHdr(), and WARNING.

Referenced by ResOwnerReleaseBufferIO().

◆ AsyncReadBuffers()

static bool AsyncReadBuffers ( ReadBuffersOperation operation,
int nblocks_progress 
)
static

Definition at line 1938 of file bufmgr.c.

1939{
1940 Buffer *buffers = &operation->buffers[0];
1941 int flags = operation->flags;
1942 ForkNumber forknum = operation->forknum;
1943 char persistence = operation->persistence;
1944 int16 nblocks_done = operation->nblocks_done;
1945 BlockNumber blocknum = operation->blocknum + nblocks_done;
1946 Buffer *io_buffers = &operation->buffers[nblocks_done];
1947 int io_buffers_len = 0;
1949 uint32 ioh_flags = 0;
1954 StartBufferIOResult status;
1955
1956 if (persistence == RELPERSISTENCE_TEMP)
1957 {
1960 }
1961 else
1962 {
1965 }
1966
1967 /*
1968 * When this IO is executed synchronously, either because the caller will
1969 * immediately block waiting for the IO or because IOMETHOD_SYNC is used,
1970 * the AIO subsystem needs to know.
1971 */
1972 if (flags & READ_BUFFERS_SYNCHRONOUSLY)
1974
1975 if (persistence == RELPERSISTENCE_TEMP)
1977
1978 /*
1979 * If zero_damaged_pages is enabled, add the READ_BUFFERS_ZERO_ON_ERROR
1980 * flag. The reason for that is that, hopefully, zero_damaged_pages isn't
1981 * set globally, but on a per-session basis. The completion callback,
1982 * which may be run in other processes, e.g. in IO workers, may have a
1983 * different value of the zero_damaged_pages GUC.
1984 *
1985 * XXX: We probably should eventually use a different flag for
1986 * zero_damaged_pages, so we can report different log levels / error codes
1987 * for zero_damaged_pages and ZERO_ON_ERROR.
1988 */
1991
1992 /*
1993 * For the same reason as with zero_damaged_pages we need to use this
1994 * backend's ignore_checksum_failure value.
1995 */
1998
1999
2000 /*
2001 * To be allowed to report stats in the local completion callback we need
2002 * to prepare to report stats now. This ensures we can safely report the
2003 * checksum failure even in a critical section.
2004 */
2005 pgstat_prepare_report_checksum_failure(operation->smgr->smgr_rlocator.locator.dbOid);
2006
2007 /*
2008 * We must get an IO handle before StartBufferIO(), as pgaio_io_acquire()
2009 * might block, which we don't want after setting IO_IN_PROGRESS. If we
2010 * don't need to do the IO, we'll release the handle.
2011 *
2012 * If we need to wait for IO before we can get a handle, submit
2013 * already-staged IO first, so that other backends don't need to wait.
2014 * There wouldn't be a deadlock risk, as pgaio_io_acquire() just needs to
2015 * wait for already submitted IO, which doesn't require additional locks,
2016 * but it could still cause undesirable waits.
2017 *
2018 * A secondary benefit is that this would allow us to measure the time in
2019 * pgaio_io_acquire() without causing undue timer overhead in the common,
2020 * non-blocking, case. However, currently the pgstats infrastructure
2021 * doesn't really allow that, as it a) asserts that an operation can't
2022 * have time without operations b) doesn't have an API to report
2023 * "accumulated" time.
2024 */
2026 if (unlikely(!ioh))
2027 {
2030 }
2031
2032 operation->foreign_io = false;
2033 pgaio_wref_clear(&operation->io_wref);
2034
2035 /*
2036 * Try to start IO on the first buffer in a new run of blocks. If AIO is
2037 * in progress, be it in this backend or another backend, we just
2038 * associate the wait reference with the operation and wait in
2039 * WaitReadBuffers(). This turns out to be important for performance in
2040 * two workloads:
2041 *
2042 * 1) A read stream that has to read the same block multiple times within
2043 * the readahead distance. This can happen e.g. for the table accesses of
2044 * an index scan.
2045 *
2046 * 2) Concurrent scans by multiple backends on the same relation.
2047 *
2048 * If we were to synchronously wait for the in-progress IO, we'd not be
2049 * able to keep enough I/O in flight.
2050 *
2051 * If we do find there is ongoing I/O for the buffer, we set up a 1-block
2052 * ReadBuffersOperation that WaitReadBuffers then can wait on.
2053 *
2054 * It's possible that another backend has started IO on the buffer but not
2055 * yet set its wait reference. In this case, we have no choice but to wait
2056 * for either the wait reference to be valid or the IO to be done.
2057 */
2058 status = StartBufferIO(buffers[nblocks_done], true, true,
2059 &operation->io_wref);
2060 if (status != BUFFER_IO_READY_FOR_IO)
2061 {
2063 *nblocks_progress = 1;
2064 if (status == BUFFER_IO_ALREADY_DONE)
2065 {
2066 /*
2067 * Someone has already completed this block, we're done.
2068 *
2069 * When IO is necessary, ->nblocks_done is updated in
2070 * ProcessReadBuffersResult(), but that is not called if no IO is
2071 * necessary. Thus update here.
2072 */
2073 operation->nblocks_done += 1;
2074 Assert(operation->nblocks_done <= operation->nblocks);
2075
2076 Assert(!pgaio_wref_valid(&operation->io_wref));
2077
2078 /*
2079 * Report and track this as a 'hit' for this backend, even though
2080 * it must have started out as a miss in PinBufferForBlock(). The
2081 * other backend will track this as a 'read'.
2082 */
2084 operation->rel, operation->persistence,
2085 operation->smgr, operation->forknum,
2086 blocknum);
2087 return false;
2088 }
2089
2090 /* The IO is already in-progress */
2091 Assert(status == BUFFER_IO_IN_PROGRESS);
2092 Assert(pgaio_wref_valid(&operation->io_wref));
2093 operation->foreign_io = true;
2094
2095 return true;
2096 }
2097
2098 Assert(io_buffers[0] == buffers[nblocks_done]);
2099 io_pages[0] = BufferGetBlock(buffers[nblocks_done]);
2100 io_buffers_len = 1;
2101
2102 /*
2103 * NB: As little code as possible should be added between the
2104 * StartBufferIO() above, the further StartBufferIO()s below and the
2105 * smgrstartreadv(), as some of the buffers are now marked as
2106 * IO_IN_PROGRESS and will thus cause other backends to wait.
2107 */
2108
2109 /*
2110 * How many neighboring-on-disk blocks can we scatter-read into other
2111 * buffers at the same time? In this case we don't wait if we see an I/O
2112 * already in progress (see comment above).
2113 */
2114 for (int i = nblocks_done + 1; i < operation->nblocks; i++)
2115 {
2116 /* Must be consecutive block numbers. */
2117 Assert(BufferGetBlockNumber(buffers[i - 1]) ==
2118 BufferGetBlockNumber(buffers[i]) - 1);
2119
2120 status = StartBufferIO(buffers[i], true, false, NULL);
2121 if (status != BUFFER_IO_READY_FOR_IO)
2122 break;
2123
2124 Assert(io_buffers[io_buffers_len] == buffers[i]);
2125
2126 io_pages[io_buffers_len++] = BufferGetBlock(buffers[i]);
2127 }
2128
2129 /* get a reference to wait for in WaitReadBuffers() */
2130 pgaio_io_get_wref(ioh, &operation->io_wref);
2131
2132 /* provide the list of buffers to the completion callbacks */
2134
2136 persistence == RELPERSISTENCE_TEMP ?
2139 flags);
2140
2142
2143 /* ---
2144 * Even though we're trying to issue IO asynchronously, track the time
2145 * in smgrstartreadv():
2146 * - if io_method == IOMETHOD_SYNC, we will always perform the IO
2147 * immediately
2148 * - the io method might not support the IO (e.g. worker IO for a temp
2149 * table)
2150 * ---
2151 */
2153 smgrstartreadv(ioh, operation->smgr, forknum,
2154 blocknum,
2158
2159 if (persistence == RELPERSISTENCE_TEMP)
2161 else
2163
2164 /*
2165 * Track vacuum cost when issuing IO, not after waiting for it. Otherwise
2166 * we could end up issuing a lot of IO in a short timespan, despite a low
2167 * cost limit.
2168 */
2169 if (VacuumCostActive)
2171
2173
2174 return true;
2175}
bool pgaio_wref_valid(PgAioWaitRef *iow)
Definition aio.c:971
PgAioHandle * pgaio_io_acquire(struct ResourceOwnerData *resowner, PgAioReturn *ret)
Definition aio.c:162
void pgaio_wref_clear(PgAioWaitRef *iow)
Definition aio.c:964
void pgaio_io_get_wref(PgAioHandle *ioh, PgAioWaitRef *iow)
Definition aio.c:366
void pgaio_io_set_flag(PgAioHandle *ioh, PgAioHandleFlags flag)
Definition aio.c:330
void pgaio_submit_staged(void)
Definition aio.c:1133
void pgaio_io_release(PgAioHandle *ioh)
Definition aio.c:240
PgAioHandle * pgaio_io_acquire_nb(struct ResourceOwnerData *resowner, PgAioReturn *ret)
Definition aio.c:188
@ PGAIO_HCB_LOCAL_BUFFER_READV
Definition aio.h:200
@ PGAIO_HCB_SHARED_BUFFER_READV
Definition aio.h:198
@ PGAIO_HF_SYNCHRONOUS
Definition aio.h:70
@ PGAIO_HF_REFERENCES_LOCAL
Definition aio.h:60
void pgaio_io_set_handle_data_32(PgAioHandle *ioh, uint32 *data, uint8 len)
void pgaio_io_register_callbacks(PgAioHandle *ioh, PgAioHandleCallbackID cb_id, uint8 cb_data)
uint32 BlockNumber
Definition block.h:31
int Buffer
Definition buf.h:23
StartBufferIOResult
@ BUFFER_IO_IN_PROGRESS
@ BUFFER_IO_ALREADY_DONE
@ BUFFER_IO_READY_FOR_IO
bool track_io_timing
Definition bufmgr.c:192
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition bufmgr.c:4469
bool zero_damaged_pages
Definition bufmgr.c:189
static pg_attribute_always_inline void TrackBufferHit(IOObject io_object, IOContext io_context, Relation rel, char persistence, SMgrRelation smgr, ForkNumber forknum, BlockNumber blocknum)
Definition bufmgr.c:1683
StartBufferIOResult StartBufferIO(Buffer buffer, bool forInput, bool wait, PgAioWaitRef *io_wref)
Definition bufmgr.c:7370
#define READ_BUFFERS_ZERO_ON_ERROR
Definition bufmgr.h:122
static Block BufferGetBlock(Buffer buffer)
Definition bufmgr.h:435
#define MAX_IO_COMBINE_LIMIT
Definition bufmgr.h:175
#define READ_BUFFERS_IGNORE_CHECKSUM_FAILURES
Definition bufmgr.h:126
#define READ_BUFFERS_SYNCHRONOUSLY
Definition bufmgr.h:128
bool ignore_checksum_failure
Definition bufpage.c:27
int16_t int16
Definition c.h:678
#define unlikely(x)
Definition c.h:497
uint32_t uint32
Definition c.h:683
static DataChecksumsWorkerOperation operation
IOContext IOContextForStrategy(BufferAccessStrategy strategy)
Definition freelist.c:712
int VacuumCostPageMiss
Definition globals.c:155
bool VacuumCostActive
Definition globals.c:161
int VacuumCostBalance
Definition globals.c:160
BufferUsage pgBufferUsage
Definition instrument.c:25
int i
Definition isn.c:77
IOObject
Definition pgstat.h:280
@ IOOBJECT_RELATION
Definition pgstat.h:281
@ IOOBJECT_TEMP_RELATION
Definition pgstat.h:282
IOContext
Definition pgstat.h:289
@ IOCONTEXT_NORMAL
Definition pgstat.h:293
@ IOOP_READ
Definition pgstat.h:319
void pgstat_prepare_report_checksum_failure(Oid dboid)
instr_time pgstat_prepare_io_time(bool track_io_guc)
Definition pgstat_io.c:91
void pgstat_count_io_op_time(IOObject io_object, IOContext io_context, IOOp io_op, instr_time start_time, uint32 cnt, uint64 bytes)
Definition pgstat_io.c:122
ForkNumber
Definition relpath.h:56
ResourceOwner CurrentResourceOwner
Definition resowner.c:173
void smgrstartreadv(PgAioHandle *ioh, SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, void **buffers, BlockNumber nblocks)
Definition smgr.c:753
int64 shared_blks_read
Definition instrument.h:27
int64 local_blks_read
Definition instrument.h:31

References Assert, BUFFER_IO_ALREADY_DONE, BUFFER_IO_IN_PROGRESS, BUFFER_IO_READY_FOR_IO, BufferGetBlock(), BufferGetBlockNumber(), CurrentResourceOwner, fb(), i, ignore_checksum_failure, IOCONTEXT_NORMAL, IOContextForStrategy(), IOOBJECT_RELATION, IOOBJECT_TEMP_RELATION, IOOP_READ, BufferUsage::local_blks_read, MAX_IO_COMBINE_LIMIT, operation, PGAIO_HCB_LOCAL_BUFFER_READV, PGAIO_HCB_SHARED_BUFFER_READV, PGAIO_HF_REFERENCES_LOCAL, PGAIO_HF_SYNCHRONOUS, pgaio_io_acquire(), pgaio_io_acquire_nb(), pgaio_io_get_wref(), pgaio_io_register_callbacks(), pgaio_io_release(), pgaio_io_set_flag(), pgaio_io_set_handle_data_32(), pgaio_submit_staged(), pgaio_wref_clear(), pgaio_wref_valid(), pgBufferUsage, pgstat_count_io_op_time(), pgstat_prepare_io_time(), pgstat_prepare_report_checksum_failure(), READ_BUFFERS_IGNORE_CHECKSUM_FAILURES, READ_BUFFERS_SYNCHRONOUSLY, READ_BUFFERS_ZERO_ON_ERROR, BufferUsage::shared_blks_read, smgrstartreadv(), StartBufferIO(), PrivateRefCountEntry::status, track_io_timing, TrackBufferHit(), unlikely, VacuumCostActive, VacuumCostBalance, VacuumCostPageMiss, and zero_damaged_pages.

Referenced by StartReadBuffersImpl(), and WaitReadBuffers().

◆ AtEOXact_Buffers()

void AtEOXact_Buffers ( bool  isCommit)

Definition at line 4222 of file bufmgr.c.

4223{
4225
4227
4229}
static void CheckForBufferLeaks(void)
Definition bufmgr.c:4286
static int32 PrivateRefCountOverflowed
Definition bufmgr.c:266
void AtEOXact_LocalBuffers(bool isCommit)
Definition localbuf.c:1027

References Assert, AtEOXact_LocalBuffers(), CheckForBufferLeaks(), fb(), and PrivateRefCountOverflowed.

Referenced by AbortTransaction(), AutoVacLauncherMain(), BackgroundWriterMain(), CheckpointerMain(), CommitTransaction(), PrepareTransaction(), and WalWriterMain().

◆ AtProcExit_Buffers()

static void AtProcExit_Buffers ( int  code,
Datum  arg 
)
static

Definition at line 4268 of file bufmgr.c.

4269{
4270 UnlockBuffers();
4271
4273
4274 /* localbuf.c needs a chance too */
4276}
void UnlockBuffers(void)
Definition bufmgr.c:5875
void AtProcExit_LocalBuffers(void)
Definition localbuf.c:1038

References AtProcExit_LocalBuffers(), CheckForBufferLeaks(), and UnlockBuffers().

Referenced by InitBufferManagerAccess().

◆ BgBufferSync()

bool BgBufferSync ( WritebackContext wb_context)

Definition at line 3854 of file bufmgr.c.

3855{
3856 /* info obtained from freelist.c */
3857 int strategy_buf_id;
3860
3861 /*
3862 * Information saved between calls so we can determine the strategy
3863 * point's advance rate and avoid scanning already-cleaned buffers.
3864 */
3865 static bool saved_info_valid = false;
3866 static int prev_strategy_buf_id;
3868 static int next_to_clean;
3869 static uint32 next_passes;
3870
3871 /* Moving averages of allocation rate and clean-buffer density */
3872 static float smoothed_alloc = 0;
3873 static float smoothed_density = 10.0;
3874
3875 /* Potentially these could be tunables, but for now, not */
3876 float smoothing_samples = 16;
3877 float scan_whole_pool_milliseconds = 120000.0;
3878
3879 /* Used to compute how far we scan ahead */
3880 long strategy_delta;
3881 int bufs_to_lap;
3882 int bufs_ahead;
3883 float scans_per_alloc;
3886 int min_scan_buffers;
3887
3888 /* Variables for the scanning loop proper */
3889 int num_to_scan;
3890 int num_written;
3891 int reusable_buffers;
3892
3893 /* Variables for final smoothed_density update */
3894 long new_strategy_delta;
3896
3897 /*
3898 * Find out where the clock-sweep currently is, and how many buffer
3899 * allocations have happened since our last call.
3900 */
3902
3903 /* Report buffer alloc counts to pgstat */
3905
3906 /*
3907 * If we're not running the LRU scan, just stop after doing the stats
3908 * stuff. We mark the saved state invalid so that we can recover sanely
3909 * if LRU scan is turned back on later.
3910 */
3911 if (bgwriter_lru_maxpages <= 0)
3912 {
3913 saved_info_valid = false;
3914 return true;
3915 }
3916
3917 /*
3918 * Compute strategy_delta = how many buffers have been scanned by the
3919 * clock-sweep since last time. If first time through, assume none. Then
3920 * see if we are still ahead of the clock-sweep, and if so, how many
3921 * buffers we could scan before we'd catch up with it and "lap" it. Note:
3922 * weird-looking coding of xxx_passes comparisons are to avoid bogus
3923 * behavior when the passes counts wrap around.
3924 */
3925 if (saved_info_valid)
3926 {
3928
3931
3932 Assert(strategy_delta >= 0);
3933
3934 if ((int32) (next_passes - strategy_passes) > 0)
3935 {
3936 /* we're one pass ahead of the strategy point */
3938#ifdef BGW_DEBUG
3939 elog(DEBUG2, "bgwriter ahead: bgw %u-%u strategy %u-%u delta=%ld lap=%d",
3943#endif
3944 }
3945 else if (next_passes == strategy_passes &&
3947 {
3948 /* on same pass, but ahead or at least not behind */
3950#ifdef BGW_DEBUG
3951 elog(DEBUG2, "bgwriter ahead: bgw %u-%u strategy %u-%u delta=%ld lap=%d",
3955#endif
3956 }
3957 else
3958 {
3959 /*
3960 * We're behind, so skip forward to the strategy point and start
3961 * cleaning from there.
3962 */
3963#ifdef BGW_DEBUG
3964 elog(DEBUG2, "bgwriter behind: bgw %u-%u strategy %u-%u delta=%ld",
3968#endif
3972 }
3973 }
3974 else
3975 {
3976 /*
3977 * Initializing at startup or after LRU scanning had been off. Always
3978 * start at the strategy point.
3979 */
3980#ifdef BGW_DEBUG
3981 elog(DEBUG2, "bgwriter initializing: strategy %u-%u",
3983#endif
3984 strategy_delta = 0;
3988 }
3989
3990 /* Update saved info for next time */
3993 saved_info_valid = true;
3994
3995 /*
3996 * Compute how many buffers had to be scanned for each new allocation, ie,
3997 * 1/density of reusable buffers, and track a moving average of that.
3998 *
3999 * If the strategy point didn't move, we don't update the density estimate
4000 */
4001 if (strategy_delta > 0 && recent_alloc > 0)
4002 {
4006 }
4007
4008 /*
4009 * Estimate how many reusable buffers there are between the current
4010 * strategy point and where we've scanned ahead to, based on the smoothed
4011 * density estimate.
4012 */
4015
4016 /*
4017 * Track a moving average of recent buffer allocations. Here, rather than
4018 * a true average we want a fast-attack, slow-decline behavior: we
4019 * immediately follow any increase.
4020 */
4021 if (smoothed_alloc <= (float) recent_alloc)
4023 else
4026
4027 /* Scale the estimate by a GUC to allow more aggressive tuning. */
4029
4030 /*
4031 * If recent_alloc remains at zero for many cycles, smoothed_alloc will
4032 * eventually underflow to zero, and the underflows produce annoying
4033 * kernel warnings on some platforms. Once upcoming_alloc_est has gone to
4034 * zero, there's no point in tracking smaller and smaller values of
4035 * smoothed_alloc, so just reset it to exactly zero to avoid this
4036 * syndrome. It will pop back up as soon as recent_alloc increases.
4037 */
4038 if (upcoming_alloc_est == 0)
4039 smoothed_alloc = 0;
4040
4041 /*
4042 * Even in cases where there's been little or no buffer allocation
4043 * activity, we want to make a small amount of progress through the buffer
4044 * cache so that as many reusable buffers as possible are clean after an
4045 * idle period.
4046 *
4047 * (scan_whole_pool_milliseconds / BgWriterDelay) computes how many times
4048 * the BGW will be called during the scan_whole_pool time; slice the
4049 * buffer pool into that many sections.
4050 */
4052
4054 {
4055#ifdef BGW_DEBUG
4056 elog(DEBUG2, "bgwriter: alloc_est=%d too small, using min=%d + reusable_est=%d",
4058#endif
4060 }
4061
4062 /*
4063 * Now write out dirty reusable buffers, working forward from the
4064 * next_to_clean point, until we have lapped the strategy scan, or cleaned
4065 * enough buffers to match our estimate of the next cycle's allocation
4066 * requirements, or hit the bgwriter_lru_maxpages limit.
4067 */
4068
4069 num_to_scan = bufs_to_lap;
4070 num_written = 0;
4072
4073 /* Execute the LRU scan */
4074 while (num_to_scan > 0 && reusable_buffers < upcoming_alloc_est)
4075 {
4077 wb_context);
4078
4079 if (++next_to_clean >= NBuffers)
4080 {
4081 next_to_clean = 0;
4082 next_passes++;
4083 }
4084 num_to_scan--;
4085
4086 if (sync_state & BUF_WRITTEN)
4087 {
4090 {
4092 break;
4093 }
4094 }
4095 else if (sync_state & BUF_REUSABLE)
4097 }
4098
4100
4101#ifdef BGW_DEBUG
4102 elog(DEBUG1, "bgwriter: recent_alloc=%u smoothed=%.2f delta=%ld ahead=%d density=%.2f reusable_est=%d upcoming_est=%d scanned=%d wrote=%d reusable=%d",
4105 bufs_to_lap - num_to_scan,
4108#endif
4109
4110 /*
4111 * Consider the above scan as being like a new allocation scan.
4112 * Characterize its density and update the smoothed one based on it. This
4113 * effectively halves the moving average period in cases where both the
4114 * strategy and the background writer are doing some useful scanning,
4115 * which is helpful because a long memory isn't as desirable on the
4116 * density estimates.
4117 */
4118 new_strategy_delta = bufs_to_lap - num_to_scan;
4120 if (new_strategy_delta > 0 && new_recent_alloc > 0)
4121 {
4125
4126#ifdef BGW_DEBUG
4127 elog(DEBUG2, "bgwriter: cleaner density alloc=%u scan=%ld density=%.2f new smoothed=%.2f",
4130#endif
4131 }
4132
4133 /* Return true if OK to hibernate */
4134 return (bufs_to_lap == 0 && recent_alloc == 0);
4135}
int BgWriterDelay
Definition bgwriter.c:59
#define BUF_REUSABLE
Definition bufmgr.c:85
double bgwriter_lru_multiplier
Definition bufmgr.c:191
static int SyncOneBuffer(int buf_id, bool skip_recently_used, WritebackContext *wb_context)
Definition bufmgr.c:4152
int bgwriter_lru_maxpages
Definition bufmgr.c:190
#define BUF_WRITTEN
Definition bufmgr.c:84
int32_t int32
Definition c.h:679
#define DEBUG2
Definition elog.h:30
#define DEBUG1
Definition elog.h:31
#define elog(elevel,...)
Definition elog.h:228
int StrategySyncStart(uint32 *complete_passes, uint32 *num_buf_alloc)
Definition freelist.c:331
int NBuffers
Definition globals.c:144
PgStat_BgWriterStats PendingBgWriterStats
PgStat_Counter buf_written_clean
Definition pgstat.h:246
PgStat_Counter maxwritten_clean
Definition pgstat.h:247
PgStat_Counter buf_alloc
Definition pgstat.h:248

References Assert, bgwriter_lru_maxpages, bgwriter_lru_multiplier, BgWriterDelay, PgStat_BgWriterStats::buf_alloc, BUF_REUSABLE, BUF_WRITTEN, PgStat_BgWriterStats::buf_written_clean, DEBUG1, DEBUG2, elog, fb(), PgStat_BgWriterStats::maxwritten_clean, NBuffers, PendingBgWriterStats, StrategySyncStart(), and SyncOneBuffer().

Referenced by BackgroundWriterMain().

◆ buffer_readv_complete()

static pg_attribute_always_inline PgAioResult buffer_readv_complete ( PgAioHandle ioh,
PgAioResult  prior_result,
uint8  cb_data,
bool  is_temp 
)
static

Definition at line 8725 of file bufmgr.c.

8727{
8733 uint8 error_count = 0;
8734 uint8 zeroed_count = 0;
8735 uint8 ignored_count = 0;
8737 uint64 *io_data;
8738 uint8 handle_data_len;
8739
8740 if (is_temp)
8741 {
8742 Assert(td->smgr.is_temp);
8744 }
8745 else
8746 Assert(!td->smgr.is_temp);
8747
8748 /*
8749 * Iterate over all the buffers affected by this IO and call the
8750 * per-buffer completion function for each buffer.
8751 */
8752 io_data = pgaio_io_get_handle_data(ioh, &handle_data_len);
8753 for (uint8 buf_off = 0; buf_off < handle_data_len; buf_off++)
8754 {
8756 bool failed;
8757 bool failed_verification = false;
8758 bool failed_checksum = false;
8759 bool zeroed_buffer = false;
8760 bool ignored_checksum = false;
8761
8763
8764 /*
8765 * If the entire I/O failed on a lower-level, each buffer needs to be
8766 * marked as failed. In case of a partial read, the first few buffers
8767 * may be ok.
8768 */
8769 failed =
8771 || prior_result.result <= buf_off;
8772
8773 buffer_readv_complete_one(td, buf_off, buf, cb_data, failed, is_temp,
8777 &zeroed_buffer);
8778
8779 /*
8780 * Track information about the number of different kinds of error
8781 * conditions across all pages, as there can be multiple pages failing
8782 * verification as part of one IO.
8783 */
8786 if (zeroed_buffer && zeroed_count++ == 0)
8788 if (ignored_checksum && ignored_count++ == 0)
8790 if (failed_checksum)
8792 }
8793
8794 /*
8795 * If the smgr read succeeded [partially] and page verification failed for
8796 * some of the pages, adjust the IO's result state appropriately.
8797 */
8798 if (prior_result.status != PGAIO_RS_ERROR &&
8799 (error_count > 0 || ignored_count > 0 || zeroed_count > 0))
8800 {
8802 zeroed_count > 0, ignored_count > 0,
8807 }
8808
8809 /*
8810 * For shared relations this reporting is done in
8811 * shared_buffer_readv_complete_local().
8812 */
8813 if (is_temp && checkfail_count > 0)
8816
8817 return result;
8818}
ProcNumber pgaio_io_get_owner(PgAioHandle *ioh)
Definition aio.c:355
uint64 * pgaio_io_get_handle_data(PgAioHandle *ioh, uint8 *len)
void pgaio_result_report(PgAioResult result, const PgAioTargetData *target_data, int elevel)
PgAioTargetData * pgaio_io_get_target_data(PgAioHandle *ioh)
Definition aio_target.c:73
@ PGAIO_RS_ERROR
Definition aio_types.h:84
static pg_attribute_always_inline void buffer_readv_complete_one(PgAioTargetData *td, uint8 buf_off, Buffer buffer, uint8 flags, bool failed, bool is_temp, bool *buffer_invalid, bool *failed_checksum, bool *ignored_checksum, bool *zeroed_buffer)
Definition bufmgr.c:8574
static void buffer_readv_encode_error(PgAioResult *result, bool is_temp, bool zeroed_any, bool ignored_any, uint8 error_count, uint8 zeroed_count, uint8 checkfail_count, uint8 first_error_off, uint8 first_zeroed_off, uint8 first_ignored_off)
Definition bufmgr.c:8479
uint8_t uint8
Definition c.h:681
uint32 result
ProcNumber MyProcNumber
Definition globals.c:92
static char buf[DEFAULT_XLOG_SEG_SIZE]
void pgstat_report_checksum_failures_in_db(Oid dboid, int failurecount)
struct PgAioTargetData::@129 smgr
RelFileLocator rlocator
Definition aio_types.h:65

References Assert, buf, buffer_readv_complete_one(), buffer_readv_encode_error(), BufferIsValid(), RelFileLocator::dbOid, DEBUG1, fb(), PgAioTargetData::is_temp, MyProcNumber, pgaio_io_get_handle_data(), pgaio_io_get_owner(), pgaio_io_get_target_data(), pgaio_result_report(), PGAIO_RS_ERROR, pgstat_report_checksum_failures_in_db(), result, PgAioTargetData::rlocator, and PgAioTargetData::smgr.

Referenced by local_buffer_readv_complete(), and shared_buffer_readv_complete().

◆ buffer_readv_complete_one()

static pg_attribute_always_inline void buffer_readv_complete_one ( PgAioTargetData td,
uint8  buf_off,
Buffer  buffer,
uint8  flags,
bool  failed,
bool  is_temp,
bool buffer_invalid,
bool failed_checksum,
bool ignored_checksum,
bool zeroed_buffer 
)
static

Definition at line 8574 of file bufmgr.c.

8580{
8581 BufferDesc *buf_hdr = is_temp ?
8582 GetLocalBufferDescriptor(-buffer - 1)
8583 : GetBufferDescriptor(buffer - 1);
8584 BufferTag tag = buf_hdr->tag;
8585 char *bufdata = BufferGetBlock(buffer);
8587 int piv_flags;
8588
8589 /* check that the buffer is in the expected state for a read */
8590#ifdef USE_ASSERT_CHECKING
8591 {
8593
8596 /* temp buffers don't use BM_IO_IN_PROGRESS */
8597 if (!is_temp)
8600 }
8601#endif
8602
8603 *buffer_invalid = false;
8604 *failed_checksum = false;
8605 *ignored_checksum = false;
8606 *zeroed_buffer = false;
8607
8608 /*
8609 * We ask PageIsVerified() to only log the message about checksum errors,
8610 * as the completion might be run in any backend (or IO workers). We will
8611 * report checksum errors in buffer_readv_report().
8612 */
8614
8615 /* the local zero_damaged_pages may differ from the definer's */
8618
8619 /*
8620 * If the buffers are marked for zero on error, we want to log that in
8621 * case of a checksum failure.
8622 */
8623 if (flags & READ_BUFFERS_ZERO_ON_ERROR)
8625
8626 /* Check for garbage data. */
8627 if (!failed)
8628 {
8629 /*
8630 * If the buffer is not currently pinned by this backend, e.g. because
8631 * we're completing this IO after an error, the buffer data will have
8632 * been marked as inaccessible when the buffer was unpinned. The AIO
8633 * subsystem holds a pin, but that doesn't prevent the buffer from
8634 * having been marked as inaccessible. The completion might also be
8635 * executed in a different process.
8636 */
8637#ifdef USE_VALGRIND
8638 if (!BufferIsPinned(buffer))
8640#endif
8641
8642 if (!PageIsVerified((Page) bufdata, tag.blockNum, piv_flags,
8644 {
8645 if (flags & READ_BUFFERS_ZERO_ON_ERROR)
8646 {
8647 memset(bufdata, 0, BLCKSZ);
8648 *zeroed_buffer = true;
8649 }
8650 else
8651 {
8652 *buffer_invalid = true;
8653 /* mark buffer as having failed */
8654 failed = true;
8655 }
8656 }
8657 else if (*failed_checksum)
8658 *ignored_checksum = true;
8659
8660 /* undo what we did above */
8661#ifdef USE_VALGRIND
8662 if (!BufferIsPinned(buffer))
8664#endif
8665
8666 /*
8667 * Immediately log a message about the invalid page, but only to the
8668 * server log. The reason to do so immediately is that this may be
8669 * executed in a different backend than the one that originated the
8670 * request. The reason to do so immediately is that the originator
8671 * might not process the query result immediately (because it is busy
8672 * doing another part of query processing) or at all (e.g. if it was
8673 * cancelled or errored out due to another IO also failing). The
8674 * definer of the IO will emit an ERROR or WARNING when processing the
8675 * IO's results
8676 *
8677 * To avoid duplicating the code to emit these log messages, we reuse
8678 * buffer_readv_report().
8679 */
8681 {
8682 PgAioResult result_one = {0};
8683
8688 *zeroed_buffer ? 1 : 0,
8689 *failed_checksum ? 1 : 0,
8692 }
8693 }
8694
8695 /* Terminate I/O and set BM_VALID. */
8696 set_flag_bits = failed ? BM_IO_ERROR : BM_VALID;
8697 if (is_temp)
8699 else
8700 TerminateBufferIO(buf_hdr, false, set_flag_bits, false, true);
8701
8702 /*
8703 * Call the BUFFER_READ_DONE tracepoint in the callback, even though the
8704 * callback may not be executed in the same backend that called
8705 * BUFFER_READ_START. The alternative would be to defer calling the
8706 * tracepoint to a later point (e.g. the local completion callback for
8707 * shared buffer reads), which seems even less helpful.
8708 */
8710 tag.blockNum,
8711 tag.spcOid,
8712 tag.dbOid,
8713 tag.relNumber,
8715 false);
8716}
static uint64 pg_atomic_read_u64(volatile pg_atomic_uint64 *ptr)
Definition atomics.h:462
static BufferDesc * GetLocalBufferDescriptor(int id)
#define BufferIsPinned(bufnum)
Definition bufmgr.c:599
bool PageIsVerified(PageData *page, BlockNumber blkno, int flags, bool *checksum_failure_p)
Definition bufpage.c:94
#define PIV_LOG_LOG
Definition bufpage.h:500
#define PIV_ZERO_BUFFERS_ON_ERROR
Definition bufpage.h:502
PageData * Page
Definition bufpage.h:81
#define PIV_IGNORE_CHECKSUM_FAILURE
Definition bufpage.h:501
#define LOG_SERVER_ONLY
Definition elog.h:33
#define false
void TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint64 set_flag_bits, bool release_aio)
Definition localbuf.c:586
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
Definition memdebug.h:26
#define VALGRIND_MAKE_MEM_NOACCESS(addr, size)
Definition memdebug.h:27
#define INVALID_PROC_NUMBER
Definition procnumber.h:26
BlockNumber blockNum
RelFileNumber relNumber
ForkNumber forkNum

References Assert, buftag::blockNum, BM_DIRTY, BM_IO_ERROR, BM_IO_IN_PROGRESS, BM_TAG_VALID, BM_VALID, PrivateRefCountEntry::buffer, buffer_readv_encode_error(), BufferGetBlock(), BufferIsPinned, buftag::dbOid, fb(), buftag::forkNum, GetBufferDescriptor(), GetLocalBufferDescriptor(), INVALID_PROC_NUMBER, LOG_SERVER_ONLY, MyProcNumber, PageIsVerified(), pg_atomic_read_u64(), pgaio_result_report(), PIV_IGNORE_CHECKSUM_FAILURE, PIV_LOG_LOG, PIV_ZERO_BUFFERS_ON_ERROR, READ_BUFFERS_IGNORE_CHECKSUM_FAILURES, READ_BUFFERS_ZERO_ON_ERROR, buftag::relNumber, buftag::spcOid, TerminateBufferIO(), TerminateLocalBufferIO(), VALGRIND_MAKE_MEM_DEFINED, and VALGRIND_MAKE_MEM_NOACCESS.

Referenced by buffer_readv_complete().

◆ buffer_readv_decode_error()

static void buffer_readv_decode_error ( PgAioResult  result,
bool zeroed_any,
bool ignored_any,
uint8 zeroed_or_error_count,
uint8 checkfail_count,
uint8 first_off 
)
inlinestatic

Definition at line 8437 of file bufmgr.c.

8443{
8444 uint32 rem_error = result.error_data;
8445
8446 /* see static asserts in buffer_readv_encode_error */
8447#define READV_COUNT_BITS 7
8448#define READV_COUNT_MASK ((1 << READV_COUNT_BITS) - 1)
8449
8450 *zeroed_any = rem_error & 1;
8451 rem_error >>= 1;
8452
8453 *ignored_any = rem_error & 1;
8454 rem_error >>= 1;
8455
8458
8461
8464}
#define READV_COUNT_BITS
#define READV_COUNT_MASK

References fb(), READV_COUNT_BITS, READV_COUNT_MASK, and result.

Referenced by buffer_readv_encode_error(), buffer_readv_report(), and shared_buffer_readv_complete_local().

◆ buffer_readv_encode_error()

static void buffer_readv_encode_error ( PgAioResult result,
bool  is_temp,
bool  zeroed_any,
bool  ignored_any,
uint8  error_count,
uint8  zeroed_count,
uint8  checkfail_count,
uint8  first_error_off,
uint8  first_zeroed_off,
uint8  first_ignored_off 
)
inlinestatic

Definition at line 8479 of file bufmgr.c.

8489{
8490
8491 uint8 shift = 0;
8495
8497 "PG_IOV_MAX is bigger than reserved space for error data");
8499 "PGAIO_RESULT_ERROR_BITS is insufficient for buffer_readv");
8500
8501 /*
8502 * We only have space to encode one offset - but luckily that's good
8503 * enough. If there is an error, the error is the interesting offset, same
8504 * with a zeroed buffer vs an ignored buffer.
8505 */
8506 if (error_count > 0)
8508 else if (zeroed_count > 0)
8510 else
8512
8513 Assert(!zeroed_any || error_count == 0);
8514
8515 result->error_data = 0;
8516
8517 result->error_data |= zeroed_any << shift;
8518 shift += 1;
8519
8520 result->error_data |= ignored_any << shift;
8521 shift += 1;
8522
8523 result->error_data |= ((uint32) zeroed_or_error_count) << shift;
8524 shift += READV_COUNT_BITS;
8525
8526 result->error_data |= ((uint32) checkfail_count) << shift;
8527 shift += READV_COUNT_BITS;
8528
8529 result->error_data |= ((uint32) first_off) << shift;
8530 shift += READV_COUNT_BITS;
8531
8532 result->id = is_temp ? PGAIO_HCB_LOCAL_BUFFER_READV :
8534
8535 if (error_count > 0)
8536 result->status = PGAIO_RS_ERROR;
8537 else
8538 result->status = PGAIO_RS_WARNING;
8539
8540 /*
8541 * The encoding is complicated enough to warrant cross-checking it against
8542 * the decode function.
8543 */
8544#ifdef USE_ASSERT_CHECKING
8545 {
8546 bool zeroed_any_2,
8551
8556 &first_off_2);
8562 }
8563#endif
8564
8565#undef READV_COUNT_BITS
8566#undef READV_COUNT_MASK
8567}
#define PGAIO_RESULT_ERROR_BITS
Definition aio_types.h:98
@ PGAIO_RS_WARNING
Definition aio_types.h:83
static void buffer_readv_decode_error(PgAioResult result, bool *zeroed_any, bool *ignored_any, uint8 *zeroed_or_error_count, uint8 *checkfail_count, uint8 *first_off)
Definition bufmgr.c:8437
#define StaticAssertDecl(condition, errmessage)
Definition c.h:1067
#define PG_IOV_MAX
Definition pg_iovec.h:47

References Assert, buffer_readv_decode_error(), fb(), PG_IOV_MAX, PGAIO_HCB_LOCAL_BUFFER_READV, PGAIO_HCB_SHARED_BUFFER_READV, PGAIO_RESULT_ERROR_BITS, PGAIO_RS_ERROR, PGAIO_RS_WARNING, READV_COUNT_BITS, result, and StaticAssertDecl.

Referenced by buffer_readv_complete(), and buffer_readv_complete_one().

◆ buffer_readv_report()

static void buffer_readv_report ( PgAioResult  result,
const PgAioTargetData td,
int  elevel 
)
static

Definition at line 8828 of file bufmgr.c.

8830{
8831 int nblocks = td->smgr.nblocks;
8832 BlockNumber first = td->smgr.blockNum;
8833 BlockNumber last = first + nblocks - 1;
8836 RelPathStr rpath =
8838 bool zeroed_any,
8842 first_off;
8844 const char *msg_one,
8845 *msg_mult,
8846 *det_mult,
8847 *hint_mult;
8848
8852 &first_off);
8853
8854 /*
8855 * Treat a read that had both zeroed buffers *and* ignored checksums as a
8856 * special case, it's too irregular to be emitted the same way as the
8857 * other cases.
8858 */
8859 if (zeroed_any && ignored_any)
8860 {
8862 Assert(nblocks > 1); /* same block can't be both zeroed and ignored */
8863 Assert(result.status != PGAIO_RS_ERROR);
8865
8866 ereport(elevel,
8868 errmsg("zeroing %u page(s) and ignoring %u checksum failure(s) among blocks %u..%u of relation \"%s\"",
8869 affected_count, checkfail_count, first, last, rpath.str),
8870 affected_count > 1 ?
8871 errdetail("Block %u held the first zeroed page.",
8872 first + first_off) : 0,
8873 errhint_plural("See server log for details about the other %d invalid block.",
8874 "See server log for details about the other %d invalid blocks.",
8877 return;
8878 }
8879
8880 /*
8881 * The other messages are highly repetitive. To avoid duplicating a long
8882 * and complicated ereport(), gather the translated format strings
8883 * separately and then do one common ereport.
8884 */
8885 if (result.status == PGAIO_RS_ERROR)
8886 {
8887 Assert(!zeroed_any); /* can't have invalid pages when zeroing them */
8889 msg_one = _("invalid page in block %u of relation \"%s\"");
8890 msg_mult = _("%u invalid pages among blocks %u..%u of relation \"%s\"");
8891 det_mult = _("Block %u held the first invalid page.");
8892 hint_mult = _("See server log for the other %u invalid block(s).");
8893 }
8894 else if (zeroed_any && !ignored_any)
8895 {
8897 msg_one = _("invalid page in block %u of relation \"%s\"; zeroing out page");
8898 msg_mult = _("zeroing out %u invalid pages among blocks %u..%u of relation \"%s\"");
8899 det_mult = _("Block %u held the first zeroed page.");
8900 hint_mult = _("See server log for the other %u zeroed block(s).");
8901 }
8902 else if (!zeroed_any && ignored_any)
8903 {
8905 msg_one = _("ignoring checksum failure in block %u of relation \"%s\"");
8906 msg_mult = _("ignoring %u checksum failures among blocks %u..%u of relation \"%s\"");
8907 det_mult = _("Block %u held the first ignored page.");
8908 hint_mult = _("See server log for the other %u ignored block(s).");
8909 }
8910 else
8912
8913 ereport(elevel,
8915 affected_count == 1 ?
8916 errmsg_internal(msg_one, first + first_off, rpath.str) :
8917 errmsg_internal(msg_mult, affected_count, first, last, rpath.str),
8920}
#define pg_unreachable()
Definition c.h:426
#define _(x)
Definition elog.c:96
int int errdetail_internal(const char *fmt,...) pg_attribute_printf(1
int int int errhint_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...) pg_attribute_printf(1
int int errmsg_internal(const char *fmt,...) pg_attribute_printf(1
int int errhint_internal(const char *fmt,...) pg_attribute_printf(1
const char * str
#define ERRCODE_DATA_CORRUPTED
int ProcNumber
Definition procnumber.h:24
#define relpathbackend(rlocator, backend, forknum)
Definition relpath.h:141
char str[REL_PATH_STR_MAXLEN+1]
Definition relpath.h:123
BlockNumber blockNum
Definition aio_types.h:66
BlockNumber nblocks
Definition aio_types.h:67
ForkNumber forkNum
Definition aio_types.h:68

References _, Assert, PgAioTargetData::blockNum, buffer_readv_decode_error(), ereport, errcode(), ERRCODE_DATA_CORRUPTED, errdetail(), errdetail_internal(), errhint_internal(), errhint_plural(), errmsg, errmsg_internal(), fb(), PgAioTargetData::forkNum, INVALID_PROC_NUMBER, PgAioTargetData::is_temp, MyProcNumber, PgAioTargetData::nblocks, pg_unreachable, PGAIO_RS_ERROR, relpathbackend, result, PgAioTargetData::rlocator, PgAioTargetData::smgr, and RelPathStr::str.

◆ buffer_stage_common()

static pg_attribute_always_inline void buffer_stage_common ( PgAioHandle ioh,
bool  is_write,
bool  is_temp 
)
static

Definition at line 8330 of file bufmgr.c.

8331{
8332 uint64 *io_data;
8333 uint8 handle_data_len;
8336
8337 io_data = pgaio_io_get_handle_data(ioh, &handle_data_len);
8338
8340
8341 /* iterate over all buffers affected by the vectored readv/writev */
8342 for (int i = 0; i < handle_data_len; i++)
8343 {
8344 Buffer buffer = (Buffer) io_data[i];
8345 BufferDesc *buf_hdr = is_temp ?
8346 GetLocalBufferDescriptor(-buffer - 1)
8347 : GetBufferDescriptor(buffer - 1);
8349
8350 /*
8351 * Check that all the buffers are actually ones that could conceivably
8352 * be done in one IO, i.e. are sequential. This is the last
8353 * buffer-aware code before IO is actually executed and confusion
8354 * about which buffers are targeted by IO can be hard to debug, making
8355 * it worth doing extra-paranoid checks.
8356 */
8357 if (i == 0)
8358 first = buf_hdr->tag;
8359 else
8360 {
8361 Assert(buf_hdr->tag.relNumber == first.relNumber);
8362 Assert(buf_hdr->tag.blockNum == first.blockNum + i);
8363 }
8364
8365 if (is_temp)
8367 else
8369
8370 /* verify the buffer is in the expected state */
8372 if (is_write)
8373 {
8376 }
8377 else
8378 {
8381 }
8382
8383 /* temp buffers don't use BM_IO_IN_PROGRESS */
8384 if (!is_temp)
8386
8388
8389 /*
8390 * Reflect that the buffer is now owned by the AIO subsystem.
8391 *
8392 * For local buffers: This can't be done just via LocalRefCount, as
8393 * one might initially think, as this backend could error out while
8394 * AIO is still in progress, releasing all the pins by the backend
8395 * itself.
8396 *
8397 * This pin is released again in TerminateBufferIO().
8398 */
8399 buf_hdr->io_wref = io_ref;
8400
8401 if (is_temp)
8402 {
8405 }
8406 else
8408
8409 /*
8410 * Ensure the content lock that prevents buffer modifications while
8411 * the buffer is being written out is not released early due to an
8412 * error.
8413 */
8414 if (is_write && !is_temp)
8415 {
8417
8418 /*
8419 * Lock is now owned by AIO subsystem.
8420 */
8421 BufferLockDisown(buffer, buf_hdr);
8422 }
8423
8424 /*
8425 * Stop tracking this buffer via the resowner - the AIO system now
8426 * keeps track.
8427 */
8428 if (!is_temp)
8430 }
8431}
static void pg_atomic_unlocked_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition atomics.h:489
#define BUF_REFCOUNT_ONE
static uint64 UnlockBufHdrExt(BufferDesc *desc, uint64 old_buf_state, uint64 set_bits, uint64 unset_bits, int refcount_change)
static void ResourceOwnerForgetBufferIO(ResourceOwner owner, Buffer buffer)
#define BUF_STATE_GET_REFCOUNT(state)
static void BufferLockDisown(Buffer buffer, BufferDesc *buf_hdr)
Definition bufmgr.c:6294
static bool BufferLockHeldByMe(BufferDesc *buf_hdr)
Definition bufmgr.c:6566
#define PG_USED_FOR_ASSERTS_ONLY
Definition c.h:308
BufferTag tag

References Assert, BM_DIRTY, BM_IO_IN_PROGRESS, BM_TAG_VALID, BM_VALID, BUF_REFCOUNT_ONE, BUF_STATE_GET_REFCOUNT, PrivateRefCountEntry::buffer, BufferLockDisown(), BufferLockHeldByMe(), CurrentResourceOwner, fb(), GetBufferDescriptor(), GetLocalBufferDescriptor(), i, LockBufHdr(), pg_atomic_read_u64(), pg_atomic_unlocked_write_u64(), PG_USED_FOR_ASSERTS_ONLY, pgaio_io_get_handle_data(), pgaio_io_get_wref(), ResourceOwnerForgetBufferIO(), and UnlockBufHdrExt().

Referenced by local_buffer_readv_stage(), and shared_buffer_readv_stage().

◆ BufferAlloc()

static pg_attribute_always_inline BufferDesc * BufferAlloc ( SMgrRelation  smgr,
char  relpersistence,
ForkNumber  forkNum,
BlockNumber  blockNum,
BufferAccessStrategy  strategy,
bool foundPtr,
IOContext  io_context 
)
inlinestatic

Definition at line 2197 of file bufmgr.c.

2201{
2202 BufferTag newTag; /* identity of requested block */
2203 uint32 newHash; /* hash value for newTag */
2204 LWLock *newPartitionLock; /* buffer partition lock for it */
2205 int existing_buf_id;
2209 uint64 set_bits = 0;
2210
2211 /* Make sure we will have room to remember the buffer pin */
2214
2215 /* create a tag so we can lookup the buffer */
2216 InitBufferTag(&newTag, &smgr->smgr_rlocator.locator, forkNum, blockNum);
2217
2218 /* determine its hash code and partition lock ID */
2221
2222 /* see if the block is in the buffer pool already */
2225 if (existing_buf_id >= 0)
2226 {
2227 BufferDesc *buf;
2228 bool valid;
2229
2230 /*
2231 * Found it. Now, pin the buffer so no one can steal it from the
2232 * buffer pool, and check to see if the correct data has been loaded
2233 * into the buffer.
2234 */
2236
2237 valid = PinBuffer(buf, strategy, false);
2238
2239 /* Can release the mapping lock as soon as we've pinned it */
2241
2242 *foundPtr = true;
2243
2244 if (!valid)
2245 {
2246 /*
2247 * We can only get here if (a) someone else is still reading in
2248 * the page, (b) a previous read attempt failed, or (c) someone
2249 * called StartReadBuffers() but not yet WaitReadBuffers().
2250 */
2251 *foundPtr = false;
2252 }
2253
2254 return buf;
2255 }
2256
2257 /*
2258 * Didn't find it in the buffer pool. We'll have to initialize a new
2259 * buffer. Remember to unlock the mapping lock while doing the work.
2260 */
2262
2263 /*
2264 * Acquire a victim buffer. Somebody else might try to do the same, we
2265 * don't hold any conflicting locks. If so we'll have to undo our work
2266 * later.
2267 */
2270
2271 /*
2272 * Try to make a hashtable entry for the buffer under its new tag. If
2273 * somebody else inserted another buffer for the tag, we'll release the
2274 * victim buffer we acquired and use the already inserted one.
2275 */
2278 if (existing_buf_id >= 0)
2279 {
2281 bool valid;
2282
2283 /*
2284 * Got a collision. Someone has already done what we were about to do.
2285 * We'll just handle this as if it were found in the buffer pool in
2286 * the first place. First, give up the buffer we were planning to
2287 * use.
2288 *
2289 * We could do this after releasing the partition lock, but then we'd
2290 * have to call ResourceOwnerEnlarge() & ReservePrivateRefCountEntry()
2291 * before acquiring the lock, for the rare case of such a collision.
2292 */
2294
2295 /* remaining code should match code at top of routine */
2296
2298
2299 valid = PinBuffer(existing_buf_hdr, strategy, false);
2300
2301 /* Can release the mapping lock as soon as we've pinned it */
2303
2304 *foundPtr = true;
2305
2306 if (!valid)
2307 {
2308 /*
2309 * We can only get here if (a) someone else is still reading in
2310 * the page, (b) a previous read attempt failed, or (c) someone
2311 * called StartReadBuffers() but not yet WaitReadBuffers().
2312 */
2313 *foundPtr = false;
2314 }
2315
2316 return existing_buf_hdr;
2317 }
2318
2319 /*
2320 * Need to lock the buffer header too in order to change its tag.
2321 */
2323
2324 /* some sanity checks while we hold the buffer header lock */
2327
2328 victim_buf_hdr->tag = newTag;
2329
2330 /*
2331 * Make sure BM_PERMANENT is set for buffers that must be written at every
2332 * checkpoint. Unlogged buffers only need to be written at shutdown
2333 * checkpoints, except for their "init" forks, which need to be treated
2334 * just like permanent relations.
2335 */
2337 if (relpersistence == RELPERSISTENCE_PERMANENT || forkNum == INIT_FORKNUM)
2339
2341 set_bits, 0, 0);
2342
2344
2345 /*
2346 * Buffer contents are currently invalid.
2347 */
2348 *foundPtr = false;
2349
2350 return victim_buf_hdr;
2351}
static void InitBufferTag(BufferTag *tag, const RelFileLocator *rlocator, ForkNumber forkNum, BlockNumber blockNum)
#define BM_PERMANENT
#define BUF_USAGECOUNT_ONE
static LWLock * BufMappingPartitionLock(uint32 hashcode)
int BufTableLookup(BufferTag *tagPtr, uint32 hashcode)
Definition buf_table.c:96
uint32 BufTableHashCode(BufferTag *tagPtr)
Definition buf_table.c:84
int BufTableInsert(BufferTag *tagPtr, uint32 hashcode, int buf_id)
Definition buf_table.c:124
static Buffer GetVictimBuffer(BufferAccessStrategy strategy, IOContext io_context)
Definition bufmgr.c:2548
static bool PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, bool skip_if_not_valid)
Definition bufmgr.c:3295
static void ReservePrivateRefCountEntry(void)
Definition bufmgr.c:309
static void UnpinBuffer(BufferDesc *buf)
Definition bufmgr.c:3479
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1150
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1767
@ LW_SHARED
Definition lwlock.h:105
@ LW_EXCLUSIVE
Definition lwlock.h:104
@ INIT_FORKNUM
Definition relpath.h:61
void ResourceOwnerEnlarge(ResourceOwner owner)
Definition resowner.c:459
RelFileLocator locator
RelFileLocatorBackend smgr_rlocator
Definition smgr.h:38

References Assert, BM_DIRTY, BM_IO_IN_PROGRESS, BM_PERMANENT, BM_TAG_VALID, BM_VALID, buf, BUF_STATE_GET_REFCOUNT, BUF_USAGECOUNT_ONE, BufMappingPartitionLock(), BufTableHashCode(), BufTableInsert(), BufTableLookup(), CurrentResourceOwner, fb(), GetBufferDescriptor(), GetVictimBuffer(), INIT_FORKNUM, InitBufferTag(), RelFileLocatorBackend::locator, LockBufHdr(), LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), PinBuffer(), ReservePrivateRefCountEntry(), ResourceOwnerEnlarge(), SMgrRelationData::smgr_rlocator, UnlockBufHdrExt(), and UnpinBuffer().

Referenced by PinBufferForBlock().

◆ BufferBeginSetHintBits()

bool BufferBeginSetHintBits ( Buffer  buffer)

Definition at line 7091 of file bufmgr.c.

7092{
7095
7096 if (BufferIsLocal(buffer))
7097 {
7098 /*
7099 * NB: Will need to check if there is a write in progress, once it is
7100 * possible for writes to be done asynchronously.
7101 */
7102 return true;
7103 }
7104
7105 buf_hdr = GetBufferDescriptor(buffer - 1);
7106
7108}
#define BufferIsLocal(buffer)
Definition buf.h:37
static bool SharedBufferBeginSetHintBits(Buffer buffer, BufferDesc *buf_hdr, uint64 *lockstate)
Definition bufmgr.c:7000

References PrivateRefCountEntry::buffer, BufferIsLocal, fb(), GetBufferDescriptor(), and SharedBufferBeginSetHintBits().

Referenced by _bt_check_unique(), _bt_killitems(), _hash_kill_items(), fsm_search_avail(), fsm_vacuum_page(), gistkillitems(), and SetHintBitsExt().

◆ BufferFinishSetHintBits()

void BufferFinishSetHintBits ( Buffer  buffer,
bool  mark_dirty,
bool  buffer_std 
)

Definition at line 7119 of file bufmgr.c.

7120{
7121 if (!BufferIsLocal(buffer))
7124
7125 if (mark_dirty)
7127}
bool BufferIsLockedByMeInMode(Buffer buffer, BufferLockMode mode)
Definition bufmgr.c:3110
void MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
Definition bufmgr.c:5844
@ BUFFER_LOCK_SHARE_EXCLUSIVE
Definition bufmgr.h:217
@ BUFFER_LOCK_EXCLUSIVE
Definition bufmgr.h:222

References Assert, PrivateRefCountEntry::buffer, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_SHARE_EXCLUSIVE, BufferIsLocal, BufferIsLockedByMeInMode(), fb(), and MarkBufferDirtyHint().

Referenced by _bt_check_unique(), _bt_killitems(), _hash_kill_items(), fsm_search_avail(), fsm_vacuum_page(), gistkillitems(), and HeapTupleSatisfiesMVCCBatch().

◆ BufferGetBlockNumber()

BlockNumber BufferGetBlockNumber ( Buffer  buffer)

Definition at line 4469 of file bufmgr.c.

4470{
4472
4473 Assert(BufferIsPinned(buffer));
4474
4475 if (BufferIsLocal(buffer))
4476 bufHdr = GetLocalBufferDescriptor(-buffer - 1);
4477 else
4478 bufHdr = GetBufferDescriptor(buffer - 1);
4479
4480 /* pinned, so OK to read tag without spinlock */
4481 return bufHdr->tag.blockNum;
4482}

References Assert, PrivateRefCountEntry::buffer, BufferIsLocal, BufferIsPinned, fb(), GetBufferDescriptor(), and GetLocalBufferDescriptor().

Referenced by _bt_binsrch_insert(), _bt_bottomupdel_pass(), _bt_check_unique(), _bt_checkpage(), _bt_delitems_delete(), _bt_delitems_vacuum(), _bt_doinsert(), _bt_finish_split(), _bt_getroot(), _bt_insert_parent(), _bt_insertonpg(), _bt_mark_page_halfdead(), _bt_moveright(), _bt_newlevel(), _bt_pagedel(), _bt_readpage(), _bt_relandgetbuf(), _bt_restore_meta(), _bt_search(), _bt_simpledel_pass(), _bt_split(), _bt_unlink_halfdead_page(), _hash_addovflpage(), _hash_checkpage(), _hash_doinsert(), _hash_first(), _hash_freeovflpage(), _hash_getnewbuf(), _hash_readnext(), _hash_readpage(), _hash_splitbucket(), allocNewBuffer(), AsyncReadBuffers(), BitmapHeapScanNextBlock(), blinsert(), BloomInitMetapage(), brin_doinsert(), brin_doupdate(), brin_getinsertbuffer(), brin_initialize_empty_new_buffer(), brin_page_cleanup(), brin_xlog_insert_update(), brinbuild(), brinGetTupleForHeapBlock(), btvacuumpage(), check_index_page(), CheckReadBuffersOperation(), collect_corrupt_items(), collectMatchBitmap(), createPostingTree(), dataBeginPlaceToPageLeaf(), dataPrepareDownlink(), doPickSplit(), entryPrepareDownlink(), fill_seq_fork_with_data(), ginDeletePostingPage(), ginEntryInsert(), ginFindParents(), ginFinishSplit(), ginPlaceToPage(), ginRedoDeleteListPages(), ginRedoUpdateMetapage(), gistbufferinginserttuples(), gistbuild(), gistcheckpage(), gistdeletepage(), gistformdownlink(), gistinserttuples(), gistMemorizeAllDownlinks(), gistplacetopage(), gistRelocateBuildBuffersOnSplit(), gistScanPage(), gistvacuumpage(), hash_xlog_add_ovfl_page(), heap_delete(), heap_fetch_next_buffer(), heap_hot_search_buffer(), heap_insert(), heap_multi_insert(), heap_page_prune_opt(), heap_page_would_be_all_visible(), heap_prepare_pagescan(), heap_update(), heap_xlog_confirm(), heap_xlog_lock(), heapam_index_fetch_tuple(), heapam_scan_analyze_next_block(), heapgettup(), heapgettup_pagemode(), index_compute_xid_horizon_for_tuples(), lazy_scan_heap(), lazy_scan_noprune(), lazy_scan_prune(), lazy_vacuum_heap_rel(), makeSublist(), moveLeafs(), moveRightIfItNeeded(), pgstathashindex(), prune_freeze_setup(), read_buffers(), read_stream_start_pending_read(), ReadBufferBI(), RelationAddBlocks(), RelationCopyStorageUsingBuffer(), RelationGetBufferForTuple(), RelationPutHeapTuple(), revmap_get_buffer(), revmap_physical_extend(), ScanSourceDatabasePgClassPage(), spgAddNodeAction(), spgbuild(), spgdoinsert(), SpGistSetLastUsedPage(), spgSplitNodeAction(), spgvacuumpage(), spgWalk(), StartReadBuffersImpl(), startScanEntry(), statapprox_heap(), terminate_brin_buildstate(), vacuumLeafPage(), verify_heapam(), visibilitymap_clear(), visibilitymap_get_status(), visibilitymap_pin(), visibilitymap_pin_ok(), and visibilitymap_set().

◆ BufferGetLSNAtomic()

XLogRecPtr BufferGetLSNAtomic ( Buffer  buffer)

Definition at line 4736 of file bufmgr.c.

4737{
4738 /* Make sure we've got a real buffer, and that we hold a pin on it. */
4739 Assert(BufferIsValid(buffer));
4740 Assert(BufferIsPinned(buffer));
4741
4742#ifdef PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY
4743 return PageGetLSN(BufferGetPage(buffer));
4744#else
4745 {
4746 char *page = BufferGetPage(buffer);
4748 XLogRecPtr lsn;
4749
4750 /*
4751 * If we don't need locking for correctness, fastpath out.
4752 */
4753 if (!XLogHintBitIsNeeded() || BufferIsLocal(buffer))
4754 return PageGetLSN(page);
4755
4756 bufHdr = GetBufferDescriptor(buffer - 1);
4758 lsn = PageGetLSN(page);
4760
4761 return lsn;
4762 }
4763#endif
4764}
static Page BufferGetPage(Buffer buffer)
Definition bufmgr.h:468
static XLogRecPtr PageGetLSN(const PageData *page)
Definition bufpage.h:410
#define XLogHintBitIsNeeded()
Definition xlog.h:123
uint64 XLogRecPtr
Definition xlogdefs.h:21

References Assert, PrivateRefCountEntry::buffer, BufferGetPage(), BufferIsLocal, BufferIsPinned, BufferIsValid(), fb(), GetBufferDescriptor(), LockBufHdr(), PageGetLSN(), UnlockBufHdr(), and XLogHintBitIsNeeded.

Referenced by _bt_drop_lock_and_maybe_pin(), _bt_killitems(), gistdoinsert(), gistFindPath(), gistkillitems(), gistScanPage(), and SetHintBitsExt().

◆ BufferGetTag()

void BufferGetTag ( Buffer  buffer,
RelFileLocator rlocator,
ForkNumber forknum,
BlockNumber blknum 
)

Definition at line 4490 of file bufmgr.c.

4492{
4494
4495 /* Do the same checks as BufferGetBlockNumber. */
4496 Assert(BufferIsPinned(buffer));
4497
4498 if (BufferIsLocal(buffer))
4499 bufHdr = GetLocalBufferDescriptor(-buffer - 1);
4500 else
4501 bufHdr = GetBufferDescriptor(buffer - 1);
4502
4503 /* pinned, so OK to read tag without spinlock */
4504 *rlocator = BufTagGetRelFileLocator(&bufHdr->tag);
4505 *forknum = BufTagGetForkNum(&bufHdr->tag);
4506 *blknum = bufHdr->tag.blockNum;
4507}

References Assert, PrivateRefCountEntry::buffer, BufferIsLocal, BufferIsPinned, BufTagGetForkNum(), BufTagGetRelFileLocator(), fb(), GetBufferDescriptor(), and GetLocalBufferDescriptor().

Referenced by fsm_search_avail(), ginRedoInsertEntry(), heap_inplace_update_and_unlock(), log_newpage_buffer(), ResolveCminCmaxDuringDecoding(), and XLogRegisterBuffer().

◆ BufferIsDirty()

bool BufferIsDirty ( Buffer  buffer)

◆ BufferIsLockedByMe()

bool BufferIsLockedByMe ( Buffer  buffer)

Definition at line 3084 of file bufmgr.c.

3085{
3087
3088 Assert(BufferIsPinned(buffer));
3089
3090 if (BufferIsLocal(buffer))
3091 {
3092 /* Content locks are not maintained for local buffers. */
3093 return true;
3094 }
3095 else
3096 {
3097 bufHdr = GetBufferDescriptor(buffer - 1);
3098 return BufferLockHeldByMe(bufHdr);
3099 }
3100}

References Assert, PrivateRefCountEntry::buffer, BufferIsLocal, BufferIsPinned, BufferLockHeldByMe(), fb(), and GetBufferDescriptor().

Referenced by FlushOneBuffer().

◆ BufferIsLockedByMeInMode()

bool BufferIsLockedByMeInMode ( Buffer  buffer,
BufferLockMode  mode 
)

Definition at line 3110 of file bufmgr.c.

3111{
3113
3114 Assert(BufferIsPinned(buffer));
3115
3116 if (BufferIsLocal(buffer))
3117 {
3118 /* Content locks are not maintained for local buffers. */
3119 return true;
3120 }
3121 else
3122 {
3123 bufHdr = GetBufferDescriptor(buffer - 1);
3125 }
3126}
static bool BufferLockHeldByMeInMode(BufferDesc *buf_hdr, BufferLockMode mode)
Definition bufmgr.c:6548
static PgChecksumMode mode

References Assert, PrivateRefCountEntry::buffer, BufferIsLocal, BufferIsPinned, BufferLockHeldByMeInMode(), fb(), GetBufferDescriptor(), and mode.

Referenced by BufferFinishSetHintBits(), BufferIsDirty(), heap_page_fix_vm_corruption(), HeapTupleSetHintBits(), IsBufferCleanupOK(), MarkBufferDirty(), visibilitymap_set(), and XLogRegisterBuffer().

◆ BufferIsPermanent()

bool BufferIsPermanent ( Buffer  buffer)

Definition at line 4700 of file bufmgr.c.

4701{
4703
4704 /* Local buffers are used only for temp relations. */
4705 if (BufferIsLocal(buffer))
4706 return false;
4707
4708 /* Make sure we've got a real buffer, and that we hold a pin on it. */
4709 Assert(BufferIsValid(buffer));
4710 Assert(BufferIsPinned(buffer));
4711
4712 /*
4713 * BM_PERMANENT can't be changed while we hold a pin on the buffer, so we
4714 * need not bother with the buffer header spinlock. Even if someone else
4715 * changes the buffer header state while we're doing this, the state is
4716 * changed atomically, so we'll read the old value or the new value, but
4717 * not random garbage.
4718 */
4719 bufHdr = GetBufferDescriptor(buffer - 1);
4720 return (pg_atomic_read_u64(&bufHdr->state) & BM_PERMANENT) != 0;
4721}

References Assert, BM_PERMANENT, PrivateRefCountEntry::buffer, BufferIsLocal, BufferIsPinned, BufferIsValid(), fb(), GetBufferDescriptor(), and pg_atomic_read_u64().

Referenced by SetHintBitsExt().

◆ BufferLockAcquire()

static void BufferLockAcquire ( Buffer  buffer,
BufferDesc buf_hdr,
BufferLockMode  mode 
)
inlinestatic

Definition at line 5921 of file bufmgr.c.

5922{
5923 PrivateRefCountEntry *entry;
5924 int extraWaits = 0;
5925
5926 /*
5927 * Get reference to the refcount entry before we hold the lock, it seems
5928 * better to do before holding the lock.
5929 */
5930 entry = GetPrivateRefCountEntry(buffer, true);
5931
5932 /*
5933 * We better not already hold a lock on the buffer.
5934 */
5936
5937 /*
5938 * Lock out cancel/die interrupts until we exit the code section protected
5939 * by the content lock. This ensures that interrupts will not interfere
5940 * with manipulations of data structures in shared memory.
5941 */
5943
5944 for (;;)
5945 {
5946 uint32 wait_event = 0; /* initialized to avoid compiler warning */
5947 bool mustwait;
5948
5949 /*
5950 * Try to grab the lock the first time, we're not in the waitqueue
5951 * yet/anymore.
5952 */
5954
5955 if (likely(!mustwait))
5956 {
5957 break;
5958 }
5959
5960 /*
5961 * Ok, at this point we couldn't grab the lock on the first try. We
5962 * cannot simply queue ourselves to the end of the list and wait to be
5963 * woken up because by now the lock could long have been released.
5964 * Instead add us to the queue and try to grab the lock again. If we
5965 * succeed we need to revert the queuing and be happy, otherwise we
5966 * recheck the lock. If we still couldn't grab it, we know that the
5967 * other locker will see our queue entries when releasing since they
5968 * existed before we checked for the lock.
5969 */
5970
5971 /* add to the queue */
5973
5974 /* we're now guaranteed to be woken up if necessary */
5976
5977 /* ok, grabbed the lock the second time round, need to undo queueing */
5978 if (!mustwait)
5979 {
5981 break;
5982 }
5983
5984 switch (mode)
5985 {
5988 break;
5991 break;
5992 case BUFFER_LOCK_SHARE:
5994 break;
5995 case BUFFER_LOCK_UNLOCK:
5997
5998 }
6000
6001 /*
6002 * Wait until awakened.
6003 *
6004 * It is possible that we get awakened for a reason other than being
6005 * signaled by BufferLockWakeup(). If so, loop back and wait again.
6006 * Once we've gotten the lock, re-increment the sema by the number of
6007 * additional signals received.
6008 */
6009 for (;;)
6010 {
6013 break;
6014 extraWaits++;
6015 }
6016
6018
6019 /* Retrying, allow BufferLockReleaseSub to release waiters again. */
6021 }
6022
6023 /* Remember that we now hold this lock */
6024 entry->data.lockmode = mode;
6025
6026 /*
6027 * Fix the process wait semaphore's count for any absorbed wakeups.
6028 */
6029 while (unlikely(extraWaits-- > 0))
6031}
static uint64 pg_atomic_fetch_and_u64(volatile pg_atomic_uint64 *ptr, uint64 and_)
Definition atomics.h:546
#define BM_LOCK_WAKE_IN_PROGRESS
static bool BufferLockAttempt(BufferDesc *buf_hdr, BufferLockMode mode)
Definition bufmgr.c:6119
static void BufferLockDequeueSelf(BufferDesc *buf_hdr)
Definition bufmgr.c:6226
static void BufferLockQueueSelf(BufferDesc *buf_hdr, BufferLockMode mode)
Definition bufmgr.c:6186
static PrivateRefCountEntry * GetPrivateRefCountEntry(Buffer buffer, bool do_move)
Definition bufmgr.c:507
@ BUFFER_LOCK_SHARE
Definition bufmgr.h:212
@ BUFFER_LOCK_UNLOCK
Definition bufmgr.h:207
#define likely(x)
Definition c.h:496
@ LW_WS_NOT_WAITING
Definition lwlock.h:30
#define HOLD_INTERRUPTS()
Definition miscadmin.h:136
void PGSemaphoreUnlock(PGSemaphore sema)
Definition posix_sema.c:333
void PGSemaphoreLock(PGSemaphore sema)
Definition posix_sema.c:313
PGPROC * MyProc
Definition proc.c:71
PGSemaphore sem
Definition proc.h:258
uint8 lwWaiting
Definition proc.h:283
BufferLockMode lockmode
Definition bufmgr.c:112
PrivateRefCountData data
Definition bufmgr.c:130
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition wait_event.h:67
static void pgstat_report_wait_end(void)
Definition wait_event.h:83

References Assert, BM_LOCK_WAKE_IN_PROGRESS, PrivateRefCountEntry::buffer, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_SHARE, BUFFER_LOCK_SHARE_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferLockAttempt(), BufferLockDequeueSelf(), BufferLockQueueSelf(), PrivateRefCountEntry::data, fb(), GetPrivateRefCountEntry(), HOLD_INTERRUPTS, likely, PrivateRefCountData::lockmode, LW_WS_NOT_WAITING, PGPROC::lwWaiting, mode, MyProc, pg_atomic_fetch_and_u64(), pg_unreachable, PGSemaphoreLock(), PGSemaphoreUnlock(), pgstat_report_wait_end(), pgstat_report_wait_start(), PGPROC::sem, and unlikely.

Referenced by FlushUnlockedBuffer(), LockBufferInternal(), and MarkDirtyUnpinnedBufferInternal().

◆ BufferLockAttempt()

static bool BufferLockAttempt ( BufferDesc buf_hdr,
BufferLockMode  mode 
)
inlinestatic

Definition at line 6119 of file bufmgr.c.

6120{
6122
6123 /*
6124 * Read once outside the loop, later iterations will get the newer value
6125 * via compare & exchange.
6126 */
6128
6129 /* loop until we've determined whether we could acquire the lock or not */
6130 while (true)
6131 {
6133 bool lock_free;
6134
6136
6138 {
6139 lock_free = (old_state & BM_LOCK_MASK) == 0;
6140 if (lock_free)
6142 }
6144 {
6146 if (lock_free)
6148 }
6149 else
6150 {
6152 if (lock_free)
6154 }
6155
6156 /*
6157 * Attempt to swap in the state we are expecting. If we didn't see
6158 * lock to be free, that's just the old value. If we saw it as free,
6159 * we'll attempt to mark it acquired. The reason that we always swap
6160 * in the value is that this doubles as a memory barrier. We could try
6161 * to be smarter and only swap in values if we saw the lock as free,
6162 * but benchmark haven't shown it as beneficial so far.
6163 *
6164 * Retry if the value changed since we last looked at it.
6165 */
6168 {
6169 if (lock_free)
6170 {
6171 /* Great! Got the lock. */
6172 return false;
6173 }
6174 else
6175 return true; /* somebody else has the lock */
6176 }
6177 }
6178
6180}
static bool pg_atomic_compare_exchange_u64(volatile pg_atomic_uint64 *ptr, uint64 *expected, uint64 newval)
Definition atomics.h:517
#define BM_LOCK_VAL_SHARED
#define BM_LOCK_VAL_EXCLUSIVE
#define BM_LOCK_MASK
#define BM_LOCK_VAL_SHARE_EXCLUSIVE

References BM_LOCK_MASK, BM_LOCK_VAL_EXCLUSIVE, BM_LOCK_VAL_SHARE_EXCLUSIVE, BM_LOCK_VAL_SHARED, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_SHARE_EXCLUSIVE, fb(), likely, mode, pg_atomic_compare_exchange_u64(), pg_atomic_read_u64(), and pg_unreachable.

Referenced by BufferLockAcquire(), and BufferLockConditional().

◆ BufferLockConditional()

static bool BufferLockConditional ( Buffer  buffer,
BufferDesc buf_hdr,
BufferLockMode  mode 
)
static

Definition at line 6073 of file bufmgr.c.

6074{
6075 PrivateRefCountEntry *entry = GetPrivateRefCountEntry(buffer, true);
6076 bool mustwait;
6077
6078 /*
6079 * As described above, if we're trying to lock a buffer this backend
6080 * already has locked, return false, independent of the existing and
6081 * desired lock level.
6082 */
6083 if (entry->data.lockmode != BUFFER_LOCK_UNLOCK)
6084 return false;
6085
6086 /*
6087 * Lock out cancel/die interrupts until we exit the code section protected
6088 * by the content lock. This ensures that interrupts will not interfere
6089 * with manipulations of data structures in shared memory.
6090 */
6092
6093 /* Check for the lock */
6095
6096 if (mustwait)
6097 {
6098 /* Failed to get lock, so release interrupt holdoff */
6100 }
6101 else
6102 {
6103 entry->data.lockmode = mode;
6104 }
6105
6106 return !mustwait;
6107}
#define RESUME_INTERRUPTS()
Definition miscadmin.h:138

References PrivateRefCountEntry::buffer, BUFFER_LOCK_UNLOCK, BufferLockAttempt(), PrivateRefCountEntry::data, fb(), GetPrivateRefCountEntry(), HOLD_INTERRUPTS, PrivateRefCountData::lockmode, mode, and RESUME_INTERRUPTS.

Referenced by ConditionalLockBuffer(), and GetVictimBuffer().

◆ BufferLockDequeueSelf()

static void BufferLockDequeueSelf ( BufferDesc buf_hdr)
static

Definition at line 6226 of file bufmgr.c.

6227{
6228 bool on_waitlist;
6229
6231
6233 if (on_waitlist)
6234 proclist_delete(&buf_hdr->lock_waiters, MyProcNumber, lwWaitLink);
6235
6236 if (proclist_is_empty(&buf_hdr->lock_waiters) &&
6238 {
6240 }
6241
6242 /* XXX: combine with fetch_and above? */
6244
6245 /* clear waiting state again, nice for debugging */
6246 if (on_waitlist)
6248 else
6249 {
6250 int extraWaits = 0;
6251
6252
6253 /*
6254 * Somebody else dequeued us and has or will wake us up. Deal with the
6255 * superfluous absorption of a wakeup.
6256 */
6257
6258 /*
6259 * Clear BM_LOCK_WAKE_IN_PROGRESS if somebody woke us before we
6260 * removed ourselves - they'll have set it.
6261 */
6263
6264 /*
6265 * Now wait for the scheduled wakeup, otherwise our ->lwWaiting would
6266 * get reset at some inconvenient point later. Most of the time this
6267 * will immediately return.
6268 */
6269 for (;;)
6270 {
6273 break;
6274 extraWaits++;
6275 }
6276
6277 /*
6278 * Fix the process wait semaphore's count for any absorbed wakeups.
6279 */
6280 while (extraWaits-- > 0)
6282 }
6283}
#define BM_LOCK_HAS_WAITERS
@ LW_WS_WAITING
Definition lwlock.h:31
#define proclist_delete(list, procno, link_member)
Definition proclist.h:187
static bool proclist_is_empty(const proclist_head *list)
Definition proclist.h:38

References BM_LOCK_HAS_WAITERS, BM_LOCK_WAKE_IN_PROGRESS, fb(), LockBufHdr(), LW_WS_NOT_WAITING, LW_WS_WAITING, PGPROC::lwWaiting, MyProc, MyProcNumber, pg_atomic_fetch_and_u64(), pg_atomic_read_u64(), PGSemaphoreLock(), PGSemaphoreUnlock(), proclist_delete, proclist_is_empty(), PGPROC::sem, and UnlockBufHdr().

Referenced by BufferLockAcquire().

◆ BufferLockDisown()

static void BufferLockDisown ( Buffer  buffer,
BufferDesc buf_hdr 
)
inlinestatic

Definition at line 6294 of file bufmgr.c.

6295{
6298}
static int BufferLockDisownInternal(Buffer buffer, BufferDesc *buf_hdr)
Definition bufmgr.c:6308

References PrivateRefCountEntry::buffer, BufferLockDisownInternal(), fb(), and RESUME_INTERRUPTS.

Referenced by buffer_stage_common().

◆ BufferLockDisownInternal()

static int BufferLockDisownInternal ( Buffer  buffer,
BufferDesc buf_hdr 
)
inlinestatic

Definition at line 6308 of file bufmgr.c.

6309{
6312
6313 ref = GetPrivateRefCountEntry(buffer, false);
6314 if (ref == NULL)
6315 elog(ERROR, "lock %d is not held", buffer);
6316 mode = ref->data.lockmode;
6317 ref->data.lockmode = BUFFER_LOCK_UNLOCK;
6318
6319 return mode;
6320}
BufferLockMode
Definition bufmgr.h:206
#define ERROR
Definition elog.h:40

References PrivateRefCountEntry::buffer, BUFFER_LOCK_UNLOCK, elog, ERROR, fb(), GetPrivateRefCountEntry(), and mode.

Referenced by BufferLockDisown(), BufferLockUnlock(), and UnlockReleaseBuffer().

◆ BufferLockHeldByMe()

static bool BufferLockHeldByMe ( BufferDesc buf_hdr)
static

Definition at line 6566 of file bufmgr.c.

6567{
6568 PrivateRefCountEntry *entry =
6570
6571 if (!entry)
6572 return false;
6573 else
6574 return entry->data.lockmode != BUFFER_LOCK_UNLOCK;
6575}
static Buffer BufferDescriptorGetBuffer(const BufferDesc *bdesc)

References BUFFER_LOCK_UNLOCK, BufferDescriptorGetBuffer(), PrivateRefCountEntry::data, fb(), GetPrivateRefCountEntry(), and PrivateRefCountData::lockmode.

Referenced by buffer_stage_common(), BufferIsLockedByMe(), and UnpinBufferNoOwner().

◆ BufferLockHeldByMeInMode()

static bool BufferLockHeldByMeInMode ( BufferDesc buf_hdr,
BufferLockMode  mode 
)
static

Definition at line 6548 of file bufmgr.c.

6549{
6550 PrivateRefCountEntry *entry =
6552
6553 if (!entry)
6554 return false;
6555 else
6556 return entry->data.lockmode == mode;
6557}

References BufferDescriptorGetBuffer(), PrivateRefCountEntry::data, fb(), GetPrivateRefCountEntry(), PrivateRefCountData::lockmode, and mode.

Referenced by BufferIsLockedByMeInMode(), FlushBuffer(), and MarkSharedBufferDirtyHint().

◆ BufferLockProcessRelease()

static void BufferLockProcessRelease ( BufferDesc buf_hdr,
BufferLockMode  mode,
uint64  lockstate 
)
static

Definition at line 6493 of file bufmgr.c.

6494{
6495 bool check_waiters = false;
6496 bool wake_exclusive = false;
6497
6498 /* nobody else can have that kind of lock */
6500
6501 /*
6502 * If we're still waiting for backends to get scheduled, don't wake them
6503 * up again. Otherwise check if we need to look through the waitqueue to
6504 * wake other backends.
6505 */
6508 {
6509 if ((lockstate & BM_LOCK_MASK) == 0)
6510 {
6511 /*
6512 * We released a lock and the lock was, in that moment, free. We
6513 * therefore can wake waiters for any kind of lock.
6514 */
6515 check_waiters = true;
6516 wake_exclusive = true;
6517 }
6519 {
6520 /*
6521 * We released the lock, but another backend still holds a lock.
6522 * We can't have released an exclusive lock, as there couldn't
6523 * have been other lock holders. If we released a share lock, no
6524 * waiters need to be woken up, as there must be other share
6525 * lockers. However, if we held a share-exclusive lock, another
6526 * backend now could acquire a share-exclusive lock.
6527 */
6528 check_waiters = true;
6529 wake_exclusive = false;
6530 }
6531 }
6532
6533 /*
6534 * As waking up waiters requires the spinlock to be acquired, only do so
6535 * if necessary.
6536 */
6537 if (check_waiters)
6539}
static void BufferLockWakeup(BufferDesc *buf_hdr, bool wake_exclusive)
Definition bufmgr.c:6328

References Assert, BM_LOCK_HAS_WAITERS, BM_LOCK_MASK, BM_LOCK_VAL_EXCLUSIVE, BM_LOCK_WAKE_IN_PROGRESS, BUFFER_LOCK_SHARE_EXCLUSIVE, BufferLockWakeup(), fb(), and mode.

Referenced by BufferLockUnlock(), and UnlockReleaseBuffer().

◆ BufferLockQueueSelf()

static void BufferLockQueueSelf ( BufferDesc buf_hdr,
BufferLockMode  mode 
)
static

Definition at line 6186 of file bufmgr.c.

6187{
6188 /*
6189 * If we don't have a PGPROC structure, there's no way to wait. This
6190 * should never occur, since MyProc should only be null during shared
6191 * memory initialization.
6192 */
6193 if (MyProc == NULL)
6194 elog(PANIC, "cannot wait without a PGPROC structure");
6195
6197 elog(PANIC, "queueing for lock while waiting on another one");
6198
6200
6201 /* setting the flag is protected by the spinlock */
6203
6204 /*
6205 * These are currently used both for lwlocks and buffer content locks,
6206 * which is acceptable, although not pretty, because a backend can't wait
6207 * for both types of locks at the same time.
6208 */
6211
6212 proclist_push_tail(&buf_hdr->lock_waiters, MyProcNumber, lwWaitLink);
6213
6214 /* Can release the mutex now */
6216}
static uint64 pg_atomic_fetch_or_u64(volatile pg_atomic_uint64 *ptr, uint64 or_)
Definition atomics.h:555
#define PANIC
Definition elog.h:44
#define proclist_push_tail(list, procno, link_member)
Definition proclist.h:191
uint8 lwWaitMode
Definition proc.h:284

References BM_LOCK_HAS_WAITERS, elog, fb(), LockBufHdr(), LW_WS_NOT_WAITING, LW_WS_WAITING, PGPROC::lwWaiting, PGPROC::lwWaitMode, mode, MyProc, MyProcNumber, PANIC, pg_atomic_fetch_or_u64(), proclist_push_tail, and UnlockBufHdr().

Referenced by BufferLockAcquire().

◆ BufferLockReleaseSub()

static uint64 BufferLockReleaseSub ( BufferLockMode  mode)
inlinestatic

Definition at line 6464 of file bufmgr.c.

6465{
6466 /*
6467 * Turns out that a switch() leads gcc to generate sufficiently worse code
6468 * for this to show up in profiles...
6469 */
6471 return BM_LOCK_VAL_EXCLUSIVE;
6474 else
6475 {
6477 return BM_LOCK_VAL_SHARED;
6478 }
6479
6480 return 0; /* keep compiler quiet */
6481}

References Assert, BM_LOCK_VAL_EXCLUSIVE, BM_LOCK_VAL_SHARE_EXCLUSIVE, BM_LOCK_VAL_SHARED, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_SHARE, BUFFER_LOCK_SHARE_EXCLUSIVE, and mode.

Referenced by BufferLockUnlock(), and UnlockReleaseBuffer().

◆ BufferLockUnlock()

static void BufferLockUnlock ( Buffer  buffer,
BufferDesc buf_hdr 
)
static

Definition at line 6037 of file bufmgr.c.

6038{
6041 uint64 sub;
6042
6044
6045 /*
6046 * Release my hold on lock, after that it can immediately be acquired by
6047 * others, even if we still have to wakeup other waiters.
6048 */
6050
6052
6054
6055 /*
6056 * Now okay to allow cancel/die interrupts.
6057 */
6059}
static uint64 pg_atomic_sub_fetch_u64(volatile pg_atomic_uint64 *ptr, int64 sub_)
Definition atomics.h:573
static void BufferLockProcessRelease(BufferDesc *buf_hdr, BufferLockMode mode, uint64 lockstate)
Definition bufmgr.c:6493
static uint64 BufferLockReleaseSub(BufferLockMode mode)
Definition bufmgr.c:6464

References PrivateRefCountEntry::buffer, BufferLockDisownInternal(), BufferLockProcessRelease(), BufferLockReleaseSub(), fb(), mode, pg_atomic_sub_fetch_u64(), and RESUME_INTERRUPTS.

Referenced by FlushUnlockedBuffer(), MarkDirtyUnpinnedBufferInternal(), ResOwnerReleaseBuffer(), and UnlockBuffer().

◆ BufferLockWakeup()

static void BufferLockWakeup ( BufferDesc buf_hdr,
bool  wake_exclusive 
)
static

Definition at line 6328 of file bufmgr.c.

6329{
6330 bool new_wake_in_progress = false;
6331 bool wake_share_exclusive = true;
6334
6336
6337 /* lock wait list while collecting backends to wake up */
6339
6340 proclist_foreach_modify(iter, &buf_hdr->lock_waiters, lwWaitLink)
6341 {
6342 PGPROC *waiter = GetPGProcByNumber(iter.cur);
6343
6344 /*
6345 * Already woke up a conflicting lock, so skip over this wait list
6346 * entry.
6347 */
6349 continue;
6351 continue;
6352
6353 proclist_delete(&buf_hdr->lock_waiters, iter.cur, lwWaitLink);
6354 proclist_push_tail(&wakeup, iter.cur, lwWaitLink);
6355
6356 /*
6357 * Prevent additional wakeups until retryer gets to run. Backends that
6358 * are just waiting for the lock to become free don't retry
6359 * automatically.
6360 */
6361 new_wake_in_progress = true;
6362
6363 /*
6364 * Signal that the process isn't on the wait list anymore. This allows
6365 * BufferLockDequeueSelf() to remove itself from the waitlist with a
6366 * proclist_delete(), rather than having to check if it has been
6367 * removed from the list.
6368 */
6369 Assert(waiter->lwWaiting == LW_WS_WAITING);
6371
6372 /*
6373 * Don't wakeup further waiters after waking a conflicting waiter.
6374 */
6375 if (waiter->lwWaitMode == BUFFER_LOCK_SHARE)
6376 {
6377 /*
6378 * Share locks conflict with exclusive locks.
6379 */
6380 wake_exclusive = false;
6381 }
6382 else if (waiter->lwWaitMode == BUFFER_LOCK_SHARE_EXCLUSIVE)
6383 {
6384 /*
6385 * Share-exclusive locks conflict with share-exclusive and
6386 * exclusive locks.
6387 */
6388 wake_exclusive = false;
6389 wake_share_exclusive = false;
6390 }
6391 else if (waiter->lwWaitMode == BUFFER_LOCK_EXCLUSIVE)
6392 {
6393 /*
6394 * Exclusive locks conflict with all other locks, there's no point
6395 * in waking up anybody else.
6396 */
6397 break;
6398 }
6399 }
6400
6402
6403 /* unset required flags, and release lock, in one fell swoop */
6404 {
6407
6409 while (true)
6410 {
6412
6413 /* compute desired flags */
6414
6417 else
6419
6420 if (proclist_is_empty(&buf_hdr->lock_waiters))
6422
6423 desired_state &= ~BM_LOCKED; /* release lock */
6424
6427 break;
6428 }
6429 }
6430
6431 /* Awaken any waiters I removed from the queue. */
6432 proclist_foreach_modify(iter, &wakeup, lwWaitLink)
6433 {
6434 PGPROC *waiter = GetPGProcByNumber(iter.cur);
6435
6436 proclist_delete(&wakeup, iter.cur, lwWaitLink);
6437
6438 /*
6439 * Guarantee that lwWaiting being unset only becomes visible once the
6440 * unlink from the link has completed. Otherwise the target backend
6441 * could be woken up for other reason and enqueue for a new lock - if
6442 * that happens before the list unlink happens, the list would end up
6443 * being corrupted.
6444 *
6445 * The barrier pairs with the LockBufHdr() when enqueuing for another
6446 * lock.
6447 */
6449 waiter->lwWaiting = LW_WS_NOT_WAITING;
6450 PGSemaphoreUnlock(waiter->sem);
6451 }
6452}
#define pg_write_barrier()
Definition atomics.h:155
@ LW_WS_PENDING_WAKEUP
Definition lwlock.h:32
#define GetPGProcByNumber(n)
Definition proc.h:504
static void proclist_init(proclist_head *list)
Definition proclist.h:29
#define proclist_foreach_modify(iter, lhead, link_member)
Definition proclist.h:206
Definition proc.h:179
static TimestampTz wakeup[NUM_WALRCV_WAKEUPS]

References Assert, BM_LOCK_HAS_WAITERS, BM_LOCK_WAKE_IN_PROGRESS, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_SHARE, BUFFER_LOCK_SHARE_EXCLUSIVE, proclist_mutable_iter::cur, fb(), GetPGProcByNumber, LockBufHdr(), LW_WS_NOT_WAITING, LW_WS_PENDING_WAKEUP, LW_WS_WAITING, PGPROC::lwWaiting, PGPROC::lwWaitMode, pg_atomic_compare_exchange_u64(), pg_atomic_read_u64(), pg_write_barrier, PGSemaphoreUnlock(), proclist_delete, proclist_foreach_modify, proclist_init(), proclist_is_empty(), proclist_push_tail, PGPROC::sem, and wakeup.

Referenced by BufferLockProcessRelease().

◆ BufferSetHintBits16()

bool BufferSetHintBits16 ( uint16 ptr,
uint16  val,
Buffer  buffer 
)

Definition at line 7142 of file bufmgr.c.

7143{
7146#ifdef USE_ASSERT_CHECKING
7147 char *page;
7148
7149 /* verify that the address is on the page */
7150 page = BufferGetPage(buffer);
7151 Assert((char *) ptr >= page && (char *) ptr < (page + BLCKSZ));
7152#endif
7153
7154 if (BufferIsLocal(buffer))
7155 {
7156 *ptr = val;
7157
7158 MarkLocalBufferDirty(buffer);
7159
7160 return true;
7161 }
7162
7163 buf_hdr = GetBufferDescriptor(buffer - 1);
7164
7166 {
7167 *ptr = val;
7168
7170
7171 return true;
7172 }
7173
7174 return false;
7175}
static void MarkSharedBufferDirtyHint(Buffer buffer, BufferDesc *bufHdr, uint64 lockstate, bool buffer_std)
Definition bufmgr.c:5719
long val
Definition informix.c:689
void MarkLocalBufferDirty(Buffer buffer)
Definition localbuf.c:500

References Assert, PrivateRefCountEntry::buffer, BufferGetPage(), BufferIsLocal, fb(), GetBufferDescriptor(), MarkLocalBufferDirty(), MarkSharedBufferDirtyHint(), SharedBufferBeginSetHintBits(), and val.

Referenced by SetHintBitsExt().

◆ BufferSync()

static void BufferSync ( int  flags)
static

Definition at line 3575 of file bufmgr.c.

3576{
3578 int buf_id;
3579 int num_to_scan;
3580 int num_spaces;
3581 int num_processed;
3582 int num_written;
3584 Oid last_tsid;
3586 int i;
3587 uint64 mask = BM_DIRTY;
3589
3590 /*
3591 * Unless this is a shutdown checkpoint or we have been explicitly told,
3592 * we write only permanent, dirty buffers. But at shutdown or end of
3593 * recovery, we write all dirty buffers.
3594 */
3597 mask |= BM_PERMANENT;
3598
3599 /*
3600 * Loop over all buffers, and mark the ones that need to be written with
3601 * BM_CHECKPOINT_NEEDED. Count them as we go (num_to_scan), so that we
3602 * can estimate how much work needs to be done.
3603 *
3604 * This allows us to write only those pages that were dirty when the
3605 * checkpoint began, and not those that get dirtied while it proceeds.
3606 * Whenever a page with BM_CHECKPOINT_NEEDED is written out, either by us
3607 * later in this function, or by normal backends or the bgwriter cleaning
3608 * scan, the flag is cleared. Any buffer dirtied after this point won't
3609 * have the flag set.
3610 *
3611 * Note that if we fail to write some buffer, we may leave buffers with
3612 * BM_CHECKPOINT_NEEDED still set. This is OK since any such buffer would
3613 * certainly need to be written for the next checkpoint attempt, too.
3614 */
3615 num_to_scan = 0;
3616 for (buf_id = 0; buf_id < NBuffers; buf_id++)
3617 {
3619 uint64 set_bits = 0;
3620
3621 /*
3622 * Header spinlock is enough to examine BM_DIRTY, see comment in
3623 * SyncOneBuffer.
3624 */
3626
3627 if ((buf_state & mask) == mask)
3628 {
3629 CkptSortItem *item;
3630
3632
3633 item = &CkptBufferIds[num_to_scan++];
3634 item->buf_id = buf_id;
3635 item->tsId = bufHdr->tag.spcOid;
3636 item->relNumber = BufTagGetRelNumber(&bufHdr->tag);
3637 item->forkNum = BufTagGetForkNum(&bufHdr->tag);
3638 item->blockNum = bufHdr->tag.blockNum;
3639 }
3640
3642 set_bits, 0,
3643 0);
3644
3645 /* Check for barrier events in case NBuffers is large. */
3648 }
3649
3650 if (num_to_scan == 0)
3651 return; /* nothing to do */
3652
3654
3656
3657 /*
3658 * Sort buffers that need to be written to reduce the likelihood of random
3659 * IO. The sorting is also important for the implementation of balancing
3660 * writes between tablespaces. Without balancing writes we'd potentially
3661 * end up writing to the tablespaces one-by-one; possibly overloading the
3662 * underlying system.
3663 */
3665
3666 num_spaces = 0;
3667
3668 /*
3669 * Allocate progress status for each tablespace with buffers that need to
3670 * be flushed. This requires the to-be-flushed array to be sorted.
3671 */
3673 for (i = 0; i < num_to_scan; i++)
3674 {
3675 CkptTsStatus *s;
3676 Oid cur_tsid;
3677
3679
3680 /*
3681 * Grow array of per-tablespace status structs, every time a new
3682 * tablespace is found.
3683 */
3685 {
3686 Size sz;
3687
3688 num_spaces++;
3689
3690 /*
3691 * Not worth adding grow-by-power-of-2 logic here - even with a
3692 * few hundred tablespaces this should be fine.
3693 */
3694 sz = sizeof(CkptTsStatus) * num_spaces;
3695
3696 if (per_ts_stat == NULL)
3698 else
3700
3701 s = &per_ts_stat[num_spaces - 1];
3702 memset(s, 0, sizeof(*s));
3703 s->tsId = cur_tsid;
3704
3705 /*
3706 * The first buffer in this tablespace. As CkptBufferIds is sorted
3707 * by tablespace all (s->num_to_scan) buffers in this tablespace
3708 * will follow afterwards.
3709 */
3710 s->index = i;
3711
3712 /*
3713 * progress_slice will be determined once we know how many buffers
3714 * are in each tablespace, i.e. after this loop.
3715 */
3716
3718 }
3719 else
3720 {
3721 s = &per_ts_stat[num_spaces - 1];
3722 }
3723
3724 s->num_to_scan++;
3725
3726 /* Check for barrier events. */
3729 }
3730
3731 Assert(num_spaces > 0);
3732
3733 /*
3734 * Build a min-heap over the write-progress in the individual tablespaces,
3735 * and compute how large a portion of the total progress a single
3736 * processed buffer is.
3737 */
3740 NULL);
3741
3742 for (i = 0; i < num_spaces; i++)
3743 {
3745
3746 ts_stat->progress_slice = (float8) num_to_scan / ts_stat->num_to_scan;
3747
3749 }
3750
3752
3753 /*
3754 * Iterate through to-be-checkpointed buffers and write the ones (still)
3755 * marked with BM_CHECKPOINT_NEEDED. The writes are balanced between
3756 * tablespaces; otherwise the sorting would lead to only one tablespace
3757 * receiving writes at a time, making inefficient use of the hardware.
3758 */
3759 num_processed = 0;
3760 num_written = 0;
3761 while (!binaryheap_empty(ts_heap))
3762 {
3766
3767 buf_id = CkptBufferIds[ts_stat->index].buf_id;
3768 Assert(buf_id != -1);
3769
3770 bufHdr = GetBufferDescriptor(buf_id);
3771
3772 num_processed++;
3773
3774 /*
3775 * We don't need to acquire the lock here, because we're only looking
3776 * at a single bit. It's possible that someone else writes the buffer
3777 * and clears the flag right after we check, but that doesn't matter
3778 * since SyncOneBuffer will then do nothing. However, there is a
3779 * further race condition: it's conceivable that between the time we
3780 * examine the bit here and the time SyncOneBuffer acquires the lock,
3781 * someone else not only wrote the buffer but replaced it with another
3782 * page and dirtied it. In that improbable case, SyncOneBuffer will
3783 * write the buffer though we didn't need to. It doesn't seem worth
3784 * guarding against this, though.
3785 */
3787 {
3788 if (SyncOneBuffer(buf_id, false, &wb_context) & BUF_WRITTEN)
3789 {
3792 num_written++;
3793 }
3794 }
3795
3796 /*
3797 * Measure progress independent of actually having to flush the buffer
3798 * - otherwise writing become unbalanced.
3799 */
3800 ts_stat->progress += ts_stat->progress_slice;
3801 ts_stat->num_scanned++;
3802 ts_stat->index++;
3803
3804 /* Have all the buffers from the tablespace been processed? */
3805 if (ts_stat->num_scanned == ts_stat->num_to_scan)
3806 {
3808 }
3809 else
3810 {
3811 /* update heap with the new progress */
3813 }
3814
3815 /*
3816 * Sleep to throttle our I/O rate.
3817 *
3818 * (This will check for barrier events even if it doesn't sleep.)
3819 */
3820 CheckpointWriteDelay(flags, (double) num_processed / num_to_scan);
3821 }
3822
3823 /*
3824 * Issue all pending flushes. Only checkpointer calls BufferSync(), so
3825 * IOContext will always be IOCONTEXT_NORMAL.
3826 */
3828
3830 per_ts_stat = NULL;
3832
3833 /*
3834 * Update checkpoint statistics. As noted above, this doesn't include
3835 * buffers written by other backends or bgwriter scan.
3836 */
3838
3840}
void binaryheap_build(binaryheap *heap)
Definition binaryheap.c:136
void binaryheap_replace_first(binaryheap *heap, bh_node_type d)
Definition binaryheap.c:253
bh_node_type binaryheap_first(binaryheap *heap)
Definition binaryheap.c:175
bh_node_type binaryheap_remove_first(binaryheap *heap)
Definition binaryheap.c:190
void binaryheap_free(binaryheap *heap)
Definition binaryheap.c:73
void binaryheap_add_unordered(binaryheap *heap, bh_node_type d)
Definition binaryheap.c:114
binaryheap * binaryheap_allocate(int capacity, binaryheap_comparator compare, void *arg)
Definition binaryheap.c:37
#define binaryheap_empty(h)
Definition binaryheap.h:65
CkptSortItem * CkptBufferIds
Definition buf_init.c:28
static RelFileNumber BufTagGetRelNumber(const BufferTag *tag)
#define BM_CHECKPOINT_NEEDED
static int ts_ckpt_progress_comparator(Datum a, Datum b, void *arg)
Definition bufmgr.c:7704
int checkpoint_flush_after
Definition bufmgr.c:223
void WritebackContextInit(WritebackContext *context, int *max_pending)
Definition bufmgr.c:7727
void IssuePendingWritebacks(WritebackContext *wb_context, IOContext io_context)
Definition bufmgr.c:7789
double float8
Definition c.h:773
size_t Size
Definition c.h:748
void CheckpointWriteDelay(int flags, double progress)
volatile sig_atomic_t ProcSignalBarrierPending
Definition globals.c:40
void * repalloc(void *pointer, Size size)
Definition mcxt.c:1635
void pfree(void *pointer)
Definition mcxt.c:1619
void * palloc(Size size)
Definition mcxt.c:1390
PgStat_CheckpointerStats PendingCheckpointerStats
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
#define PointerGetDatum(X)
Definition postgres.h:354
#define InvalidOid
unsigned int Oid
void ProcessProcSignalBarrier(void)
Definition procsignal.c:511
int ckpt_bufs_written
Definition xlog.h:179
ForkNumber forkNum
RelFileNumber relNumber
BlockNumber blockNum
float8 progress_slice
Definition bufmgr.c:164
int num_to_scan
Definition bufmgr.c:167
PgStat_Counter buffers_written
Definition pgstat.h:270
CheckpointStatsData CheckpointStats
Definition xlog.c:216
#define CHECKPOINT_FLUSH_UNLOGGED
Definition xlog.h:155
#define CHECKPOINT_END_OF_RECOVERY
Definition xlog.h:152
#define CHECKPOINT_IS_SHUTDOWN
Definition xlog.h:151

References Assert, binaryheap_add_unordered(), binaryheap_allocate(), binaryheap_build(), binaryheap_empty, binaryheap_first(), binaryheap_free(), binaryheap_remove_first(), binaryheap_replace_first(), CkptSortItem::blockNum, BM_CHECKPOINT_NEEDED, BM_DIRTY, BM_PERMANENT, CkptSortItem::buf_id, BUF_WRITTEN, PgStat_CheckpointerStats::buffers_written, BufTagGetForkNum(), BufTagGetRelNumber(), CHECKPOINT_END_OF_RECOVERY, checkpoint_flush_after, CHECKPOINT_FLUSH_UNLOGGED, CHECKPOINT_IS_SHUTDOWN, CheckpointStats, CheckpointWriteDelay(), CheckpointStatsData::ckpt_bufs_written, CkptBufferIds, DatumGetPointer(), fb(), CkptSortItem::forkNum, GetBufferDescriptor(), i, CkptTsStatus::index, InvalidOid, IOCONTEXT_NORMAL, IssuePendingWritebacks(), LockBufHdr(), NBuffers, CkptTsStatus::num_to_scan, palloc(), PendingCheckpointerStats, pfree(), pg_atomic_read_u64(), PointerGetDatum, ProcessProcSignalBarrier(), ProcSignalBarrierPending, CkptTsStatus::progress_slice, CkptSortItem::relNumber, repalloc(), SyncOneBuffer(), ts_ckpt_progress_comparator(), CkptTsStatus::tsId, CkptSortItem::tsId, UnlockBufHdrExt(), and WritebackContextInit().

Referenced by CheckPointBuffers().

◆ buffertag_comparator()

static int buffertag_comparator ( const BufferTag ba,
const BufferTag bb 
)
inlinestatic

Definition at line 7639 of file bufmgr.c.

7640{
7641 int ret;
7644
7647
7649
7650 if (ret != 0)
7651 return ret;
7652
7654 return -1;
7656 return 1;
7657
7658 if (ba->blockNum < bb->blockNum)
7659 return -1;
7660 if (ba->blockNum > bb->blockNum)
7661 return 1;
7662
7663 return 0;
7664}
static int rlocator_comparator(const void *p1, const void *p2)
Definition bufmgr.c:7540

References BufTagGetForkNum(), BufTagGetRelFileLocator(), fb(), and rlocator_comparator().

◆ CheckBufferIsPinnedOnce()

void CheckBufferIsPinnedOnce ( Buffer  buffer)

Definition at line 6660 of file bufmgr.c.

6661{
6662 if (BufferIsLocal(buffer))
6663 {
6664 if (LocalRefCount[-buffer - 1] != 1)
6665 elog(ERROR, "incorrect local pin count: %d",
6666 LocalRefCount[-buffer - 1]);
6667 }
6668 else
6669 {
6670 if (GetPrivateRefCount(buffer) != 1)
6671 elog(ERROR, "incorrect local pin count: %d",
6672 GetPrivateRefCount(buffer));
6673 }
6674}

References PrivateRefCountEntry::buffer, BufferIsLocal, elog, ERROR, GetPrivateRefCount(), and LocalRefCount.

Referenced by GetVictimBuffer(), lazy_scan_heap(), and LockBufferForCleanup().

◆ CheckForBufferLeaks()

static void CheckForBufferLeaks ( void  )
static

Definition at line 4286 of file bufmgr.c.

4287{
4288#ifdef USE_ASSERT_CHECKING
4289 int RefCountErrors = 0;
4291 int i;
4292 char *s;
4293
4294 /* check the array */
4295 for (i = 0; i < REFCOUNT_ARRAY_ENTRIES; i++)
4296 {
4298 {
4299 res = &PrivateRefCountArray[i];
4300
4302 elog(WARNING, "buffer refcount leak: %s", s);
4303 pfree(s);
4304
4306 }
4307 }
4308
4309 /* if necessary search the hash */
4311 {
4312 refcount_iterator iter;
4313
4315 while ((res = refcount_iterate(PrivateRefCountHash, &iter)) != NULL)
4316 {
4318 elog(WARNING, "buffer refcount leak: %s", s);
4319 pfree(s);
4321 }
4322 }
4323
4324 Assert(RefCountErrors == 0);
4325#endif
4326}
#define InvalidBuffer
Definition buf.h:25
static Buffer PrivateRefCountArrayKeys[REFCOUNT_ARRAY_ENTRIES]
Definition bufmgr.c:263
static refcount_hash * PrivateRefCountHash
Definition bufmgr.c:265
char * DebugPrintBufferRefcount(Buffer buffer)
Definition bufmgr.c:4412
#define REFCOUNT_ARRAY_ENTRIES
Definition bufmgr.c:145
static struct PrivateRefCountEntry PrivateRefCountArray[REFCOUNT_ARRAY_ENTRIES]
Definition bufmgr.c:264

References Assert, PrivateRefCountEntry::buffer, DebugPrintBufferRefcount(), elog, fb(), i, InvalidBuffer, pfree(), PrivateRefCountArray, PrivateRefCountArrayKeys, PrivateRefCountHash, PrivateRefCountOverflowed, REFCOUNT_ARRAY_ENTRIES, and WARNING.

Referenced by AtEOXact_Buffers(), and AtProcExit_Buffers().

◆ CheckPointBuffers()

void CheckPointBuffers ( int  flags)

Definition at line 4455 of file bufmgr.c.

4456{
4457 BufferSync(flags);
4458}
static void BufferSync(int flags)
Definition bufmgr.c:3575

References BufferSync().

Referenced by CheckPointGuts().

◆ CheckReadBuffersOperation()

static void CheckReadBuffersOperation ( ReadBuffersOperation operation,
bool  is_complete 
)
static

Definition at line 1656 of file bufmgr.c.

1657{
1658#ifdef USE_ASSERT_CHECKING
1659 Assert(operation->nblocks_done <= operation->nblocks);
1660 Assert(!is_complete || operation->nblocks == operation->nblocks_done);
1661
1662 for (int i = 0; i < operation->nblocks; i++)
1663 {
1664 Buffer buffer = operation->buffers[i];
1665 BufferDesc *buf_hdr = BufferIsLocal(buffer) ?
1666 GetLocalBufferDescriptor(-buffer - 1) :
1667 GetBufferDescriptor(buffer - 1);
1668
1669 Assert(BufferGetBlockNumber(buffer) == operation->blocknum + i);
1671
1672 if (i < operation->nblocks_done)
1674 }
1675#endif
1676}

References Assert, BM_TAG_VALID, BM_VALID, PrivateRefCountEntry::buffer, BufferGetBlockNumber(), BufferIsLocal, fb(), GetBufferDescriptor(), GetLocalBufferDescriptor(), i, operation, and pg_atomic_read_u64().

Referenced by StartReadBuffersImpl(), and WaitReadBuffers().

◆ ckpt_buforder_comparator()

static int ckpt_buforder_comparator ( const CkptSortItem a,
const CkptSortItem b 
)
inlinestatic

Definition at line 7673 of file bufmgr.c.

7674{
7675 /* compare tablespace */
7676 if (a->tsId < b->tsId)
7677 return -1;
7678 else if (a->tsId > b->tsId)
7679 return 1;
7680 /* compare relation */
7681 if (a->relNumber < b->relNumber)
7682 return -1;
7683 else if (a->relNumber > b->relNumber)
7684 return 1;
7685 /* compare fork */
7686 else if (a->forkNum < b->forkNum)
7687 return -1;
7688 else if (a->forkNum > b->forkNum)
7689 return 1;
7690 /* compare block number */
7691 else if (a->blockNum < b->blockNum)
7692 return -1;
7693 else if (a->blockNum > b->blockNum)
7694 return 1;
7695 /* equal page IDs are unlikely, but not impossible */
7696 return 0;
7697}
int b
Definition isn.c:74
int a
Definition isn.c:73

References a, and b.

◆ ConditionalLockBuffer()

bool ConditionalLockBuffer ( Buffer  buffer)

Definition at line 6640 of file bufmgr.c.

6641{
6642 BufferDesc *buf;
6643
6644 Assert(BufferIsPinned(buffer));
6645 if (BufferIsLocal(buffer))
6646 return true; /* act as though we got it */
6647
6648 buf = GetBufferDescriptor(buffer - 1);
6649
6651}
static bool BufferLockConditional(Buffer buffer, BufferDesc *buf_hdr, BufferLockMode mode)
Definition bufmgr.c:6073

References Assert, buf, PrivateRefCountEntry::buffer, BUFFER_LOCK_EXCLUSIVE, BufferIsLocal, BufferIsPinned, BufferLockConditional(), and GetBufferDescriptor().

Referenced by _bt_conditionallockbuf(), BloomNewBuffer(), ConditionalLockBufferForCleanup(), GinNewBuffer(), gistNewBuffer(), RelationGetBufferForTuple(), spgdoinsert(), SpGistGetBuffer(), SpGistNewBuffer(), and SpGistUpdateMetaPage().

◆ ConditionalLockBufferForCleanup()

bool ConditionalLockBufferForCleanup ( Buffer  buffer)

Definition at line 6892 of file bufmgr.c.

6893{
6896 refcount;
6897
6898 Assert(BufferIsValid(buffer));
6899
6900 /* see AIO related comment in LockBufferForCleanup() */
6901
6902 if (BufferIsLocal(buffer))
6903 {
6904 refcount = LocalRefCount[-buffer - 1];
6905 /* There should be exactly one pin */
6906 Assert(refcount > 0);
6907 if (refcount != 1)
6908 return false;
6909 /* Nobody else to wait for */
6910 return true;
6911 }
6912
6913 /* There should be exactly one local pin */
6914 refcount = GetPrivateRefCount(buffer);
6915 Assert(refcount);
6916 if (refcount != 1)
6917 return false;
6918
6919 /* Try to acquire lock */
6920 if (!ConditionalLockBuffer(buffer))
6921 return false;
6922
6923 bufHdr = GetBufferDescriptor(buffer - 1);
6926
6927 Assert(refcount > 0);
6928 if (refcount == 1)
6929 {
6930 /* Successfully acquired exclusive lock with pincount 1 */
6932 return true;
6933 }
6934
6935 /* Failed, so release the lock */
6938 return false;
6939}
bool ConditionalLockBuffer(Buffer buffer)
Definition bufmgr.c:6640
static void LockBuffer(Buffer buffer, BufferLockMode mode)
Definition bufmgr.h:334

References Assert, BUF_STATE_GET_REFCOUNT, PrivateRefCountEntry::buffer, BUFFER_LOCK_UNLOCK, BufferIsLocal, BufferIsValid(), ConditionalLockBuffer(), fb(), GetBufferDescriptor(), GetPrivateRefCount(), LocalRefCount, LockBuffer(), LockBufHdr(), and UnlockBufHdr().

Referenced by _hash_finish_split(), _hash_getbuf_with_condlock_cleanup(), heap_page_prune_opt(), and lazy_scan_heap().

◆ CreateAndCopyRelationData()

void CreateAndCopyRelationData ( RelFileLocator  src_rlocator,
RelFileLocator  dst_rlocator,
bool  permanent 
)

Definition at line 5485 of file bufmgr.c.

5487{
5488 char relpersistence;
5491
5492 /* Set the relpersistence. */
5493 relpersistence = permanent ?
5495
5498
5499 /*
5500 * Create and copy all forks of the relation. During create database we
5501 * have a separate cleanup mechanism which deletes complete database
5502 * directory. Therefore, each individual relation doesn't need to be
5503 * registered for cleanup.
5504 */
5505 RelationCreateStorage(dst_rlocator, relpersistence, false);
5506
5507 /* copy main fork. */
5509 permanent);
5510
5511 /* copy those extra forks that exist */
5512 for (ForkNumber forkNum = MAIN_FORKNUM + 1;
5513 forkNum <= MAX_FORKNUM; forkNum++)
5514 {
5515 if (smgrexists(src_rel, forkNum))
5516 {
5517 smgrcreate(dst_rel, forkNum, false);
5518
5519 /*
5520 * WAL log creation if the relation is persistent, or this is the
5521 * init fork of an unlogged relation.
5522 */
5523 if (permanent || forkNum == INIT_FORKNUM)
5524 log_smgrcreate(&dst_rlocator, forkNum);
5525
5526 /* Copy a fork's data, block by block. */
5528 permanent);
5529 }
5530 }
5531}
static void RelationCopyStorageUsingBuffer(RelFileLocator srclocator, RelFileLocator dstlocator, ForkNumber forkNum, bool permanent)
Definition bufmgr.c:5371
@ MAIN_FORKNUM
Definition relpath.h:58
#define MAX_FORKNUM
Definition relpath.h:70
SMgrRelation smgropen(RelFileLocator rlocator, ProcNumber backend)
Definition smgr.c:240
void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
Definition smgr.c:481
bool smgrexists(SMgrRelation reln, ForkNumber forknum)
Definition smgr.c:462
SMgrRelation RelationCreateStorage(RelFileLocator rlocator, char relpersistence, bool register_delete)
Definition storage.c:122
void log_smgrcreate(const RelFileLocator *rlocator, ForkNumber forkNum)
Definition storage.c:187

References fb(), INIT_FORKNUM, INVALID_PROC_NUMBER, log_smgrcreate(), MAIN_FORKNUM, MAX_FORKNUM, RelationCopyStorageUsingBuffer(), RelationCreateStorage(), smgrcreate(), smgrexists(), and smgropen().

Referenced by CreateDatabaseUsingWalLog().

◆ DebugPrintBufferRefcount()

char * DebugPrintBufferRefcount ( Buffer  buffer)

Definition at line 4412 of file bufmgr.c.

4413{
4414 BufferDesc *buf;
4416 char *result;
4417 ProcNumber backend;
4419
4420 Assert(BufferIsValid(buffer));
4421 if (BufferIsLocal(buffer))
4422 {
4423 buf = GetLocalBufferDescriptor(-buffer - 1);
4424 loccount = LocalRefCount[-buffer - 1];
4425 backend = MyProcNumber;
4426 }
4427 else
4428 {
4429 buf = GetBufferDescriptor(buffer - 1);
4430 loccount = GetPrivateRefCount(buffer);
4431 backend = INVALID_PROC_NUMBER;
4432 }
4433
4434 /* theoretically we should lock the bufHdr here */
4435 buf_state = pg_atomic_read_u64(&buf->state);
4436
4437 result = psprintf("[%03d] (rel=%s, blockNum=%u, flags=0x%" PRIx64 ", refcount=%u %d)",
4438 buffer,
4440 BufTagGetForkNum(&buf->tag)).str,
4441 buf->tag.blockNum, buf_state & BUF_FLAG_MASK,
4443 return result;
4444}
#define BUF_FLAG_MASK
char * psprintf(const char *fmt,...)
Definition psprintf.c:43

References Assert, buf, BUF_FLAG_MASK, BUF_STATE_GET_REFCOUNT, PrivateRefCountEntry::buffer, BufferIsLocal, BufferIsValid(), BufTagGetForkNum(), BufTagGetRelFileLocator(), fb(), GetBufferDescriptor(), GetLocalBufferDescriptor(), GetPrivateRefCount(), INVALID_PROC_NUMBER, LocalRefCount, MyProcNumber, pg_atomic_read_u64(), psprintf(), relpathbackend, and result.

Referenced by buffer_call_start_io(), buffer_call_terminate_io(), CheckForBufferLeaks(), CheckForLocalBufferLeaks(), and ResOwnerPrintBuffer().

◆ DropDatabaseBuffers()

void DropDatabaseBuffers ( Oid  dbid)

Definition at line 5138 of file bufmgr.c.

5139{
5140 int i;
5141
5142 /*
5143 * We needn't consider local buffers, since by assumption the target
5144 * database isn't our own.
5145 */
5146
5147 for (i = 0; i < NBuffers; i++)
5148 {
5150
5151 /*
5152 * As in DropRelationBuffers, an unlocked precheck should be safe and
5153 * saves some cycles.
5154 */
5155 if (bufHdr->tag.dbOid != dbid)
5156 continue;
5157
5159 if (bufHdr->tag.dbOid == dbid)
5160 InvalidateBuffer(bufHdr); /* releases spinlock */
5161 else
5163 }
5164}
static void InvalidateBuffer(BufferDesc *buf)
Definition bufmgr.c:2370

References fb(), GetBufferDescriptor(), i, InvalidateBuffer(), LockBufHdr(), NBuffers, and UnlockBufHdr().

Referenced by createdb_failure_callback(), dbase_redo(), dropdb(), and movedb().

◆ DropRelationBuffers()

void DropRelationBuffers ( SMgrRelation  smgr_reln,
ForkNumber forkNum,
int  nforks,
BlockNumber firstDelBlock 
)

Definition at line 4788 of file bufmgr.c.

4790{
4791 int i;
4792 int j;
4793 RelFileLocatorBackend rlocator;
4796
4797 rlocator = smgr_reln->smgr_rlocator;
4798
4799 /* If it's a local relation, it's localbuf.c's problem. */
4800 if (RelFileLocatorBackendIsTemp(rlocator))
4801 {
4802 if (rlocator.backend == MyProcNumber)
4803 DropRelationLocalBuffers(rlocator.locator, forkNum, nforks,
4805
4806 return;
4807 }
4808
4809 /*
4810 * To remove all the pages of the specified relation forks from the buffer
4811 * pool, we need to scan the entire buffer pool but we can optimize it by
4812 * finding the buffers from BufMapping table provided we know the exact
4813 * size of each fork of the relation. The exact size is required to ensure
4814 * that we don't leave any buffer for the relation being dropped as
4815 * otherwise the background writer or checkpointer can lead to a PANIC
4816 * error while flushing buffers corresponding to files that don't exist.
4817 *
4818 * To know the exact size, we rely on the size cached for each fork by us
4819 * during recovery which limits the optimization to recovery and on
4820 * standbys but we can easily extend it once we have shared cache for
4821 * relation size.
4822 *
4823 * In recovery, we cache the value returned by the first lseek(SEEK_END)
4824 * and the future writes keeps the cached value up-to-date. See
4825 * smgrextend. It is possible that the value of the first lseek is smaller
4826 * than the actual number of existing blocks in the file due to buggy
4827 * Linux kernels that might not have accounted for the recent write. But
4828 * that should be fine because there must not be any buffers after that
4829 * file size.
4830 */
4831 for (i = 0; i < nforks; i++)
4832 {
4833 /* Get the number of blocks for a relation's fork */
4835
4837 {
4839 break;
4840 }
4841
4842 /* calculate the number of blocks to be invalidated */
4844 }
4845
4846 /*
4847 * We apply the optimization iff the total number of blocks to invalidate
4848 * is below the BUF_DROP_FULL_SCAN_THRESHOLD.
4849 */
4852 {
4853 for (j = 0; j < nforks; j++)
4854 FindAndDropRelationBuffers(rlocator.locator, forkNum[j],
4856 return;
4857 }
4858
4859 for (i = 0; i < NBuffers; i++)
4860 {
4862
4863 /*
4864 * We can make this a tad faster by prechecking the buffer tag before
4865 * we attempt to lock the buffer; this saves a lot of lock
4866 * acquisitions in typical cases. It should be safe because the
4867 * caller must have AccessExclusiveLock on the relation, or some other
4868 * reason to be certain that no one is loading new pages of the rel
4869 * into the buffer pool. (Otherwise we might well miss such pages
4870 * entirely.) Therefore, while the tag might be changing while we
4871 * look at it, it can't be changing *to* a value we care about, only
4872 * *away* from such a value. So false negatives are impossible, and
4873 * false positives are safe because we'll recheck after getting the
4874 * buffer lock.
4875 *
4876 * We could check forkNum and blockNum as well as the rlocator, but
4877 * the incremental win from doing so seems small.
4878 */
4879 if (!BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator.locator))
4880 continue;
4881
4883
4884 for (j = 0; j < nforks; j++)
4885 {
4886 if (BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator.locator) &&
4887 BufTagGetForkNum(&bufHdr->tag) == forkNum[j] &&
4888 bufHdr->tag.blockNum >= firstDelBlock[j])
4889 {
4890 InvalidateBuffer(bufHdr); /* releases spinlock */
4891 break;
4892 }
4893 }
4894 if (j >= nforks)
4896 }
4897}
#define InvalidBlockNumber
Definition block.h:33
static bool BlockNumberIsValid(BlockNumber blockNumber)
Definition block.h:71
static bool BufTagMatchesRelFileLocator(const BufferTag *tag, const RelFileLocator *rlocator)
#define BUF_DROP_FULL_SCAN_THRESHOLD
Definition bufmgr.c:95
static void FindAndDropRelationBuffers(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber nForkBlock, BlockNumber firstDelBlock)
Definition bufmgr.c:5078
int j
Definition isn.c:78
void DropRelationLocalBuffers(RelFileLocator rlocator, ForkNumber *forkNum, int nforks, BlockNumber *firstDelBlock)
Definition localbuf.c:689
#define RelFileLocatorBackendIsTemp(rlocator)
BlockNumber smgrnblocks_cached(SMgrRelation reln, ForkNumber forknum)
Definition smgr.c:847

References RelFileLocatorBackend::backend, BlockNumberIsValid(), BUF_DROP_FULL_SCAN_THRESHOLD, BufTagGetForkNum(), BufTagMatchesRelFileLocator(), DropRelationLocalBuffers(), fb(), FindAndDropRelationBuffers(), GetBufferDescriptor(), i, InvalidateBuffer(), InvalidBlockNumber, j, RelFileLocatorBackend::locator, LockBufHdr(), MAX_FORKNUM, MyProcNumber, NBuffers, RelFileLocatorBackendIsTemp, smgrnblocks_cached(), and UnlockBufHdr().

Referenced by smgrtruncate().

◆ DropRelationsAllBuffers()

void DropRelationsAllBuffers ( SMgrRelation smgr_reln,
int  nlocators 
)

Definition at line 4908 of file bufmgr.c.

4909{
4910 int i;
4911 int n = 0;
4912 SMgrRelation *rels;
4913 BlockNumber (*block)[MAX_FORKNUM + 1];
4916 bool cached = true;
4917 bool use_bsearch;
4918
4919 if (nlocators == 0)
4920 return;
4921
4922 rels = palloc_array(SMgrRelation, nlocators); /* non-local relations */
4923
4924 /* If it's a local relation, it's localbuf.c's problem. */
4925 for (i = 0; i < nlocators; i++)
4926 {
4927 if (RelFileLocatorBackendIsTemp(smgr_reln[i]->smgr_rlocator))
4928 {
4929 if (smgr_reln[i]->smgr_rlocator.backend == MyProcNumber)
4930 DropRelationAllLocalBuffers(smgr_reln[i]->smgr_rlocator.locator);
4931 }
4932 else
4933 rels[n++] = smgr_reln[i];
4934 }
4935
4936 /*
4937 * If there are no non-local relations, then we're done. Release the
4938 * memory and return.
4939 */
4940 if (n == 0)
4941 {
4942 pfree(rels);
4943 return;
4944 }
4945
4946 /*
4947 * This is used to remember the number of blocks for all the relations
4948 * forks.
4949 */
4950 block = (BlockNumber (*)[MAX_FORKNUM + 1])
4951 palloc(sizeof(BlockNumber) * n * (MAX_FORKNUM + 1));
4952
4953 /*
4954 * We can avoid scanning the entire buffer pool if we know the exact size
4955 * of each of the given relation forks. See DropRelationBuffers.
4956 */
4957 for (i = 0; i < n && cached; i++)
4958 {
4959 for (int j = 0; j <= MAX_FORKNUM; j++)
4960 {
4961 /* Get the number of blocks for a relation's fork. */
4962 block[i][j] = smgrnblocks_cached(rels[i], j);
4963
4964 /* We need to only consider the relation forks that exists. */
4965 if (block[i][j] == InvalidBlockNumber)
4966 {
4967 if (!smgrexists(rels[i], j))
4968 continue;
4969 cached = false;
4970 break;
4971 }
4972
4973 /* calculate the total number of blocks to be invalidated */
4974 nBlocksToInvalidate += block[i][j];
4975 }
4976 }
4977
4978 /*
4979 * We apply the optimization iff the total number of blocks to invalidate
4980 * is below the BUF_DROP_FULL_SCAN_THRESHOLD.
4981 */
4983 {
4984 for (i = 0; i < n; i++)
4985 {
4986 for (int j = 0; j <= MAX_FORKNUM; j++)
4987 {
4988 /* ignore relation forks that doesn't exist */
4989 if (!BlockNumberIsValid(block[i][j]))
4990 continue;
4991
4992 /* drop all the buffers for a particular relation fork */
4993 FindAndDropRelationBuffers(rels[i]->smgr_rlocator.locator,
4994 j, block[i][j], 0);
4995 }
4996 }
4997
4998 pfree(block);
4999 pfree(rels);
5000 return;
5001 }
5002
5003 pfree(block);
5004 locators = palloc_array(RelFileLocator, n); /* non-local relations */
5005 for (i = 0; i < n; i++)
5006 locators[i] = rels[i]->smgr_rlocator.locator;
5007
5008 /*
5009 * For low number of relations to drop just use a simple walk through, to
5010 * save the bsearch overhead. The threshold to use is rather a guess than
5011 * an exactly determined value, as it depends on many factors (CPU and RAM
5012 * speeds, amount of shared buffers etc.).
5013 */
5015
5016 /* sort the list of rlocators if necessary */
5017 if (use_bsearch)
5019
5020 for (i = 0; i < NBuffers; i++)
5021 {
5022 RelFileLocator *rlocator = NULL;
5024
5025 /*
5026 * As in DropRelationBuffers, an unlocked precheck should be safe and
5027 * saves some cycles.
5028 */
5029
5030 if (!use_bsearch)
5031 {
5032 int j;
5033
5034 for (j = 0; j < n; j++)
5035 {
5037 {
5038 rlocator = &locators[j];
5039 break;
5040 }
5041 }
5042 }
5043 else
5044 {
5045 RelFileLocator locator;
5046
5047 locator = BufTagGetRelFileLocator(&bufHdr->tag);
5048 rlocator = bsearch(&locator,
5049 locators, n, sizeof(RelFileLocator),
5051 }
5052
5053 /* buffer doesn't belong to any of the given relfilelocators; skip it */
5054 if (rlocator == NULL)
5055 continue;
5056
5058 if (BufTagMatchesRelFileLocator(&bufHdr->tag, rlocator))
5059 InvalidateBuffer(bufHdr); /* releases spinlock */
5060 else
5062 }
5063
5064 pfree(locators);
5065 pfree(rels);
5066}
#define RELS_BSEARCH_THRESHOLD
Definition bufmgr.c:87
#define palloc_array(type, count)
Definition fe_memutils.h:91
void DropRelationAllLocalBuffers(RelFileLocator rlocator)
Definition localbuf.c:726
#define qsort(a, b, c, d)
Definition port.h:496

References BlockNumberIsValid(), BUF_DROP_FULL_SCAN_THRESHOLD, BufTagGetRelFileLocator(), BufTagMatchesRelFileLocator(), DropRelationAllLocalBuffers(), fb(), FindAndDropRelationBuffers(), GetBufferDescriptor(), i, InvalidateBuffer(), InvalidBlockNumber, j, LockBufHdr(), MAX_FORKNUM, MyProcNumber, NBuffers, palloc(), palloc_array, pfree(), qsort, RelFileLocatorBackendIsTemp, RELS_BSEARCH_THRESHOLD, rlocator_comparator(), smgrexists(), smgrnblocks_cached(), and UnlockBufHdr().

Referenced by smgrdounlinkall().

◆ EvictAllUnpinnedBuffers()

void EvictAllUnpinnedBuffers ( int32 buffers_evicted,
int32 buffers_flushed,
int32 buffers_skipped 
)

Definition at line 8031 of file bufmgr.c.

8033{
8034 *buffers_evicted = 0;
8035 *buffers_skipped = 0;
8036 *buffers_flushed = 0;
8037
8038 for (int buf = 1; buf <= NBuffers; buf++)
8039 {
8040 BufferDesc *desc = GetBufferDescriptor(buf - 1);
8042 bool buffer_flushed;
8043
8045
8047 if (!(buf_state & BM_VALID))
8048 continue;
8049
8052
8053 LockBufHdr(desc);
8054
8056 (*buffers_evicted)++;
8057 else
8058 (*buffers_skipped)++;
8059
8060 if (buffer_flushed)
8061 (*buffers_flushed)++;
8062 }
8063}
static bool EvictUnpinnedBufferInternal(BufferDesc *desc, bool *buffer_flushed)
Definition bufmgr.c:7940
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:125
pg_atomic_uint64 state

References BM_VALID, buf, CHECK_FOR_INTERRUPTS, CurrentResourceOwner, EvictUnpinnedBufferInternal(), fb(), GetBufferDescriptor(), LockBufHdr(), NBuffers, pg_atomic_read_u64(), ReservePrivateRefCountEntry(), ResourceOwnerEnlarge(), and BufferDesc::state.

Referenced by pg_buffercache_evict_all().

◆ EvictRelUnpinnedBuffers()

void EvictRelUnpinnedBuffers ( Relation  rel,
int32 buffers_evicted,
int32 buffers_flushed,
int32 buffers_skipped 
)

Definition at line 8081 of file bufmgr.c.

8083{
8085
8086 *buffers_skipped = 0;
8087 *buffers_evicted = 0;
8088 *buffers_flushed = 0;
8089
8090 for (int buf = 1; buf <= NBuffers; buf++)
8091 {
8092 BufferDesc *desc = GetBufferDescriptor(buf - 1);
8094 bool buffer_flushed;
8095
8097
8098 /* An unlocked precheck should be safe and saves some cycles. */
8099 if ((buf_state & BM_VALID) == 0 ||
8101 continue;
8102
8103 /* Make sure we can pin the buffer. */
8106
8107 buf_state = LockBufHdr(desc);
8108
8109 /* recheck, could have changed without the lock */
8110 if ((buf_state & BM_VALID) == 0 ||
8112 {
8113 UnlockBufHdr(desc);
8114 continue;
8115 }
8116
8118 (*buffers_evicted)++;
8119 else
8120 (*buffers_skipped)++;
8121
8122 if (buffer_flushed)
8123 (*buffers_flushed)++;
8124 }
8125}
#define RelationUsesLocalBuffers(relation)
Definition rel.h:648
RelFileLocator rd_locator
Definition rel.h:57

References Assert, BM_VALID, buf, BufTagMatchesRelFileLocator(), CHECK_FOR_INTERRUPTS, CurrentResourceOwner, EvictUnpinnedBufferInternal(), fb(), GetBufferDescriptor(), LockBufHdr(), NBuffers, pg_atomic_read_u64(), RelationData::rd_locator, RelationUsesLocalBuffers, ReservePrivateRefCountEntry(), ResourceOwnerEnlarge(), BufferDesc::state, BufferDesc::tag, and UnlockBufHdr().

Referenced by evict_rel(), and pg_buffercache_evict_relation().

◆ EvictUnpinnedBuffer()

bool EvictUnpinnedBuffer ( Buffer  buf,
bool buffer_flushed 
)

◆ EvictUnpinnedBufferInternal()

static bool EvictUnpinnedBufferInternal ( BufferDesc desc,
bool buffer_flushed 
)
static

Definition at line 7940 of file bufmgr.c.

7941{
7943 bool result;
7944
7945 *buffer_flushed = false;
7946
7949
7950 if ((buf_state & BM_VALID) == 0)
7951 {
7952 UnlockBufHdr(desc);
7953 return false;
7954 }
7955
7956 /* Check that it's not pinned already. */
7958 {
7959 UnlockBufHdr(desc);
7960 return false;
7961 }
7962
7963 PinBuffer_Locked(desc); /* releases spinlock */
7964
7965 /* If it was dirty, try to clean it once. */
7966 if (buf_state & BM_DIRTY)
7967 {
7969 *buffer_flushed = true;
7970 }
7971
7972 /* This will return false if it becomes dirty or someone else pins it. */
7974
7975 UnpinBuffer(desc);
7976
7977 return result;
7978}
#define BM_LOCKED
static void FlushUnlockedBuffer(BufferDesc *buf, SMgrRelation reln, IOObject io_object, IOContext io_context)
Definition bufmgr.c:4649
static void PinBuffer_Locked(BufferDesc *buf)
Definition bufmgr.c:3411
static bool InvalidateVictimBuffer(BufferDesc *buf_hdr)
Definition bufmgr.c:2471

References Assert, BM_DIRTY, BM_LOCKED, BM_VALID, BUF_STATE_GET_REFCOUNT, fb(), FlushUnlockedBuffer(), InvalidateVictimBuffer(), IOCONTEXT_NORMAL, IOOBJECT_RELATION, pg_atomic_read_u64(), PinBuffer_Locked(), result, BufferDesc::state, UnlockBufHdr(), and UnpinBuffer().

Referenced by EvictAllUnpinnedBuffers(), EvictRelUnpinnedBuffers(), and EvictUnpinnedBuffer().

◆ ExtendBufferedRel()

Buffer ExtendBufferedRel ( BufferManagerRelation  bmr,
ForkNumber  forkNum,
BufferAccessStrategy  strategy,
uint32  flags 
)

Definition at line 970 of file bufmgr.c.

974{
975 Buffer buf;
976 uint32 extend_by = 1;
977
978 ExtendBufferedRelBy(bmr, forkNum, strategy, flags, extend_by,
979 &buf, &extend_by);
980
981 return buf;
982}
BlockNumber ExtendBufferedRelBy(BufferManagerRelation bmr, ForkNumber fork, BufferAccessStrategy strategy, uint32 flags, uint32 extend_by, Buffer *buffers, uint32 *extended_by)
Definition bufmgr.c:1002

References buf, ExtendBufferedRelBy(), and fb().

Referenced by _bt_allocbuf(), _hash_getnewbuf(), BloomNewBuffer(), brinbuild(), brinbuildempty(), fill_seq_fork_with_data(), ginbuildempty(), GinNewBuffer(), gistbuildempty(), gistNewBuffer(), ReadBuffer_common(), revmap_physical_extend(), and SpGistNewBuffer().

◆ ExtendBufferedRelBy()

BlockNumber ExtendBufferedRelBy ( BufferManagerRelation  bmr,
ForkNumber  fork,
BufferAccessStrategy  strategy,
uint32  flags,
uint32  extend_by,
Buffer buffers,
uint32 extended_by 
)

Definition at line 1002 of file bufmgr.c.

1009{
1010 Assert((bmr.rel != NULL) != (bmr.smgr != NULL));
1011 Assert(bmr.smgr == NULL || bmr.relpersistence != '\0');
1012 Assert(extend_by > 0);
1013
1014 if (bmr.relpersistence == '\0')
1015 bmr.relpersistence = bmr.rel->rd_rel->relpersistence;
1016
1017 return ExtendBufferedRelCommon(bmr, fork, strategy, flags,
1019 buffers, extended_by);
1020}
static BlockNumber ExtendBufferedRelCommon(BufferManagerRelation bmr, ForkNumber fork, BufferAccessStrategy strategy, uint32 flags, uint32 extend_by, BlockNumber extend_upto, Buffer *buffers, uint32 *extended_by)
Definition bufmgr.c:2751

References Assert, ExtendBufferedRelCommon(), fb(), and InvalidBlockNumber.

Referenced by ExtendBufferedRel(), grow_rel(), and RelationAddBlocks().

◆ ExtendBufferedRelCommon()

static BlockNumber ExtendBufferedRelCommon ( BufferManagerRelation  bmr,
ForkNumber  fork,
BufferAccessStrategy  strategy,
uint32  flags,
uint32  extend_by,
BlockNumber  extend_upto,
Buffer buffers,
uint32 extended_by 
)
static

Definition at line 2751 of file bufmgr.c.

2759{
2761
2763 BMR_GET_SMGR(bmr)->smgr_rlocator.locator.spcOid,
2764 BMR_GET_SMGR(bmr)->smgr_rlocator.locator.dbOid,
2765 BMR_GET_SMGR(bmr)->smgr_rlocator.locator.relNumber,
2766 BMR_GET_SMGR(bmr)->smgr_rlocator.backend,
2767 extend_by);
2768
2769 if (bmr.relpersistence == RELPERSISTENCE_TEMP)
2770 {
2771 /*
2772 * Reject attempts to extend non-local temporary relations; we have no
2773 * ability to transfer about-to-be-created local buffers into the
2774 * owning session's local buffers. This is the canonical place for
2775 * the check, covering any attempt to extend a non-local temporary
2776 * relation.
2777 */
2778 if (bmr.rel && RELATION_IS_OTHER_TEMP(bmr.rel))
2779 ereport(ERROR,
2781 errmsg("cannot access temporary tables of other sessions")));
2782
2785 buffers, &extend_by);
2786 }
2787 else
2788 first_block = ExtendBufferedRelShared(bmr, fork, strategy, flags,
2790 buffers, &extend_by);
2792
2794 BMR_GET_SMGR(bmr)->smgr_rlocator.locator.spcOid,
2795 BMR_GET_SMGR(bmr)->smgr_rlocator.locator.dbOid,
2796 BMR_GET_SMGR(bmr)->smgr_rlocator.locator.relNumber,
2797 BMR_GET_SMGR(bmr)->smgr_rlocator.backend,
2798 *extended_by,
2799 first_block);
2800
2801 return first_block;
2802}
static BlockNumber ExtendBufferedRelShared(BufferManagerRelation bmr, ForkNumber fork, BufferAccessStrategy strategy, uint32 flags, uint32 extend_by, BlockNumber extend_upto, Buffer *buffers, uint32 *extended_by)
Definition bufmgr.c:2809
#define BMR_GET_SMGR(bmr)
Definition bufmgr.h:118
BlockNumber ExtendBufferedRelLocal(BufferManagerRelation bmr, ForkNumber fork, uint32 flags, uint32 extend_by, BlockNumber extend_upto, Buffer *buffers, uint32 *extended_by)
Definition localbuf.c:355
#define RELATION_IS_OTHER_TEMP(relation)
Definition rel.h:678

References BMR_GET_SMGR, ereport, errcode(), errmsg, ERROR, ExtendBufferedRelLocal(), ExtendBufferedRelShared(), fb(), and RELATION_IS_OTHER_TEMP.

Referenced by ExtendBufferedRelBy(), and ExtendBufferedRelTo().

◆ ExtendBufferedRelShared()

static BlockNumber ExtendBufferedRelShared ( BufferManagerRelation  bmr,
ForkNumber  fork,
BufferAccessStrategy  strategy,
uint32  flags,
uint32  extend_by,
BlockNumber  extend_upto,
Buffer buffers,
uint32 extended_by 
)
static

Definition at line 2809 of file bufmgr.c.

2817{
2821
2823
2824 /*
2825 * Acquire victim buffers for extension without holding extension lock.
2826 * Writing out victim buffers is the most expensive part of extending the
2827 * relation, particularly when doing so requires WAL flushes. Zeroing out
2828 * the buffers is also quite expensive, so do that before holding the
2829 * extension lock as well.
2830 *
2831 * These pages are pinned by us and not valid. While we hold the pin they
2832 * can't be acquired as victim buffers by another backend.
2833 */
2834 for (uint32 i = 0; i < extend_by; i++)
2835 {
2837
2838 buffers[i] = GetVictimBuffer(strategy, io_context);
2840
2841 /* new buffers are zero-filled */
2842 MemSet(buf_block, 0, BLCKSZ);
2843 }
2844
2845 /*
2846 * Lock relation against concurrent extensions, unless requested not to.
2847 *
2848 * We use the same extension lock for all forks. That's unnecessarily
2849 * restrictive, but currently extensions for forks don't happen often
2850 * enough to make it worth locking more granularly.
2851 *
2852 * Note that another backend might have extended the relation by the time
2853 * we get the lock.
2854 */
2855 if (!(flags & EB_SKIP_EXTENSION_LOCK))
2857
2858 /*
2859 * If requested, invalidate size cache, so that smgrnblocks asks the
2860 * kernel.
2861 */
2862 if (flags & EB_CLEAR_SIZE_CACHE)
2863 BMR_GET_SMGR(bmr)->smgr_cached_nblocks[fork] = InvalidBlockNumber;
2864
2866
2867 /*
2868 * Now that we have the accurate relation size, check if the caller wants
2869 * us to extend to only up to a specific size. If there were concurrent
2870 * extensions, we might have acquired too many buffers and need to release
2871 * them.
2872 */
2874 {
2876
2878 extend_by = 0;
2879 else if ((uint64) first_block + extend_by > extend_upto)
2881
2882 for (uint32 i = extend_by; i < orig_extend_by; i++)
2883 {
2884 BufferDesc *buf_hdr = GetBufferDescriptor(buffers[i] - 1);
2885
2887 }
2888
2889 if (extend_by == 0)
2890 {
2891 if (!(flags & EB_SKIP_EXTENSION_LOCK))
2894 return first_block;
2895 }
2896 }
2897
2898 /* Fail if relation is already at maximum possible length */
2900 ereport(ERROR,
2902 errmsg("cannot extend relation %s beyond %u blocks",
2903 relpath(BMR_GET_SMGR(bmr)->smgr_rlocator, fork).str,
2904 MaxBlockNumber)));
2905
2906 /*
2907 * Insert buffers into buffer table, mark as IO_IN_PROGRESS.
2908 *
2909 * This needs to happen before we extend the relation, because as soon as
2910 * we do, other backends can start to read in those pages.
2911 */
2912 for (uint32 i = 0; i < extend_by; i++)
2913 {
2914 Buffer victim_buf = buffers[i];
2916 BufferTag tag;
2917 uint32 hash;
2919 int existing_id;
2920
2921 /* in case we need to pin an existing buffer below */
2924
2925 InitBufferTag(&tag, &BMR_GET_SMGR(bmr)->smgr_rlocator.locator, fork,
2926 first_block + i);
2927 hash = BufTableHashCode(&tag);
2929
2931
2933
2934 /*
2935 * We get here only in the corner case where we are trying to extend
2936 * the relation but we found a pre-existing buffer. This can happen
2937 * because a prior attempt at extending the relation failed, and
2938 * because mdread doesn't complain about reads beyond EOF (when
2939 * zero_damaged_pages is ON) and so a previous attempt to read a block
2940 * beyond EOF could have left a "valid" zero-filled buffer.
2941 *
2942 * This has also been observed when relation was overwritten by
2943 * external process. Since the legitimate cases should always have
2944 * left a zero-filled buffer, complain if not PageIsNew.
2945 */
2946 if (existing_id >= 0)
2947 {
2950 bool valid;
2951
2952 /*
2953 * Pin the existing buffer before releasing the partition lock,
2954 * preventing it from being evicted.
2955 */
2956 valid = PinBuffer(existing_hdr, strategy, false);
2957
2960
2963
2964 if (valid && !PageIsNew((Page) buf_block))
2965 ereport(ERROR,
2966 (errmsg("unexpected data beyond EOF in block %u of relation \"%s\"",
2967 existing_hdr->tag.blockNum,
2968 relpath(BMR_GET_SMGR(bmr)->smgr_rlocator, fork).str)));
2969
2970 /*
2971 * We *must* do smgr[zero]extend before succeeding, else the page
2972 * will not be reserved by the kernel, and the next P_NEW call
2973 * will decide to return the same page. Clear the BM_VALID bit,
2974 * do StartSharedBufferIO() and proceed.
2975 *
2976 * Loop to handle the very small possibility that someone re-sets
2977 * BM_VALID between our clearing it and StartSharedBufferIO
2978 * inspecting it.
2979 */
2980 while (true)
2981 {
2983
2985
2987
2989 break;
2990 }
2991 }
2992 else
2993 {
2995 uint64 set_bits = 0;
2996
2998
2999 /* some sanity checks while we hold the buffer header lock */
3002
3003 victim_buf_hdr->tag = tag;
3004
3006 if (bmr.relpersistence == RELPERSISTENCE_PERMANENT || fork == INIT_FORKNUM)
3008
3010 set_bits, 0,
3011 0);
3012
3014
3015 /* XXX: could combine the locked operations in it with the above */
3017 }
3018 }
3019
3021
3022 /*
3023 * Note: if smgrzeroextend fails, we will end up with buffers that are
3024 * allocated but not marked BM_VALID. The next relation extension will
3025 * still select the same block number (because the relation didn't get any
3026 * longer on disk) and so future attempts to extend the relation will find
3027 * the same buffers (if they have not been recycled) but come right back
3028 * here to try smgrzeroextend again.
3029 *
3030 * We don't need to set checksum for all-zero pages.
3031 */
3033
3034 /*
3035 * Release the file-extension lock; it's now OK for someone else to extend
3036 * the relation some more.
3037 *
3038 * We remove IO_IN_PROGRESS after this, as waking up waiting backends can
3039 * take noticeable time.
3040 */
3041 if (!(flags & EB_SKIP_EXTENSION_LOCK))
3043
3045 io_start, 1, extend_by * BLCKSZ);
3046
3047 /* Set BM_VALID, terminate IO, and wake up any waiters */
3048 for (uint32 i = 0; i < extend_by; i++)
3049 {
3050 Buffer buf = buffers[i];
3052 bool lock = false;
3053
3054 if (flags & EB_LOCK_FIRST && i == 0)
3055 lock = true;
3056 else if (flags & EB_LOCK_TARGET)
3057 {
3059 if (first_block + i + 1 == extend_upto)
3060 lock = true;
3061 }
3062
3063 if (lock)
3065
3066 TerminateBufferIO(buf_hdr, false, BM_VALID, true, false);
3067 }
3068
3070
3072
3073 return first_block;
3074}
#define MaxBlockNumber
Definition block.h:35
#define BufHdrGetBlock(bufHdr)
Definition bufmgr.c:76
StartBufferIOResult StartSharedBufferIO(BufferDesc *buf, bool forInput, bool wait, PgAioWaitRef *io_wref)
Definition bufmgr.c:7290
void LimitAdditionalPins(uint32 *additional_pins)
Definition bufmgr.c:2733
void * Block
Definition bufmgr.h:26
@ EB_LOCK_TARGET
Definition bufmgr.h:93
@ EB_CLEAR_SIZE_CACHE
Definition bufmgr.h:90
@ EB_SKIP_EXTENSION_LOCK
Definition bufmgr.h:75
@ EB_LOCK_FIRST
Definition bufmgr.h:87
static bool PageIsNew(const PageData *page)
Definition bufpage.h:258
#define MemSet(start, val, len)
Definition c.h:1166
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition lmgr.c:424
void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition lmgr.c:474
#define ExclusiveLock
Definition lockdefs.h:42
@ IOOP_EXTEND
Definition pgstat.h:318
static unsigned hash(unsigned *uv, int n)
Definition rege_dfa.c:724
#define relpath(rlocator, forknum)
Definition relpath.h:150
BlockNumber smgrnblocks(SMgrRelation reln, ForkNumber forknum)
Definition smgr.c:819
void smgrzeroextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, int nblocks, bool skipFsync)
Definition smgr.c:649
int64 shared_blks_written
Definition instrument.h:29

References Assert, BM_DIRTY, BM_PERMANENT, BM_TAG_VALID, BM_VALID, BMR_GET_SMGR, buf, BUF_STATE_GET_REFCOUNT, BUF_USAGECOUNT_ONE, BUFFER_IO_ALREADY_DONE, BUFFER_LOCK_EXCLUSIVE, BufferDescriptorGetBuffer(), BufHdrGetBlock, BufMappingPartitionLock(), BufTableHashCode(), BufTableInsert(), CurrentResourceOwner, EB_CLEAR_SIZE_CACHE, EB_LOCK_FIRST, EB_LOCK_TARGET, EB_SKIP_EXTENSION_LOCK, ereport, errcode(), errmsg, ERROR, ExclusiveLock, fb(), GetBufferDescriptor(), GetVictimBuffer(), hash(), i, INIT_FORKNUM, InitBufferTag(), InvalidBlockNumber, IOContextForStrategy(), IOOBJECT_RELATION, IOOP_EXTEND, LimitAdditionalPins(), LockBuffer(), LockBufHdr(), LockRelationForExtension(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MaxBlockNumber, MemSet, PageIsNew(), pg_atomic_fetch_and_u64(), pgBufferUsage, pgstat_count_io_op_time(), pgstat_prepare_io_time(), PinBuffer(), relpath, ReservePrivateRefCountEntry(), ResourceOwnerEnlarge(), BufferUsage::shared_blks_written, smgrnblocks(), smgrzeroextend(), StartSharedBufferIO(), str, TerminateBufferIO(), track_io_timing, UnlockBufHdrExt(), UnlockRelationForExtension(), and UnpinBuffer().

Referenced by ExtendBufferedRelCommon().

◆ ExtendBufferedRelTo()

Buffer ExtendBufferedRelTo ( BufferManagerRelation  bmr,
ForkNumber  fork,
BufferAccessStrategy  strategy,
uint32  flags,
BlockNumber  extend_to,
ReadBufferMode  mode 
)

Definition at line 1031 of file bufmgr.c.

1037{
1039 uint32 extended_by = 0;
1040 Buffer buffer = InvalidBuffer;
1041 Buffer buffers[64];
1042
1043 Assert((bmr.rel != NULL) != (bmr.smgr != NULL));
1044 Assert(bmr.smgr == NULL || bmr.relpersistence != '\0');
1046
1047 if (bmr.relpersistence == '\0')
1048 bmr.relpersistence = bmr.rel->rd_rel->relpersistence;
1049
1050 /*
1051 * If desired, create the file if it doesn't exist. If
1052 * smgr_cached_nblocks[fork] is positive then it must exist, no need for
1053 * an smgrexists call.
1054 */
1055 if ((flags & EB_CREATE_FORK_IF_NEEDED) &&
1056 (BMR_GET_SMGR(bmr)->smgr_cached_nblocks[fork] == 0 ||
1057 BMR_GET_SMGR(bmr)->smgr_cached_nblocks[fork] == InvalidBlockNumber) &&
1059 {
1061
1062 /* recheck, fork might have been created concurrently */
1065
1067 }
1068
1069 /*
1070 * If requested, invalidate size cache, so that smgrnblocks asks the
1071 * kernel.
1072 */
1073 if (flags & EB_CLEAR_SIZE_CACHE)
1074 BMR_GET_SMGR(bmr)->smgr_cached_nblocks[fork] = InvalidBlockNumber;
1075
1076 /*
1077 * Estimate how many pages we'll need to extend by. This avoids acquiring
1078 * unnecessarily many victim buffers.
1079 */
1081
1082 /*
1083 * Since no-one else can be looking at the page contents yet, there is no
1084 * difference between an exclusive lock and a cleanup-strength lock. Note
1085 * that we pass the original mode to ReadBuffer_common() below, when
1086 * falling back to reading the buffer to a concurrent relation extension.
1087 */
1089 flags |= EB_LOCK_TARGET;
1090
1091 while (current_size < extend_to)
1092 {
1093 uint32 num_pages = lengthof(buffers);
1095
1096 if ((uint64) current_size + num_pages > extend_to)
1097 num_pages = extend_to - current_size;
1098
1099 first_block = ExtendBufferedRelCommon(bmr, fork, strategy, flags,
1100 num_pages, extend_to,
1101 buffers, &extended_by);
1102
1104 Assert(num_pages != 0 || current_size >= extend_to);
1105
1106 for (uint32 i = 0; i < extended_by; i++)
1107 {
1108 if (first_block + i != extend_to - 1)
1109 ReleaseBuffer(buffers[i]);
1110 else
1111 buffer = buffers[i];
1112 }
1113 }
1114
1115 /*
1116 * It's possible that another backend concurrently extended the relation.
1117 * In that case read the buffer.
1118 *
1119 * XXX: Should we control this via a flag?
1120 */
1121 if (buffer == InvalidBuffer)
1122 {
1123 Assert(extended_by == 0);
1124 buffer = ReadBuffer_common(bmr.rel, BMR_GET_SMGR(bmr), bmr.relpersistence,
1125 fork, extend_to - 1, mode, strategy);
1126 }
1127
1128 return buffer;
1129}
static Buffer ReadBuffer_common(Relation rel, SMgrRelation smgr, char smgr_persistence, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition bufmgr.c:1276
void ReleaseBuffer(Buffer buffer)
Definition bufmgr.c:5609
@ EB_PERFORMING_RECOVERY
Definition bufmgr.h:78
@ EB_CREATE_FORK_IF_NEEDED
Definition bufmgr.h:84
@ RBM_ZERO_AND_CLEANUP_LOCK
Definition bufmgr.h:49
@ RBM_ZERO_AND_LOCK
Definition bufmgr.h:47
#define lengthof(array)
Definition c.h:932
static int64 current_size

References Assert, BMR_GET_SMGR, PrivateRefCountEntry::buffer, current_size, EB_CLEAR_SIZE_CACHE, EB_CREATE_FORK_IF_NEEDED, EB_LOCK_TARGET, EB_PERFORMING_RECOVERY, ExclusiveLock, ExtendBufferedRelCommon(), fb(), i, InvalidBlockNumber, InvalidBuffer, lengthof, LockRelationForExtension(), mode, RBM_ZERO_AND_CLEANUP_LOCK, RBM_ZERO_AND_LOCK, ReadBuffer_common(), ReleaseBuffer(), smgrcreate(), smgrexists(), smgrnblocks(), and UnlockRelationForExtension().

Referenced by fsm_extend(), vm_extend(), and XLogReadBufferExtended().

◆ FindAndDropRelationBuffers()

static void FindAndDropRelationBuffers ( RelFileLocator  rlocator,
ForkNumber  forkNum,
BlockNumber  nForkBlock,
BlockNumber  firstDelBlock 
)
static

Definition at line 5078 of file bufmgr.c.

5081{
5082 BlockNumber curBlock;
5083
5084 for (curBlock = firstDelBlock; curBlock < nForkBlock; curBlock++)
5085 {
5086 uint32 bufHash; /* hash value for tag */
5087 BufferTag bufTag; /* identity of requested block */
5088 LWLock *bufPartitionLock; /* buffer partition lock for it */
5089 int buf_id;
5091
5092 /* create a tag so we can lookup the buffer */
5093 InitBufferTag(&bufTag, &rlocator, forkNum, curBlock);
5094
5095 /* determine its hash code and partition lock ID */
5098
5099 /* Check that it is in the buffer pool. If not, do nothing. */
5101 buf_id = BufTableLookup(&bufTag, bufHash);
5103
5104 if (buf_id < 0)
5105 continue;
5106
5107 bufHdr = GetBufferDescriptor(buf_id);
5108
5109 /*
5110 * We need to lock the buffer header and recheck if the buffer is
5111 * still associated with the same block because the buffer could be
5112 * evicted by some other backend loading blocks for a different
5113 * relation after we release lock on the BufMapping table.
5114 */
5116
5117 if (BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator) &&
5118 BufTagGetForkNum(&bufHdr->tag) == forkNum &&
5119 bufHdr->tag.blockNum >= firstDelBlock)
5120 InvalidateBuffer(bufHdr); /* releases spinlock */
5121 else
5123 }
5124}

References BufMappingPartitionLock(), BufTableHashCode(), BufTableLookup(), BufTagGetForkNum(), BufTagMatchesRelFileLocator(), fb(), GetBufferDescriptor(), InitBufferTag(), InvalidateBuffer(), LockBufHdr(), LW_SHARED, LWLockAcquire(), LWLockRelease(), and UnlockBufHdr().

Referenced by DropRelationBuffers(), and DropRelationsAllBuffers().

◆ FlushBuffer()

static void FlushBuffer ( BufferDesc buf,
SMgrRelation  reln,
IOObject  io_object,
IOContext  io_context 
)
static

Definition at line 4526 of file bufmgr.c.

4528{
4530 ErrorContextCallback errcallback;
4533
4536
4537 /*
4538 * Try to start an I/O operation. If StartBufferIO returns false, then
4539 * someone else flushed the buffer before we could, so we need not do
4540 * anything.
4541 */
4542 if (StartSharedBufferIO(buf, false, true, NULL) == BUFFER_IO_ALREADY_DONE)
4543 return;
4544
4545 /* Setup error traceback support for ereport() */
4547 errcallback.arg = buf;
4548 errcallback.previous = error_context_stack;
4549 error_context_stack = &errcallback;
4550
4551 /* Find smgr relation for buffer */
4552 if (reln == NULL)
4554
4556 buf->tag.blockNum,
4557 reln->smgr_rlocator.locator.spcOid,
4558 reln->smgr_rlocator.locator.dbOid,
4559 reln->smgr_rlocator.locator.relNumber);
4560
4561 /*
4562 * As we hold at least a share-exclusive lock on the buffer, the LSN
4563 * cannot change during the flush (and thus can't be torn).
4564 */
4566
4567 /*
4568 * Force XLOG flush up to buffer's LSN. This implements the basic WAL
4569 * rule that log updates must hit disk before any of the data-file changes
4570 * they describe do.
4571 *
4572 * However, this rule does not apply to unlogged relations, which will be
4573 * lost after a crash anyway. Most unlogged relation pages do not bear
4574 * LSNs since we never emit WAL records for them, and therefore flushing
4575 * up through the buffer LSN would be useless, but harmless. However,
4576 * some index AMs use LSNs internally to detect concurrent page
4577 * modifications, and therefore unlogged index pages bear "fake" LSNs
4578 * generated by XLogGetFakeLSN. It is unlikely but possible that the fake
4579 * LSN counter could advance past the WAL insertion point; and if it did
4580 * happen, attempting to flush WAL through that location would fail, with
4581 * disastrous system-wide consequences. To make sure that can't happen,
4582 * skip the flush if the buffer isn't permanent.
4583 */
4584 if (pg_atomic_read_u64(&buf->state) & BM_PERMANENT)
4586
4587 /*
4588 * Now it's safe to write the buffer to disk. Note that no one else should
4589 * have been able to write it, while we were busy with log flushing,
4590 * because we got the exclusive right to perform I/O by setting the
4591 * BM_IO_IN_PROGRESS bit.
4592 */
4594
4595 /* Update page checksum if desired. */
4596 PageSetChecksum((Page) bufBlock, buf->tag.blockNum);
4597
4599
4601 BufTagGetForkNum(&buf->tag),
4602 buf->tag.blockNum,
4603 bufBlock,
4604 false);
4605
4606 /*
4607 * When a strategy is in use, only flushes of dirty buffers already in the
4608 * strategy ring are counted as strategy writes (IOCONTEXT
4609 * [BULKREAD|BULKWRITE|VACUUM] IOOP_WRITE) for the purpose of IO
4610 * statistics tracking.
4611 *
4612 * If a shared buffer initially added to the ring must be flushed before
4613 * being used, this is counted as an IOCONTEXT_NORMAL IOOP_WRITE.
4614 *
4615 * If a shared buffer which was added to the ring later because the
4616 * current strategy buffer is pinned or in use or because all strategy
4617 * buffers were dirty and rejected (for BAS_BULKREAD operations only)
4618 * requires flushing, this is counted as an IOCONTEXT_NORMAL IOOP_WRITE
4619 * (from_ring will be false).
4620 *
4621 * When a strategy is not in use, the write can only be a "regular" write
4622 * of a dirty shared buffer (IOCONTEXT_NORMAL IOOP_WRITE).
4623 */
4626
4628
4629 /*
4630 * Mark the buffer as clean and end the BM_IO_IN_PROGRESS state.
4631 */
4632 TerminateBufferIO(buf, true, 0, true, false);
4633
4635 buf->tag.blockNum,
4636 reln->smgr_rlocator.locator.spcOid,
4637 reln->smgr_rlocator.locator.dbOid,
4638 reln->smgr_rlocator.locator.relNumber);
4639
4640 /* Pop the error context stack */
4641 error_context_stack = errcallback.previous;
4642}
#define BufferGetLSN(bufHdr)
Definition bufmgr.c:77
static void shared_buffer_write_error_callback(void *arg)
Definition bufmgr.c:7508
void PageSetChecksum(Page page, BlockNumber blkno)
Definition bufpage.c:1518
ErrorContextCallback * error_context_stack
Definition elog.c:100
@ IOOP_WRITE
Definition pgstat.h:320
static void smgrwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, const void *buffer, bool skipFsync)
Definition smgr.h:131
struct ErrorContextCallback * previous
Definition elog.h:299
void(* callback)(void *arg)
Definition elog.h:300
void XLogFlush(XLogRecPtr record)
Definition xlog.c:2801

References ErrorContextCallback::arg, Assert, BM_PERMANENT, buf, BUFFER_IO_ALREADY_DONE, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_SHARE_EXCLUSIVE, BufferGetLSN, BufferLockHeldByMeInMode(), BufHdrGetBlock, BufTagGetForkNum(), BufTagGetRelFileLocator(), ErrorContextCallback::callback, error_context_stack, fb(), INVALID_PROC_NUMBER, IOOP_WRITE, PageSetChecksum(), pg_atomic_read_u64(), pgBufferUsage, pgstat_count_io_op_time(), pgstat_prepare_io_time(), ErrorContextCallback::previous, BufferUsage::shared_blks_written, shared_buffer_write_error_callback(), smgropen(), smgrwrite(), StartSharedBufferIO(), TerminateBufferIO(), track_io_timing, and XLogFlush().

Referenced by FlushOneBuffer(), FlushUnlockedBuffer(), and GetVictimBuffer().

◆ FlushDatabaseBuffers()

void FlushDatabaseBuffers ( Oid  dbid)

Definition at line 5549 of file bufmgr.c.

5550{
5551 int i;
5553
5554 for (i = 0; i < NBuffers; i++)
5555 {
5557
5559
5560 /*
5561 * As in DropRelationBuffers, an unlocked precheck should be safe and
5562 * saves some cycles.
5563 */
5564 if (bufHdr->tag.dbOid != dbid)
5565 continue;
5566
5567 /* Make sure we can handle the pin */
5570
5572 if (bufHdr->tag.dbOid == dbid &&
5574 {
5578 }
5579 else
5581 }
5582}

References BM_DIRTY, BM_VALID, CurrentResourceOwner, fb(), FlushUnlockedBuffer(), GetBufferDescriptor(), i, IOCONTEXT_NORMAL, IOOBJECT_RELATION, LockBufHdr(), NBuffers, PinBuffer_Locked(), ReservePrivateRefCountEntry(), ResourceOwnerEnlarge(), UnlockBufHdr(), and UnpinBuffer().

Referenced by dbase_redo().

◆ FlushOneBuffer()

void FlushOneBuffer ( Buffer  buffer)

Definition at line 5589 of file bufmgr.c.

5590{
5592
5593 /* currently not needed, but no fundamental reason not to support */
5594 Assert(!BufferIsLocal(buffer));
5595
5596 Assert(BufferIsPinned(buffer));
5597
5598 bufHdr = GetBufferDescriptor(buffer - 1);
5599
5600 Assert(BufferIsLockedByMe(buffer));
5601
5603}
static void FlushBuffer(BufferDesc *buf, SMgrRelation reln, IOObject io_object, IOContext io_context)
Definition bufmgr.c:4526
bool BufferIsLockedByMe(Buffer buffer)
Definition bufmgr.c:3084

References Assert, PrivateRefCountEntry::buffer, BufferIsLocal, BufferIsLockedByMe(), BufferIsPinned, fb(), FlushBuffer(), GetBufferDescriptor(), IOCONTEXT_NORMAL, and IOOBJECT_RELATION.

Referenced by invalidate_one_block(), XLogFlushBufferForRedoIfInit(), and XLogReadBufferForRedoExtended().

◆ FlushRelationBuffers()

void FlushRelationBuffers ( Relation  rel)

Definition at line 5185 of file bufmgr.c.

5186{
5187 int i;
5189 SMgrRelation srel = RelationGetSmgr(rel);
5190
5191 if (RelationUsesLocalBuffers(rel))
5192 {
5193 for (i = 0; i < NLocBuffer; i++)
5194 {
5196
5198 if (BufTagMatchesRelFileLocator(&bufHdr->tag, &rel->rd_locator) &&
5199 ((buf_state = pg_atomic_read_u64(&bufHdr->state)) &
5200 (BM_VALID | BM_DIRTY)) == (BM_VALID | BM_DIRTY))
5201 {
5202 ErrorContextCallback errcallback;
5203
5204 /* Setup error traceback support for ereport() */
5206 errcallback.arg = bufHdr;
5207 errcallback.previous = error_context_stack;
5208 error_context_stack = &errcallback;
5209
5210 /* Make sure we can handle the pin */
5213
5214 /*
5215 * Pin/unpin mostly to make valgrind work, but it also seems
5216 * like the right thing to do.
5217 */
5218 PinLocalBuffer(bufHdr, false);
5219
5220
5221 FlushLocalBuffer(bufHdr, srel);
5222
5224
5225 /* Pop the error context stack */
5226 error_context_stack = errcallback.previous;
5227 }
5228 }
5229
5230 return;
5231 }
5232
5233 for (i = 0; i < NBuffers; i++)
5234 {
5236
5238
5239 /*
5240 * As in DropRelationBuffers, an unlocked precheck should be safe and
5241 * saves some cycles.
5242 */
5244 continue;
5245
5246 /* Make sure we can handle the pin */
5249
5251 if (BufTagMatchesRelFileLocator(&bufHdr->tag, &rel->rd_locator) &&
5253 {
5257 }
5258 else
5260 }
5261}
static void local_buffer_write_error_callback(void *arg)
Definition bufmgr.c:7524
void FlushLocalBuffer(BufferDesc *bufHdr, SMgrRelation reln)
Definition localbuf.c:183
void UnpinLocalBuffer(Buffer buffer)
Definition localbuf.c:865
bool PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount)
Definition localbuf.c:829
int NLocBuffer
Definition localbuf.c:45
static SMgrRelation RelationGetSmgr(Relation rel)
Definition rel.h:578

References ErrorContextCallback::arg, BM_DIRTY, BM_VALID, BufferDescriptorGetBuffer(), BufTagMatchesRelFileLocator(), ErrorContextCallback::callback, CurrentResourceOwner, error_context_stack, fb(), FlushLocalBuffer(), FlushUnlockedBuffer(), GetBufferDescriptor(), GetLocalBufferDescriptor(), i, IOCONTEXT_NORMAL, IOOBJECT_RELATION, local_buffer_write_error_callback(), LockBufHdr(), NBuffers, NLocBuffer, pg_atomic_read_u64(), PinBuffer_Locked(), PinLocalBuffer(), ErrorContextCallback::previous, RelationData::rd_locator, RelationGetSmgr(), RelationUsesLocalBuffers, ReservePrivateRefCountEntry(), ResourceOwnerEnlarge(), UnlockBufHdr(), UnpinBuffer(), and UnpinLocalBuffer().

Referenced by fill_seq_with_data(), heapam_relation_copy_data(), and index_copy_data().

◆ FlushRelationsAllBuffers()

void FlushRelationsAllBuffers ( SMgrRelation smgrs,
int  nrels 
)

Definition at line 5273 of file bufmgr.c.

5274{
5275 int i;
5277 bool use_bsearch;
5278
5279 if (nrels == 0)
5280 return;
5281
5282 /* fill-in array for qsort */
5284
5285 for (i = 0; i < nrels; i++)
5286 {
5287 Assert(!RelFileLocatorBackendIsTemp(smgrs[i]->smgr_rlocator));
5288
5289 srels[i].rlocator = smgrs[i]->smgr_rlocator.locator;
5290 srels[i].srel = smgrs[i];
5291 }
5292
5293 /*
5294 * Save the bsearch overhead for low number of relations to sync. See
5295 * DropRelationsAllBuffers for details.
5296 */
5298
5299 /* sort the list of SMgrRelations if necessary */
5300 if (use_bsearch)
5301 qsort(srels, nrels, sizeof(SMgrSortArray), rlocator_comparator);
5302
5303 for (i = 0; i < NBuffers; i++)
5304 {
5308
5309 /*
5310 * As in DropRelationBuffers, an unlocked precheck should be safe and
5311 * saves some cycles.
5312 */
5313
5314 if (!use_bsearch)
5315 {
5316 int j;
5317
5318 for (j = 0; j < nrels; j++)
5319 {
5320 if (BufTagMatchesRelFileLocator(&bufHdr->tag, &srels[j].rlocator))
5321 {
5322 srelent = &srels[j];
5323 break;
5324 }
5325 }
5326 }
5327 else
5328 {
5329 RelFileLocator rlocator;
5330
5331 rlocator = BufTagGetRelFileLocator(&bufHdr->tag);
5332 srelent = bsearch(&rlocator,
5333 srels, nrels, sizeof(SMgrSortArray),
5335 }
5336
5337 /* buffer doesn't belong to any of the given relfilelocators; skip it */
5338 if (srelent == NULL)
5339 continue;
5340
5341 /* Make sure we can handle the pin */
5344
5346 if (BufTagMatchesRelFileLocator(&bufHdr->tag, &srelent->rlocator) &&
5348 {
5352 }
5353 else
5355 }
5356
5357 pfree(srels);
5358}

References Assert, BM_DIRTY, BM_VALID, BufTagGetRelFileLocator(), BufTagMatchesRelFileLocator(), CurrentResourceOwner, fb(), FlushUnlockedBuffer(), GetBufferDescriptor(), i, IOCONTEXT_NORMAL, IOOBJECT_RELATION, j, LockBufHdr(), NBuffers, palloc_array, pfree(), PinBuffer_Locked(), qsort, RelFileLocatorBackendIsTemp, RELS_BSEARCH_THRESHOLD, ReservePrivateRefCountEntry(), ResourceOwnerEnlarge(), rlocator_comparator(), UnlockBufHdr(), and UnpinBuffer().

Referenced by smgrdosyncall().

◆ FlushUnlockedBuffer()

static void FlushUnlockedBuffer ( BufferDesc buf,
SMgrRelation  reln,
IOObject  io_object,
IOContext  io_context 
)
static

Definition at line 4649 of file bufmgr.c.

4651{
4653
4656 BufferLockUnlock(buffer, buf);
4657}
static void BufferLockAcquire(Buffer buffer, BufferDesc *buf_hdr, BufferLockMode mode)
Definition bufmgr.c:5921
static void BufferLockUnlock(Buffer buffer, BufferDesc *buf_hdr)
Definition bufmgr.c:6037

References buf, PrivateRefCountEntry::buffer, BUFFER_LOCK_SHARE_EXCLUSIVE, BufferDescriptorGetBuffer(), BufferLockAcquire(), BufferLockUnlock(), fb(), and FlushBuffer().

Referenced by EvictUnpinnedBufferInternal(), FlushDatabaseBuffers(), FlushRelationBuffers(), FlushRelationsAllBuffers(), and SyncOneBuffer().

◆ ForgetPrivateRefCountEntry()

static void ForgetPrivateRefCountEntry ( PrivateRefCountEntry ref)
static

Definition at line 565 of file bufmgr.c.

566{
567 Assert(ref->data.refcount == 0);
568 Assert(ref->data.lockmode == BUFFER_LOCK_UNLOCK);
569
570 if (ref >= &PrivateRefCountArray[0] &&
572 {
573 ref->buffer = InvalidBuffer;
575
576
577 /*
578 * Mark the just used entry as reserved - in many scenarios that
579 * allows us to avoid ever having to search the array/hash for free
580 * entries.
581 */
583 }
584 else
585 {
589 }
590}
static int ReservedRefCountSlot
Definition bufmgr.c:268

References Assert, BUFFER_LOCK_UNLOCK, fb(), InvalidBuffer, PrivateRefCountArray, PrivateRefCountArrayKeys, PrivateRefCountHash, PrivateRefCountOverflowed, REFCOUNT_ARRAY_ENTRIES, and ReservedRefCountSlot.

Referenced by UnlockReleaseBuffer(), and UnpinBufferNoOwner().

◆ GetAdditionalPinLimit()

uint32 GetAdditionalPinLimit ( void  )

Definition at line 2707 of file bufmgr.c.

2708{
2710
2711 /*
2712 * We get the number of "overflowed" pins for free, but don't know the
2713 * number of pins in PrivateRefCountArray. The cost of calculating that
2714 * exactly doesn't seem worth it, so just assume the max.
2715 */
2717
2718 /* Is this backend already holding more than its fair share? */
2720 return 0;
2721
2723}
static uint32 MaxProportionalPins
Definition bufmgr.c:271

References fb(), MaxProportionalPins, PrivateRefCountOverflowed, and REFCOUNT_ARRAY_ENTRIES.

Referenced by LimitAdditionalPins(), and read_stream_start_pending_read().

◆ GetPinLimit()

uint32 GetPinLimit ( void  )

Definition at line 2695 of file bufmgr.c.

2696{
2697 return MaxProportionalPins;
2698}

References MaxProportionalPins.

Referenced by GetAccessStrategy(), and read_stream_begin_impl().

◆ GetPrivateRefCount()

static int32 GetPrivateRefCount ( Buffer  buffer)
inlinestatic

Definition at line 542 of file bufmgr.c.

543{
545
546 Assert(BufferIsValid(buffer));
547 Assert(!BufferIsLocal(buffer));
548
549 /*
550 * Not moving the entry - that's ok for the current users, but we might
551 * want to change this one day.
552 */
553 ref = GetPrivateRefCountEntry(buffer, false);
554
555 if (ref == NULL)
556 return 0;
557 return ref->data.refcount;
558}

References Assert, PrivateRefCountEntry::buffer, BufferIsLocal, BufferIsValid(), fb(), and GetPrivateRefCountEntry().

Referenced by CheckBufferIsPinnedOnce(), ConditionalLockBufferForCleanup(), DebugPrintBufferRefcount(), HoldingBufferPinThatDelaysRecovery(), InvalidateBuffer(), InvalidateVictimBuffer(), IsBufferCleanupOK(), and MarkSharedBufferDirtyHint().

◆ GetPrivateRefCountEntry()

static PrivateRefCountEntry * GetPrivateRefCountEntry ( Buffer  buffer,
bool  do_move 
)
inlinestatic

Definition at line 507 of file bufmgr.c.

508{
509 Assert(BufferIsValid(buffer));
510 Assert(!BufferIsLocal(buffer));
511
512 /*
513 * It's very common to look up the same buffer repeatedly. To make that
514 * fast, we have a one-entry cache.
515 *
516 * In contrast to the loop in GetPrivateRefCountEntrySlow(), here it
517 * faster to check PrivateRefCountArray[].buffer, as in the case of a hit
518 * fewer addresses are computed and fewer cachelines are accessed. Whereas
519 * in GetPrivateRefCountEntrySlow()'s case, checking
520 * PrivateRefCountArrayKeys saves a lot of memory accesses.
521 */
522 if (likely(PrivateRefCountEntryLast != -1) &&
524 {
526 }
527
528 /*
529 * The code for the cached lookup is small enough to be worth inlining
530 * into the caller. In the miss case however, that empirically doesn't
531 * seem worth it.
532 */
533 return GetPrivateRefCountEntrySlow(buffer, do_move);
534}
static pg_noinline PrivateRefCountEntry * GetPrivateRefCountEntrySlow(Buffer buffer, bool do_move)
Definition bufmgr.c:419
static int PrivateRefCountEntryLast
Definition bufmgr.c:269

References Assert, PrivateRefCountEntry::buffer, BufferIsLocal, BufferIsValid(), fb(), GetPrivateRefCountEntrySlow(), likely, PrivateRefCountArray, and PrivateRefCountEntryLast.

Referenced by BufferLockAcquire(), BufferLockConditional(), BufferLockDisownInternal(), BufferLockHeldByMe(), BufferLockHeldByMeInMode(), GetPrivateRefCount(), IncrBufferRefCount(), PinBuffer(), PinBuffer_Locked(), ResOwnerReleaseBuffer(), SharedBufferBeginSetHintBits(), UnlockReleaseBuffer(), and UnpinBufferNoOwner().

◆ GetPrivateRefCountEntrySlow()

static pg_noinline PrivateRefCountEntry * GetPrivateRefCountEntrySlow ( Buffer  buffer,
bool  do_move 
)
static

Definition at line 419 of file bufmgr.c.

420{
422 int match = -1;
423 int i;
424
425 /*
426 * First search for references in the array, that'll be sufficient in the
427 * majority of cases.
428 */
429 for (i = 0; i < REFCOUNT_ARRAY_ENTRIES; i++)
430 {
431 if (PrivateRefCountArrayKeys[i] == buffer)
432 {
433 match = i;
434 /* see ReservePrivateRefCountEntry() for why we don't return */
435 }
436 }
437
438 if (likely(match != -1))
439 {
440 /* update cache for the next lookup */
442
443 return &PrivateRefCountArray[match];
444 }
445
446 /*
447 * By here we know that the buffer, if already pinned, isn't residing in
448 * the array.
449 *
450 * Only look up the buffer in the hashtable if we've previously overflowed
451 * into it.
452 */
454 return NULL;
455
457
458 if (res == NULL)
459 return NULL;
460 else if (!do_move)
461 {
462 /* caller doesn't want us to move the hash entry into the array */
463 return res;
464 }
465 else
466 {
467 /* move buffer from hashtable into the free array slot */
470
471 /* Save data and delete from hashtable while res is still valid */
472 data = res->data;
476
477 /* Ensure there's a free array slot */
479
480 /* Use up the reserved slot */
484 Assert(free->buffer == InvalidBuffer);
485
486 /* and fill it */
487 free->buffer = buffer;
488 free->data = data;
490 /* update cache for the next lookup */
492
494
495 return free;
496 }
497}
const void * data
#define free(a)

References Assert, PrivateRefCountEntry::buffer, PrivateRefCountEntry::data, data, fb(), free, i, InvalidBuffer, likely, PrivateRefCountArray, PrivateRefCountArrayKeys, PrivateRefCountEntryLast, PrivateRefCountHash, PrivateRefCountOverflowed, REFCOUNT_ARRAY_ENTRIES, ReservedRefCountSlot, and ReservePrivateRefCountEntry().

Referenced by GetPrivateRefCountEntry().

◆ GetVictimBuffer()

static Buffer GetVictimBuffer ( BufferAccessStrategy  strategy,
IOContext  io_context 
)
static

Definition at line 2548 of file bufmgr.c.

2549{
2551 Buffer buf;
2553 bool from_ring;
2554
2555 /*
2556 * Ensure, before we pin a victim buffer, that there's a free refcount
2557 * entry and resource owner slot for the pin.
2558 */
2561
2562 /* we return here if a prospective victim buffer gets used concurrently */
2563again:
2564
2565 /*
2566 * Select a victim buffer. The buffer is returned pinned and owned by
2567 * this backend.
2568 */
2571
2572 /*
2573 * We shouldn't have any other pins for this buffer.
2574 */
2576
2577 /*
2578 * If the buffer was dirty, try to write it out. There is a race
2579 * condition here, another backend could dirty the buffer between
2580 * StrategyGetBuffer() checking that it is not in use and invalidating the
2581 * buffer below. That's addressed by InvalidateVictimBuffer() verifying
2582 * that the buffer is not dirty.
2583 */
2584 if (buf_state & BM_DIRTY)
2585 {
2588
2589 /*
2590 * We need a share-exclusive lock on the buffer contents to write it
2591 * out (else we might write invalid data, eg because someone else is
2592 * compacting the page contents while we write). We must use a
2593 * conditional lock acquisition here to avoid deadlock. Even though
2594 * the buffer was not pinned (and therefore surely not locked) when
2595 * StrategyGetBuffer returned it, someone else could have pinned and
2596 * (share-)exclusive-locked it by the time we get here. If we try to
2597 * get the lock unconditionally, we'd block waiting for them; if they
2598 * later block waiting for us, deadlock ensues. (This has been
2599 * observed to happen when two backends are both trying to split btree
2600 * index pages, and the second one just happens to be trying to split
2601 * the page the first one got from StrategyGetBuffer.)
2602 */
2604 {
2605 /*
2606 * Someone else has locked the buffer, so give it up and loop back
2607 * to get another one.
2608 */
2610 goto again;
2611 }
2612
2613 /*
2614 * If using a nondefault strategy, and this victim came from the
2615 * strategy ring, let the strategy decide whether to reject it when
2616 * reusing it would require a WAL flush. This only applies to
2617 * permanent buffers; unlogged buffers can have fake LSNs, so
2618 * XLogNeedsFlush() is not meaningful for them.
2619 *
2620 * We need to hold the content lock in at least share-exclusive mode
2621 * to safely inspect the page LSN, so this couldn't have been done
2622 * inside StrategyGetBuffer().
2623 */
2624 if (strategy && from_ring &&
2628 {
2630 goto again;
2631 }
2632
2633 /* OK, do the I/O */
2636
2638 &buf_hdr->tag);
2639 }
2640
2641
2642 if (buf_state & BM_VALID)
2643 {
2644 /*
2645 * When a BufferAccessStrategy is in use, blocks evicted from shared
2646 * buffers are counted as IOOP_EVICT in the corresponding context
2647 * (e.g. IOCONTEXT_BULKWRITE). Shared buffers are evicted by a
2648 * strategy in two cases: 1) while initially claiming buffers for the
2649 * strategy ring 2) to replace an existing strategy ring buffer
2650 * because it is pinned or in use and cannot be reused.
2651 *
2652 * Blocks evicted from buffers already in the strategy ring are
2653 * counted as IOOP_REUSE in the corresponding strategy context.
2654 *
2655 * At this point, we can accurately count evictions and reuses,
2656 * because we have successfully claimed the valid buffer. Previously,
2657 * we may have been forced to release the buffer due to concurrent
2658 * pinners or erroring out.
2659 */
2661 from_ring ? IOOP_REUSE : IOOP_EVICT, 1, 0);
2662 }
2663
2664 /*
2665 * If the buffer has an entry in the buffer mapping table, delete it. This
2666 * can fail because another backend could have pinned or dirtied the
2667 * buffer.
2668 */
2670 {
2672 goto again;
2673 }
2674
2675 /* a final set of sanity checks */
2676#ifdef USE_ASSERT_CHECKING
2678
2681
2683#endif
2684
2685 return buf;
2686}
WritebackContext BackendWritebackContext
Definition buf_init.c:27
void CheckBufferIsPinnedOnce(Buffer buffer)
Definition bufmgr.c:6660
void UnlockReleaseBuffer(Buffer buffer)
Definition bufmgr.c:5626
void ScheduleBufferTagForWriteback(WritebackContext *wb_context, IOContext io_context, BufferTag *tag)
Definition bufmgr.c:7739
BufferDesc * StrategyGetBuffer(BufferAccessStrategy strategy, uint64 *buf_state, bool *from_ring)
Definition freelist.c:184
bool StrategyRejectBuffer(BufferAccessStrategy strategy, BufferDesc *buf, bool from_ring)
Definition freelist.c:752
@ IOOP_EVICT
Definition pgstat.h:311
@ IOOP_REUSE
Definition pgstat.h:314
void pgstat_count_io_op(IOObject io_object, IOContext io_context, IOOp io_op, uint32 cnt, uint64 bytes)
Definition pgstat_io.c:68
bool XLogNeedsFlush(XLogRecPtr record)
Definition xlog.c:3159

References Assert, BackendWritebackContext, BM_DIRTY, BM_PERMANENT, BM_TAG_VALID, BM_VALID, buf, BUF_STATE_GET_REFCOUNT, BUFFER_LOCK_SHARE_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferDescriptorGetBuffer(), BufferGetLSN, BufferLockConditional(), CheckBufferIsPinnedOnce(), CurrentResourceOwner, fb(), FlushBuffer(), InvalidateVictimBuffer(), IOOBJECT_RELATION, IOOP_EVICT, IOOP_REUSE, LockBuffer(), pg_atomic_read_u64(), pgstat_count_io_op(), ReservePrivateRefCountEntry(), ResourceOwnerEnlarge(), ScheduleBufferTagForWriteback(), StrategyGetBuffer(), StrategyRejectBuffer(), UnlockReleaseBuffer(), UnpinBuffer(), and XLogNeedsFlush().

Referenced by BufferAlloc(), and ExtendBufferedRelShared().

◆ HoldingBufferPinThatDelaysRecovery()

bool HoldingBufferPinThatDelaysRecovery ( void  )

Definition at line 6866 of file bufmgr.c.

6867{
6869
6870 /*
6871 * If we get woken slowly then it's possible that the Startup process was
6872 * already woken by other backends before we got here. Also possible that
6873 * we get here by multiple interrupts or interrupts at inappropriate
6874 * times, so make sure we do nothing if the bufid is not set.
6875 */
6876 if (bufid < 0)
6877 return false;
6878
6879 if (GetPrivateRefCount(bufid + 1) > 0)
6880 return true;
6881
6882 return false;
6883}
int GetStartupBufferPinWaitBufId(void)
Definition proc.c:771

References fb(), GetPrivateRefCount(), and GetStartupBufferPinWaitBufId().

Referenced by CheckRecoveryConflictDeadlock(), and ProcessRecoveryConflictInterrupt().

◆ IncrBufferRefCount()

void IncrBufferRefCount ( Buffer  buffer)

Definition at line 5693 of file bufmgr.c.

5694{
5695 Assert(BufferIsPinned(buffer));
5697 if (BufferIsLocal(buffer))
5698 LocalRefCount[-buffer - 1]++;
5699 else
5700 {
5702
5703 ref = GetPrivateRefCountEntry(buffer, true);
5704 Assert(ref != NULL);
5705 ref->data.refcount++;
5706 }
5708}
static void ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer)

References Assert, PrivateRefCountEntry::buffer, BufferIsLocal, BufferIsPinned, CurrentResourceOwner, fb(), GetPrivateRefCountEntry(), LocalRefCount, ResourceOwnerEnlarge(), and ResourceOwnerRememberBuffer().

Referenced by _bt_steppage(), btrestrpos(), entryLoadMoreItems(), ReadBufferBI(), RelationAddBlocks(), scanPostingTree(), startScanEntry(), and tts_buffer_heap_store_tuple().

◆ InitBufferManagerAccess()

void InitBufferManagerAccess ( void  )

Definition at line 4239 of file bufmgr.c.

4240{
4241 /*
4242 * An advisory limit on the number of pins each backend should hold, based
4243 * on shared_buffers and the maximum number of connections possible.
4244 * That's very pessimistic, but outside toy-sized shared_buffers it should
4245 * allow plenty of pins. LimitAdditionalPins() and
4246 * GetAdditionalPinLimit() can be used to check the remaining balance.
4247 */
4249
4252
4254
4255 /*
4256 * AtProcExit_Buffers needs LWLock access, and thereby has to be called at
4257 * the corresponding phase of backend shutdown.
4258 */
4259 Assert(MyProc != NULL);
4261}
static void AtProcExit_Buffers(int code, Datum arg)
Definition bufmgr.c:4268
int MaxBackends
Definition globals.c:149
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition ipc.c:372
MemoryContext CurrentMemoryContext
Definition mcxt.c:161
#define NUM_AUXILIARY_PROCS
Definition proc.h:527

References Assert, AtProcExit_Buffers(), CurrentMemoryContext, fb(), MaxBackends, MaxProportionalPins, MyProc, NBuffers, NUM_AUXILIARY_PROCS, on_shmem_exit(), PrivateRefCountArray, PrivateRefCountArrayKeys, and PrivateRefCountHash.

Referenced by BaseInit().

◆ InvalidateBuffer()

static void InvalidateBuffer ( BufferDesc buf)
static

Definition at line 2370 of file bufmgr.c.

2371{
2373 uint32 oldHash; /* hash value for oldTag */
2374 LWLock *oldPartitionLock; /* buffer partition lock for it */
2377
2378 /* Save the original buffer tag before dropping the spinlock */
2379 oldTag = buf->tag;
2380
2382
2383 /*
2384 * Need to compute the old tag's hashcode and partition lock ID. XXX is it
2385 * worth storing the hashcode in BufferDesc so we need not recompute it
2386 * here? Probably not.
2387 */
2390
2391retry:
2392
2393 /*
2394 * Acquire exclusive mapping lock in preparation for changing the buffer's
2395 * association.
2396 */
2398
2399 /* Re-lock the buffer header */
2401
2402 /* If it's changed while we were waiting for lock, do nothing */
2403 if (!BufferTagsEqual(&buf->tag, &oldTag))
2404 {
2407 return;
2408 }
2409
2410 /*
2411 * We assume the reason for it to be pinned is that either we were
2412 * asynchronously reading the page in before erroring out or someone else
2413 * is flushing the page out. Wait for the IO to finish. (This could be
2414 * an infinite loop if the refcount is messed up... it would be nice to
2415 * time out after awhile, but there seems no way to be sure how many loops
2416 * may be needed. Note that if the other guy has pinned the buffer but
2417 * not yet done StartBufferIO, WaitIO will fall through and we'll
2418 * effectively be busy-looping here.)
2419 */
2421 {
2424 /* safety check: should definitely not be our *own* pin */
2426 elog(ERROR, "buffer is pinned in InvalidateBuffer");
2427 WaitIO(buf);
2428 goto retry;
2429 }
2430
2431 /*
2432 * An invalidated buffer should not have any backends waiting to lock the
2433 * buffer, therefore BM_LOCK_WAKE_IN_PROGRESS should not be set.
2434 */
2436
2437 /*
2438 * Clear out the buffer's tag and flags. We must do this to ensure that
2439 * linear scans of the buffer array don't think the buffer is valid.
2440 */
2442 ClearBufferTag(&buf->tag);
2443
2445 0,
2447 0);
2448
2449 /*
2450 * Remove the buffer from the lookup hashtable, if it was in there.
2451 */
2452 if (oldFlags & BM_TAG_VALID)
2454
2455 /*
2456 * Done with mapping lock.
2457 */
2459}
#define BUF_USAGECOUNT_MASK
static bool BufferTagsEqual(const BufferTag *tag1, const BufferTag *tag2)
static void ClearBufferTag(BufferTag *tag)
void BufTableDelete(BufferTag *tagPtr, uint32 hashcode)
Definition buf_table.c:154
static void WaitIO(BufferDesc *buf)
Definition bufmgr.c:7188

References Assert, BM_LOCK_WAKE_IN_PROGRESS, BM_TAG_VALID, buf, BUF_FLAG_MASK, BUF_STATE_GET_REFCOUNT, BUF_USAGECOUNT_MASK, BufferDescriptorGetBuffer(), BufferTagsEqual(), BufMappingPartitionLock(), BufTableDelete(), BufTableHashCode(), ClearBufferTag(), elog, ERROR, fb(), GetPrivateRefCount(), LockBufHdr(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), UnlockBufHdr(), UnlockBufHdrExt(), and WaitIO().

Referenced by DropDatabaseBuffers(), DropRelationBuffers(), DropRelationsAllBuffers(), and FindAndDropRelationBuffers().

◆ InvalidateVictimBuffer()

static bool InvalidateVictimBuffer ( BufferDesc buf_hdr)
static

Definition at line 2471 of file bufmgr.c.

2472{
2474 uint32 hash;
2476 BufferTag tag;
2477
2479
2480 /* have buffer pinned, so it's safe to read tag without lock */
2481 tag = buf_hdr->tag;
2482
2483 hash = BufTableHashCode(&tag);
2485
2487
2488 /* lock the buffer header */
2490
2491 /*
2492 * We have the buffer pinned nobody else should have been able to unset
2493 * this concurrently.
2494 */
2497 Assert(BufferTagsEqual(&buf_hdr->tag, &tag));
2498
2499 /*
2500 * If somebody else pinned the buffer since, or even worse, dirtied it,
2501 * give up on this buffer: It's clearly in use.
2502 */
2504 {
2506
2509
2510 return false;
2511 }
2512
2513 /*
2514 * An invalidated buffer should not have any backends waiting to lock the
2515 * buffer, therefore BM_LOCK_WAKE_IN_PROGRESS should not be set.
2516 */
2518
2519 /*
2520 * Clear out the buffer's tag and flags and usagecount. This is not
2521 * strictly required, as BM_TAG_VALID/BM_VALID needs to be checked before
2522 * doing anything with the buffer. But currently it's beneficial, as the
2523 * cheaper pre-check for several linear scans of shared buffers use the
2524 * tag (see e.g. FlushDatabaseBuffers()).
2525 */
2526 ClearBufferTag(&buf_hdr->tag);
2528 0,
2530 0);
2531
2533
2534 /* finally delete buffer from the buffer mapping table */
2535 BufTableDelete(&tag, hash);
2536
2538
2543
2544 return true;
2545}

References Assert, BM_DIRTY, BM_LOCK_WAKE_IN_PROGRESS, BM_TAG_VALID, BM_VALID, BUF_FLAG_MASK, BUF_STATE_GET_REFCOUNT, BUF_USAGECOUNT_MASK, BufferDescriptorGetBuffer(), BufferTagsEqual(), BufMappingPartitionLock(), BufTableDelete(), BufTableHashCode(), ClearBufferTag(), fb(), GetPrivateRefCount(), hash(), LockBufHdr(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), pg_atomic_read_u64(), UnlockBufHdr(), and UnlockBufHdrExt().

Referenced by EvictUnpinnedBufferInternal(), and GetVictimBuffer().

◆ IsBufferCleanupOK()

bool IsBufferCleanupOK ( Buffer  buffer)

Definition at line 6950 of file bufmgr.c.

6951{
6954
6955 Assert(BufferIsValid(buffer));
6956
6957 /* see AIO related comment in LockBufferForCleanup() */
6958
6959 if (BufferIsLocal(buffer))
6960 {
6961 /* There should be exactly one pin */
6962 if (LocalRefCount[-buffer - 1] != 1)
6963 return false;
6964 /* Nobody else to wait for */
6965 return true;
6966 }
6967
6968 /* There should be exactly one local pin */
6969 if (GetPrivateRefCount(buffer) != 1)
6970 return false;
6971
6972 bufHdr = GetBufferDescriptor(buffer - 1);
6973
6974 /* caller must hold exclusive lock on buffer */
6976
6978
6981 {
6982 /* pincount is OK. */
6984 return true;
6985 }
6986
6988 return false;
6989}

References Assert, BUF_STATE_GET_REFCOUNT, PrivateRefCountEntry::buffer, BUFFER_LOCK_EXCLUSIVE, BufferIsLocal, BufferIsLockedByMeInMode(), BufferIsValid(), fb(), GetBufferDescriptor(), GetPrivateRefCount(), LocalRefCount, LockBufHdr(), and UnlockBufHdr().

Referenced by _hash_doinsert(), _hash_expandtable(), _hash_splitbucket(), and hashbucketcleanup().

◆ IssuePendingWritebacks()

void IssuePendingWritebacks ( WritebackContext wb_context,
IOContext  io_context 
)

Definition at line 7789 of file bufmgr.c.

7790{
7792 int i;
7793
7794 if (wb_context->nr_pending == 0)
7795 return;
7796
7797 /*
7798 * Executing the writes in-order can make them a lot faster, and allows to
7799 * merge writeback requests to consecutive blocks into larger writebacks.
7800 */
7801 sort_pending_writebacks(wb_context->pending_writebacks,
7802 wb_context->nr_pending);
7803
7805
7806 /*
7807 * Coalesce neighbouring writes, but nothing else. For that we iterate
7808 * through the, now sorted, array of pending flushes, and look forward to
7809 * find all neighbouring (or identical) writes.
7810 */
7811 for (i = 0; i < wb_context->nr_pending; i++)
7812 {
7816 int ahead;
7817 BufferTag tag;
7819 Size nblocks = 1;
7820
7821 cur = &wb_context->pending_writebacks[i];
7822 tag = cur->tag;
7824
7825 /*
7826 * Peek ahead, into following writeback requests, to see if they can
7827 * be combined with the current one.
7828 */
7829 for (ahead = 0; i + ahead + 1 < wb_context->nr_pending; ahead++)
7830 {
7831
7832 next = &wb_context->pending_writebacks[i + ahead + 1];
7833
7834 /* different file, stop */
7836 BufTagGetRelFileLocator(&next->tag)) ||
7837 BufTagGetForkNum(&cur->tag) != BufTagGetForkNum(&next->tag))
7838 break;
7839
7840 /* ok, block queued twice, skip */
7841 if (cur->tag.blockNum == next->tag.blockNum)
7842 continue;
7843
7844 /* only merge consecutive writes */
7845 if (cur->tag.blockNum + 1 != next->tag.blockNum)
7846 break;
7847
7848 nblocks++;
7849 cur = next;
7850 }
7851
7852 i += ahead;
7853
7854 /* and finally tell the kernel to write the data to storage */
7856 smgrwriteback(reln, BufTagGetForkNum(&tag), tag.blockNum, nblocks);
7857 }
7858
7859 /*
7860 * Assume that writeback requests are only issued for buffers containing
7861 * blocks of permanent relations.
7862 */
7864 IOOP_WRITEBACK, io_start, wb_context->nr_pending, 0);
7865
7866 wb_context->nr_pending = 0;
7867}
static int32 next
Definition blutils.c:225
struct cursor * cur
Definition ecpg.c:29
@ IOOP_WRITEBACK
Definition pgstat.h:315
#define RelFileLocatorEquals(locator1, locator2)
void smgrwriteback(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, BlockNumber nblocks)
Definition smgr.c:805

References buftag::blockNum, BufTagGetForkNum(), BufTagGetRelFileLocator(), cur, fb(), i, INVALID_PROC_NUMBER, IOOBJECT_RELATION, IOOP_WRITEBACK, next, pgstat_count_io_op_time(), pgstat_prepare_io_time(), RelFileLocatorEquals, smgropen(), smgrwriteback(), and track_io_timing.

Referenced by BufferSync(), and ScheduleBufferTagForWriteback().

◆ LimitAdditionalPins()

void LimitAdditionalPins ( uint32 additional_pins)

Definition at line 2733 of file bufmgr.c.

2734{
2735 uint32 limit;
2736
2737 if (*additional_pins <= 1)
2738 return;
2739
2740 limit = GetAdditionalPinLimit();
2741 limit = Max(limit, 1);
2742 if (limit < *additional_pins)
2743 *additional_pins = limit;
2744}
uint32 GetAdditionalPinLimit(void)
Definition bufmgr.c:2707
#define Max(x, y)
Definition c.h:1144

References fb(), GetAdditionalPinLimit(), and Max.

Referenced by ExtendBufferedRelShared().

◆ local_buffer_readv_complete()

static PgAioResult local_buffer_readv_complete ( PgAioHandle ioh,
PgAioResult  prior_result,
uint8  cb_data 
)
static

Definition at line 8980 of file bufmgr.c.

8982{
8984}
static pg_attribute_always_inline PgAioResult buffer_readv_complete(PgAioHandle *ioh, PgAioResult prior_result, uint8 cb_data, bool is_temp)
Definition bufmgr.c:8725

References buffer_readv_complete(), and fb().

◆ local_buffer_readv_stage()

static void local_buffer_readv_stage ( PgAioHandle ioh,
uint8  cb_data 
)
static

Definition at line 8974 of file bufmgr.c.

8975{
8976 buffer_stage_common(ioh, false, true);
8977}
static pg_attribute_always_inline void buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp)
Definition bufmgr.c:8330

References buffer_stage_common(), and fb().

◆ local_buffer_write_error_callback()

static void local_buffer_write_error_callback ( void arg)
static

Definition at line 7524 of file bufmgr.c.

7525{
7527
7528 if (bufHdr != NULL)
7529 errcontext("writing block %u of relation \"%s\"",
7530 bufHdr->tag.blockNum,
7533 BufTagGetForkNum(&bufHdr->tag)).str);
7534}
Datum arg
Definition elog.c:1323
#define errcontext
Definition elog.h:200

References arg, BufTagGetForkNum(), BufTagGetRelFileLocator(), errcontext, fb(), MyProcNumber, and relpathbackend.

Referenced by FlushRelationBuffers().

◆ LockBufferForCleanup()

void LockBufferForCleanup ( Buffer  buffer)

Definition at line 6693 of file bufmgr.c.

6694{
6696 TimestampTz waitStart = 0;
6697 bool waiting = false;
6698 bool logged_recovery_conflict = false;
6699
6700 Assert(BufferIsPinned(buffer));
6702
6704
6705 /*
6706 * We do not yet need to be worried about in-progress AIOs holding a pin,
6707 * as we, so far, only support doing reads via AIO and this function can
6708 * only be called once the buffer is valid (i.e. no read can be in
6709 * flight).
6710 */
6711
6712 /* Nobody else to wait for */
6713 if (BufferIsLocal(buffer))
6714 return;
6715
6716 bufHdr = GetBufferDescriptor(buffer - 1);
6717
6718 for (;;)
6719 {
6721 uint64 unset_bits = 0;
6722
6723 /* Try to acquire lock */
6726
6729 {
6730 /* Successfully acquired exclusive lock with pincount 1 */
6733 }
6734 /* Failed, so mark myself as waiting for pincount 1 */
6736 {
6739 elog(ERROR, "multiple backends attempting to wait for pincount 1");
6740 }
6741 bufHdr->wait_backend_pgprocno = MyProcNumber;
6743
6744 /*
6745 * Publish BM_PIN_COUNT_WAITER while retaining the buffer header lock.
6746 * The shared refcount can be decremented while BM_LOCKED is set, so
6747 * use an atomic operation that preserves concurrent refcount changes.
6748 */
6750
6751 /*
6752 * Recheck the refcount after publishing the waiter flag, while shared
6753 * refcount increments are still prevented by BM_LOCKED. If only our
6754 * pin remains, the cleanup-lock condition has already been satisfied,
6755 * so remove the waiter state and return without sleeping.
6756 */
6758
6760 {
6763 0);
6766 }
6767
6770
6771 /* Wait to be signaled by UnpinBuffer() */
6772 if (InHotStandby)
6773 {
6774 if (!waiting)
6775 {
6776 /* adjust the process title to indicate that it's waiting */
6777 set_ps_display_suffix("waiting");
6778 waiting = true;
6779 }
6780
6781 /*
6782 * Emit the log message if the startup process is waiting longer
6783 * than deadlock_timeout for recovery conflict on buffer pin.
6784 *
6785 * Skip this if first time through because the startup process has
6786 * not started waiting yet in this case. So, the wait start
6787 * timestamp is set after this logic.
6788 */
6789 if (waitStart != 0 && !logged_recovery_conflict)
6790 {
6792
6793 if (TimestampDifferenceExceeds(waitStart, now,
6795 {
6797 waitStart, now, NULL, true);
6799 }
6800 }
6801
6802 /*
6803 * Set the wait start timestamp if logging is enabled and first
6804 * time through.
6805 */
6806 if (log_recovery_conflict_waits && waitStart == 0)
6807 waitStart = GetCurrentTimestamp();
6808
6809 /* Publish the bufid that Startup process waits on */
6810 SetStartupBufferPinWaitBufId(buffer - 1);
6811 /* Set alarm and then wait to be signaled by UnpinBuffer() */
6813 /* Reset the published bufid */
6815 }
6816 else
6818
6819 /*
6820 * Remove flag marking us as waiter. Normally this will not be set
6821 * anymore, but ProcWaitForSignal() can return for other signals as
6822 * well. We take care to only reset the flag if we're the waiter, as
6823 * theoretically another backend could have started waiting. That's
6824 * impossible with the current usages due to table level locking, but
6825 * better be safe.
6826 */
6828 if ((buf_state & BM_PIN_COUNT_WAITER) != 0 &&
6829 bufHdr->wait_backend_pgprocno == MyProcNumber)
6831
6833 0, unset_bits,
6834 0);
6835
6837 /* Loop back and try again */
6838 }
6839
6841
6842 /*
6843 * Emit the log message if recovery conflict on buffer pin was resolved
6844 * but the startup process waited longer than deadlock_timeout for it.
6845 */
6848 waitStart, GetCurrentTimestamp(),
6849 NULL, false);
6850
6851 if (waiting)
6852 {
6853 /* reset ps display to remove the suffix if we added one */
6855 waiting = false;
6856 }
6857
6858 return;
6859}
bool TimestampDifferenceExceeds(TimestampTz start_time, TimestampTz stop_time, int msec)
Definition timestamp.c:1789
TimestampTz GetCurrentTimestamp(void)
Definition timestamp.c:1649
Datum now(PG_FUNCTION_ARGS)
Definition timestamp.c:1613
#define BM_PIN_COUNT_WAITER
static BufferDesc * PinCountWaitBuf
Definition bufmgr.c:228
int64 TimestampTz
Definition timestamp.h:39
void set_ps_display_remove_suffix(void)
Definition ps_status.c:440
void set_ps_display_suffix(const char *suffix)
Definition ps_status.c:388
int DeadlockTimeout
Definition proc.c:62
void SetStartupBufferPinWaitBufId(int bufid)
Definition proc.c:759
void ProcWaitForSignal(uint32 wait_event_info)
Definition proc.c:2049
void ResolveRecoveryConflictWithBufferPin(void)
Definition standby.c:795
bool log_recovery_conflict_waits
Definition standby.c:43
void LogRecoveryConflict(RecoveryConflictReason reason, TimestampTz wait_start, TimestampTz now, VirtualTransactionId *wait_list, bool still_waiting)
Definition standby.c:275
@ RECOVERY_CONFLICT_BUFFERPIN
Definition standby.h:49
static volatile sig_atomic_t waiting
#define InHotStandby
Definition xlogutils.h:60

References Assert, BM_PIN_COUNT_WAITER, BUF_STATE_GET_REFCOUNT, PrivateRefCountEntry::buffer, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferIsLocal, BufferIsPinned, CheckBufferIsPinnedOnce(), DeadlockTimeout, elog, ERROR, fb(), GetBufferDescriptor(), GetCurrentTimestamp(), InHotStandby, LockBuffer(), LockBufHdr(), log_recovery_conflict_waits, LogRecoveryConflict(), MyProcNumber, now(), pg_atomic_fetch_or_u64(), pg_atomic_read_u64(), PinCountWaitBuf, ProcWaitForSignal(), RECOVERY_CONFLICT_BUFFERPIN, ResolveRecoveryConflictWithBufferPin(), set_ps_display_remove_suffix(), set_ps_display_suffix(), SetStartupBufferPinWaitBufId(), TimestampDifferenceExceeds(), UnlockBufHdr(), UnlockBufHdrExt(), and waiting.

Referenced by _bt_upgradelockbufcleanup(), ginVacuumPostingTree(), hashbulkdelete(), heap_force_common(), lazy_scan_heap(), XLogReadBufferForRedoExtended(), and ZeroAndLockBuffer().

◆ LockBufferInternal()

void LockBufferInternal ( Buffer  buffer,
BufferLockMode  mode 
)

Definition at line 6597 of file bufmgr.c.

6598{
6600
6601 /*
6602 * We can't wait if we haven't got a PGPROC. This should only occur
6603 * during bootstrap or shared memory initialization. Put an Assert here
6604 * to catch unsafe coding practices.
6605 */
6607
6608 /* handled in LockBuffer() wrapper */
6610
6611 Assert(BufferIsPinned(buffer));
6612 if (BufferIsLocal(buffer))
6613 return; /* local buffers need no lock */
6614
6615 buf_hdr = GetBufferDescriptor(buffer - 1);
6616
6617 /*
6618 * Test the most frequent lock modes first. While a switch (mode) would be
6619 * nice, at least gcc generates considerably worse code for it.
6620 *
6621 * Call BufferLockAcquire() with a constant argument for mode, to generate
6622 * more efficient code for the different lock modes.
6623 */
6624 if (mode == BUFFER_LOCK_SHARE)
6626 else if (mode == BUFFER_LOCK_EXCLUSIVE)
6630 else
6631 elog(ERROR, "unrecognized buffer lock mode: %d", mode);
6632}
bool IsUnderPostmaster
Definition globals.c:122

References Assert, PrivateRefCountEntry::buffer, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_SHARE, BUFFER_LOCK_SHARE_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferIsLocal, BufferIsPinned, BufferLockAcquire(), elog, ERROR, fb(), GetBufferDescriptor(), IsUnderPostmaster, mode, and MyProc.

Referenced by LockBuffer().

◆ LockBufHdr()

uint64 LockBufHdr ( BufferDesc desc)

Definition at line 7567 of file bufmgr.c.

7568{
7570
7572
7573 while (true)
7574 {
7575 /*
7576 * Always try once to acquire the lock directly, without setting up
7577 * the spin-delay infrastructure. The work necessary for that shows up
7578 * in profiles and is rarely necessary.
7579 */
7581 if (likely(!(old_buf_state & BM_LOCKED)))
7582 break; /* got lock */
7583
7584 /* and then spin without atomic operations until lock is released */
7585 {
7587
7589
7590 while (old_buf_state & BM_LOCKED)
7591 {
7594 }
7596 }
7597
7598 /*
7599 * Retry. The lock might obviously already be re-acquired by the time
7600 * we're attempting to get it again.
7601 */
7602 }
7603
7604 return old_buf_state | BM_LOCKED;
7605}
void perform_spin_delay(SpinDelayStatus *status)
Definition s_lock.c:126
void finish_spin_delay(SpinDelayStatus *status)
Definition s_lock.c:186
#define init_local_spin_delay(status)
Definition s_lock.h:749

References Assert, BM_LOCKED, BufferDescriptorGetBuffer(), BufferIsLocal, fb(), finish_spin_delay(), init_local_spin_delay, likely, perform_spin_delay(), pg_atomic_fetch_or_u64(), pg_atomic_read_u64(), and BufferDesc::state.

Referenced by AbortBufferIO(), apw_dump_now(), buffer_stage_common(), BufferAlloc(), BufferGetLSNAtomic(), BufferLockDequeueSelf(), BufferLockQueueSelf(), BufferLockWakeup(), BufferSync(), ConditionalLockBufferForCleanup(), create_toy_buffer(), DropDatabaseBuffers(), DropRelationBuffers(), DropRelationsAllBuffers(), EvictAllUnpinnedBuffers(), EvictRelUnpinnedBuffers(), EvictUnpinnedBuffer(), ExtendBufferedRelShared(), FindAndDropRelationBuffers(), FlushDatabaseBuffers(), FlushRelationBuffers(), FlushRelationsAllBuffers(), InvalidateBuffer(), InvalidateVictimBuffer(), IsBufferCleanupOK(), LockBufferForCleanup(), MarkDirtyAllUnpinnedBuffers(), MarkDirtyRelUnpinnedBuffers(), MarkDirtyUnpinnedBuffer(), MarkSharedBufferDirtyHint(), pg_buffercache_os_pages_internal(), pg_buffercache_pages(), StartSharedBufferIO(), SyncOneBuffer(), TerminateBufferIO(), UnlockBuffers(), WaitIO(), and WakePinCountWaiter().

◆ MarkBufferDirty()

void MarkBufferDirty ( Buffer  buffer)

Definition at line 3170 of file bufmgr.c.

3171{
3175
3176 if (!BufferIsValid(buffer))
3177 elog(ERROR, "bad buffer ID: %d", buffer);
3178
3179 if (BufferIsLocal(buffer))
3180 {
3181 MarkLocalBufferDirty(buffer);
3182 return;
3183 }
3184
3185 bufHdr = GetBufferDescriptor(buffer - 1);
3186
3187 Assert(BufferIsPinned(buffer));
3189
3190 /*
3191 * NB: We have to wait for the buffer header spinlock to be not held, as
3192 * TerminateBufferIO() relies on the spinlock.
3193 */
3195 for (;;)
3196 {
3199
3201
3204
3206 buf_state))
3207 break;
3208 }
3209
3210 /*
3211 * If the buffer was not dirty already, do vacuum accounting.
3212 */
3213 if (!(old_buf_state & BM_DIRTY))
3214 {
3216 if (VacuumCostActive)
3218 }
3219}
pg_noinline uint64 WaitBufHdrUnlocked(BufferDesc *buf)
Definition bufmgr.c:7615
int VacuumCostPageDirty
Definition globals.c:156
int64 shared_blks_dirtied
Definition instrument.h:28

References Assert, BM_DIRTY, BM_LOCKED, BUF_STATE_GET_REFCOUNT, PrivateRefCountEntry::buffer, BUFFER_LOCK_EXCLUSIVE, BufferIsLocal, BufferIsLockedByMeInMode(), BufferIsPinned, BufferIsValid(), elog, ERROR, fb(), GetBufferDescriptor(), MarkLocalBufferDirty(), pg_atomic_compare_exchange_u64(), pg_atomic_read_u64(), pgBufferUsage, BufferUsage::shared_blks_dirtied, VacuumCostActive, VacuumCostBalance, VacuumCostPageDirty, and WaitBufHdrUnlocked().

Referenced by _bt_clear_incomplete_split(), _bt_dedup_pass(), _bt_delitems_delete(), _bt_delitems_vacuum(), _bt_getroot(), _bt_insertonpg(), _bt_mark_page_halfdead(), _bt_newlevel(), _bt_restore_meta(), _bt_set_cleanup_info(), _bt_split(), _bt_unlink_halfdead_page(), _hash_addovflpage(), _hash_doinsert(), _hash_expandtable(), _hash_freeovflpage(), _hash_init(), _hash_splitbucket(), _hash_squeezebucket(), _hash_vacuum_one_page(), addLeafTuple(), brin_doinsert(), brin_doupdate(), brin_initialize_empty_new_buffer(), brin_xlog_createidx(), brin_xlog_desummarize_page(), brin_xlog_insert_update(), brin_xlog_revmap_extend(), brin_xlog_samepage_update(), brin_xlog_update(), brinbuild(), brinbuildempty(), brinRevmapDesummarizeRange(), btree_xlog_dedup(), btree_xlog_delete(), btree_xlog_insert(), btree_xlog_mark_page_halfdead(), btree_xlog_newroot(), btree_xlog_split(), btree_xlog_unlink_page(), btree_xlog_vacuum(), createPostingTree(), dataExecPlaceToPageInternal(), dataExecPlaceToPageLeaf(), doPickSplit(), entryExecPlaceToPage(), fill_seq_fork_with_data(), FreeSpaceMapPrepareTruncateRel(), generic_redo(), GenericXLogFinish(), ginbuild(), ginbuildempty(), ginbulkdelete(), ginDeletePostingPage(), ginHeapTupleFastInsert(), ginPlaceToPage(), ginRedoClearIncompleteSplit(), ginRedoCreatePTree(), ginRedoDeleteListPages(), ginRedoDeletePage(), ginRedoInsert(), ginRedoInsertListPage(), ginRedoUpdateMetapage(), ginRedoVacuumDataLeafPage(), ginUpdateStats(), ginVacuumPostingTreeLeaf(), gistbuild(), gistbuildempty(), gistdeletepage(), gistplacetopage(), gistprunepage(), gistRedoClearFollowRight(), gistRedoDeleteRecord(), gistRedoPageDelete(), gistRedoPageSplitRecord(), gistRedoPageUpdateRecord(), gistvacuumpage(), hash_xlog_add_ovfl_page(), hash_xlog_delete(), hash_xlog_init_bitmap_page(), hash_xlog_init_meta_page(), hash_xlog_insert(), hash_xlog_move_page_contents(), hash_xlog_split_allocate_page(), hash_xlog_split_cleanup(), hash_xlog_split_complete(), hash_xlog_squeeze_page(), hash_xlog_update_meta_page(), hash_xlog_vacuum_one_page(), hashbucketcleanup(), hashbulkdelete(), heap_abort_speculative(), heap_delete(), heap_finish_speculative(), heap_force_common(), heap_inplace_update_and_unlock(), heap_insert(), heap_lock_tuple(), heap_lock_updated_tuple_rec(), heap_multi_insert(), heap_page_prune_and_freeze(), heap_update(), heap_xlog_confirm(), heap_xlog_delete(), heap_xlog_inplace(), heap_xlog_insert(), heap_xlog_lock(), heap_xlog_lock_updated(), heap_xlog_multi_insert(), heap_xlog_prune_freeze(), heap_xlog_update(), lazy_scan_new_or_empty(), lazy_vacuum_heap_page(), log_newpage_range(), MarkDirtyUnpinnedBufferInternal(), moveLeafs(), nextval_internal(), ProcessSingleRelationFork(), RelationAddBlocks(), RelationCopyStorageUsingBuffer(), RelationGetBufferForTuple(), revmap_physical_extend(), saveNodeLink(), seq_redo(), SetSequence(), shiftList(), spgAddNodeAction(), spgbuild(), SpGistUpdateMetaPage(), spgRedoAddLeaf(), spgRedoAddNode(), spgRedoMoveLeafs(), spgRedoPickSplit(), spgRedoSplitTuple(), spgRedoVacuumLeaf(), spgRedoVacuumRedirect(), spgRedoVacuumRoot(), spgSplitNodeAction(), vacuumLeafPage(), vacuumLeafRoot(), vacuumRedirectAndPlaceholder(), visibilitymap_clear(), visibilitymap_prepare_truncate(), visibilitymap_set(), writeListPage(), XLogReadBufferForRedoExtended(), and XLogRecordPageWithFreeSpace().

◆ MarkBufferDirtyHint()

void MarkBufferDirtyHint ( Buffer  buffer,
bool  buffer_std 
)
inline

◆ MarkDirtyAllUnpinnedBuffers()

void MarkDirtyAllUnpinnedBuffers ( int32 buffers_dirtied,
int32 buffers_already_dirty,
int32 buffers_skipped 
)

Definition at line 8281 of file bufmgr.c.

8284{
8285 *buffers_dirtied = 0;
8287 *buffers_skipped = 0;
8288
8289 for (int buf = 1; buf <= NBuffers; buf++)
8290 {
8291 BufferDesc *desc = GetBufferDescriptor(buf - 1);
8294
8296
8298 if (!(buf_state & BM_VALID))
8299 continue;
8300
8303
8304 LockBufHdr(desc);
8305
8307 (*buffers_dirtied)++;
8308 else if (buffer_already_dirty)
8309 (*buffers_already_dirty)++;
8310 else
8311 (*buffers_skipped)++;
8312 }
8313}
static bool MarkDirtyUnpinnedBufferInternal(Buffer buf, BufferDesc *desc, bool *buffer_already_dirty)
Definition bufmgr.c:8132

References BM_VALID, buf, CHECK_FOR_INTERRUPTS, CurrentResourceOwner, fb(), GetBufferDescriptor(), LockBufHdr(), MarkDirtyUnpinnedBufferInternal(), NBuffers, pg_atomic_read_u64(), ReservePrivateRefCountEntry(), ResourceOwnerEnlarge(), and BufferDesc::state.

Referenced by pg_buffercache_mark_dirty_all().

◆ MarkDirtyRelUnpinnedBuffers()

void MarkDirtyRelUnpinnedBuffers ( Relation  rel,
int32 buffers_dirtied,
int32 buffers_already_dirty,
int32 buffers_skipped 
)

Definition at line 8224 of file bufmgr.c.

8228{
8230
8231 *buffers_dirtied = 0;
8233 *buffers_skipped = 0;
8234
8235 for (int buf = 1; buf <= NBuffers; buf++)
8236 {
8237 BufferDesc *desc = GetBufferDescriptor(buf - 1);
8240
8242
8243 /* An unlocked precheck should be safe and saves some cycles. */
8244 if ((buf_state & BM_VALID) == 0 ||
8246 continue;
8247
8248 /* Make sure we can pin the buffer. */
8251
8252 buf_state = LockBufHdr(desc);
8253
8254 /* recheck, could have changed without the lock */
8255 if ((buf_state & BM_VALID) == 0 ||
8257 {
8258 UnlockBufHdr(desc);
8259 continue;
8260 }
8261
8263 (*buffers_dirtied)++;
8264 else if (buffer_already_dirty)
8265 (*buffers_already_dirty)++;
8266 else
8267 (*buffers_skipped)++;
8268 }
8269}

References Assert, BM_VALID, buf, BufTagMatchesRelFileLocator(), CHECK_FOR_INTERRUPTS, CurrentResourceOwner, fb(), GetBufferDescriptor(), LockBufHdr(), MarkDirtyUnpinnedBufferInternal(), NBuffers, pg_atomic_read_u64(), RelationData::rd_locator, RelationUsesLocalBuffers, ReservePrivateRefCountEntry(), ResourceOwnerEnlarge(), BufferDesc::state, BufferDesc::tag, and UnlockBufHdr().

Referenced by pg_buffercache_mark_dirty_relation().

◆ MarkDirtyUnpinnedBuffer()

bool MarkDirtyUnpinnedBuffer ( Buffer  buf,
bool buffer_already_dirty 
)

Definition at line 8188 of file bufmgr.c.

8189{
8190 BufferDesc *desc;
8191 bool buffer_dirtied = false;
8192
8194
8195 /* Make sure we can pin the buffer. */
8198
8199 desc = GetBufferDescriptor(buf - 1);
8200 LockBufHdr(desc);
8201
8203 /* Both can not be true at the same time */
8205
8206 return buffer_dirtied;
8207}

References Assert, buf, BufferIsLocal, CurrentResourceOwner, fb(), GetBufferDescriptor(), LockBufHdr(), MarkDirtyUnpinnedBufferInternal(), ReservePrivateRefCountEntry(), and ResourceOwnerEnlarge().

Referenced by pg_buffercache_mark_dirty().

◆ MarkDirtyUnpinnedBufferInternal()

static bool MarkDirtyUnpinnedBufferInternal ( Buffer  buf,
BufferDesc desc,
bool buffer_already_dirty 
)
static

Definition at line 8132 of file bufmgr.c.

8134{
8136 bool result = false;
8137
8138 *buffer_already_dirty = false;
8139
8142
8143 if ((buf_state & BM_VALID) == 0)
8144 {
8145 UnlockBufHdr(desc);
8146 return false;
8147 }
8148
8149 /* Check that it's not pinned already. */
8151 {
8152 UnlockBufHdr(desc);
8153 return false;
8154 }
8155
8156 /* Pin the buffer and then release the buffer spinlock */
8157 PinBuffer_Locked(desc);
8158
8159 /* If it was not already dirty, mark it as dirty. */
8160 if (!(buf_state & BM_DIRTY))
8161 {
8164 result = true;
8165 BufferLockUnlock(buf, desc);
8166 }
8167 else
8168 *buffer_already_dirty = true;
8169
8170 UnpinBuffer(desc);
8171
8172 return result;
8173}
void MarkBufferDirty(Buffer buffer)
Definition bufmgr.c:3170

References Assert, BM_DIRTY, BM_LOCKED, BM_VALID, buf, BUF_STATE_GET_REFCOUNT, BUFFER_LOCK_EXCLUSIVE, BufferLockAcquire(), BufferLockUnlock(), fb(), MarkBufferDirty(), pg_atomic_read_u64(), PinBuffer_Locked(), result, BufferDesc::state, UnlockBufHdr(), and UnpinBuffer().

Referenced by MarkDirtyAllUnpinnedBuffers(), MarkDirtyRelUnpinnedBuffers(), and MarkDirtyUnpinnedBuffer().

◆ MarkSharedBufferDirtyHint()

static void MarkSharedBufferDirtyHint ( Buffer  buffer,
BufferDesc bufHdr,
uint64  lockstate,
bool  buffer_std 
)
inlinestatic

Definition at line 5719 of file bufmgr.c.

5721{
5722 Page page = BufferGetPage(buffer);
5723
5724 Assert(GetPrivateRefCount(buffer) > 0);
5725
5726 /* here, either share-exclusive or exclusive lock is OK */
5729
5730 /*
5731 * This routine might get called many times on the same page, if we are
5732 * making the first scan after commit of an xact that added/deleted many
5733 * tuples. So, be as quick as we can if the buffer is already dirty.
5734 *
5735 * As we are holding (at least) a share-exclusive lock, nobody could have
5736 * cleaned or dirtied the page concurrently, so we can just rely on the
5737 * previously fetched value here without any danger of races.
5738 */
5739 if (unlikely(!(lockstate & BM_DIRTY)))
5740 {
5742 bool wal_log = false;
5744
5745 /*
5746 * If we need to protect hint bit updates from torn writes, WAL-log a
5747 * full page image of the page. This full page image is only necessary
5748 * if the hint bit update is the first change to the page since the
5749 * last checkpoint.
5750 *
5751 * We don't check full_page_writes here because that logic is included
5752 * when we call XLogInsert() since the value changes dynamically.
5753 */
5755 {
5756 /*
5757 * If we must not write WAL, due to a relfilelocator-specific
5758 * condition or being in recovery, don't dirty the page. We can
5759 * set the hint, just not dirty the page as a result so the hint
5760 * is lost when we evict the page or shutdown.
5761 *
5762 * See src/backend/storage/page/README for longer discussion.
5763 */
5764 if (RecoveryInProgress() ||
5766 return;
5767
5768 wal_log = true;
5769 }
5770
5771 /*
5772 * We must mark the page dirty before we emit the WAL record, as per
5773 * the usual rules, to ensure that BufferSync()/SyncOneBuffer() try to
5774 * flush the buffer, even if we haven't inserted the WAL record yet.
5775 * As we hold at least a share-exclusive lock, checkpoints will wait
5776 * for this backend to be done with the buffer before continuing. If
5777 * we did it the other way round, a checkpoint could start between
5778 * writing the WAL record and marking the buffer dirty.
5779 */
5781
5782 /*
5783 * It should not be possible for the buffer to already be dirty, see
5784 * comment above.
5785 */
5789 BM_DIRTY,
5790 0, 0);
5791
5792 /*
5793 * If the block is already dirty because we either made a change or
5794 * set a hint already, then we don't need to write a full page image.
5795 * Note that aggressive cleaning of blocks dirtied by hint bit setting
5796 * would increase the call rate. Bulk setting of hint bits would
5797 * reduce the call rate...
5798 */
5799 if (wal_log)
5800 lsn = XLogSaveBufferForHint(buffer, buffer_std);
5801
5802 if (XLogRecPtrIsValid(lsn))
5803 {
5804 /*
5805 * Set the page LSN if we wrote a backup block. To allow backends
5806 * that only hold a share lock on the buffer to read the LSN in a
5807 * tear-free manner, we set the page LSN while holding the buffer
5808 * header lock. This allows any reader of an LSN who holds only a
5809 * share lock to also obtain a buffer header lock before using
5810 * PageGetLSN() to read the LSN in a tear free way. This is done
5811 * in BufferGetLSNAtomic().
5812 *
5813 * If checksums are enabled, you might think we should reset the
5814 * checksum here. That will happen when the page is written
5815 * sometime later in this checkpoint cycle.
5816 */
5818 PageSetLSN(page, lsn);
5820 }
5821
5823 if (VacuumCostActive)
5825 }
5826}
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition bufpage.h:416
bool RelFileLocatorSkippingWAL(RelFileLocator rlocator)
Definition storage.c:573
bool RecoveryInProgress(void)
Definition xlog.c:6836
#define XLogRecPtrIsValid(r)
Definition xlogdefs.h:29
#define InvalidXLogRecPtr
Definition xlogdefs.h:28
XLogRecPtr XLogSaveBufferForHint(Buffer buffer, bool buffer_std)

References Assert, BM_DIRTY, BM_PERMANENT, BUF_STATE_GET_REFCOUNT, PrivateRefCountEntry::buffer, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_SHARE_EXCLUSIVE, BufferGetPage(), BufferLockHeldByMeInMode(), BufTagGetRelFileLocator(), fb(), GetPrivateRefCount(), InvalidXLogRecPtr, LockBufHdr(), PageSetLSN(), pgBufferUsage, RecoveryInProgress(), RelFileLocatorSkippingWAL(), BufferUsage::shared_blks_dirtied, unlikely, UnlockBufHdr(), UnlockBufHdrExt(), VacuumCostActive, VacuumCostBalance, VacuumCostPageDirty, XLogHintBitIsNeeded, XLogRecPtrIsValid, and XLogSaveBufferForHint().

Referenced by BufferSetHintBits16(), and MarkBufferDirtyHint().

◆ NewPrivateRefCountEntry()

static PrivateRefCountEntry * NewPrivateRefCountEntry ( Buffer  buffer)
static

Definition at line 388 of file bufmgr.c.

389{
391
392 /* only allowed to be called when a reservation has been made */
394
395 /* use up the reserved entry */
397
398 /* and fill it */
400 res->buffer = buffer;
401 res->data.refcount = 0;
403
404 /* update cache for the next lookup */
406
408
409 return res;
410}

References Assert, PrivateRefCountEntry::buffer, BUFFER_LOCK_UNLOCK, PrivateRefCountEntry::data, PrivateRefCountData::lockmode, PrivateRefCountArray, PrivateRefCountArrayKeys, PrivateRefCountEntryLast, PrivateRefCountData::refcount, and ReservedRefCountSlot.

Referenced by TrackNewBufferPin().

◆ PinBuffer()

static bool PinBuffer ( BufferDesc buf,
BufferAccessStrategy  strategy,
bool  skip_if_not_valid 
)
static

Definition at line 3295 of file bufmgr.c.

3297{
3299 bool result;
3301
3304
3305 ref = GetPrivateRefCountEntry(b, true);
3306
3307 if (ref == NULL)
3308 {
3311
3313 for (;;)
3314 {
3316 return false;
3317
3318 /*
3319 * We're not allowed to increase the refcount while the buffer
3320 * header spinlock is held. Wait for the lock to be released.
3321 */
3323 {
3325
3326 /* perform checks at the top of the loop again */
3327 continue;
3328 }
3329
3331
3332 /* increase refcount */
3334
3335 if (strategy == NULL)
3336 {
3337 /* Default case: increase usagecount unless already max. */
3340 }
3341 else
3342 {
3343 /*
3344 * Ring buffers shouldn't evict others from pool. Thus we
3345 * don't make usagecount more than 1.
3346 */
3349 }
3350
3352 buf_state))
3353 {
3354 result = (buf_state & BM_VALID) != 0;
3355
3357 break;
3358 }
3359 }
3360 }
3361 else
3362 {
3363 /*
3364 * If we previously pinned the buffer, it is likely to be valid, but
3365 * it may not be if StartReadBuffers() was called and
3366 * WaitReadBuffers() hasn't been called yet. We'll check by loading
3367 * the flags without locking. This is racy, but it's OK to return
3368 * false spuriously: when WaitReadBuffers() calls StartBufferIO(),
3369 * it'll see that it's now valid.
3370 *
3371 * Note: We deliberately avoid a Valgrind client request here.
3372 * Individual access methods can optionally superimpose buffer page
3373 * client requests on top of our client requests to enforce that
3374 * buffers are only accessed while locked (and pinned). It's possible
3375 * that the buffer page is legitimately non-accessible here. We
3376 * cannot meddle with that.
3377 */
3378 result = (pg_atomic_read_u64(&buf->state) & BM_VALID) != 0;
3379
3380 Assert(ref->data.refcount > 0);
3381 ref->data.refcount++;
3383 }
3384
3385 return result;
3386}
#define BM_MAX_USAGE_COUNT
#define BUF_STATE_GET_USAGECOUNT(state)
void TrackNewBufferPin(Buffer buf)
Definition bufmgr.c:3535

References Assert, b, BM_LOCKED, BM_MAX_USAGE_COUNT, BM_VALID, buf, BUF_REFCOUNT_ONE, BUF_STATE_GET_USAGECOUNT, BUF_USAGECOUNT_ONE, BufferDescriptorGetBuffer(), BufferIsLocal, CurrentResourceOwner, fb(), GetPrivateRefCountEntry(), pg_atomic_compare_exchange_u64(), pg_atomic_read_u64(), ReservedRefCountSlot, ResourceOwnerRememberBuffer(), result, TrackNewBufferPin(), unlikely, and WaitBufHdrUnlocked().

Referenced by BufferAlloc(), ExtendBufferedRelShared(), and ReadRecentBuffer().

◆ PinBuffer_Locked()

static void PinBuffer_Locked ( BufferDesc buf)
static

Definition at line 3411 of file bufmgr.c.

3412{
3414
3415 /*
3416 * As explained, We don't expect any preexisting pins. That allows us to
3417 * manipulate the PrivateRefCount after releasing the spinlock
3418 */
3420
3421 /*
3422 * Since we hold the buffer spinlock, we can update the buffer state and
3423 * release the lock in one operation.
3424 */
3426
3428 0, 0, 1);
3429
3431}

References Assert, buf, BufferDescriptorGetBuffer(), fb(), GetPrivateRefCountEntry(), pg_atomic_read_u64(), TrackNewBufferPin(), and UnlockBufHdrExt().

Referenced by EvictUnpinnedBufferInternal(), FlushDatabaseBuffers(), FlushRelationBuffers(), FlushRelationsAllBuffers(), MarkDirtyUnpinnedBufferInternal(), and SyncOneBuffer().

◆ PinBufferForBlock()

static pg_attribute_always_inline Buffer PinBufferForBlock ( Relation  rel,
SMgrRelation  smgr,
char  persistence,
ForkNumber  forkNum,
BlockNumber  blockNum,
BufferAccessStrategy  strategy,
IOObject  io_object,
IOContext  io_context,
bool foundPtr 
)
static

Definition at line 1223 of file bufmgr.c.

1232{
1234
1235 Assert(blockNum != P_NEW);
1236
1237 /* Persistence should be set before */
1238 Assert((persistence == RELPERSISTENCE_TEMP ||
1239 persistence == RELPERSISTENCE_PERMANENT ||
1240 persistence == RELPERSISTENCE_UNLOGGED));
1241
1242 TRACE_POSTGRESQL_BUFFER_READ_START(forkNum, blockNum,
1246 smgr->smgr_rlocator.backend);
1247
1248 if (persistence == RELPERSISTENCE_TEMP)
1249 bufHdr = LocalBufferAlloc(smgr, forkNum, blockNum, foundPtr);
1250 else
1251 bufHdr = BufferAlloc(smgr, persistence, forkNum, blockNum,
1252 strategy, foundPtr, io_context);
1253
1254 if (*foundPtr)
1255 TrackBufferHit(io_object, io_context, rel, persistence, smgr, forkNum, blockNum);
1256
1257 if (rel)
1258 {
1259 /*
1260 * While pgBufferUsage's "read" counter isn't bumped unless we reach
1261 * WaitReadBuffers() (so, not for hits, and not for buffers that are
1262 * zeroed instead), the per-relation stats always count them.
1263 */
1265 }
1266
1268}
static BufferDesc * BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, BlockNumber blockNum, BufferAccessStrategy strategy, bool *foundPtr, IOContext io_context)
Definition bufmgr.c:2197
#define P_NEW
Definition bufmgr.h:200
BufferDesc * LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, bool *foundPtr)
Definition localbuf.c:119
#define pgstat_count_buffer_read(rel)
Definition pgstat.h:755
RelFileNumber relNumber

References Assert, RelFileLocatorBackend::backend, BufferAlloc(), BufferDescriptorGetBuffer(), RelFileLocator::dbOid, fb(), LocalBufferAlloc(), RelFileLocatorBackend::locator, P_NEW, pgstat_count_buffer_read, RelFileLocator::relNumber, SMgrRelationData::smgr_rlocator, RelFileLocator::spcOid, and TrackBufferHit().

Referenced by ReadBuffer_common(), and StartReadBuffersImpl().

◆ PrefetchBuffer()

PrefetchBufferResult PrefetchBuffer ( Relation  reln,
ForkNumber  forkNum,
BlockNumber  blockNum 
)

Definition at line 787 of file bufmgr.c.

788{
790 Assert(BlockNumberIsValid(blockNum));
791
793 {
794 /* see comments in ReadBuffer_common */
798 errmsg("cannot access temporary tables of other sessions")));
799
800 /* pass it off to localbuf.c */
801 return PrefetchLocalBuffer(RelationGetSmgr(reln), forkNum, blockNum);
802 }
803 else
804 {
805 /* pass it to the shared buffer version */
806 return PrefetchSharedBuffer(RelationGetSmgr(reln), forkNum, blockNum);
807 }
808}
PrefetchBufferResult PrefetchSharedBuffer(SMgrRelation smgr_reln, ForkNumber forkNum, BlockNumber blockNum)
Definition bufmgr.c:697
PrefetchBufferResult PrefetchLocalBuffer(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum)
Definition localbuf.c:72
#define RelationIsValid(relation)
Definition rel.h:491

References Assert, BlockNumberIsValid(), ereport, errcode(), errmsg, ERROR, fb(), PrefetchLocalBuffer(), PrefetchSharedBuffer(), RELATION_IS_OTHER_TEMP, RelationGetSmgr(), RelationIsValid, and RelationUsesLocalBuffers.

Referenced by count_nondeletable_pages(), invalidate_one_block(), and pg_prewarm().

◆ PrefetchSharedBuffer()

PrefetchBufferResult PrefetchSharedBuffer ( SMgrRelation  smgr_reln,
ForkNumber  forkNum,
BlockNumber  blockNum 
)

Definition at line 697 of file bufmgr.c.

700{
702 BufferTag newTag; /* identity of requested block */
703 uint32 newHash; /* hash value for newTag */
704 LWLock *newPartitionLock; /* buffer partition lock for it */
705 int buf_id;
706
707 Assert(BlockNumberIsValid(blockNum));
708
709 /* create a tag so we can lookup the buffer */
710 InitBufferTag(&newTag, &smgr_reln->smgr_rlocator.locator,
711 forkNum, blockNum);
712
713 /* determine its hash code and partition lock ID */
716
717 /* see if the block is in the buffer pool already */
719 buf_id = BufTableLookup(&newTag, newHash);
721
722 /* If not in buffers, initiate prefetch */
723 if (buf_id < 0)
724 {
725#ifdef USE_PREFETCH
726 /*
727 * Try to initiate an asynchronous read. This returns false in
728 * recovery if the relation file doesn't exist.
729 */
730 if ((io_direct_flags & IO_DIRECT_DATA) == 0 &&
731 smgrprefetch(smgr_reln, forkNum, blockNum, 1))
732 {
733 result.initiated_io = true;
734 }
735#endif /* USE_PREFETCH */
736 }
737 else
738 {
739 /*
740 * Report the buffer it was in at that time. The caller may be able
741 * to avoid a buffer table lookup, but it's not pinned and it must be
742 * rechecked!
743 */
744 result.recent_buffer = buf_id + 1;
745 }
746
747 /*
748 * If the block *is* in buffers, we do nothing. This is not really ideal:
749 * the block might be just about to be evicted, which would be stupid
750 * since we know we are going to need it soon. But the only easy answer
751 * is to bump the usage_count, which does not seem like a great solution:
752 * when the caller does ultimately touch the block, usage_count would get
753 * bumped again, resulting in too much favoritism for blocks that are
754 * involved in a prefetch sequence. A real fix would involve some
755 * additional per-buffer state, and it's not clear that there's enough of
756 * a problem to justify that.
757 */
758
759 return result;
760}
int io_direct_flags
Definition fd.c:172
#define IO_DIRECT_DATA
Definition fd.h:54
bool smgrprefetch(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, int nblocks)
Definition smgr.c:678

References Assert, BlockNumberIsValid(), BufMappingPartitionLock(), BufTableHashCode(), BufTableLookup(), fb(), InitBufferTag(), InvalidBuffer, IO_DIRECT_DATA, io_direct_flags, LW_SHARED, LWLockAcquire(), LWLockRelease(), result, and smgrprefetch().

Referenced by PrefetchBuffer(), and XLogPrefetcherNextBlock().

◆ ProcessReadBuffersResult()

static void ProcessReadBuffersResult ( ReadBuffersOperation operation)
static

Definition at line 1714 of file bufmgr.c.

1715{
1716 PgAioReturn *aio_ret = &operation->io_return;
1718 int newly_read_blocks = 0;
1719
1720 Assert(pgaio_wref_valid(&operation->io_wref));
1721 Assert(aio_ret->result.status != PGAIO_RS_UNKNOWN);
1722
1723 /*
1724 * SMGR reports the number of blocks successfully read as the result of
1725 * the IO operation. Thus we can simply add that to ->nblocks_done.
1726 */
1727
1728 if (likely(rs != PGAIO_RS_ERROR))
1729 newly_read_blocks = aio_ret->result.result;
1730
1731 if (rs == PGAIO_RS_ERROR || rs == PGAIO_RS_WARNING)
1732 pgaio_result_report(aio_ret->result, &aio_ret->target_data,
1733 rs == PGAIO_RS_ERROR ? ERROR : WARNING);
1734 else if (aio_ret->result.status == PGAIO_RS_PARTIAL)
1735 {
1736 /*
1737 * We'll retry, so we just emit a debug message to the server log (or
1738 * not even that in prod scenarios).
1739 */
1740 pgaio_result_report(aio_ret->result, &aio_ret->target_data, DEBUG1);
1741 elog(DEBUG3, "partial read, will retry");
1742 }
1743
1746
1747 operation->nblocks_done += newly_read_blocks;
1748
1749 Assert(operation->nblocks_done <= operation->nblocks);
1750}
PgAioResultStatus
Definition aio_types.h:79
@ PGAIO_RS_UNKNOWN
Definition aio_types.h:80
@ PGAIO_RS_PARTIAL
Definition aio_types.h:82
#define DEBUG3
Definition elog.h:29
uint32 status
Definition aio_types.h:108
PgAioResult result
Definition aio_types.h:132

References Assert, DEBUG1, DEBUG3, elog, ERROR, fb(), likely, MAX_IO_COMBINE_LIMIT, operation, pgaio_result_report(), PGAIO_RS_ERROR, PGAIO_RS_PARTIAL, PGAIO_RS_UNKNOWN, PGAIO_RS_WARNING, pgaio_wref_valid(), PgAioReturn::result, PgAioResult::status, and WARNING.

Referenced by WaitReadBuffers().

◆ ReadBuffer()

Buffer ReadBuffer ( Relation  reln,
BlockNumber  blockNum 
)

Definition at line 879 of file bufmgr.c.

880{
882}
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition bufmgr.c:926
@ RBM_NORMAL
Definition bufmgr.h:46

References fb(), MAIN_FORKNUM, RBM_NORMAL, and ReadBufferExtended().

Referenced by _bt_allocbuf(), _bt_getbuf(), _bt_relandgetbuf(), _bt_search_insert(), _hash_getbuf(), _hash_getbuf_with_condlock_cleanup(), blbulkdelete(), blinsert(), BloomNewBuffer(), brin_getinsertbuffer(), brinGetStats(), brinGetTupleForHeapBlock(), brinRevmapDesummarizeRange(), brinRevmapInitialize(), bt_metap(), bt_multi_page_stats(), bt_page_items_internal(), bt_page_stats_internal(), ginFindLeafPage(), ginFindParents(), ginGetStats(), ginHeapTupleFastInsert(), ginInsertCleanup(), GinNewBuffer(), ginStepRight(), ginUpdateStats(), gistBufferingFindCorrectParent(), gistbufferinginserttuples(), gistdoinsert(), gistFindCorrectParent(), gistFindPath(), gistfixsplit(), gistGetMaxLevel(), gistkillitems(), gistNewBuffer(), gistProcessItup(), gistScanPage(), heap_abort_speculative(), heap_delete(), heap_fetch(), heap_finish_speculative(), heap_force_common(), heap_get_latest_tid(), heap_index_delete_tuples(), heap_lock_tuple(), heap_update(), heapam_index_fetch_tuple(), initBloomState(), pg_visibility(), pgstatginindex_internal(), read_seq_tuple(), RelationGetBufferForTuple(), ReleaseAndReadBuffer(), revmap_get_buffer(), revmap_physical_extend(), scanGetCandidate(), scanPendingInsert(), shiftList(), spgdoinsert(), spgGetCache(), SpGistGetBuffer(), SpGistNewBuffer(), SpGistUpdateMetaPage(), and spgWalk().

◆ ReadBuffer_common()

static pg_attribute_always_inline Buffer ReadBuffer_common ( Relation  rel,
SMgrRelation  smgr,
char  smgr_persistence,
ForkNumber  forkNum,
BlockNumber  blockNum,
ReadBufferMode  mode,
BufferAccessStrategy  strategy 
)
static

Definition at line 1276 of file bufmgr.c.

1280{
1282 Buffer buffer;
1283 int flags;
1284 char persistence;
1285
1286 /*
1287 * Reject attempts to read non-local temporary relations; we would be
1288 * likely to get wrong data since we have no visibility into the owning
1289 * session's local buffers. This is the canonical place for the check,
1290 * covering the ReadBufferExtended() entry point and any other caller that
1291 * supplies a Relation.
1292 */
1293 if (rel && RELATION_IS_OTHER_TEMP(rel))
1294 ereport(ERROR,
1296 errmsg("cannot access temporary tables of other sessions")));
1297
1298 /*
1299 * Backward compatibility path, most code should use ExtendBufferedRel()
1300 * instead, as acquiring the extension lock inside ExtendBufferedRel()
1301 * scales a lot better.
1302 */
1303 if (unlikely(blockNum == P_NEW))
1304 {
1306
1307 /*
1308 * Since no-one else can be looking at the page contents yet, there is
1309 * no difference between an exclusive lock and a cleanup-strength
1310 * lock.
1311 */
1313 flags |= EB_LOCK_FIRST;
1314
1315 return ExtendBufferedRel(BMR_REL(rel), forkNum, strategy, flags);
1316 }
1317
1318 if (rel)
1319 persistence = rel->rd_rel->relpersistence;
1320 else
1321 persistence = smgr_persistence;
1322
1325 {
1326 bool found;
1329
1330 if (persistence == RELPERSISTENCE_TEMP)
1331 {
1334 }
1335 else
1336 {
1337 io_context = IOContextForStrategy(strategy);
1339 }
1340
1341 buffer = PinBufferForBlock(rel, smgr, persistence,
1342 forkNum, blockNum, strategy,
1343 io_object, io_context, &found);
1344 ZeroAndLockBuffer(buffer, mode, found);
1345 return buffer;
1346 }
1347
1348 /*
1349 * Signal that we are going to immediately wait. If we're immediately
1350 * waiting, there is no benefit in actually executing the IO
1351 * asynchronously, it would just add dispatch overhead.
1352 */
1354 if (mode == RBM_ZERO_ON_ERROR)
1356 operation.smgr = smgr;
1357 operation.rel = rel;
1358 operation.persistence = persistence;
1359 operation.forknum = forkNum;
1360 operation.strategy = strategy;
1362 &buffer,
1363 blockNum,
1364 flags))
1366
1367 return buffer;
1368}
Buffer ExtendBufferedRel(BufferManagerRelation bmr, ForkNumber forkNum, BufferAccessStrategy strategy, uint32 flags)
Definition bufmgr.c:970
static void ZeroAndLockBuffer(Buffer buffer, ReadBufferMode mode, bool already_valid)
Definition bufmgr.c:1137
static pg_attribute_always_inline Buffer PinBufferForBlock(Relation rel, SMgrRelation smgr, char persistence, ForkNumber forkNum, BlockNumber blockNum, BufferAccessStrategy strategy, IOObject io_object, IOContext io_context, bool *foundPtr)
Definition bufmgr.c:1223
bool WaitReadBuffers(ReadBuffersOperation *operation)
Definition bufmgr.c:1759
bool StartReadBuffer(ReadBuffersOperation *operation, Buffer *buffer, BlockNumber blocknum, int flags)
Definition bufmgr.c:1637
@ RBM_ZERO_ON_ERROR
Definition bufmgr.h:51
#define BMR_REL(p_rel)
Definition bufmgr.h:114
Form_pg_class rd_rel
Definition rel.h:111

References BMR_REL, PrivateRefCountEntry::buffer, EB_LOCK_FIRST, EB_SKIP_EXTENSION_LOCK, ereport, errcode(), errmsg, ERROR, ExtendBufferedRel(), fb(), IOCONTEXT_NORMAL, IOContextForStrategy(), IOOBJECT_RELATION, IOOBJECT_TEMP_RELATION, mode, operation, P_NEW, PinBufferForBlock(), RBM_ZERO_AND_CLEANUP_LOCK, RBM_ZERO_AND_LOCK, RBM_ZERO_ON_ERROR, RelationData::rd_rel, READ_BUFFERS_SYNCHRONOUSLY, READ_BUFFERS_ZERO_ON_ERROR, RELATION_IS_OTHER_TEMP, StartReadBuffer(), unlikely, WaitReadBuffers(), and ZeroAndLockBuffer().

Referenced by ExtendBufferedRelTo(), ReadBufferExtended(), and ReadBufferWithoutRelcache().

◆ ReadBufferExtended()

◆ ReadBufferWithoutRelcache()

Buffer ReadBufferWithoutRelcache ( RelFileLocator  rlocator,
ForkNumber  forkNum,
BlockNumber  blockNum,
ReadBufferMode  mode,
BufferAccessStrategy  strategy,
bool  permanent 
)

Definition at line 954 of file bufmgr.c.

957{
958 SMgrRelation smgr = smgropen(rlocator, INVALID_PROC_NUMBER);
959
960 return ReadBuffer_common(NULL, smgr,
962 forkNum, blockNum,
963 mode, strategy);
964}

References fb(), INVALID_PROC_NUMBER, mode, ReadBuffer_common(), and smgropen().

Referenced by RelationCopyStorageUsingBuffer(), ScanSourceDatabasePgClass(), and XLogReadBufferExtended().

◆ ReadRecentBuffer()

bool ReadRecentBuffer ( RelFileLocator  rlocator,
ForkNumber  forkNum,
BlockNumber  blockNum,
Buffer  recent_buffer 
)

Definition at line 818 of file bufmgr.c.

820{
822 BufferTag tag;
824
825 Assert(BufferIsValid(recent_buffer));
826
829 InitBufferTag(&tag, &rlocator, forkNum, blockNum);
830
831 if (BufferIsLocal(recent_buffer))
832 {
833 int b = -recent_buffer - 1;
834
837
838 /* Is it still valid and holding the right tag? */
839 if ((buf_state & BM_VALID) && BufferTagsEqual(&tag, &bufHdr->tag))
840 {
841 PinLocalBuffer(bufHdr, true);
842
844
845 return true;
846 }
847 }
848 else
849 {
850 bufHdr = GetBufferDescriptor(recent_buffer - 1);
851
852 /*
853 * Is it still valid and holding the right tag? We do an unlocked tag
854 * comparison first, to make it unlikely that we'll increment the
855 * usage counter of the wrong buffer, if someone calls us with a very
856 * out of date recent_buffer. Then we'll check it again if we get the
857 * pin.
858 */
859 if (BufferTagsEqual(&tag, &bufHdr->tag) &&
860 PinBuffer(bufHdr, NULL, true))
861 {
862 if (BufferTagsEqual(&tag, &bufHdr->tag))
863 {
865 return true;
866 }
868 }
869 }
870
871 return false;
872}
int64 local_blks_hit
Definition instrument.h:30
int64 shared_blks_hit
Definition instrument.h:26

References Assert, b, BM_VALID, BufferIsLocal, BufferIsValid(), BufferTagsEqual(), CurrentResourceOwner, fb(), GetBufferDescriptor(), GetLocalBufferDescriptor(), InitBufferTag(), BufferUsage::local_blks_hit, pg_atomic_read_u64(), pgBufferUsage, PinBuffer(), PinLocalBuffer(), ReservePrivateRefCountEntry(), ResourceOwnerEnlarge(), BufferUsage::shared_blks_hit, and UnpinBuffer().

Referenced by invalidate_one_block(), and XLogReadBufferExtended().

◆ RelationCopyStorageUsingBuffer()

static void RelationCopyStorageUsingBuffer ( RelFileLocator  srclocator,
RelFileLocator  dstlocator,
ForkNumber  forkNum,
bool  permanent 
)
static

Definition at line 5371 of file bufmgr.c.

5374{
5375 Buffer srcBuf;
5376 Buffer dstBuf;
5377 Page srcPage;
5378 Page dstPage;
5379 bool use_wal;
5380 BlockNumber nblocks;
5381 BlockNumber blkno;
5388
5389 /*
5390 * In general, we want to write WAL whenever wal_level > 'minimal', but we
5391 * can skip it when copying any fork of an unlogged relation other than
5392 * the init fork.
5393 */
5394 use_wal = XLogIsNeeded() && (permanent || forkNum == INIT_FORKNUM);
5395
5396 /* Get number of blocks in the source relation. */
5398 forkNum);
5399
5400 /* Nothing to copy; just return. */
5401 if (nblocks == 0)
5402 return;
5403
5404 /*
5405 * Bulk extend the destination relation of the same size as the source
5406 * relation before starting to copy block by block.
5407 */
5408 memset(buf.data, 0, BLCKSZ);
5409 smgrextend(smgropen(dstlocator, INVALID_PROC_NUMBER), forkNum, nblocks - 1,
5410 buf.data, true);
5411
5412 /* This is a bulk operation, so use buffer access strategies. */
5415
5416 /* Initialize streaming read */
5417 p.current_blocknum = 0;
5418 p.last_exclusive = nblocks;
5420
5421 /*
5422 * It is safe to use batchmode as block_range_read_stream_cb takes no
5423 * locks.
5424 */
5428 src_smgr,
5430 forkNum,
5432 &p,
5433 0);
5434
5435 /* Iterate over each block of the source relation file. */
5436 for (blkno = 0; blkno < nblocks; blkno++)
5437 {
5439
5440 /* Read block from source relation. */
5444
5448 permanent);
5450
5452
5453 /* Copy page data from the source to the destination. */
5456
5457 /* WAL-log the copied page. */
5458 if (use_wal)
5460
5462
5465 }
5468
5471}
Buffer ReadBufferWithoutRelcache(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy, bool permanent)
Definition bufmgr.c:954
@ BAS_BULKREAD
Definition bufmgr.h:37
@ BAS_BULKWRITE
Definition bufmgr.h:39
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
Definition freelist.c:426
void FreeAccessStrategy(BufferAccessStrategy strategy)
Definition freelist.c:608
#define START_CRIT_SECTION()
Definition miscadmin.h:152
#define END_CRIT_SECTION()
Definition miscadmin.h:154
ReadStream * read_stream_begin_smgr_relation(int flags, BufferAccessStrategy strategy, SMgrRelation smgr, char smgr_persistence, ForkNumber forknum, ReadStreamBlockNumberCB callback, void *callback_private_data, size_t per_buffer_data_size)
Buffer read_stream_next_buffer(ReadStream *stream, void **per_buffer_data)
void read_stream_end(ReadStream *stream)
BlockNumber block_range_read_stream_cb(ReadStream *stream, void *callback_private_data, void *per_buffer_data)
#define READ_STREAM_USE_BATCHING
Definition read_stream.h:64
#define READ_STREAM_FULL
Definition read_stream.h:43
void smgrextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, const void *buffer, bool skipFsync)
Definition smgr.c:620
#define XLogIsNeeded()
Definition xlog.h:112
XLogRecPtr log_newpage_buffer(Buffer buffer, bool page_std)

References Assert, BAS_BULKREAD, BAS_BULKWRITE, block_range_read_stream_cb(), buf, BUFFER_LOCK_SHARE, BufferGetBlockNumber(), BufferGetPage(), CHECK_FOR_INTERRUPTS, BlockRangeReadStreamPrivate::current_blocknum, END_CRIT_SECTION, fb(), FreeAccessStrategy(), GetAccessStrategy(), INIT_FORKNUM, INVALID_PROC_NUMBER, InvalidBuffer, BlockRangeReadStreamPrivate::last_exclusive, LockBuffer(), log_newpage_buffer(), MarkBufferDirty(), memcpy(), RBM_ZERO_AND_LOCK, read_stream_begin_smgr_relation(), read_stream_end(), READ_STREAM_FULL, read_stream_next_buffer(), READ_STREAM_USE_BATCHING, ReadBufferWithoutRelcache(), smgrextend(), smgrnblocks(), smgropen(), START_CRIT_SECTION, UnlockReleaseBuffer(), and XLogIsNeeded.

Referenced by CreateAndCopyRelationData().

◆ RelationGetNumberOfBlocksInFork()

BlockNumber RelationGetNumberOfBlocksInFork ( Relation  relation,
ForkNumber  forkNum 
)

Definition at line 4668 of file bufmgr.c.

4669{
4670 if (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind))
4671 {
4672 /*
4673 * Not every table AM uses BLCKSZ wide fixed size blocks. Therefore
4674 * tableam returns the size in bytes - but for the purpose of this
4675 * routine, we want the number of blocks. Therefore divide, rounding
4676 * up.
4677 */
4679
4680 szbytes = table_relation_size(relation, forkNum);
4681
4682 return (szbytes + (BLCKSZ - 1)) / BLCKSZ;
4683 }
4684 else if (RELKIND_HAS_STORAGE(relation->rd_rel->relkind))
4685 {
4686 return smgrnblocks(RelationGetSmgr(relation), forkNum);
4687 }
4688 else
4689 Assert(false);
4690
4691 return 0; /* keep compiler quiet */
4692}
static uint64 table_relation_size(Relation rel, ForkNumber forkNumber)
Definition tableam.h:1938

References Assert, fb(), RelationData::rd_rel, RelationGetSmgr(), smgrnblocks(), and table_relation_size().

Referenced by _hash_getnewbuf(), _hash_init(), autoprewarm_database_main(), get_raw_page_internal(), pg_prewarm(), and ProcessSingleRelationFork().

◆ ReleaseAndReadBuffer()

Buffer ReleaseAndReadBuffer ( Buffer  buffer,
Relation  relation,
BlockNumber  blockNum 
)

Definition at line 3235 of file bufmgr.c.

3238{
3239 ForkNumber forkNum = MAIN_FORKNUM;
3241
3242 if (BufferIsValid(buffer))
3243 {
3244 Assert(BufferIsPinned(buffer));
3245 if (BufferIsLocal(buffer))
3246 {
3247 bufHdr = GetLocalBufferDescriptor(-buffer - 1);
3248 if (bufHdr->tag.blockNum == blockNum &&
3249 BufTagMatchesRelFileLocator(&bufHdr->tag, &relation->rd_locator) &&
3250 BufTagGetForkNum(&bufHdr->tag) == forkNum)
3251 return buffer;
3252 UnpinLocalBuffer(buffer);
3253 }
3254 else
3255 {
3256 bufHdr = GetBufferDescriptor(buffer - 1);
3257 /* we have pin, so it's ok to examine tag without spinlock */
3258 if (bufHdr->tag.blockNum == blockNum &&
3259 BufTagMatchesRelFileLocator(&bufHdr->tag, &relation->rd_locator) &&
3260 BufTagGetForkNum(&bufHdr->tag) == forkNum)
3261 return buffer;
3263 }
3264 }
3265
3266 return ReadBuffer(relation, blockNum);
3267}
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition bufmgr.c:879

References Assert, PrivateRefCountEntry::buffer, BufferIsLocal, BufferIsPinned, BufferIsValid(), BufTagGetForkNum(), BufTagMatchesRelFileLocator(), fb(), GetBufferDescriptor(), GetLocalBufferDescriptor(), MAIN_FORKNUM, RelationData::rd_locator, ReadBuffer(), UnpinBuffer(), and UnpinLocalBuffer().

Referenced by ginFindLeafPage().

◆ ReleaseBuffer()

void ReleaseBuffer ( Buffer  buffer)

Definition at line 5609 of file bufmgr.c.

5610{
5611 if (!BufferIsValid(buffer))
5612 elog(ERROR, "bad buffer ID: %d", buffer);
5613
5614 if (BufferIsLocal(buffer))
5615 UnpinLocalBuffer(buffer);
5616 else
5617 UnpinBuffer(GetBufferDescriptor(buffer - 1));
5618}

References PrivateRefCountEntry::buffer, BufferIsLocal, BufferIsValid(), elog, ERROR, GetBufferDescriptor(), UnpinBuffer(), and UnpinLocalBuffer().

Referenced by _bt_allocbuf(), _bt_pagedel(), _bt_search_insert(), _bt_unlink_halfdead_page(), _hash_dropbuf(), _hash_getbuf_with_condlock_cleanup(), autoprewarm_database_main(), BitmapHeapScanNextBlock(), blinsert(), BloomNewBuffer(), brin_getinsertbuffer(), brin_vacuum_scan(), bringetbitmap(), brinGetTupleForHeapBlock(), brininsert(), brinRevmapTerminate(), brinsummarize(), buffer_create_toy(), collect_corrupt_items(), collect_visibility_data(), entryLoadMoreItems(), ExecEndIndexOnlyScan(), ExtendBufferedRelTo(), FreeBulkInsertState(), freeGinBtreeStack(), fsm_search(), get_actual_variable_endpoint(), GetRecordedFreeSpace(), ginFindParents(), ginFinishSplit(), ginFreeScanKeys(), ginInsertCleanup(), GinNewBuffer(), gistdoinsert(), gistFindCorrectParent(), gistNewBuffer(), gistvacuum_delete_empty_pages(), grow_rel(), heap_abort_speculative(), heap_delete(), heap_endscan(), heap_fetch(), heap_fetch_next_buffer(), heap_force_common(), heap_insert(), heap_lock_tuple(), heap_lock_updated_tuple_rec(), heap_multi_insert(), heap_rescan(), heap_update(), heap_vac_scan_next_block(), heap_xlog_delete(), heap_xlog_insert(), heap_xlog_lock(), heap_xlog_lock_updated(), heap_xlog_multi_insert(), heap_xlog_update(), heapam_index_fetch_end(), heapam_index_fetch_tuple(), heapam_scan_sample_next_block(), heapam_tuple_lock(), heapgettup(), heapgettup_pagemode(), lazy_scan_heap(), lazy_vacuum_heap_rel(), pg_prewarm(), pg_visibility(), pg_visibility_map(), pgstatindex_impl(), read_buffers(), read_rel_block_ll(), read_stream_for_blocks(), read_stream_reset(), ReadBufferBI(), RelationAddBlocks(), ReleaseBulkInsertStatePin(), revmap_get_buffer(), spgdoinsert(), SpGistGetBuffer(), SpGistNewBuffer(), SpGistUpdateMetaPage(), statapprox_heap(), summarize_range(), terminate_brin_buildstate(), tts_buffer_heap_clear(), tts_buffer_heap_materialize(), tts_buffer_heap_store_tuple(), verify_heapam(), visibilitymap_count(), visibilitymap_get_status(), visibilitymap_pin(), and XLogReadBufferExtended().

◆ ReservePrivateRefCountEntry()

static void ReservePrivateRefCountEntry ( void  )
static

Definition at line 309 of file bufmgr.c.

310{
311 /* Already reserved (or freed), nothing to do */
312 if (ReservedRefCountSlot != -1)
313 return;
314
315 /*
316 * First search for a free entry the array, that'll be sufficient in the
317 * majority of cases.
318 */
319 {
320 int i;
321
322 for (i = 0; i < REFCOUNT_ARRAY_ENTRIES; i++)
323 {
325 {
327
328 /*
329 * We could return immediately, but iterating till the end of
330 * the array allows compiler-autovectorization.
331 */
332 }
333 }
334
335 if (ReservedRefCountSlot != -1)
336 return;
337 }
338
339 /*
340 * No luck. All array entries are full. Move one array entry into the hash
341 * table.
342 */
343 {
344 /*
345 * Move entry from the current clock position in the array into the
346 * hashtable. Use that slot.
347 */
348 int victim_slot;
351 bool found;
352
353 /* select victim slot */
357
358 /* Better be used, otherwise we shouldn't get here. */
362
363 /* enter victim array entry into hashtable */
366 &found);
367 Assert(!found);
368 /* move data from the entry in the array to the hash entry */
369 hashent->data = victim_entry->data;
370
371 /* clear the now free array slot */
373 victim_entry->buffer = InvalidBuffer;
374
375 /* clear the whole data member, just for future proofing */
376 memset(&victim_entry->data, 0, sizeof(victim_entry->data));
377 victim_entry->data.refcount = 0;
378 victim_entry->data.lockmode = BUFFER_LOCK_UNLOCK;
379
381 }
382}
static uint32 PrivateRefCountClock
Definition bufmgr.c:267

References Assert, PrivateRefCountEntry::buffer, BUFFER_LOCK_UNLOCK, fb(), i, InvalidBuffer, PrivateRefCountArray, PrivateRefCountArrayKeys, PrivateRefCountClock, PrivateRefCountHash, PrivateRefCountOverflowed, REFCOUNT_ARRAY_ENTRIES, and ReservedRefCountSlot.

Referenced by BufferAlloc(), EvictAllUnpinnedBuffers(), EvictRelUnpinnedBuffers(), EvictUnpinnedBuffer(), ExtendBufferedRelShared(), FlushDatabaseBuffers(), FlushRelationBuffers(), FlushRelationsAllBuffers(), GetPrivateRefCountEntrySlow(), GetVictimBuffer(), MarkDirtyAllUnpinnedBuffers(), MarkDirtyRelUnpinnedBuffers(), MarkDirtyUnpinnedBuffer(), ReadRecentBuffer(), and SyncOneBuffer().

◆ ResOwnerPrintBuffer()

static char * ResOwnerPrintBuffer ( Datum  res)
static

Definition at line 7930 of file bufmgr.c.

7931{
7933}
static int32 DatumGetInt32(Datum X)
Definition postgres.h:202

References DatumGetInt32(), and DebugPrintBufferRefcount().

◆ ResOwnerPrintBufferIO()

static char * ResOwnerPrintBufferIO ( Datum  res)
static

Definition at line 7880 of file bufmgr.c.

7881{
7882 Buffer buffer = DatumGetInt32(res);
7883
7884 return psprintf("lost track of buffer IO on buffer %d", buffer);
7885}

References PrivateRefCountEntry::buffer, DatumGetInt32(), and psprintf().

◆ ResOwnerReleaseBuffer()

static void ResOwnerReleaseBuffer ( Datum  res)
static

Definition at line 7894 of file bufmgr.c.

7895{
7896 Buffer buffer = DatumGetInt32(res);
7897
7898 /* Like ReleaseBuffer, but don't call ResourceOwnerForgetBuffer */
7899 if (!BufferIsValid(buffer))
7900 elog(ERROR, "bad buffer ID: %d", buffer);
7901
7902 if (BufferIsLocal(buffer))
7904 else
7905 {
7907
7908 ref = GetPrivateRefCountEntry(buffer, false);
7909
7910 /* not having a private refcount would imply resowner corruption */
7911 Assert(ref != NULL);
7912
7913 /*
7914 * If the buffer was locked at the time of the resowner release,
7915 * release the lock now. This should only happen after errors.
7916 */
7917 if (ref->data.lockmode != BUFFER_LOCK_UNLOCK)
7918 {
7919 BufferDesc *buf = GetBufferDescriptor(buffer - 1);
7920
7921 HOLD_INTERRUPTS(); /* match the upcoming RESUME_INTERRUPTS */
7922 BufferLockUnlock(buffer, buf);
7923 }
7924
7926 }
7927}
static void UnpinBufferNoOwner(BufferDesc *buf)
Definition bufmgr.c:3488
void UnpinLocalBufferNoOwner(Buffer buffer)
Definition localbuf.c:872

References Assert, buf, PrivateRefCountEntry::buffer, BUFFER_LOCK_UNLOCK, BufferIsLocal, BufferIsValid(), BufferLockUnlock(), DatumGetInt32(), elog, ERROR, fb(), GetBufferDescriptor(), GetPrivateRefCountEntry(), HOLD_INTERRUPTS, UnpinBufferNoOwner(), and UnpinLocalBufferNoOwner().

◆ ResOwnerReleaseBufferIO()

static void ResOwnerReleaseBufferIO ( Datum  res)
static

Definition at line 7872 of file bufmgr.c.

7873{
7874 Buffer buffer = DatumGetInt32(res);
7875
7876 AbortBufferIO(buffer);
7877}
static void AbortBufferIO(Buffer buffer)
Definition bufmgr.c:7469

References AbortBufferIO(), PrivateRefCountEntry::buffer, and DatumGetInt32().

◆ rlocator_comparator()

static int rlocator_comparator ( const void p1,
const void p2 
)
static

Definition at line 7540 of file bufmgr.c.

7541{
7542 RelFileLocator n1 = *(const RelFileLocator *) p1;
7543 RelFileLocator n2 = *(const RelFileLocator *) p2;
7544
7545 if (n1.relNumber < n2.relNumber)
7546 return -1;
7547 else if (n1.relNumber > n2.relNumber)
7548 return 1;
7549
7550 if (n1.dbOid < n2.dbOid)
7551 return -1;
7552 else if (n1.dbOid > n2.dbOid)
7553 return 1;
7554
7555 if (n1.spcOid < n2.spcOid)
7556 return -1;
7557 else if (n1.spcOid > n2.spcOid)
7558 return 1;
7559 else
7560 return 0;
7561}

References fb().

Referenced by buffertag_comparator(), DropRelationsAllBuffers(), and FlushRelationsAllBuffers().

◆ ScheduleBufferTagForWriteback()

void ScheduleBufferTagForWriteback ( WritebackContext wb_context,
IOContext  io_context,
BufferTag tag 
)

Definition at line 7739 of file bufmgr.c.

7741{
7742 PendingWriteback *pending;
7743
7744 /*
7745 * As pg_flush_data() doesn't do anything with fsync disabled, there's no
7746 * point in tracking in that case.
7747 */
7749 !enableFsync)
7750 return;
7751
7752 /*
7753 * Add buffer to the pending writeback array, unless writeback control is
7754 * disabled.
7755 */
7756 if (*wb_context->max_pending > 0)
7757 {
7759
7760 pending = &wb_context->pending_writebacks[wb_context->nr_pending++];
7761
7762 pending->tag = *tag;
7763 }
7764
7765 /*
7766 * Perform pending flushes if the writeback limit is exceeded. This
7767 * includes the case where previously an item has been added, but control
7768 * is now disabled.
7769 */
7770 if (wb_context->nr_pending >= *wb_context->max_pending)
7772}
bool enableFsync
Definition globals.c:131
#define WRITEBACK_MAX_PENDING_FLUSHES

References Assert, enableFsync, fb(), IO_DIRECT_DATA, io_direct_flags, IssuePendingWritebacks(), PendingWriteback::tag, and WRITEBACK_MAX_PENDING_FLUSHES.

Referenced by GetVictimBuffer(), and SyncOneBuffer().

◆ shared_buffer_readv_complete()

static PgAioResult shared_buffer_readv_complete ( PgAioHandle ioh,
PgAioResult  prior_result,
uint8  cb_data 
)
static

Definition at line 8929 of file bufmgr.c.

8931{
8933}

References buffer_readv_complete(), and fb().

◆ shared_buffer_readv_complete_local()

static PgAioResult shared_buffer_readv_complete_local ( PgAioHandle ioh,
PgAioResult  prior_result,
uint8  cb_data 
)
static

◆ shared_buffer_readv_stage()

static void shared_buffer_readv_stage ( PgAioHandle ioh,
uint8  cb_data 
)
static

Definition at line 8923 of file bufmgr.c.

8924{
8925 buffer_stage_common(ioh, false, false);
8926}

References buffer_stage_common(), and fb().

◆ shared_buffer_write_error_callback()

static void shared_buffer_write_error_callback ( void arg)
static

Definition at line 7508 of file bufmgr.c.

7509{
7511
7512 /* Buffer is pinned, so we can read the tag without locking the spinlock */
7513 if (bufHdr != NULL)
7514 errcontext("writing block %u of relation \"%s\"",
7515 bufHdr->tag.blockNum,
7517 BufTagGetForkNum(&bufHdr->tag)).str);
7518}

References arg, BufTagGetForkNum(), BufTagGetRelFileLocator(), errcontext, fb(), and relpathperm.

Referenced by FlushBuffer().

◆ SharedBufferBeginSetHintBits()

static bool SharedBufferBeginSetHintBits ( Buffer  buffer,
BufferDesc buf_hdr,
uint64 lockstate 
)
inlinestatic

Definition at line 7000 of file bufmgr.c.

7001{
7005
7006 ref = GetPrivateRefCountEntry(buffer, true);
7007
7008 if (ref == NULL)
7009 elog(ERROR, "buffer is not pinned");
7010
7011 mode = ref->data.lockmode;
7012 if (mode == BUFFER_LOCK_UNLOCK)
7013 elog(ERROR, "buffer is not locked");
7014
7015 /* we're done if we are already holding a sufficient lock level */
7017 {
7019 return true;
7020 }
7021
7022 /*
7023 * We are only holding a share lock right now, try to upgrade it to
7024 * SHARE_EXCLUSIVE.
7025 */
7027
7029 while (true)
7030 {
7032
7034
7035 /*
7036 * Can't upgrade if somebody else holds the lock in exclusive or
7037 * share-exclusive mode.
7038 */
7040 {
7041 return false;
7042 }
7043
7044 /* currently held lock state */
7046
7047 /* new lock level */
7049
7052 {
7053 ref->data.lockmode = BUFFER_LOCK_SHARE_EXCLUSIVE;
7055
7056 return true;
7057 }
7058 }
7059}

References Assert, BM_LOCK_VAL_EXCLUSIVE, BM_LOCK_VAL_SHARE_EXCLUSIVE, BM_LOCK_VAL_SHARED, PrivateRefCountEntry::buffer, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_SHARE, BUFFER_LOCK_SHARE_EXCLUSIVE, BUFFER_LOCK_UNLOCK, elog, ERROR, fb(), GetPrivateRefCountEntry(), likely, mode, pg_atomic_compare_exchange_u64(), pg_atomic_read_u64(), and unlikely.

Referenced by BufferBeginSetHintBits(), and BufferSetHintBits16().

◆ StartBufferIO()

StartBufferIOResult StartBufferIO ( Buffer  buffer,
bool  forInput,
bool  wait,
PgAioWaitRef io_wref 
)

Definition at line 7370 of file bufmgr.c.

7371{
7373
7374 if (BufferIsLocal(buffer))
7375 {
7376 buf_hdr = GetLocalBufferDescriptor(-buffer - 1);
7377
7378 return StartLocalBufferIO(buf_hdr, forInput, wait, io_wref);
7379 }
7380 else
7381 {
7382 buf_hdr = GetBufferDescriptor(buffer - 1);
7383
7384 return StartSharedBufferIO(buf_hdr, forInput, wait, io_wref);
7385 }
7386}
StartBufferIOResult StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool wait, PgAioWaitRef *io_wref)
Definition localbuf.c:532

References PrivateRefCountEntry::buffer, BufferIsLocal, fb(), GetBufferDescriptor(), GetLocalBufferDescriptor(), StartLocalBufferIO(), and StartSharedBufferIO().

Referenced by AsyncReadBuffers().

◆ StartReadBuffer()

bool StartReadBuffer ( ReadBuffersOperation operation,
Buffer buffer,
BlockNumber  blocknum,
int  flags 
)

Definition at line 1637 of file bufmgr.c.

1641{
1642 int nblocks = 1;
1643 bool result;
1644
1645 result = StartReadBuffersImpl(operation, buffer, blocknum, &nblocks, flags,
1646 false /* single block, no forwarding */ );
1647 Assert(nblocks == 1); /* single block can't be short */
1648
1649 return result;
1650}
static pg_attribute_always_inline bool StartReadBuffersImpl(ReadBuffersOperation *operation, Buffer *buffers, BlockNumber blockNum, int *nblocks, int flags, bool allow_forwarding)
Definition bufmgr.c:1371

References Assert, PrivateRefCountEntry::buffer, operation, result, and StartReadBuffersImpl().

Referenced by read_stream_next_buffer(), and ReadBuffer_common().

◆ StartReadBuffers()

bool StartReadBuffers ( ReadBuffersOperation operation,
Buffer buffers,
BlockNumber  blockNum,
int nblocks,
int  flags 
)

Definition at line 1618 of file bufmgr.c.

1623{
1624 return StartReadBuffersImpl(operation, buffers, blockNum, nblocks, flags,
1625 true /* expect forwarded buffers */ );
1626}

References operation, and StartReadBuffersImpl().

Referenced by read_buffers(), and read_stream_start_pending_read().

◆ StartReadBuffersImpl()

static pg_attribute_always_inline bool StartReadBuffersImpl ( ReadBuffersOperation operation,
Buffer buffers,
BlockNumber  blockNum,
int nblocks,
int  flags,
bool  allow_forwarding 
)
static

Definition at line 1371 of file bufmgr.c.

1377{
1378 int actual_nblocks = *nblocks;
1379 int maxcombine = 0;
1380 bool did_start_io;
1383
1384 Assert(*nblocks == 1 || allow_forwarding);
1385 Assert(*nblocks > 0);
1386 Assert(*nblocks <= MAX_IO_COMBINE_LIMIT);
1387
1388 /* see comments in ReadBuffer_common */
1389 if (operation->rel && RELATION_IS_OTHER_TEMP(operation->rel))
1390 ereport(ERROR,
1392 errmsg("cannot access temporary tables of other sessions")));
1393
1394 if (operation->persistence == RELPERSISTENCE_TEMP)
1395 {
1398 }
1399 else
1400 {
1403 }
1404
1405 for (int i = 0; i < actual_nblocks; ++i)
1406 {
1407 bool found;
1408
1409 if (allow_forwarding && buffers[i] != InvalidBuffer)
1410 {
1412
1413 /*
1414 * This is a buffer that was pinned by an earlier call to
1415 * StartReadBuffers(), but couldn't be handled in one operation at
1416 * that time. The operation was split, and the caller has passed
1417 * an already pinned buffer back to us to handle the rest of the
1418 * operation. It must continue at the expected block number.
1419 */
1420 Assert(BufferGetBlockNumber(buffers[i]) == blockNum + i);
1421
1422 /*
1423 * It might be an already valid buffer (a hit) that followed the
1424 * final contiguous block of an earlier I/O (a miss) marking the
1425 * end of it, or a buffer that some other backend has since made
1426 * valid by performing the I/O for us, in which case we can handle
1427 * it as a hit now. It is safe to check for a BM_VALID flag with
1428 * a relaxed load, because we got a fresh view of it while pinning
1429 * it in the previous call.
1430 *
1431 * On the other hand if we don't see BM_VALID yet, it must be an
1432 * I/O that was split by the previous call and we need to try to
1433 * start a new I/O from this block. We're also racing against any
1434 * other backend that might start the I/O or even manage to mark
1435 * it BM_VALID after this check, but StartBufferIO() will handle
1436 * those cases.
1437 */
1438 if (BufferIsLocal(buffers[i]))
1439 bufHdr = GetLocalBufferDescriptor(-buffers[i] - 1);
1440 else
1441 bufHdr = GetBufferDescriptor(buffers[i] - 1);
1443 found = pg_atomic_read_u64(&bufHdr->state) & BM_VALID;
1444 }
1445 else
1446 {
1447 buffers[i] = PinBufferForBlock(operation->rel,
1448 operation->smgr,
1449 operation->persistence,
1450 operation->forknum,
1451 blockNum + i,
1452 operation->strategy,
1454 &found);
1455 }
1456
1457 if (found)
1458 {
1459 /*
1460 * We have a hit. If it's the first block in the requested range,
1461 * we can return it immediately and report that WaitReadBuffers()
1462 * does not need to be called. If the initial value of *nblocks
1463 * was larger, the caller will have to call again for the rest.
1464 */
1465 if (i == 0)
1466 {
1467 *nblocks = 1;
1468
1469#ifdef USE_ASSERT_CHECKING
1470
1471 /*
1472 * Initialize enough of ReadBuffersOperation to make
1473 * CheckReadBuffersOperation() work. Outside of assertions
1474 * that's not necessary when no IO is issued.
1475 */
1476 operation->buffers = buffers;
1477 operation->blocknum = blockNum;
1478 operation->nblocks = 1;
1479 operation->nblocks_done = 1;
1481#endif
1482 return false;
1483 }
1484
1485 /*
1486 * Otherwise we already have an I/O to perform, but this block
1487 * can't be included as it is already valid. Split the I/O here.
1488 * There may or may not be more blocks requiring I/O after this
1489 * one, we haven't checked, but they can't be contiguous with this
1490 * one in the way. We'll leave this buffer pinned, forwarding it
1491 * to the next call, avoiding the need to unpin it here and re-pin
1492 * it in the next call.
1493 */
1494 actual_nblocks = i;
1495 break;
1496 }
1497 else
1498 {
1499 /*
1500 * Check how many blocks we can cover with the same IO. The smgr
1501 * implementation might e.g. be limited due to a segment boundary.
1502 */
1503 if (i == 0 && actual_nblocks > 1)
1504 {
1506 operation->forknum,
1507 blockNum);
1509 {
1510 elog(DEBUG2, "limiting nblocks at %u from %u to %u",
1511 blockNum, actual_nblocks, maxcombine);
1513 }
1514 }
1515 }
1516 }
1517 *nblocks = actual_nblocks;
1518
1519 /* Populate information needed for I/O. */
1520 operation->buffers = buffers;
1521 operation->blocknum = blockNum;
1522 operation->flags = flags;
1523 operation->nblocks = actual_nblocks;
1524 operation->nblocks_done = 0;
1525 pgaio_wref_clear(&operation->io_wref);
1526
1527 /*
1528 * When using AIO, start the IO in the background. If not, issue prefetch
1529 * requests if desired by the caller.
1530 *
1531 * The reason we have a dedicated path for IOMETHOD_SYNC here is to
1532 * de-risk the introduction of AIO somewhat. It's a large architectural
1533 * change, with lots of chances for unanticipated performance effects.
1534 *
1535 * Use of IOMETHOD_SYNC already leads to not actually performing IO
1536 * asynchronously, but without the check here we'd execute IO earlier than
1537 * we used to. Eventually this IOMETHOD_SYNC specific path should go away.
1538 */
1539 if (io_method != IOMETHOD_SYNC)
1540 {
1541 /*
1542 * Try to start IO asynchronously. It's possible that no IO needs to
1543 * be started, if another backend already performed the IO.
1544 *
1545 * Note that if an IO is started, it might not cover the entire
1546 * requested range, e.g. because an intermediary block has been read
1547 * in by another backend. In that case any "trailing" buffers we
1548 * already pinned above will be "forwarded" by read_stream.c to the
1549 * next call to StartReadBuffers().
1550 *
1551 * This is signalled to the caller by decrementing *nblocks *and*
1552 * reducing operation->nblocks. The latter is done here, but not below
1553 * WaitReadBuffers(), as in WaitReadBuffers() we can't "shorten" the
1554 * overall read size anymore, we need to retry until done in its
1555 * entirety or until failed.
1556 */
1558
1559 operation->nblocks = *nblocks;
1560 }
1561 else
1562 {
1564
1565 if (flags & READ_BUFFERS_ISSUE_ADVICE)
1566 {
1567 /*
1568 * In theory we should only do this if PinBufferForBlock() had to
1569 * allocate new buffers above. That way, if two calls to
1570 * StartReadBuffers() were made for the same blocks before
1571 * WaitReadBuffers(), only the first would issue the advice.
1572 * That'd be a better simulation of true asynchronous I/O, which
1573 * would only start the I/O once, but isn't done here for
1574 * simplicity.
1575 */
1576 smgrprefetch(operation->smgr,
1577 operation->forknum,
1578 blockNum,
1580 }
1581
1582 /*
1583 * Indicate that WaitReadBuffers() should be called. WaitReadBuffers()
1584 * will initiate the necessary IO.
1585 */
1586 did_start_io = true;
1587 }
1588
1590
1591 return did_start_io;
1592}
int io_method
Definition aio.c:74
@ IOMETHOD_SYNC
Definition aio.h:34
static void CheckReadBuffersOperation(ReadBuffersOperation *operation, bool is_complete)
Definition bufmgr.c:1656
static bool AsyncReadBuffers(ReadBuffersOperation *operation, int *nblocks_progress)
Definition bufmgr.c:1938
#define READ_BUFFERS_ISSUE_ADVICE
Definition bufmgr.h:124
uint32 smgrmaxcombine(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum)
Definition smgr.c:697

References Assert, AsyncReadBuffers(), BM_TAG_VALID, BM_VALID, BufferGetBlockNumber(), BufferIsLocal, CheckReadBuffersOperation(), DEBUG2, elog, ereport, errcode(), errmsg, ERROR, fb(), GetBufferDescriptor(), GetLocalBufferDescriptor(), i, InvalidBuffer, io_method, IOCONTEXT_NORMAL, IOContextForStrategy(), IOMETHOD_SYNC, IOOBJECT_RELATION, IOOBJECT_TEMP_RELATION, MAX_IO_COMBINE_LIMIT, operation, pg_atomic_read_u64(), pgaio_wref_clear(), PinBufferForBlock(), READ_BUFFERS_ISSUE_ADVICE, READ_BUFFERS_SYNCHRONOUSLY, RELATION_IS_OTHER_TEMP, smgrmaxcombine(), smgrprefetch(), and unlikely.

Referenced by StartReadBuffer(), and StartReadBuffers().

◆ StartSharedBufferIO()

StartBufferIOResult StartSharedBufferIO ( BufferDesc buf,
bool  forInput,
bool  wait,
PgAioWaitRef io_wref 
)

Definition at line 7290 of file bufmgr.c.

7291{
7293
7295
7296 for (;;)
7297 {
7299
7301 break;
7302
7303 /* Join the existing IO */
7304 if (io_wref != NULL && pgaio_wref_valid(&buf->io_wref))
7305 {
7306 *io_wref = buf->io_wref;
7308
7309 return BUFFER_IO_IN_PROGRESS;
7310 }
7311 else if (!wait)
7312 {
7314 return BUFFER_IO_IN_PROGRESS;
7315 }
7316 else
7317 {
7318 /*
7319 * With wait = true, we always have to wait if the caller has
7320 * passed io_wref = NULL.
7321 *
7322 * Even with io_wref != NULL, we have to wait if the buffer's wait
7323 * ref is not valid but the IO is in progress, someone else
7324 * started IO but hasn't set the wait ref yet. We have no choice
7325 * but to wait until the IO completes.
7326 */
7328
7329 /*
7330 * If this backend currently has staged IO, submit it before
7331 * waiting for in-progress IO, to avoid potential deadlocks and
7332 * unnecessary delays.
7333 */
7335
7336 WaitIO(buf);
7337 }
7338 }
7339
7340 /* Once we get here, there is definitely no I/O active on this buffer */
7341
7342 /* Check if someone else already did the I/O */
7343 if (forInput ? (buf_state & BM_VALID) : !(buf_state & BM_DIRTY))
7344 {
7347 }
7348
7349 /*
7350 * No IO in progress and not already done; we will start IO. It's possible
7351 * that the IO was in progress but we're not done, because the IO errored
7352 * out. We'll do the IO ourselves.
7353 */
7356 0);
7357
7360
7362}
static void ResourceOwnerRememberBufferIO(ResourceOwner owner, Buffer buffer)

References BM_DIRTY, BM_IO_IN_PROGRESS, BM_VALID, buf, BUFFER_IO_ALREADY_DONE, BUFFER_IO_IN_PROGRESS, BUFFER_IO_READY_FOR_IO, BufferDescriptorGetBuffer(), CurrentResourceOwner, fb(), LockBufHdr(), pgaio_submit_staged(), pgaio_wref_valid(), ResourceOwnerEnlarge(), ResourceOwnerRememberBufferIO(), UnlockBufHdr(), UnlockBufHdrExt(), and WaitIO().

Referenced by buffer_call_start_io(), ExtendBufferedRelShared(), FlushBuffer(), read_rel_block_ll(), StartBufferIO(), and ZeroAndLockBuffer().

◆ SyncOneBuffer()

static int SyncOneBuffer ( int  buf_id,
bool  skip_recently_used,
WritebackContext wb_context 
)
static

Definition at line 4152 of file bufmgr.c.

4153{
4155 int result = 0;
4157 BufferTag tag;
4158
4159 /* Make sure we can handle the pin */
4162
4163 /*
4164 * Check whether buffer needs writing.
4165 *
4166 * We can make this check without taking the buffer content lock so long
4167 * as we mark pages dirty in access methods *before* logging changes with
4168 * XLogInsert(): if someone marks the buffer dirty just after our check we
4169 * don't worry because our checkpoint.redo points before log record for
4170 * upcoming changes and so we are not required to write such dirty buffer.
4171 */
4173
4176 {
4178 }
4179 else if (skip_recently_used)
4180 {
4181 /* Caller told us not to write recently-used buffers */
4183 return result;
4184 }
4185
4186 if (!(buf_state & BM_VALID) || !(buf_state & BM_DIRTY))
4187 {
4188 /* It's clean, so nothing to do */
4190 return result;
4191 }
4192
4193 /*
4194 * Pin it, share-exclusive-lock it, write it. (FlushBuffer will do
4195 * nothing if the buffer is clean by the time we've locked it.)
4196 */
4198
4200
4201 tag = bufHdr->tag;
4202
4204
4205 /*
4206 * SyncOneBuffer() is only called by checkpointer and bgwriter, so
4207 * IOContext will always be IOCONTEXT_NORMAL.
4208 */
4210
4211 return result | BUF_WRITTEN;
4212}

References BM_DIRTY, BM_VALID, BUF_REUSABLE, BUF_STATE_GET_REFCOUNT, BUF_STATE_GET_USAGECOUNT, BUF_WRITTEN, CurrentResourceOwner, fb(), FlushUnlockedBuffer(), GetBufferDescriptor(), IOCONTEXT_NORMAL, IOOBJECT_RELATION, LockBufHdr(), PinBuffer_Locked(), ReservePrivateRefCountEntry(), ResourceOwnerEnlarge(), result, ScheduleBufferTagForWriteback(), UnlockBufHdr(), and UnpinBuffer().

Referenced by BgBufferSync(), and BufferSync().

◆ TerminateBufferIO()

void TerminateBufferIO ( BufferDesc buf,
bool  clear_dirty,
uint64  set_flag_bits,
bool  forget_owner,
bool  release_aio 
)

Definition at line 7407 of file bufmgr.c.

7409{
7412 int refcount_change = 0;
7413
7415
7418
7419 /* Clear earlier errors, if this IO failed, it'll be marked again */
7421
7422 if (clear_dirty)
7424
7425 if (release_aio)
7426 {
7427 /* release ownership by the AIO subsystem */
7429 refcount_change = -1;
7430 pgaio_wref_clear(&buf->io_wref);
7431 }
7432
7436
7437 if (forget_owner)
7440
7442
7443 /*
7444 * Support LockBufferForCleanup()
7445 *
7446 * We may have just released the last pin other than the waiter's. In most
7447 * cases, this backend holds another pin on the buffer. But, if, for
7448 * example, this backend is completing an IO issued by another backend, it
7449 * may be time to wake the waiter.
7450 */
7453}
static ConditionVariable * BufferDescriptorGetIOCV(const BufferDesc *bdesc)
static void WakePinCountWaiter(BufferDesc *buf)
Definition bufmgr.c:3443
void ConditionVariableBroadcast(ConditionVariable *cv)

References Assert, BM_CHECKPOINT_NEEDED, BM_DIRTY, BM_IO_ERROR, BM_IO_IN_PROGRESS, BM_PIN_COUNT_WAITER, buf, BUF_STATE_GET_REFCOUNT, BufferDescriptorGetBuffer(), BufferDescriptorGetIOCV(), ConditionVariableBroadcast(), CurrentResourceOwner, fb(), LockBufHdr(), pgaio_wref_clear(), ResourceOwnerForgetBufferIO(), UnlockBufHdrExt(), and WakePinCountWaiter().

Referenced by AbortBufferIO(), buffer_call_terminate_io(), buffer_readv_complete_one(), ExtendBufferedRelShared(), FlushBuffer(), and ZeroAndLockBuffer().

◆ TrackBufferHit()

◆ TrackNewBufferPin()

void TrackNewBufferPin ( Buffer  buf)
inline

Definition at line 3535 of file bufmgr.c.

3536{
3538
3540 ref->data.refcount++;
3541
3543
3544 /*
3545 * This is the first pin for this page by this backend, mark its page as
3546 * defined to valgrind. While the page contents might not actually be
3547 * valid yet, we don't currently guarantee that such pages are marked
3548 * undefined or non-accessible.
3549 *
3550 * It's not necessarily the prettiest to do this here, but otherwise we'd
3551 * need this block of code in multiple places.
3552 */
3554 BLCKSZ);
3555}
static PrivateRefCountEntry * NewPrivateRefCountEntry(Buffer buffer)
Definition bufmgr.c:388

References buf, BufHdrGetBlock, CurrentResourceOwner, fb(), GetBufferDescriptor(), NewPrivateRefCountEntry(), ResourceOwnerRememberBuffer(), and VALGRIND_MAKE_MEM_DEFINED.

Referenced by GetBufferFromRing(), PinBuffer(), PinBuffer_Locked(), and StrategyGetBuffer().

◆ ts_ckpt_progress_comparator()

static int ts_ckpt_progress_comparator ( Datum  a,
Datum  b,
void arg 
)
static

Definition at line 7704 of file bufmgr.c.

7705{
7708
7709 /* we want a min-heap, so return 1 for the a < b */
7710 if (sa->progress < sb->progress)
7711 return 1;
7712 else if (sa->progress == sb->progress)
7713 return 0;
7714 else
7715 return -1;
7716}

References a, b, DatumGetPointer(), and fb().

Referenced by BufferSync().

◆ UnlockBuffer()

void UnlockBuffer ( Buffer  buffer)

Definition at line 6581 of file bufmgr.c.

6582{
6584
6585 Assert(BufferIsPinned(buffer));
6586 if (BufferIsLocal(buffer))
6587 return; /* local buffers need no lock */
6588
6589 buf_hdr = GetBufferDescriptor(buffer - 1);
6590 BufferLockUnlock(buffer, buf_hdr);
6591}

References Assert, PrivateRefCountEntry::buffer, BufferIsLocal, BufferIsPinned, BufferLockUnlock(), fb(), and GetBufferDescriptor().

Referenced by LockBuffer().

◆ UnlockBuffers()

void UnlockBuffers ( void  )

Definition at line 5875 of file bufmgr.c.

5876{
5878
5879 if (buf)
5880 {
5882 uint64 unset_bits = 0;
5883
5885
5886 /*
5887 * Don't complain if flag bit not set; it could have been reset but we
5888 * got a cancel/die interrupt before getting the signal.
5889 */
5890 if ((buf_state & BM_PIN_COUNT_WAITER) != 0 &&
5891 buf->wait_backend_pgprocno == MyProcNumber)
5893
5895 0, unset_bits,
5896 0);
5897
5899 }
5900}

References BM_PIN_COUNT_WAITER, buf, fb(), LockBufHdr(), MyProcNumber, PinCountWaitBuf, and UnlockBufHdrExt().

Referenced by AbortSubTransaction(), AbortTransaction(), AtProcExit_Buffers(), AutoVacLauncherMain(), BackgroundWriterMain(), CheckpointerMain(), and WalWriterMain().

◆ UnlockReleaseBuffer()

void UnlockReleaseBuffer ( Buffer  buffer)

Definition at line 5626 of file bufmgr.c.

5627{
5628 int mode;
5629 BufferDesc *buf;
5631 uint64 sub;
5633
5634 Assert(BufferIsPinned(buffer));
5635
5636 if (BufferIsLocal(buffer))
5637 {
5638 UnpinLocalBuffer(buffer);
5639 return;
5640 }
5641
5643
5644 buf = GetBufferDescriptor(buffer - 1);
5645
5647
5648 /* compute state modification for lock release */
5650
5651 /* compute state modification for pin release */
5652 ref = GetPrivateRefCountEntry(buffer, false);
5653 Assert(ref != NULL);
5654 Assert(ref->data.refcount > 0);
5655 ref->data.refcount--;
5656
5657 /* no more backend local pins, reduce shared pin count */
5658 if (likely(ref->data.refcount == 0))
5659 {
5660 /* See comment in UnpinBufferNoOwner() */
5662
5663 sub |= BUF_REFCOUNT_ONE;
5665 }
5666
5667 /* perform the lock and pin release in one atomic op */
5668 lockstate = pg_atomic_sub_fetch_u64(&buf->state, sub);
5669
5670 /* wake up waiters for the lock */
5672
5673 /* wake up waiter for the pin release */
5676
5677 /*
5678 * Now okay to allow cancel/die interrupts again, which were held when the
5679 * lock was acquired.
5680 */
5682}
static void ResourceOwnerForgetBuffer(ResourceOwner owner, Buffer buffer)
static void ForgetPrivateRefCountEntry(PrivateRefCountEntry *ref)
Definition bufmgr.c:565

References Assert, BM_PIN_COUNT_WAITER, buf, BUF_REFCOUNT_ONE, PrivateRefCountEntry::buffer, BufferIsLocal, BufferIsPinned, BufferLockDisownInternal(), BufferLockProcessRelease(), BufferLockReleaseSub(), BufHdrGetBlock, CurrentResourceOwner, fb(), ForgetPrivateRefCountEntry(), GetBufferDescriptor(), GetPrivateRefCountEntry(), likely, mode, pg_atomic_sub_fetch_u64(), ResourceOwnerForgetBuffer(), RESUME_INTERRUPTS, UnpinLocalBuffer(), VALGRIND_MAKE_MEM_NOACCESS, and WakePinCountWaiter().

Referenced by _bt_clear_incomplete_split(), _bt_relbuf(), _bt_restore_meta(), _hash_relbuf(), allocNewBuffer(), AlterSequence(), blbulkdelete(), blgetbitmap(), blinsert(), BloomInitMetapage(), blvacuumcleanup(), brin_doinsert(), brin_doupdate(), brin_evacuate_page(), brin_getinsertbuffer(), brin_xlog_createidx(), brin_xlog_desummarize_page(), brin_xlog_insert_update(), brin_xlog_revmap_extend(), brin_xlog_samepage_update(), brin_xlog_update(), brinbuild(), brinbuildempty(), brinGetStats(), brinRevmapDesummarizeRange(), bt_metap(), bt_multi_page_stats(), bt_page_items_internal(), bt_page_stats_internal(), bt_recheck_sibling_links(), btree_xlog_dedup(), btree_xlog_delete(), btree_xlog_insert(), btree_xlog_mark_page_halfdead(), btree_xlog_newroot(), btree_xlog_split(), btree_xlog_unlink_page(), btree_xlog_vacuum(), collect_corrupt_items(), collect_visibility_data(), count_nondeletable_pages(), createPostingTree(), doPickSplit(), entryLoadMoreItems(), fill_seq_fork_with_data(), flushCachedPage(), FreeSpaceMapPrepareTruncateRel(), fsm_search(), fsm_set_and_search(), fsm_vacuum_page(), generic_redo(), get_raw_page_internal(), GetVictimBuffer(), gin_check_parent_keys_consistency(), gin_check_posting_tree_parent_keys_consistency(), gin_refind_parent(), ginbuild(), ginbuildempty(), ginbulkdelete(), ginGetStats(), ginHeapTupleFastInsert(), ginInsertCleanup(), ginPlaceToPage(), ginRedoClearIncompleteSplit(), ginRedoCreatePTree(), ginRedoDeleteListPages(), ginRedoDeletePage(), ginRedoInsert(), ginRedoInsertListPage(), ginRedoSplit(), ginRedoUpdateMetapage(), ginRedoVacuumDataLeafPage(), ginRedoVacuumPage(), ginScanPostingTreeToDelete(), ginStepRight(), ginUpdateStats(), ginvacuumcleanup(), ginVacuumPostingTree(), ginVacuumPostingTreeLeaves(), gistbufferinginserttuples(), gistbuild(), gistbuildempty(), gistdoinsert(), gistFindCorrectParent(), gistFindPath(), gistGetMaxLevel(), gistinserttuples(), gistkillitems(), gistplacetopage(), gistProcessItup(), gistRedoClearFollowRight(), gistRedoDeleteRecord(), gistRedoPageDelete(), gistRedoPageSplitRecord(), gistRedoPageUpdateRecord(), gistScanPage(), gistvacuum_delete_empty_pages(), gistvacuumpage(), hash_xlog_add_ovfl_page(), hash_xlog_delete(), hash_xlog_init_bitmap_page(), hash_xlog_init_meta_page(), hash_xlog_insert(), hash_xlog_move_page_contents(), hash_xlog_split_allocate_page(), hash_xlog_split_cleanup(), hash_xlog_split_complete(), hash_xlog_split_page(), hash_xlog_squeeze_page(), hash_xlog_update_meta_page(), hash_xlog_vacuum_one_page(), heap_delete(), heap_fetch(), heap_finish_speculative(), heap_force_common(), heap_get_latest_tid(), heap_index_delete_tuples(), heap_insert(), heap_lock_updated_tuple_rec(), heap_multi_insert(), heap_update(), heap_xlog_confirm(), heap_xlog_delete(), heap_xlog_inplace(), heap_xlog_insert(), heap_xlog_lock(), heap_xlog_lock_updated(), heap_xlog_multi_insert(), heap_xlog_prune_freeze(), heap_xlog_update(), heapam_scan_analyze_next_tuple(), initBloomState(), invalidate_one_block(), lazy_scan_heap(), lazy_scan_new_or_empty(), lazy_vacuum_heap_rel(), log_newpage_range(), modify_rel_block(), moveLeafs(), nextval_internal(), palloc_btree_page(), pg_get_sequence_data(), pg_sequence_last_value(), pg_visibility(), pgstat_gist_page(), pgstat_heap(), pgstatginindex_internal(), pgstathashindex(), pgstatindex_impl(), ProcessSingleRelationFork(), RelationCopyStorageUsingBuffer(), RelationGetBufferForTuple(), ResetSequence(), revmap_physical_extend(), scanGetCandidate(), scanPendingInsert(), scanPostingTree(), ScanSourceDatabasePgClass(), seq_redo(), SequenceChangePersistence(), SetSequence(), shiftList(), spgAddNodeAction(), spgbuild(), spgdoinsert(), spgGetCache(), SpGistGetBuffer(), SpGistUpdateMetaPage(), spgMatchNodeAction(), spgprocesspending(), spgRedoAddLeaf(), spgRedoAddNode(), spgRedoMoveLeafs(), spgRedoPickSplit(), spgRedoSplitTuple(), spgRedoVacuumLeaf(), spgRedoVacuumRedirect(), spgRedoVacuumRoot(), spgSplitNodeAction(), spgvacuumpage(), spgWalk(), statapprox_heap(), verify_heapam(), verifyBackupPageConsistency(), visibilitymap_prepare_truncate(), writeListPage(), xlog_redo(), and XLogRecordPageWithFreeSpace().

◆ UnpinBuffer()

◆ UnpinBufferNoOwner()

static void UnpinBufferNoOwner ( BufferDesc buf)
static

Definition at line 3488 of file bufmgr.c.

3489{
3492
3494
3495 /* not moving as we're likely deleting it soon anyway */
3496 ref = GetPrivateRefCountEntry(b, false);
3497 Assert(ref != NULL);
3498 Assert(ref->data.refcount > 0);
3499 ref->data.refcount--;
3500 if (ref->data.refcount == 0)
3501 {
3503
3504 /*
3505 * Mark buffer non-accessible to Valgrind.
3506 *
3507 * Note that the buffer may have already been marked non-accessible
3508 * within access method code that enforces that buffers are only
3509 * accessed while a buffer lock is held.
3510 */
3512
3513 /*
3514 * I'd better not still hold the buffer content lock. Can't use
3515 * BufferIsLockedByMe(), as that asserts the buffer is pinned.
3516 */
3518
3519 /* decrement the shared reference count */
3521
3522 /* Support LockBufferForCleanup() */
3525
3527 }
3528}
static uint64 pg_atomic_fetch_sub_u64(volatile pg_atomic_uint64 *ptr, int64 sub_)
Definition atomics.h:536

References Assert, b, BM_PIN_COUNT_WAITER, buf, BUF_REFCOUNT_ONE, BufferDescriptorGetBuffer(), BufferIsLocal, BufferLockHeldByMe(), BufHdrGetBlock, fb(), ForgetPrivateRefCountEntry(), GetPrivateRefCountEntry(), pg_atomic_fetch_sub_u64(), VALGRIND_MAKE_MEM_NOACCESS, and WakePinCountWaiter().

Referenced by ResOwnerReleaseBuffer(), and UnpinBuffer().

◆ WaitBufHdrUnlocked()

pg_noinline uint64 WaitBufHdrUnlocked ( BufferDesc buf)

◆ WaitIO()

static void WaitIO ( BufferDesc buf)
static

Definition at line 7188 of file bufmgr.c.

7189{
7191
7192 /*
7193 * Should never end up here with unsubmitted IO, as no AIO unaware code
7194 * may be used while in batch mode and AIO aware code needs to have
7195 * submitted all staged IO to avoid deadlocks & slowness.
7196 */
7198
7200 for (;;)
7201 {
7204
7205 /*
7206 * It may not be necessary to acquire the spinlock to check the flag
7207 * here, but since this test is essential for correctness, we'd better
7208 * play it safe.
7209 */
7211
7212 /*
7213 * Copy the wait reference while holding the spinlock. This protects
7214 * against a concurrent TerminateBufferIO() in another backend from
7215 * clearing the wref while it's being read.
7216 */
7217 iow = buf->io_wref;
7219
7220 /* no IO in progress, we don't need to wait */
7222 break;
7223
7224 /*
7225 * The buffer has asynchronous IO in progress, wait for it to
7226 * complete.
7227 */
7228 if (pgaio_wref_valid(&iow))
7229 {
7231
7232 /*
7233 * The AIO subsystem internally uses condition variables and thus
7234 * might remove this backend from the BufferDesc's CV. While that
7235 * wouldn't cause a correctness issue (the first CV sleep just
7236 * immediately returns if not already registered), it seems worth
7237 * avoiding unnecessary loop iterations, given that we take care
7238 * to do so at the start of the function.
7239 */
7241 continue;
7242 }
7243
7244 /* wait on BufferDesc->cv, e.g. for concurrent synchronous IO */
7246 }
7248}
bool pgaio_have_staged(void)
Definition aio.c:1117
void pgaio_wref_wait(PgAioWaitRef *iow)
Definition aio.c:991
bool ConditionVariableCancelSleep(void)
void ConditionVariablePrepareToSleep(ConditionVariable *cv)
void ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)

References Assert, BM_IO_IN_PROGRESS, buf, BufferDescriptorGetIOCV(), ConditionVariableCancelSleep(), ConditionVariablePrepareToSleep(), ConditionVariableSleep(), fb(), LockBufHdr(), pgaio_have_staged(), pgaio_wref_valid(), pgaio_wref_wait(), and UnlockBufHdr().

Referenced by InvalidateBuffer(), and StartSharedBufferIO().

◆ WaitReadBuffers()

bool WaitReadBuffers ( ReadBuffersOperation operation)

Definition at line 1759 of file bufmgr.c.

1760{
1761 PgAioReturn *aio_ret = &operation->io_return;
1764 bool needed_wait = false;
1765
1766 if (operation->persistence == RELPERSISTENCE_TEMP)
1767 {
1770 }
1771 else
1772 {
1775 }
1776
1777 /*
1778 * If we get here without an IO operation having been issued, the
1779 * io_method == IOMETHOD_SYNC path must have been used. Otherwise the
1780 * caller should not have called WaitReadBuffers().
1781 *
1782 * In the case of IOMETHOD_SYNC, we start - as we used to before the
1783 * introducing of AIO - the IO in WaitReadBuffers(). This is done as part
1784 * of the retry logic below, no extra code is required.
1785 *
1786 * This path is expected to eventually go away.
1787 */
1788 if (!pgaio_wref_valid(&operation->io_wref) && io_method != IOMETHOD_SYNC)
1789 elog(ERROR, "waiting for read operation that didn't read");
1790
1791 /*
1792 * To handle partial reads, and IOMETHOD_SYNC, we re-issue IO until we're
1793 * done. We may need multiple retries, not just because we could get
1794 * multiple partial reads, but also because some of the remaining
1795 * to-be-read buffers may have been read in by other backends, limiting
1796 * the IO size.
1797 */
1798 while (true)
1799 {
1801
1803
1804 /*
1805 * If there is an IO associated with the operation, we may need to
1806 * wait for it.
1807 */
1808 if (pgaio_wref_valid(&operation->io_wref))
1809 {
1810 /*
1811 * Track the time spent waiting for the IO to complete. As
1812 * tracking a wait even if we don't actually need to wait
1813 *
1814 * a) is not cheap, due to the timestamping overhead
1815 *
1816 * b) reports some time as waiting, even if we never waited
1817 *
1818 * we first check if we already know the IO is complete.
1819 *
1820 * Note that operation->io_return is uninitialized for foreign IO,
1821 * so we cannot use the cheaper PGAIO_RS_UNKNOWN pre-check.
1822 */
1823 if ((operation->foreign_io || aio_ret->result.status == PGAIO_RS_UNKNOWN) &&
1824 !pgaio_wref_check_done(&operation->io_wref))
1825 {
1827
1828 pgaio_wref_wait(&operation->io_wref);
1829 needed_wait = true;
1830
1831 /*
1832 * The IO operation itself was already counted earlier, in
1833 * AsyncReadBuffers(), this just accounts for the wait time.
1834 */
1836 io_start, 0, 0);
1837 }
1838 else
1839 {
1841 }
1842
1843 if (unlikely(operation->foreign_io))
1844 {
1845 Buffer buffer = operation->buffers[operation->nblocks_done];
1846 BufferDesc *desc = BufferIsLocal(buffer) ?
1847 GetLocalBufferDescriptor(-buffer - 1) :
1848 GetBufferDescriptor(buffer - 1);
1850
1851 if (buf_state & BM_VALID)
1852 {
1853 BlockNumber blocknum = operation->blocknum + operation->nblocks_done;
1854
1855 operation->nblocks_done += 1;
1856 Assert(operation->nblocks_done <= operation->nblocks);
1857
1858 /*
1859 * Track this as a 'hit' for this backend. The backend
1860 * performing the IO will track it as a 'read'.
1861 */
1863 operation->rel, operation->persistence,
1864 operation->smgr, operation->forknum,
1865 blocknum);
1866 }
1867
1868 /*
1869 * If the foreign IO failed and left the buffer invalid,
1870 * nblocks_done is not incremented. The retry loop below will
1871 * call AsyncReadBuffers() which will attempt the IO itself.
1872 */
1873 }
1874 else
1875 {
1876 /*
1877 * We now are sure the IO completed. Check the results. This
1878 * includes reporting on errors if there were any.
1879 */
1881 }
1882 }
1883
1884 /*
1885 * Most of the time, the one IO we already started, will read in
1886 * everything. But we need to deal with partial reads and buffers not
1887 * needing IO anymore.
1888 */
1889 if (operation->nblocks_done == operation->nblocks)
1890 break;
1891
1893
1894 /*
1895 * If the IO completed only partially, we need to perform additional
1896 * work, consider that a form of having had to wait.
1897 */
1898 needed_wait = true;
1899
1900 /*
1901 * This may only complete the IO partially, either because some
1902 * buffers were already valid, or because of a partial read.
1903 *
1904 * NB: In contrast to after the AsyncReadBuffers() call in
1905 * StartReadBuffers(), we do *not* reduce
1906 * ReadBuffersOperation->nblocks here, callers expect the full
1907 * operation to be completed at this point (as more operations may
1908 * have been queued).
1909 */
1911 }
1912
1914
1915 /* NB: READ_DONE tracepoint was already executed in completion callback */
1916 return needed_wait;
1917}
bool pgaio_wref_check_done(PgAioWaitRef *iow)
Definition aio.c:1005
static void ProcessReadBuffersResult(ReadBuffersOperation *operation)
Definition bufmgr.c:1714

References Assert, AsyncReadBuffers(), BM_VALID, PrivateRefCountEntry::buffer, BufferIsLocal, CHECK_FOR_INTERRUPTS, CheckReadBuffersOperation(), elog, ERROR, fb(), GetBufferDescriptor(), GetLocalBufferDescriptor(), io_method, IOCONTEXT_NORMAL, IOContextForStrategy(), IOMETHOD_SYNC, IOOBJECT_RELATION, IOOBJECT_TEMP_RELATION, IOOP_READ, operation, pg_atomic_read_u64(), PGAIO_RS_UNKNOWN, pgaio_wref_check_done(), pgaio_wref_valid(), pgaio_wref_wait(), pgstat_count_io_op_time(), pgstat_prepare_io_time(), ProcessReadBuffersResult(), BufferDesc::state, track_io_timing, TrackBufferHit(), and unlikely.

Referenced by read_buffers(), read_stream_next_buffer(), and ReadBuffer_common().

◆ WakePinCountWaiter()

static void WakePinCountWaiter ( BufferDesc buf)
static

Definition at line 3443 of file bufmgr.c.

3444{
3445 /*
3446 * Acquire the buffer header lock, re-check that there's a waiter. Another
3447 * backend could have unpinned this buffer, and already woken up the
3448 * waiter.
3449 *
3450 * There's no danger of the buffer being replaced after we unpinned it
3451 * above, as it's pinned by the waiter. The waiter removes
3452 * BM_PIN_COUNT_WAITER if it stops waiting for a reason other than this
3453 * backend waking it up.
3454 */
3456
3459 {
3460 /* we just released the last pin other than the waiter's */
3461 int wait_backend_pgprocno = buf->wait_backend_pgprocno;
3462
3465 0);
3466 ProcSendSignal(wait_backend_pgprocno);
3467 }
3468 else
3470}
void ProcSendSignal(ProcNumber procNumber)
Definition proc.c:2061

References BM_PIN_COUNT_WAITER, buf, BUF_STATE_GET_REFCOUNT, fb(), LockBufHdr(), ProcSendSignal(), UnlockBufHdr(), and UnlockBufHdrExt().

Referenced by TerminateBufferIO(), UnlockReleaseBuffer(), and UnpinBufferNoOwner().

◆ WritebackContextInit()

void WritebackContextInit ( WritebackContext context,
int max_pending 
)

Definition at line 7727 of file bufmgr.c.

7728{
7729 Assert(*max_pending <= WRITEBACK_MAX_PENDING_FLUSHES);
7730
7731 context->max_pending = max_pending;
7732 context->nr_pending = 0;
7733}

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

Referenced by BackgroundWriterMain(), BufferManagerShmemAttach(), BufferManagerShmemInit(), and BufferSync().

◆ ZeroAndLockBuffer()

static void ZeroAndLockBuffer ( Buffer  buffer,
ReadBufferMode  mode,
bool  already_valid 
)
static

Definition at line 1137 of file bufmgr.c.

1138{
1140 bool need_to_zero;
1141 bool isLocalBuf = BufferIsLocal(buffer);
1143
1145
1146 if (already_valid)
1147 {
1148 /*
1149 * If the caller already knew the buffer was valid, we can skip some
1150 * header interaction. The caller just wants to lock the buffer.
1151 */
1152 need_to_zero = false;
1153 }
1154 else
1155 {
1156 if (isLocalBuf)
1157 {
1158 /* Simple case for non-shared buffers. */
1159 bufHdr = GetLocalBufferDescriptor(-buffer - 1);
1160 sbres = StartLocalBufferIO(bufHdr, true, true, NULL);
1161 }
1162 else
1163 {
1164 /*
1165 * Take BM_IO_IN_PROGRESS, or discover that BM_VALID has been set
1166 * concurrently. Even though we aren't doing I/O, that ensures
1167 * that we don't zero a page that someone else has pinned. An
1168 * exclusive content lock wouldn't be enough, because readers are
1169 * allowed to drop the content lock after determining that a tuple
1170 * is visible (see buffer access rules in README).
1171 */
1172 bufHdr = GetBufferDescriptor(buffer - 1);
1173 sbres = StartSharedBufferIO(bufHdr, true, true, NULL);
1174 }
1175
1178 }
1179
1180 if (need_to_zero)
1181 {
1182 memset(BufferGetPage(buffer), 0, BLCKSZ);
1183
1184 /*
1185 * Grab the buffer content lock before marking the page as valid, to
1186 * make sure that no other backend sees the zeroed page before the
1187 * caller has had a chance to initialize it.
1188 *
1189 * Since no-one else can be looking at the page contents yet, there is
1190 * no difference between an exclusive lock and a cleanup-strength
1191 * lock. (Note that we cannot use LockBuffer() or
1192 * LockBufferForCleanup() here, because they assert that the buffer is
1193 * already valid.)
1194 */
1195 if (!isLocalBuf)
1197
1198 /* Set BM_VALID, terminate IO, and wake up any waiters */
1199 if (isLocalBuf)
1200 TerminateLocalBufferIO(bufHdr, false, BM_VALID, false);
1201 else
1202 TerminateBufferIO(bufHdr, false, BM_VALID, true, false);
1203 }
1204 else if (!isLocalBuf)
1205 {
1206 /*
1207 * The buffer is valid, so we can't zero it. The caller still expects
1208 * the page to be locked on return.
1209 */
1210 if (mode == RBM_ZERO_AND_LOCK)
1212 else
1213 LockBufferForCleanup(buffer);
1214 }
1215}
void LockBufferForCleanup(Buffer buffer)
Definition bufmgr.c:6693

References Assert, BM_VALID, PrivateRefCountEntry::buffer, BUFFER_IO_IN_PROGRESS, BUFFER_IO_READY_FOR_IO, BUFFER_LOCK_EXCLUSIVE, BufferGetPage(), BufferIsLocal, fb(), GetBufferDescriptor(), GetLocalBufferDescriptor(), LockBuffer(), LockBufferForCleanup(), mode, RBM_ZERO_AND_CLEANUP_LOCK, RBM_ZERO_AND_LOCK, StartLocalBufferIO(), StartSharedBufferIO(), TerminateBufferIO(), and TerminateLocalBufferIO().

Referenced by ReadBuffer_common().

Variable Documentation

◆ aio_local_buffer_readv_cb

const PgAioHandleCallbacks aio_local_buffer_readv_cb
Initial value:
= {
.complete_local = local_buffer_readv_complete,
}
static PgAioResult local_buffer_readv_complete(PgAioHandle *ioh, PgAioResult prior_result, uint8 cb_data)
Definition bufmgr.c:8980
static void local_buffer_readv_stage(PgAioHandle *ioh, uint8 cb_data)
Definition bufmgr.c:8974
static void buffer_readv_report(PgAioResult result, const PgAioTargetData *td, int elevel)
Definition bufmgr.c:8828

Definition at line 8996 of file bufmgr.c.

8996 {
8997 .stage = local_buffer_readv_stage,
8998
8999 /*
9000 * Note that this, in contrast to the shared_buffers case, uses
9001 * complete_local, as only the issuing backend has access to the required
9002 * datastructures. This is important in case the IO completion may be
9003 * consumed incidentally by another backend.
9004 */
9005 .complete_local = local_buffer_readv_complete,
9006 .report = buffer_readv_report,
9007};

◆ aio_shared_buffer_readv_cb

const PgAioHandleCallbacks aio_shared_buffer_readv_cb
Initial value:
= {
.complete_shared = shared_buffer_readv_complete,
}
static PgAioResult shared_buffer_readv_complete_local(PgAioHandle *ioh, PgAioResult prior_result, uint8 cb_data)
Definition bufmgr.c:8943
static void shared_buffer_readv_stage(PgAioHandle *ioh, uint8 cb_data)
Definition bufmgr.c:8923
static PgAioResult shared_buffer_readv_complete(PgAioHandle *ioh, PgAioResult prior_result, uint8 cb_data)
Definition bufmgr.c:8929

Definition at line 8987 of file bufmgr.c.

8987 {
8989 .complete_shared = shared_buffer_readv_complete,
8990 /* need a local callback to report checksum failures */
8991 .complete_local = shared_buffer_readv_complete_local,
8992 .report = buffer_readv_report,
8993};

◆ backend_flush_after

int backend_flush_after = DEFAULT_BACKEND_FLUSH_AFTER

Definition at line 225 of file bufmgr.c.

Referenced by BufferManagerShmemAttach(), and BufferManagerShmemInit().

◆ bgwriter_flush_after

int bgwriter_flush_after = DEFAULT_BGWRITER_FLUSH_AFTER

Definition at line 224 of file bufmgr.c.

Referenced by BackgroundWriterMain().

◆ bgwriter_lru_maxpages

int bgwriter_lru_maxpages = 100

Definition at line 190 of file bufmgr.c.

Referenced by BgBufferSync().

◆ bgwriter_lru_multiplier

double bgwriter_lru_multiplier = 2.0

Definition at line 191 of file bufmgr.c.

Referenced by BgBufferSync().

◆ buffer_io_resowner_desc

const ResourceOwnerDesc buffer_io_resowner_desc
Initial value:
=
{
.name = "buffer io",
.release_priority = RELEASE_PRIO_BUFFER_IOS,
.ReleaseResource = ResOwnerReleaseBufferIO,
.DebugPrint = ResOwnerPrintBufferIO
}
static void ResOwnerReleaseBufferIO(Datum res)
Definition bufmgr.c:7872
static char * ResOwnerPrintBufferIO(Datum res)
Definition bufmgr.c:7880
#define RELEASE_PRIO_BUFFER_IOS
Definition resowner.h:62
@ RESOURCE_RELEASE_BEFORE_LOCKS
Definition resowner.h:54

Definition at line 285 of file bufmgr.c.

286{
287 .name = "buffer io",
288 .release_phase = RESOURCE_RELEASE_BEFORE_LOCKS,
289 .release_priority = RELEASE_PRIO_BUFFER_IOS,
290 .ReleaseResource = ResOwnerReleaseBufferIO,
291 .DebugPrint = ResOwnerPrintBufferIO
292};

Referenced by ResourceOwnerForgetBufferIO(), and ResourceOwnerRememberBufferIO().

◆ buffer_resowner_desc

const ResourceOwnerDesc buffer_resowner_desc
Initial value:
=
{
.name = "buffer",
.release_priority = RELEASE_PRIO_BUFFER_PINS,
.ReleaseResource = ResOwnerReleaseBuffer,
.DebugPrint = ResOwnerPrintBuffer
}
static void ResOwnerReleaseBuffer(Datum res)
Definition bufmgr.c:7894
static char * ResOwnerPrintBuffer(Datum res)
Definition bufmgr.c:7930
#define RELEASE_PRIO_BUFFER_PINS
Definition resowner.h:63

Definition at line 294 of file bufmgr.c.

295{
296 .name = "buffer",
297 .release_phase = RESOURCE_RELEASE_BEFORE_LOCKS,
298 .release_priority = RELEASE_PRIO_BUFFER_PINS,
299 .ReleaseResource = ResOwnerReleaseBuffer,
300 .DebugPrint = ResOwnerPrintBuffer
301};

Referenced by ResourceOwnerForgetBuffer(), and ResourceOwnerRememberBuffer().

◆ checkpoint_flush_after

int checkpoint_flush_after = DEFAULT_CHECKPOINT_FLUSH_AFTER

Definition at line 223 of file bufmgr.c.

Referenced by BufferSync().

◆ effective_io_concurrency

◆ io_combine_limit

◆ io_combine_limit_guc

int io_combine_limit_guc = DEFAULT_IO_COMBINE_LIMIT

Definition at line 216 of file bufmgr.c.

Referenced by assign_io_max_combine_limit().

◆ io_max_combine_limit

◆ maintenance_io_concurrency

◆ MaxProportionalPins

uint32 MaxProportionalPins
static

Definition at line 271 of file bufmgr.c.

Referenced by GetAdditionalPinLimit(), GetPinLimit(), and InitBufferManagerAccess().

◆ PinCountWaitBuf

BufferDesc* PinCountWaitBuf = NULL
static

Definition at line 228 of file bufmgr.c.

Referenced by LockBufferForCleanup(), and UnlockBuffers().

◆ PrivateRefCountArray

◆ PrivateRefCountArrayKeys

◆ PrivateRefCountClock

uint32 PrivateRefCountClock = 0
static

Definition at line 267 of file bufmgr.c.

Referenced by ReservePrivateRefCountEntry().

◆ PrivateRefCountEntryLast

int PrivateRefCountEntryLast = -1
static

◆ PrivateRefCountHash

◆ PrivateRefCountOverflowed

◆ ReservedRefCountSlot

int ReservedRefCountSlot = -1
static

◆ track_io_timing

◆ zero_damaged_pages

bool zero_damaged_pages = false

Definition at line 189 of file bufmgr.c.

Referenced by AsyncReadBuffers(), mdreadv(), and read_rel_block_ll().