Coverage Report

Created: 2026-10-16 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/include/storage/buf_internals.h
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * buf_internals.h
4
 *    Internal definitions for buffer manager and the buffer replacement
5
 *    strategy.
6
 *
7
 *
8
 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
9
 * Portions Copyright (c) 1994, Regents of the University of California
10
 *
11
 * src/include/storage/buf_internals.h
12
 *
13
 *-------------------------------------------------------------------------
14
 */
15
#ifndef BUFMGR_INTERNALS_H
16
#define BUFMGR_INTERNALS_H
17
18
#include "pgstat.h"
19
#include "port/atomics.h"
20
#include "storage/aio_types.h"
21
#include "storage/buf.h"
22
#include "storage/bufmgr.h"
23
#include "storage/condition_variable.h"
24
#include "storage/lwlock.h"
25
#include "storage/procnumber.h"
26
#include "storage/proclist_types.h"
27
#include "storage/shmem.h"
28
#include "storage/smgr.h"
29
#include "storage/spin.h"
30
#include "utils/relcache.h"
31
#include "utils/resowner.h"
32
33
/*
34
 * Buffer state is a single 64-bit variable where following data is combined.
35
 *
36
 * State of the buffer itself (in order):
37
 * - 18 bits refcount
38
 * - 4 bits usage count
39
 * - 12 bits of flags
40
 * - 18 bits share-lock count
41
 * - 1 bit share-exclusive locked
42
 * - 1 bit exclusive locked
43
 *
44
 * Combining these values allows to perform some operations without locking
45
 * the buffer header, by modifying them together with a CAS loop.
46
 *
47
 * The definition of buffer state components is below.
48
 */
49
0
#define BUF_REFCOUNT_BITS 18
50
0
#define BUF_USAGECOUNT_BITS 4
51
0
#define BUF_FLAG_BITS 12
52
#define BUF_LOCK_BITS (18+2)
53
54
StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS + BUF_LOCK_BITS <= 64,
55
         "parts of buffer state space need to be <= 64");
56
57
/* refcount related definitions */
58
0
#define BUF_REFCOUNT_ONE 1
59
#define BUF_REFCOUNT_MASK \
60
0
  ((UINT64CONST(1) << BUF_REFCOUNT_BITS) - 1)
61
62
/* usage count related definitions */
63
#define BUF_USAGECOUNT_SHIFT \
64
0
  BUF_REFCOUNT_BITS
65
#define BUF_USAGECOUNT_MASK \
66
0
  (((UINT64CONST(1) << BUF_USAGECOUNT_BITS) - 1) << (BUF_USAGECOUNT_SHIFT))
67
#define BUF_USAGECOUNT_ONE \
68
0
  (UINT64CONST(1) << BUF_REFCOUNT_BITS)
69
70
/* flags related definitions */
71
#define BUF_FLAG_SHIFT \
72
0
  (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS)
73
#define BUF_FLAG_MASK \
74
0
  (((UINT64CONST(1) << BUF_FLAG_BITS) - 1) << BUF_FLAG_SHIFT)
75
76
/* lock state related definitions */
77
#define BM_LOCK_SHIFT \
78
0
  (BUF_FLAG_SHIFT + BUF_FLAG_BITS)
79
#define BM_LOCK_VAL_SHARED \
80
0
  (UINT64CONST(1) << (BM_LOCK_SHIFT))
81
#define BM_LOCK_VAL_SHARE_EXCLUSIVE \
82
0
  (UINT64CONST(1) << (BM_LOCK_SHIFT + MAX_BACKENDS_BITS))
83
#define BM_LOCK_VAL_EXCLUSIVE \
84
0
  (UINT64CONST(1) << (BM_LOCK_SHIFT + MAX_BACKENDS_BITS + 1))
85
#define BM_LOCK_MASK \
86
0
  ((((uint64) MAX_BACKENDS) << BM_LOCK_SHIFT) | BM_LOCK_VAL_SHARE_EXCLUSIVE | BM_LOCK_VAL_EXCLUSIVE)
87
88
89
/* Get refcount and usagecount from buffer state */
90
#define BUF_STATE_GET_REFCOUNT(state) \
91
0
  ((uint32)((state) & BUF_REFCOUNT_MASK))
92
#define BUF_STATE_GET_USAGECOUNT(state) \
93
0
  ((uint32)(((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT))
94
95
/*
96
 * Flags for buffer descriptors
97
 *
98
 * Note: BM_TAG_VALID essentially means that there is a buffer hashtable
99
 * entry associated with the buffer's tag.
100
 */
101
102
#define BUF_DEFINE_FLAG(flagno) \
103
0
  (UINT64CONST(1) << (BUF_FLAG_SHIFT + (flagno)))
104
105
/* buffer header is locked */
106
0
#define BM_LOCKED         BUF_DEFINE_FLAG( 0)
107
/* data needs writing */
108
0
#define BM_DIRTY          BUF_DEFINE_FLAG( 1)
109
/* data is valid */
110
0
#define BM_VALID          BUF_DEFINE_FLAG( 2)
111
/* tag is assigned */
112
0
#define BM_TAG_VALID        BUF_DEFINE_FLAG( 3)
113
/* read or write in progress */
114
0
#define BM_IO_IN_PROGRESS     BUF_DEFINE_FLAG( 4)
115
/* previous I/O failed */
116
0
#define BM_IO_ERROR         BUF_DEFINE_FLAG( 5)
117
/* flag bit 6 is not used anymore */
118
/* have waiter for sole pin */
119
0
#define BM_PIN_COUNT_WAITER     BUF_DEFINE_FLAG( 7)
120
/* must write for checkpoint */
121
0
#define BM_CHECKPOINT_NEEDED    BUF_DEFINE_FLAG( 8)
122
/* permanent buffer (not unlogged, or init fork) */
123
0
#define BM_PERMANENT        BUF_DEFINE_FLAG( 9)
124
/* content lock has waiters */
125
0
#define BM_LOCK_HAS_WAITERS     BUF_DEFINE_FLAG(10)
126
/* waiter for content lock has been signalled but not yet run */
127
0
#define BM_LOCK_WAKE_IN_PROGRESS  BUF_DEFINE_FLAG(11)
128
129
130
StaticAssertDecl(MAX_BACKENDS_BITS <= BUF_REFCOUNT_BITS,
131
         "MAX_BACKENDS_BITS needs to be <= BUF_REFCOUNT_BITS");
132
StaticAssertDecl(MAX_BACKENDS_BITS <= (BUF_LOCK_BITS - 2),
133
         "MAX_BACKENDS_BITS needs to be <= BUF_LOCK_BITS - 2");
134
135
136
/*
137
 * The maximum allowed value of usage_count represents a tradeoff between
138
 * accuracy and speed of the clock-sweep buffer management algorithm.  A
139
 * large value (comparable to NBuffers) would approximate LRU semantics.
140
 * But it can take as many as BM_MAX_USAGE_COUNT+1 complete cycles of the
141
 * clock-sweep hand to find a free buffer, so in practice we don't want the
142
 * value to be very large.
143
 */
144
0
#define BM_MAX_USAGE_COUNT  5
145
146
StaticAssertDecl(BM_MAX_USAGE_COUNT < (UINT64CONST(1) << BUF_USAGECOUNT_BITS),
147
         "BM_MAX_USAGE_COUNT doesn't fit in BUF_USAGECOUNT_BITS bits");
148
149
/*
150
 * Buffer tag identifies which disk block the buffer contains.
151
 *
152
 * Note: the BufferTag data must be sufficient to determine where to write the
153
 * block, without reference to pg_class or pg_tablespace entries.  It's
154
 * possible that the backend flushing the buffer doesn't even believe the
155
 * relation is visible yet (its xact may have started before the xact that
156
 * created the rel).  The storage manager must be able to cope anyway.
157
 *
158
 * Note: if there's any pad bytes in the struct, InitBufferTag will have
159
 * to be fixed to zero them, since this struct is used as a hash key.
160
 */
161
typedef struct buftag
162
{
163
  Oid     spcOid;     /* tablespace oid */
164
  Oid     dbOid;      /* database oid */
165
  RelFileNumber relNumber;  /* relation file number */
166
  ForkNumber  forkNum;    /* fork number */
167
  BlockNumber blockNum;   /* blknum relative to begin of reln */
168
} BufferTag;
169
170
static inline RelFileNumber
171
BufTagGetRelNumber(const BufferTag *tag)
172
0
{
173
0
  return tag->relNumber;
174
0
}
Unexecuted instantiation: bgwriter.c:BufTagGetRelNumber
Unexecuted instantiation: buf_init.c:BufTagGetRelNumber
Unexecuted instantiation: buf_table.c:BufTagGetRelNumber
Unexecuted instantiation: bufmgr.c:BufTagGetRelNumber
Unexecuted instantiation: freelist.c:BufTagGetRelNumber
Unexecuted instantiation: localbuf.c:BufTagGetRelNumber
175
176
static inline ForkNumber
177
BufTagGetForkNum(const BufferTag *tag)
178
0
{
179
0
  return tag->forkNum;
180
0
}
Unexecuted instantiation: bgwriter.c:BufTagGetForkNum
Unexecuted instantiation: buf_init.c:BufTagGetForkNum
Unexecuted instantiation: buf_table.c:BufTagGetForkNum
Unexecuted instantiation: bufmgr.c:BufTagGetForkNum
Unexecuted instantiation: freelist.c:BufTagGetForkNum
Unexecuted instantiation: localbuf.c:BufTagGetForkNum
181
182
static inline void
183
BufTagSetRelForkDetails(BufferTag *tag, RelFileNumber relnumber,
184
            ForkNumber forknum)
185
0
{
186
0
  tag->relNumber = relnumber;
187
0
  tag->forkNum = forknum;
188
0
}
Unexecuted instantiation: bgwriter.c:BufTagSetRelForkDetails
Unexecuted instantiation: buf_init.c:BufTagSetRelForkDetails
Unexecuted instantiation: buf_table.c:BufTagSetRelForkDetails
Unexecuted instantiation: bufmgr.c:BufTagSetRelForkDetails
Unexecuted instantiation: freelist.c:BufTagSetRelForkDetails
Unexecuted instantiation: localbuf.c:BufTagSetRelForkDetails
189
190
static inline RelFileLocator
191
BufTagGetRelFileLocator(const BufferTag *tag)
192
0
{
193
0
  RelFileLocator rlocator;
194
195
0
  rlocator.spcOid = tag->spcOid;
196
0
  rlocator.dbOid = tag->dbOid;
197
0
  rlocator.relNumber = BufTagGetRelNumber(tag);
198
199
0
  return rlocator;
200
0
}
Unexecuted instantiation: bgwriter.c:BufTagGetRelFileLocator
Unexecuted instantiation: buf_init.c:BufTagGetRelFileLocator
Unexecuted instantiation: buf_table.c:BufTagGetRelFileLocator
Unexecuted instantiation: bufmgr.c:BufTagGetRelFileLocator
Unexecuted instantiation: freelist.c:BufTagGetRelFileLocator
Unexecuted instantiation: localbuf.c:BufTagGetRelFileLocator
201
202
static inline void
203
ClearBufferTag(BufferTag *tag)
204
0
{
205
0
  tag->spcOid = InvalidOid;
206
0
  tag->dbOid = InvalidOid;
207
0
  BufTagSetRelForkDetails(tag, InvalidRelFileNumber, InvalidForkNumber);
208
0
  tag->blockNum = InvalidBlockNumber;
209
0
}
Unexecuted instantiation: bgwriter.c:ClearBufferTag
Unexecuted instantiation: buf_init.c:ClearBufferTag
Unexecuted instantiation: buf_table.c:ClearBufferTag
Unexecuted instantiation: bufmgr.c:ClearBufferTag
Unexecuted instantiation: freelist.c:ClearBufferTag
Unexecuted instantiation: localbuf.c:ClearBufferTag
210
211
static inline void
212
InitBufferTag(BufferTag *tag, const RelFileLocator *rlocator,
213
        ForkNumber forkNum, BlockNumber blockNum)
214
0
{
215
0
  tag->spcOid = rlocator->spcOid;
216
0
  tag->dbOid = rlocator->dbOid;
217
0
  BufTagSetRelForkDetails(tag, rlocator->relNumber, forkNum);
218
0
  tag->blockNum = blockNum;
219
0
}
Unexecuted instantiation: bgwriter.c:InitBufferTag
Unexecuted instantiation: buf_init.c:InitBufferTag
Unexecuted instantiation: buf_table.c:InitBufferTag
Unexecuted instantiation: bufmgr.c:InitBufferTag
Unexecuted instantiation: freelist.c:InitBufferTag
Unexecuted instantiation: localbuf.c:InitBufferTag
220
221
static inline bool
222
BufferTagsEqual(const BufferTag *tag1, const BufferTag *tag2)
223
0
{
224
0
  return (tag1->spcOid == tag2->spcOid) &&
225
0
    (tag1->dbOid == tag2->dbOid) &&
226
0
    (tag1->relNumber == tag2->relNumber) &&
227
0
    (tag1->blockNum == tag2->blockNum) &&
228
0
    (tag1->forkNum == tag2->forkNum);
229
0
}
Unexecuted instantiation: bgwriter.c:BufferTagsEqual
Unexecuted instantiation: buf_init.c:BufferTagsEqual
Unexecuted instantiation: buf_table.c:BufferTagsEqual
Unexecuted instantiation: bufmgr.c:BufferTagsEqual
Unexecuted instantiation: freelist.c:BufferTagsEqual
Unexecuted instantiation: localbuf.c:BufferTagsEqual
230
231
static inline bool
232
BufTagMatchesRelFileLocator(const BufferTag *tag,
233
              const RelFileLocator *rlocator)
234
0
{
235
0
  return (tag->spcOid == rlocator->spcOid) &&
236
0
    (tag->dbOid == rlocator->dbOid) &&
237
0
    (BufTagGetRelNumber(tag) == rlocator->relNumber);
238
0
}
Unexecuted instantiation: bgwriter.c:BufTagMatchesRelFileLocator
Unexecuted instantiation: buf_init.c:BufTagMatchesRelFileLocator
Unexecuted instantiation: buf_table.c:BufTagMatchesRelFileLocator
Unexecuted instantiation: bufmgr.c:BufTagMatchesRelFileLocator
Unexecuted instantiation: freelist.c:BufTagMatchesRelFileLocator
Unexecuted instantiation: localbuf.c:BufTagMatchesRelFileLocator
239
240
241
/*
242
 * The shared buffer mapping table is partitioned to reduce contention.
243
 * To determine which partition lock a given tag requires, compute the tag's
244
 * hash code with BufTableHashCode(), then apply BufMappingPartitionLock().
245
 * NB: NUM_BUFFER_PARTITIONS must be a power of 2!
246
 */
247
static inline uint32
248
BufTableHashPartition(uint32 hashcode)
249
0
{
250
0
  return hashcode % NUM_BUFFER_PARTITIONS;
251
0
}
Unexecuted instantiation: bgwriter.c:BufTableHashPartition
Unexecuted instantiation: buf_init.c:BufTableHashPartition
Unexecuted instantiation: buf_table.c:BufTableHashPartition
Unexecuted instantiation: bufmgr.c:BufTableHashPartition
Unexecuted instantiation: freelist.c:BufTableHashPartition
Unexecuted instantiation: localbuf.c:BufTableHashPartition
252
253
static inline LWLock *
254
BufMappingPartitionLock(uint32 hashcode)
255
0
{
256
0
  return &MainLWLockArray[BUFFER_MAPPING_LWLOCK_OFFSET +
257
0
              BufTableHashPartition(hashcode)].lock;
258
0
}
Unexecuted instantiation: bgwriter.c:BufMappingPartitionLock
Unexecuted instantiation: buf_init.c:BufMappingPartitionLock
Unexecuted instantiation: buf_table.c:BufMappingPartitionLock
Unexecuted instantiation: bufmgr.c:BufMappingPartitionLock
Unexecuted instantiation: freelist.c:BufMappingPartitionLock
Unexecuted instantiation: localbuf.c:BufMappingPartitionLock
259
260
static inline LWLock *
261
BufMappingPartitionLockByIndex(uint32 index)
262
0
{
263
0
  return &MainLWLockArray[BUFFER_MAPPING_LWLOCK_OFFSET + index].lock;
264
0
}
Unexecuted instantiation: bgwriter.c:BufMappingPartitionLockByIndex
Unexecuted instantiation: buf_init.c:BufMappingPartitionLockByIndex
Unexecuted instantiation: buf_table.c:BufMappingPartitionLockByIndex
Unexecuted instantiation: bufmgr.c:BufMappingPartitionLockByIndex
Unexecuted instantiation: freelist.c:BufMappingPartitionLockByIndex
Unexecuted instantiation: localbuf.c:BufMappingPartitionLockByIndex
265
266
/*
267
 *  BufferDesc -- shared descriptor/state data for a single shared buffer.
268
 *
269
 * The state of the buffer is controlled by the, drumroll, state variable. It
270
 * only may be modified using atomic operations.  The state variable combines
271
 * various flags, the buffer's refcount and usage count. See comment above
272
 * BUF_REFCOUNT_BITS for details about the division.  This layout allow us to
273
 * do some operations in a single atomic operation, without actually acquiring
274
 * and releasing the spinlock; for instance, increasing or decreasing the
275
 * refcount.
276
 *
277
 * One of the aforementioned flags is BM_LOCKED, used to implement the buffer
278
 * header lock. See the following paragraphs, as well as the documentation for
279
 * individual fields, for more details.
280
 *
281
 * The identity of the buffer (BufferDesc.tag) can only be changed by the
282
 * backend holding the buffer header lock.
283
 *
284
 * If the lock is held by another backend, neither additional buffer pins may
285
 * be established (we would like to relax this eventually), nor can flags be
286
 * set/cleared. These operations either need to acquire the buffer header
287
 * spinlock, or need to use a CAS loop, waiting for the lock to be released if
288
 * it is held.  However, existing buffer pins may be released while the buffer
289
 * header spinlock is held, using an atomic subtraction.
290
 *
291
 * If we have the buffer pinned, its tag can't change underneath us, so we can
292
 * examine the tag without locking the buffer header.  Also, in places we do
293
 * one-time reads of the flags without bothering to lock the buffer header;
294
 * this is generally for situations where we don't expect the flag bit being
295
 * tested to be changing.
296
 *
297
 * We can't physically remove items from a disk page if another backend has
298
 * the buffer pinned.  Hence, a backend may need to wait for all other pins
299
 * to go away.  This is signaled by storing its own pgprocno into
300
 * wait_backend_pgprocno and setting flag bit BM_PIN_COUNT_WAITER.  At present,
301
 * there can be only one such waiter per buffer.
302
 *
303
 * The content of buffers is protected via the buffer content lock,
304
 * implemented as part of the buffer state. Note that the buffer header lock
305
 * is *not* used to control access to the data in the buffer! We used to use
306
 * an LWLock to implement the content lock, but having a dedicated
307
 * implementation of content locks allows us to implement some otherwise hard
308
 * things (e.g. race-freely checking if AIO is in progress before locking a
309
 * buffer exclusively) and enables otherwise impossible optimizations
310
 * (e.g. unlocking and unpinning a buffer in one atomic operation).
311
 *
312
 * We use this same struct for local buffer headers, but the locks are not
313
 * used and not all of the flag bits are useful either. To avoid unnecessary
314
 * overhead, manipulations of the state field should be done without actual
315
 * atomic operations (i.e. only pg_atomic_read_u64() and
316
 * pg_atomic_unlocked_write_u64()).
317
 *
318
 * Be careful to avoid increasing the size of the struct when adding or
319
 * reordering members.  Keeping it below 64 bytes (the most common CPU
320
 * cache line size) is fairly important for performance.
321
 *
322
 * Per-buffer I/O condition variables are currently kept outside this struct in
323
 * a separate array.  They could be moved in here and still fit within that
324
 * limit on common systems, but for now that is not done.
325
 */
326
typedef struct BufferDesc
327
{
328
  /*
329
   * ID of page contained in buffer. The buffer header spinlock needs to be
330
   * held to modify this field.
331
   */
332
  BufferTag tag;
333
334
  /*
335
   * Buffer's index number (from 0). The field never changes after
336
   * initialization, so does not need locking.
337
   */
338
  int     buf_id;
339
340
  /*
341
   * State of the buffer, containing flags, refcount and usagecount. See
342
   * BUF_* and BM_* defines at the top of this file.
343
   */
344
  pg_atomic_uint64 state;
345
346
  /*
347
   * Backend of pin-count waiter. The buffer header spinlock needs to be
348
   * held to modify this field.
349
   */
350
  int     wait_backend_pgprocno;
351
352
  PgAioWaitRef io_wref;   /* set iff AIO is in progress */
353
354
  /*
355
   * List of PGPROCs waiting for the buffer content lock. Protected by the
356
   * buffer header spinlock.
357
   */
358
  proclist_head lock_waiters;
359
} BufferDesc;
360
361
/*
362
 * Concurrent access to buffer headers has proven to be more efficient if
363
 * they're cache line aligned. So we force the start of the BufferDescriptors
364
 * array to be on a cache line boundary and force the elements to be cache
365
 * line sized.
366
 *
367
 * XXX: As this is primarily matters in highly concurrent workloads which
368
 * probably all are 64bit these days, and the space wastage would be a bit
369
 * more noticeable on 32bit systems, we don't force the stride to be cache
370
 * line sized on those. If somebody does actual performance testing, we can
371
 * reevaluate.
372
 *
373
 * Note that local buffer descriptors aren't forced to be aligned - as there's
374
 * no concurrent access to those it's unlikely to be beneficial.
375
 *
376
 * We use a 64-byte cache line size here, because that's the most common
377
 * size. Making it bigger would be a waste of memory. Even if running on a
378
 * platform with either 32 or 128 byte line sizes, it's good to align to
379
 * boundaries and avoid false sharing.
380
 */
381
#define BUFFERDESC_PAD_TO_SIZE  (SIZEOF_VOID_P == 8 ? 64 : 1)
382
383
typedef union BufferDescPadded
384
{
385
  BufferDesc  bufferdesc;
386
  char    pad[BUFFERDESC_PAD_TO_SIZE];
387
} BufferDescPadded;
388
389
/*
390
 * The PendingWriteback & WritebackContext structure are used to keep
391
 * information about pending flush requests to be issued to the OS.
392
 */
393
typedef struct PendingWriteback
394
{
395
  /* could store different types of pending flushes here */
396
  BufferTag tag;
397
} PendingWriteback;
398
399
/* struct forward declared in bufmgr.h */
400
typedef struct WritebackContext
401
{
402
  /* pointer to the max number of writeback requests to coalesce */
403
  int      *max_pending;
404
405
  /* current number of pending writeback requests */
406
  int     nr_pending;
407
408
  /* pending requests */
409
  PendingWriteback pending_writebacks[WRITEBACK_MAX_PENDING_FLUSHES];
410
} WritebackContext;
411
412
/* in buf_init.c */
413
extern PGDLLIMPORT BufferDescPadded *BufferDescriptors;
414
extern PGDLLIMPORT ConditionVariableMinimallyPadded *BufferIOCVArray;
415
416
/* in localbuf.c */
417
extern PGDLLIMPORT BufferDesc *LocalBufferDescriptors;
418
419
420
static inline BufferDesc *
421
GetBufferDescriptor(int id)
422
0
{
423
0
  Assert(id >= 0 && id < NBuffers);
424
425
0
  return &(BufferDescriptors[id]).bufferdesc;
426
0
}
Unexecuted instantiation: bgwriter.c:GetBufferDescriptor
Unexecuted instantiation: buf_init.c:GetBufferDescriptor
Unexecuted instantiation: buf_table.c:GetBufferDescriptor
Unexecuted instantiation: bufmgr.c:GetBufferDescriptor
Unexecuted instantiation: freelist.c:GetBufferDescriptor
Unexecuted instantiation: localbuf.c:GetBufferDescriptor
427
428
static inline BufferDesc *
429
GetLocalBufferDescriptor(int id)
430
0
{
431
0
  return &LocalBufferDescriptors[id];
432
0
}
Unexecuted instantiation: bgwriter.c:GetLocalBufferDescriptor
Unexecuted instantiation: buf_init.c:GetLocalBufferDescriptor
Unexecuted instantiation: buf_table.c:GetLocalBufferDescriptor
Unexecuted instantiation: bufmgr.c:GetLocalBufferDescriptor
Unexecuted instantiation: freelist.c:GetLocalBufferDescriptor
Unexecuted instantiation: localbuf.c:GetLocalBufferDescriptor
433
434
static inline Buffer
435
BufferDescriptorGetBuffer(const BufferDesc *bdesc)
436
0
{
437
0
  return (Buffer) (bdesc->buf_id + 1);
438
0
}
Unexecuted instantiation: bgwriter.c:BufferDescriptorGetBuffer
Unexecuted instantiation: buf_init.c:BufferDescriptorGetBuffer
Unexecuted instantiation: buf_table.c:BufferDescriptorGetBuffer
Unexecuted instantiation: bufmgr.c:BufferDescriptorGetBuffer
Unexecuted instantiation: freelist.c:BufferDescriptorGetBuffer
Unexecuted instantiation: localbuf.c:BufferDescriptorGetBuffer
439
440
static inline ConditionVariable *
441
BufferDescriptorGetIOCV(const BufferDesc *bdesc)
442
0
{
443
0
  return &(BufferIOCVArray[bdesc->buf_id]).cv;
444
0
}
Unexecuted instantiation: bgwriter.c:BufferDescriptorGetIOCV
Unexecuted instantiation: buf_init.c:BufferDescriptorGetIOCV
Unexecuted instantiation: buf_table.c:BufferDescriptorGetIOCV
Unexecuted instantiation: bufmgr.c:BufferDescriptorGetIOCV
Unexecuted instantiation: freelist.c:BufferDescriptorGetIOCV
Unexecuted instantiation: localbuf.c:BufferDescriptorGetIOCV
445
446
/*
447
 * Functions for acquiring/releasing a shared buffer header's spinlock.  Do
448
 * not apply these to local buffers!
449
 */
450
extern uint64 LockBufHdr(BufferDesc *desc);
451
452
/*
453
 * Unlock the buffer header.
454
 *
455
 * This can only be used if the caller did not modify BufferDesc.state. To
456
 * set/unset flag bits or change the refcount use UnlockBufHdrExt().
457
 */
458
static inline void
459
UnlockBufHdr(BufferDesc *desc)
460
0
{
461
0
  Assert(pg_atomic_read_u64(&desc->state) & BM_LOCKED);
462
463
0
  pg_atomic_fetch_sub_u64(&desc->state, BM_LOCKED);
464
0
}
Unexecuted instantiation: bgwriter.c:UnlockBufHdr
Unexecuted instantiation: buf_init.c:UnlockBufHdr
Unexecuted instantiation: buf_table.c:UnlockBufHdr
Unexecuted instantiation: bufmgr.c:UnlockBufHdr
Unexecuted instantiation: freelist.c:UnlockBufHdr
Unexecuted instantiation: localbuf.c:UnlockBufHdr
465
466
/*
467
 * Unlock the buffer header, while atomically unsetting the ones in
468
 * unset_bits, adding the flags in set_bits, and changing the refcount by
469
 * refcount_change. If a flag is both cleared and added, it will end up being
470
 * set.
471
 *
472
 * Note that this approach would not trivially work for usagecount, since we
473
 * need to cap the usagecount at BM_MAX_USAGE_COUNT.
474
 */
475
static inline uint64
476
UnlockBufHdrExt(BufferDesc *desc, uint64 old_buf_state,
477
        uint64 set_bits, uint64 unset_bits,
478
        int refcount_change)
479
0
{
480
0
  for (;;)
481
0
  {
482
0
    uint64    buf_state = old_buf_state;
483
484
0
    Assert(buf_state & BM_LOCKED);
485
486
    /*
487
     * Set bits after clearing bits, so that a cleared and re-added flag
488
     * survives.
489
     */
490
0
    buf_state &= ~unset_bits;
491
0
    buf_state |= set_bits;
492
0
    buf_state &= ~BM_LOCKED;
493
494
0
    if (refcount_change != 0)
495
0
      buf_state += BUF_REFCOUNT_ONE * refcount_change;
496
497
0
    if (pg_atomic_compare_exchange_u64(&desc->state, &old_buf_state,
498
0
                       buf_state))
499
0
    {
500
0
      return old_buf_state;
501
0
    }
502
0
  }
503
0
}
Unexecuted instantiation: bgwriter.c:UnlockBufHdrExt
Unexecuted instantiation: buf_init.c:UnlockBufHdrExt
Unexecuted instantiation: buf_table.c:UnlockBufHdrExt
Unexecuted instantiation: bufmgr.c:UnlockBufHdrExt
Unexecuted instantiation: freelist.c:UnlockBufHdrExt
Unexecuted instantiation: localbuf.c:UnlockBufHdrExt
504
505
extern uint64 WaitBufHdrUnlocked(BufferDesc *buf);
506
507
/* in bufmgr.c */
508
509
/*
510
 * Structure to sort buffers per file on checkpoints.
511
 *
512
 * This structure is allocated per buffer in shared memory, so it should be
513
 * kept as small as possible.
514
 */
515
typedef struct CkptSortItem
516
{
517
  Oid     tsId;
518
  RelFileNumber relNumber;
519
  ForkNumber  forkNum;
520
  BlockNumber blockNum;
521
  int     buf_id;
522
} CkptSortItem;
523
524
extern PGDLLIMPORT CkptSortItem *CkptBufferIds;
525
526
/* ResourceOwner callbacks to hold buffer I/Os and pins */
527
extern PGDLLIMPORT const ResourceOwnerDesc buffer_io_resowner_desc;
528
extern PGDLLIMPORT const ResourceOwnerDesc buffer_resowner_desc;
529
530
/* Convenience wrappers over ResourceOwnerRemember/Forget */
531
static inline void
532
ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer)
533
0
{
534
0
  ResourceOwnerRemember(owner, Int32GetDatum(buffer), &buffer_resowner_desc);
535
0
}
Unexecuted instantiation: bgwriter.c:ResourceOwnerRememberBuffer
Unexecuted instantiation: buf_init.c:ResourceOwnerRememberBuffer
Unexecuted instantiation: buf_table.c:ResourceOwnerRememberBuffer
Unexecuted instantiation: bufmgr.c:ResourceOwnerRememberBuffer
Unexecuted instantiation: freelist.c:ResourceOwnerRememberBuffer
Unexecuted instantiation: localbuf.c:ResourceOwnerRememberBuffer
536
static inline void
537
ResourceOwnerForgetBuffer(ResourceOwner owner, Buffer buffer)
538
0
{
539
0
  ResourceOwnerForget(owner, Int32GetDatum(buffer), &buffer_resowner_desc);
540
0
}
Unexecuted instantiation: bgwriter.c:ResourceOwnerForgetBuffer
Unexecuted instantiation: buf_init.c:ResourceOwnerForgetBuffer
Unexecuted instantiation: buf_table.c:ResourceOwnerForgetBuffer
Unexecuted instantiation: bufmgr.c:ResourceOwnerForgetBuffer
Unexecuted instantiation: freelist.c:ResourceOwnerForgetBuffer
Unexecuted instantiation: localbuf.c:ResourceOwnerForgetBuffer
541
static inline void
542
ResourceOwnerRememberBufferIO(ResourceOwner owner, Buffer buffer)
543
0
{
544
0
  ResourceOwnerRemember(owner, Int32GetDatum(buffer), &buffer_io_resowner_desc);
545
0
}
Unexecuted instantiation: bgwriter.c:ResourceOwnerRememberBufferIO
Unexecuted instantiation: buf_init.c:ResourceOwnerRememberBufferIO
Unexecuted instantiation: buf_table.c:ResourceOwnerRememberBufferIO
Unexecuted instantiation: bufmgr.c:ResourceOwnerRememberBufferIO
Unexecuted instantiation: freelist.c:ResourceOwnerRememberBufferIO
Unexecuted instantiation: localbuf.c:ResourceOwnerRememberBufferIO
546
static inline void
547
ResourceOwnerForgetBufferIO(ResourceOwner owner, Buffer buffer)
548
0
{
549
0
  ResourceOwnerForget(owner, Int32GetDatum(buffer), &buffer_io_resowner_desc);
550
0
}
Unexecuted instantiation: bgwriter.c:ResourceOwnerForgetBufferIO
Unexecuted instantiation: buf_init.c:ResourceOwnerForgetBufferIO
Unexecuted instantiation: buf_table.c:ResourceOwnerForgetBufferIO
Unexecuted instantiation: bufmgr.c:ResourceOwnerForgetBufferIO
Unexecuted instantiation: freelist.c:ResourceOwnerForgetBufferIO
Unexecuted instantiation: localbuf.c:ResourceOwnerForgetBufferIO
551
552
/*
553
 * Internal buffer management routines
554
 */
555
/* bufmgr.c */
556
extern void WritebackContextInit(WritebackContext *context, int *max_pending);
557
extern void IssuePendingWritebacks(WritebackContext *wb_context, IOContext io_context);
558
extern void ScheduleBufferTagForWriteback(WritebackContext *wb_context,
559
                      IOContext io_context, BufferTag *tag);
560
561
extern void TrackNewBufferPin(Buffer buf);
562
563
/*
564
 * Return value for StartBufferIO / StartSharedBufferIO / StartLocalBufferIO.
565
 *
566
 * When preparing a buffer for I/O and setting BM_IO_IN_PROGRESS, the buffer
567
 * may already have I/O in progress or the I/O may have been done by another
568
 * backend.  See the documentation of StartSharedBufferIO for more details.
569
 */
570
typedef enum StartBufferIOResult
571
{
572
  BUFFER_IO_ALREADY_DONE,
573
  BUFFER_IO_IN_PROGRESS,
574
  BUFFER_IO_READY_FOR_IO,
575
} StartBufferIOResult;
576
577
/* the following are exposed to make it easier to write tests */
578
extern StartBufferIOResult StartBufferIO(Buffer buffer, bool forInput, bool wait,
579
                     PgAioWaitRef *io_wref);
580
extern StartBufferIOResult StartSharedBufferIO(BufferDesc *buf, bool forInput, bool wait,
581
                         PgAioWaitRef *io_wref);
582
extern void TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits,
583
                bool forget_owner, bool release_aio);
584
585
586
/* freelist.c */
587
extern IOContext IOContextForStrategy(BufferAccessStrategy strategy);
588
extern BufferDesc *StrategyGetBuffer(BufferAccessStrategy strategy,
589
                   uint64 *buf_state, bool *from_ring);
590
extern bool StrategyRejectBuffer(BufferAccessStrategy strategy,
591
                 BufferDesc *buf, bool from_ring);
592
593
extern int  StrategySyncStart(uint32 *complete_passes, uint32 *num_buf_alloc);
594
extern void StrategyNotifyBgWriter(int bgwprocno);
595
596
/* buf_table.c */
597
extern uint32 BufTableHashCode(BufferTag *tagPtr);
598
extern int  BufTableLookup(BufferTag *tagPtr, uint32 hashcode);
599
extern int  BufTableInsert(BufferTag *tagPtr, uint32 hashcode, int buf_id);
600
extern void BufTableDelete(BufferTag *tagPtr, uint32 hashcode);
601
602
/* localbuf.c */
603
extern bool PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount);
604
extern void UnpinLocalBuffer(Buffer buffer);
605
extern void UnpinLocalBufferNoOwner(Buffer buffer);
606
extern PrefetchBufferResult PrefetchLocalBuffer(SMgrRelation smgr,
607
                        ForkNumber forkNum,
608
                        BlockNumber blockNum);
609
extern BufferDesc *LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum,
610
                  BlockNumber blockNum, bool *foundPtr);
611
extern BlockNumber ExtendBufferedRelLocal(BufferManagerRelation bmr,
612
                      ForkNumber fork,
613
                      uint32 flags,
614
                      uint32 extend_by,
615
                      BlockNumber extend_upto,
616
                      Buffer *buffers,
617
                      uint32 *extended_by);
618
extern void MarkLocalBufferDirty(Buffer buffer);
619
extern void TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty,
620
                   uint64 set_flag_bits, bool release_aio);
621
extern StartBufferIOResult StartLocalBufferIO(BufferDesc *bufHdr, bool forInput,
622
                        bool wait, PgAioWaitRef *io_wref);
623
extern void FlushLocalBuffer(BufferDesc *bufHdr, SMgrRelation reln);
624
extern void InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced);
625
extern void DropRelationLocalBuffers(RelFileLocator rlocator,
626
                   ForkNumber *forkNum, int nforks,
627
                   BlockNumber *firstDelBlock);
628
extern void DropRelationAllLocalBuffers(RelFileLocator rlocator);
629
extern void AtEOXact_LocalBuffers(bool isCommit);
630
631
#endif              /* BUFMGR_INTERNALS_H */