PostgreSQL Source Code  git master
slru.c File Reference
#include "postgres.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include "access/slru.h"
#include "access/transam.h"
#include "access/xlog.h"
#include "access/xlogutils.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "storage/fd.h"
#include "storage/shmem.h"
#include "utils/guc_hooks.h"
Include dependency graph for slru.c:

Go to the source code of this file.

Data Structures

struct  SlruWriteAllData
 

Macros

#define MAX_WRITEALL_BUFFERS   16
 
#define SLRU_BANK_BITSHIFT   4
 
#define SLRU_BANK_SIZE   (1 << SLRU_BANK_BITSHIFT)
 
#define SlotGetBankNumber(slotno)   ((slotno) >> SLRU_BANK_BITSHIFT)
 
#define INIT_SLRUFILETAG(a, xx_handler, xx_segno)
 

Typedefs

typedef struct SlruWriteAllData SlruWriteAllData
 
typedef struct SlruWriteAllDataSlruWriteAll
 

Enumerations

enum  SlruErrorCause {
  SLRU_OPEN_FAILED , SLRU_SEEK_FAILED , SLRU_READ_FAILED , SLRU_WRITE_FAILED ,
  SLRU_FSYNC_FAILED , SLRU_CLOSE_FAILED
}
 

Functions

static int SlruFileName (SlruCtl ctl, char *path, int64 segno)
 
static void SimpleLruZeroLSNs (SlruCtl ctl, int slotno)
 
static void SimpleLruWaitIO (SlruCtl ctl, int slotno)
 
static void SlruInternalWritePage (SlruCtl ctl, int slotno, SlruWriteAll fdata)
 
static bool SlruPhysicalReadPage (SlruCtl ctl, int64 pageno, int slotno)
 
static bool SlruPhysicalWritePage (SlruCtl ctl, int64 pageno, int slotno, SlruWriteAll fdata)
 
static void SlruReportIOError (SlruCtl ctl, int64 pageno, TransactionId xid)
 
static int SlruSelectLRUPage (SlruCtl ctl, int64 pageno)
 
static bool SlruScanDirCbDeleteCutoff (SlruCtl ctl, char *filename, int64 segpage, void *data)
 
static void SlruInternalDeleteSegment (SlruCtl ctl, int64 segno)
 
static void SlruRecentlyUsed (SlruShared shared, int slotno)
 
Size SimpleLruShmemSize (int nslots, int nlsns)
 
int SimpleLruAutotuneBuffers (int divisor, int max)
 
void SimpleLruInit (SlruCtl ctl, const char *name, int nslots, int nlsns, const char *subdir, int buffer_tranche_id, int bank_tranche_id, SyncRequestHandler sync_handler, bool long_segment_names)
 
bool check_slru_buffers (const char *name, int *newval)
 
int SimpleLruZeroPage (SlruCtl ctl, int64 pageno)
 
int SimpleLruReadPage (SlruCtl ctl, int64 pageno, bool write_ok, TransactionId xid)
 
int SimpleLruReadPage_ReadOnly (SlruCtl ctl, int64 pageno, TransactionId xid)
 
void SimpleLruWritePage (SlruCtl ctl, int slotno)
 
bool SimpleLruDoesPhysicalPageExist (SlruCtl ctl, int64 pageno)
 
void SimpleLruWriteAll (SlruCtl ctl, bool allow_redirtied)
 
void SimpleLruTruncate (SlruCtl ctl, int64 cutoffPage)
 
void SlruDeleteSegment (SlruCtl ctl, int64 segno)
 
static bool SlruMayDeleteSegment (SlruCtl ctl, int64 segpage, int64 cutoffPage)
 
bool SlruScanDirCbReportPresence (SlruCtl ctl, char *filename, int64 segpage, void *data)
 
bool SlruScanDirCbDeleteAll (SlruCtl ctl, char *filename, int64 segpage, void *data)
 
static bool SlruCorrectSegmentFilenameLength (SlruCtl ctl, size_t len)
 
bool SlruScanDirectory (SlruCtl ctl, SlruScanCallback callback, void *data)
 
int SlruSyncFileTag (SlruCtl ctl, const FileTag *ftag, char *path)
 

Variables

static SlruErrorCause slru_errcause
 
static int slru_errno
 

Macro Definition Documentation

◆ INIT_SLRUFILETAG

#define INIT_SLRUFILETAG (   a,
  xx_handler,
  xx_segno 
)
Value:
( \
memset(&(a), 0, sizeof(FileTag)), \
(a).handler = (xx_handler), \
(a).segno = (xx_segno) \
)
int a
Definition: isn.c:69
Definition: sync.h:51

Definition at line 142 of file slru.c.

◆ MAX_WRITEALL_BUFFERS

#define MAX_WRITEALL_BUFFERS   16

Definition at line 109 of file slru.c.

◆ SlotGetBankNumber

#define SlotGetBankNumber (   slotno)    ((slotno) >> SLRU_BANK_BITSHIFT)

Definition at line 134 of file slru.c.

◆ SLRU_BANK_BITSHIFT

#define SLRU_BANK_BITSHIFT   4

Definition at line 128 of file slru.c.

◆ SLRU_BANK_SIZE

#define SLRU_BANK_SIZE   (1 << SLRU_BANK_BITSHIFT)

Definition at line 129 of file slru.c.

Typedef Documentation

◆ SlruWriteAll

typedef struct SlruWriteAllData* SlruWriteAll

Definition at line 118 of file slru.c.

◆ SlruWriteAllData

Enumeration Type Documentation

◆ SlruErrorCause

Enumerator
SLRU_OPEN_FAILED 
SLRU_SEEK_FAILED 
SLRU_READ_FAILED 
SLRU_WRITE_FAILED 
SLRU_FSYNC_FAILED 
SLRU_CLOSE_FAILED 

Definition at line 150 of file slru.c.

151 {
SlruErrorCause
Definition: slru.c:151
@ SLRU_WRITE_FAILED
Definition: slru.c:155
@ SLRU_FSYNC_FAILED
Definition: slru.c:156
@ SLRU_SEEK_FAILED
Definition: slru.c:153
@ SLRU_OPEN_FAILED
Definition: slru.c:152
@ SLRU_CLOSE_FAILED
Definition: slru.c:157
@ SLRU_READ_FAILED
Definition: slru.c:154

Function Documentation

◆ check_slru_buffers()

bool check_slru_buffers ( const char *  name,
int *  newval 
)

Definition at line 341 of file slru.c.

342 {
343  /* Valid values are multiples of SLRU_BANK_SIZE */
344  if (*newval % SLRU_BANK_SIZE == 0)
345  return true;
346 
347  GUC_check_errdetail("\"%s\" must be a multiple of %d", name,
349  return false;
350 }
#define newval
#define GUC_check_errdetail
Definition: guc.h:448
#define SLRU_BANK_SIZE
Definition: slru.c:129
const char * name

References GUC_check_errdetail, name, newval, and SLRU_BANK_SIZE.

Referenced by check_commit_ts_buffers(), check_multixact_member_buffers(), check_multixact_offset_buffers(), check_notify_buffers(), check_serial_buffers(), check_subtrans_buffers(), and check_transaction_buffers().

◆ SimpleLruAutotuneBuffers()

int SimpleLruAutotuneBuffers ( int  divisor,
int  max 
)

Definition at line 217 of file slru.c.

218 {
219  return Min(max - (max % SLRU_BANK_SIZE),
221  NBuffers / divisor - (NBuffers / divisor) % SLRU_BANK_SIZE));
222 }
#define Min(x, y)
Definition: c.h:1004
#define Max(x, y)
Definition: c.h:998
int NBuffers
Definition: globals.c:139

References Max, Min, NBuffers, and SLRU_BANK_SIZE.

Referenced by CLOGShmemBuffers(), CommitTsShmemBuffers(), and SUBTRANSShmemBuffers().

◆ SimpleLruDoesPhysicalPageExist()

bool SimpleLruDoesPhysicalPageExist ( SlruCtl  ctl,
int64  pageno 
)

Definition at line 729 of file slru.c.

730 {
731  int64 segno = pageno / SLRU_PAGES_PER_SEGMENT;
732  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
733  int offset = rpageno * BLCKSZ;
734  char path[MAXPGPATH];
735  int fd;
736  bool result;
737  off_t endpos;
738 
739  /* update the stats counter of checked pages */
740  pgstat_count_slru_page_exists(ctl->shared->slru_stats_idx);
741 
742  SlruFileName(ctl, path, segno);
743 
744  fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
745  if (fd < 0)
746  {
747  /* expected: file doesn't exist */
748  if (errno == ENOENT)
749  return false;
750 
751  /* report error normally */
753  slru_errno = errno;
754  SlruReportIOError(ctl, pageno, 0);
755  }
756 
757  if ((endpos = lseek(fd, 0, SEEK_END)) < 0)
758  {
760  slru_errno = errno;
761  SlruReportIOError(ctl, pageno, 0);
762  }
763 
764  result = endpos >= (off_t) (offset + BLCKSZ);
765 
766  if (CloseTransientFile(fd) != 0)
767  {
769  slru_errno = errno;
770  return false;
771  }
772 
773  return result;
774 }
#define PG_BINARY
Definition: c.h:1273
int CloseTransientFile(int fd)
Definition: fd.c:2809
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2633
#define MAXPGPATH
static XLogRecPtr endpos
Definition: pg_receivewal.c:56
void pgstat_count_slru_page_exists(int slru_idx)
Definition: pgstat_slru.c:71
static int fd(const char *x, int i)
Definition: preproc-init.c:105
tree ctl
Definition: radixtree.h:1851
static int SlruFileName(SlruCtl ctl, char *path, int64 segno)
Definition: slru.c:76
static void SlruReportIOError(SlruCtl ctl, int64 pageno, TransactionId xid)
Definition: slru.c:1031
static SlruErrorCause slru_errcause
Definition: slru.c:160
static int slru_errno
Definition: slru.c:161
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:39

References CloseTransientFile(), ctl, endpos, fd(), MAXPGPATH, OpenTransientFile(), PG_BINARY, pgstat_count_slru_page_exists(), SlruWriteAllData::segno, SLRU_CLOSE_FAILED, slru_errcause, slru_errno, SLRU_OPEN_FAILED, SLRU_PAGES_PER_SEGMENT, SLRU_SEEK_FAILED, SlruFileName(), and SlruReportIOError().

Referenced by ActivateCommitTs(), find_multixact_start(), MaybeExtendOffsetSlru(), and test_slru_page_exists().

◆ SimpleLruInit()

void SimpleLruInit ( SlruCtl  ctl,
const char *  name,
int  nslots,
int  nlsns,
const char *  subdir,
int  buffer_tranche_id,
int  bank_tranche_id,
SyncRequestHandler  sync_handler,
bool  long_segment_names 
)

Definition at line 238 of file slru.c.

241 {
242  SlruShared shared;
243  bool found;
244  int nbanks = nslots / SLRU_BANK_SIZE;
245 
246  Assert(nslots <= SLRU_MAX_ALLOWED_BUFFERS);
247 
248  shared = (SlruShared) ShmemInitStruct(name,
249  SimpleLruShmemSize(nslots, nlsns),
250  &found);
251 
252  if (!IsUnderPostmaster)
253  {
254  /* Initialize locks and shared memory area */
255  char *ptr;
256  Size offset;
257 
258  Assert(!found);
259 
260  memset(shared, 0, sizeof(SlruSharedData));
261 
262  shared->num_slots = nslots;
263  shared->lsn_groups_per_page = nlsns;
264 
266 
268 
269  ptr = (char *) shared;
270  offset = MAXALIGN(sizeof(SlruSharedData));
271  shared->page_buffer = (char **) (ptr + offset);
272  offset += MAXALIGN(nslots * sizeof(char *));
273  shared->page_status = (SlruPageStatus *) (ptr + offset);
274  offset += MAXALIGN(nslots * sizeof(SlruPageStatus));
275  shared->page_dirty = (bool *) (ptr + offset);
276  offset += MAXALIGN(nslots * sizeof(bool));
277  shared->page_number = (int64 *) (ptr + offset);
278  offset += MAXALIGN(nslots * sizeof(int64));
279  shared->page_lru_count = (int *) (ptr + offset);
280  offset += MAXALIGN(nslots * sizeof(int));
281 
282  /* Initialize LWLocks */
283  shared->buffer_locks = (LWLockPadded *) (ptr + offset);
284  offset += MAXALIGN(nslots * sizeof(LWLockPadded));
285  shared->bank_locks = (LWLockPadded *) (ptr + offset);
286  offset += MAXALIGN(nbanks * sizeof(LWLockPadded));
287  shared->bank_cur_lru_count = (int *) (ptr + offset);
288  offset += MAXALIGN(nbanks * sizeof(int));
289 
290  if (nlsns > 0)
291  {
292  shared->group_lsn = (XLogRecPtr *) (ptr + offset);
293  offset += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr));
294  }
295 
296  ptr += BUFFERALIGN(offset);
297  for (int slotno = 0; slotno < nslots; slotno++)
298  {
299  LWLockInitialize(&shared->buffer_locks[slotno].lock,
300  buffer_tranche_id);
301 
302  shared->page_buffer[slotno] = ptr;
303  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
304  shared->page_dirty[slotno] = false;
305  shared->page_lru_count[slotno] = 0;
306  ptr += BLCKSZ;
307  }
308 
309  /* Initialize the slot banks. */
310  for (int bankno = 0; bankno < nbanks; bankno++)
311  {
312  LWLockInitialize(&shared->bank_locks[bankno].lock, bank_tranche_id);
313  shared->bank_cur_lru_count[bankno] = 0;
314  }
315 
316  /* Should fit to estimated shmem size */
317  Assert(ptr - (char *) shared <= SimpleLruShmemSize(nslots, nlsns));
318  }
319  else
320  {
321  Assert(found);
322  Assert(shared->num_slots == nslots);
323  }
324 
325  /*
326  * Initialize the unshared control struct, including directory path. We
327  * assume caller set PagePrecedes.
328  */
329  ctl->shared = shared;
330  ctl->sync_handler = sync_handler;
331  ctl->long_segment_names = long_segment_names;
332  ctl->bank_mask = (nslots / SLRU_BANK_SIZE) - 1;
333  strlcpy(ctl->Dir, subdir, sizeof(ctl->Dir));
334 }
static void pg_atomic_init_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition: atomics.h:448
#define MAXALIGN(LEN)
Definition: c.h:811
#define BUFFERALIGN(LEN)
Definition: c.h:813
#define Assert(condition)
Definition: c.h:858
size_t Size
Definition: c.h:605
bool IsUnderPostmaster
Definition: globals.c:117
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition: lwlock.c:709
int pgstat_get_slru_index(const char *name)
Definition: pgstat_slru.c:132
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:387
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:184
SlruSharedData * SlruShared
Definition: slru.h:121
#define SLRU_MAX_ALLOWED_BUFFERS
Definition: slru.h:24
SlruPageStatus
Definition: slru.h:48
@ SLRU_PAGE_EMPTY
Definition: slru.h:49
int slru_stats_idx
Definition: slru.h:118
int64 * page_number
Definition: slru.h:73
int num_slots
Definition: slru.h:64
LWLockPadded * bank_locks
Definition: slru.h:80
int * page_lru_count
Definition: slru.h:74
pg_atomic_uint64 latest_page_number
Definition: slru.h:115
XLogRecPtr * group_lsn
Definition: slru.h:107
int * bank_cur_lru_count
Definition: slru.h:97
int lsn_groups_per_page
Definition: slru.h:108
SlruPageStatus * page_status
Definition: slru.h:71
bool * page_dirty
Definition: slru.h:72
LWLockPadded * buffer_locks
Definition: slru.h:77
char ** page_buffer
Definition: slru.h:70
LWLock lock
Definition: lwlock.h:70
uint64 XLogRecPtr
Definition: xlogdefs.h:21

References Assert, SlruSharedData::bank_cur_lru_count, SlruSharedData::bank_locks, SlruSharedData::buffer_locks, BUFFERALIGN, ctl, SlruSharedData::group_lsn, IsUnderPostmaster, SlruSharedData::latest_page_number, LWLockPadded::lock, SlruSharedData::lsn_groups_per_page, LWLockInitialize(), MAXALIGN, name, SlruSharedData::num_slots, SlruSharedData::page_buffer, SlruSharedData::page_dirty, SlruSharedData::page_lru_count, SlruSharedData::page_number, SlruSharedData::page_status, pg_atomic_init_u64(), pgstat_get_slru_index(), ShmemInitStruct(), SimpleLruShmemSize(), SLRU_BANK_SIZE, SLRU_MAX_ALLOWED_BUFFERS, SLRU_PAGE_EMPTY, SlruSharedData::slru_stats_idx, and strlcpy().

Referenced by AsyncShmemInit(), CLOGShmemInit(), CommitTsShmemInit(), MultiXactShmemInit(), SerialInit(), SUBTRANSShmemInit(), and test_slru_shmem_startup().

◆ SimpleLruReadPage()

int SimpleLruReadPage ( SlruCtl  ctl,
int64  pageno,
bool  write_ok,
TransactionId  xid 
)

Definition at line 488 of file slru.c.

490 {
491  SlruShared shared = ctl->shared;
492  LWLock *banklock = SimpleLruGetBankLock(ctl, pageno);
493 
495 
496  /* Outer loop handles restart if we must wait for someone else's I/O */
497  for (;;)
498  {
499  int slotno;
500  bool ok;
501 
502  /* See if page already is in memory; if not, pick victim slot */
503  slotno = SlruSelectLRUPage(ctl, pageno);
504 
505  /* Did we find the page in memory? */
506  if (shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
507  shared->page_number[slotno] == pageno)
508  {
509  /*
510  * If page is still being read in, we must wait for I/O. Likewise
511  * if the page is being written and the caller said that's not OK.
512  */
513  if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS ||
514  (shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS &&
515  !write_ok))
516  {
517  SimpleLruWaitIO(ctl, slotno);
518  /* Now we must recheck state from the top */
519  continue;
520  }
521  /* Otherwise, it's ready to use */
522  SlruRecentlyUsed(shared, slotno);
523 
524  /* update the stats counter of pages found in the SLRU */
526 
527  return slotno;
528  }
529 
530  /* We found no match; assert we selected a freeable slot */
531  Assert(shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
532  (shared->page_status[slotno] == SLRU_PAGE_VALID &&
533  !shared->page_dirty[slotno]));
534 
535  /* Mark the slot read-busy */
536  shared->page_number[slotno] = pageno;
537  shared->page_status[slotno] = SLRU_PAGE_READ_IN_PROGRESS;
538  shared->page_dirty[slotno] = false;
539 
540  /* Acquire per-buffer lock (cannot deadlock, see notes at top) */
541  LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_EXCLUSIVE);
542 
543  /* Release bank lock while doing I/O */
544  LWLockRelease(banklock);
545 
546  /* Do the read */
547  ok = SlruPhysicalReadPage(ctl, pageno, slotno);
548 
549  /* Set the LSNs for this newly read-in page to zero */
550  SimpleLruZeroLSNs(ctl, slotno);
551 
552  /* Re-acquire bank control lock and update page state */
553  LWLockAcquire(banklock, LW_EXCLUSIVE);
554 
555  Assert(shared->page_number[slotno] == pageno &&
556  shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS &&
557  !shared->page_dirty[slotno]);
558 
559  shared->page_status[slotno] = ok ? SLRU_PAGE_VALID : SLRU_PAGE_EMPTY;
560 
561  LWLockRelease(&shared->buffer_locks[slotno].lock);
562 
563  /* Now it's okay to ereport if we failed */
564  if (!ok)
565  SlruReportIOError(ctl, pageno, xid);
566 
567  SlruRecentlyUsed(shared, slotno);
568 
569  /* update the stats counter of pages not found in SLRU */
571 
572  return slotno;
573  }
574 }
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1170
bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1939
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1783
@ LW_EXCLUSIVE
Definition: lwlock.h:114
void pgstat_count_slru_page_read(int slru_idx)
Definition: pgstat_slru.c:77
void pgstat_count_slru_page_hit(int slru_idx)
Definition: pgstat_slru.c:65
static bool SlruPhysicalReadPage(SlruCtl ctl, int64 pageno, int slotno)
Definition: slru.c:787
static void SimpleLruZeroLSNs(SlruCtl ctl, int slotno)
Definition: slru.c:414
static void SimpleLruWaitIO(SlruCtl ctl, int slotno)
Definition: slru.c:431
static int SlruSelectLRUPage(SlruCtl ctl, int64 pageno)
Definition: slru.c:1152
static void SlruRecentlyUsed(SlruShared shared, int slotno)
Definition: slru.c:1106
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
Definition: slru.h:179
@ SLRU_PAGE_VALID
Definition: slru.h:51
@ SLRU_PAGE_WRITE_IN_PROGRESS
Definition: slru.h:52
@ SLRU_PAGE_READ_IN_PROGRESS
Definition: slru.h:50
Definition: lwlock.h:42

References Assert, SlruSharedData::buffer_locks, ctl, LWLockPadded::lock, LW_EXCLUSIVE, LWLockAcquire(), LWLockHeldByMeInMode(), LWLockRelease(), SlruSharedData::page_dirty, SlruSharedData::page_number, SlruSharedData::page_status, pgstat_count_slru_page_hit(), pgstat_count_slru_page_read(), SimpleLruGetBankLock(), SimpleLruWaitIO(), SimpleLruZeroLSNs(), SLRU_PAGE_EMPTY, SLRU_PAGE_READ_IN_PROGRESS, SLRU_PAGE_VALID, SLRU_PAGE_WRITE_IN_PROGRESS, SlruSharedData::slru_stats_idx, SlruPhysicalReadPage(), SlruRecentlyUsed(), SlruReportIOError(), and SlruSelectLRUPage().

Referenced by asyncQueueAddEntries(), GetMultiXactIdMembers(), RecordNewMultiXact(), SerialAdd(), SetXidCommitTsInPage(), SimpleLruReadPage_ReadOnly(), SubTransSetParent(), test_slru_page_read(), TransactionIdSetPageStatusInternal(), TrimCLOG(), and TrimMultiXact().

◆ SimpleLruReadPage_ReadOnly()

int SimpleLruReadPage_ReadOnly ( SlruCtl  ctl,
int64  pageno,
TransactionId  xid 
)

Definition at line 591 of file slru.c.

592 {
593  SlruShared shared = ctl->shared;
594  LWLock *banklock = SimpleLruGetBankLock(ctl, pageno);
595  int bankno = pageno & ctl->bank_mask;
596  int bankstart = bankno * SLRU_BANK_SIZE;
597  int bankend = bankstart + SLRU_BANK_SIZE;
598 
599  /* Try to find the page while holding only shared lock */
600  LWLockAcquire(banklock, LW_SHARED);
601 
602  /* See if page is already in a buffer */
603  for (int slotno = bankstart; slotno < bankend; slotno++)
604  {
605  if (shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
606  shared->page_number[slotno] == pageno &&
607  shared->page_status[slotno] != SLRU_PAGE_READ_IN_PROGRESS)
608  {
609  /* See comments for SlruRecentlyUsed macro */
610  SlruRecentlyUsed(shared, slotno);
611 
612  /* update the stats counter of pages found in the SLRU */
614 
615  return slotno;
616  }
617  }
618 
619  /* No luck, so switch to normal exclusive lock and do regular read */
620  LWLockRelease(banklock);
621  LWLockAcquire(banklock, LW_EXCLUSIVE);
622 
623  return SimpleLruReadPage(ctl, pageno, true, xid);
624 }
@ LW_SHARED
Definition: lwlock.h:115
int SimpleLruReadPage(SlruCtl ctl, int64 pageno, bool write_ok, TransactionId xid)
Definition: slru.c:488

References ctl, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), SlruSharedData::page_number, SlruSharedData::page_status, pgstat_count_slru_page_hit(), SimpleLruGetBankLock(), SimpleLruReadPage(), SLRU_BANK_SIZE, SLRU_PAGE_EMPTY, SLRU_PAGE_READ_IN_PROGRESS, SlruSharedData::slru_stats_idx, and SlruRecentlyUsed().

Referenced by asyncQueueReadAllNotifications(), find_multixact_start(), SerialGetMinConflictCommitSeqNo(), SubTransGetParent(), test_slru_page_readonly(), TransactionIdGetCommitTsData(), and TransactionIdGetStatus().

◆ SimpleLruShmemSize()

Size SimpleLruShmemSize ( int  nslots,
int  nlsns 
)

Definition at line 184 of file slru.c.

185 {
186  int nbanks = nslots / SLRU_BANK_SIZE;
187  Size sz;
188 
189  Assert(nslots <= SLRU_MAX_ALLOWED_BUFFERS);
190  Assert(nslots % SLRU_BANK_SIZE == 0);
191 
192  /* we assume nslots isn't so large as to risk overflow */
193  sz = MAXALIGN(sizeof(SlruSharedData));
194  sz += MAXALIGN(nslots * sizeof(char *)); /* page_buffer[] */
195  sz += MAXALIGN(nslots * sizeof(SlruPageStatus)); /* page_status[] */
196  sz += MAXALIGN(nslots * sizeof(bool)); /* page_dirty[] */
197  sz += MAXALIGN(nslots * sizeof(int64)); /* page_number[] */
198  sz += MAXALIGN(nslots * sizeof(int)); /* page_lru_count[] */
199  sz += MAXALIGN(nslots * sizeof(LWLockPadded)); /* buffer_locks[] */
200  sz += MAXALIGN(nbanks * sizeof(LWLockPadded)); /* bank_locks[] */
201  sz += MAXALIGN(nbanks * sizeof(int)); /* bank_cur_lru_count[] */
202 
203  if (nlsns > 0)
204  sz += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr)); /* group_lsn[] */
205 
206  return BUFFERALIGN(sz) + BLCKSZ * nslots;
207 }

References Assert, BUFFERALIGN, MAXALIGN, SLRU_BANK_SIZE, and SLRU_MAX_ALLOWED_BUFFERS.

Referenced by AsyncShmemSize(), CLOGShmemSize(), CommitTsShmemSize(), MultiXactShmemSize(), PredicateLockShmemSize(), SimpleLruInit(), SUBTRANSShmemSize(), and test_slru_shmem_request().

◆ SimpleLruTruncate()

void SimpleLruTruncate ( SlruCtl  ctl,
int64  cutoffPage 
)

Definition at line 1391 of file slru.c.

1392 {
1393  SlruShared shared = ctl->shared;
1394  int prevbank;
1395 
1396  /* update the stats counter of truncates */
1398 
1399  /*
1400  * Scan shared memory and remove any pages preceding the cutoff page, to
1401  * ensure we won't rewrite them later. (Since this is normally called in
1402  * or just after a checkpoint, any dirty pages should have been flushed
1403  * already ... we're just being extra careful here.)
1404  */
1405 restart:
1406 
1407  /*
1408  * An important safety check: the current endpoint page must not be
1409  * eligible for removal. This check is just a backstop against wraparound
1410  * bugs elsewhere in SLRU handling, so we don't care if we read a slightly
1411  * outdated value; therefore we don't add a memory barrier.
1412  */
1413  if (ctl->PagePrecedes(pg_atomic_read_u64(&shared->latest_page_number),
1414  cutoffPage))
1415  {
1416  ereport(LOG,
1417  (errmsg("could not truncate directory \"%s\": apparent wraparound",
1418  ctl->Dir)));
1419  return;
1420  }
1421 
1422  prevbank = SlotGetBankNumber(0);
1423  LWLockAcquire(&shared->bank_locks[prevbank].lock, LW_EXCLUSIVE);
1424  for (int slotno = 0; slotno < shared->num_slots; slotno++)
1425  {
1426  int curbank = SlotGetBankNumber(slotno);
1427 
1428  /*
1429  * If the current bank lock is not same as the previous bank lock then
1430  * release the previous lock and acquire the new lock.
1431  */
1432  if (curbank != prevbank)
1433  {
1434  LWLockRelease(&shared->bank_locks[prevbank].lock);
1435  LWLockAcquire(&shared->bank_locks[curbank].lock, LW_EXCLUSIVE);
1436  prevbank = curbank;
1437  }
1438 
1439  if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
1440  continue;
1441  if (!ctl->PagePrecedes(shared->page_number[slotno], cutoffPage))
1442  continue;
1443 
1444  /*
1445  * If page is clean, just change state to EMPTY (expected case).
1446  */
1447  if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1448  !shared->page_dirty[slotno])
1449  {
1450  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
1451  continue;
1452  }
1453 
1454  /*
1455  * Hmm, we have (or may have) I/O operations acting on the page, so
1456  * we've got to wait for them to finish and then start again. This is
1457  * the same logic as in SlruSelectLRUPage. (XXX if page is dirty,
1458  * wouldn't it be OK to just discard it without writing it?
1459  * SlruMayDeleteSegment() uses a stricter qualification, so we might
1460  * not delete this page in the end; even if we don't delete it, we
1461  * won't have cause to read its data again. For now, keep the logic
1462  * the same as it was.)
1463  */
1464  if (shared->page_status[slotno] == SLRU_PAGE_VALID)
1465  SlruInternalWritePage(ctl, slotno, NULL);
1466  else
1467  SimpleLruWaitIO(ctl, slotno);
1468 
1469  LWLockRelease(&shared->bank_locks[prevbank].lock);
1470  goto restart;
1471  }
1472 
1473  LWLockRelease(&shared->bank_locks[prevbank].lock);
1474 
1475  /* Now we can remove the old segment(s) */
1476  (void) SlruScanDirectory(ctl, SlruScanDirCbDeleteCutoff, &cutoffPage);
1477 }
static uint64 pg_atomic_read_u64(volatile pg_atomic_uint64 *ptr)
Definition: atomics.h:462
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define LOG
Definition: elog.h:31
#define ereport(elevel,...)
Definition: elog.h:149
void pgstat_count_slru_truncate(int slru_idx)
Definition: pgstat_slru.c:95
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruWriteAll fdata)
Definition: slru.c:638
bool SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data)
Definition: slru.c:1774
#define SlotGetBankNumber(slotno)
Definition: slru.c:134
static bool SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename, int64 segpage, void *data)
Definition: slru.c:1711

References SlruSharedData::bank_locks, ctl, ereport, errmsg(), SlruSharedData::latest_page_number, LWLockPadded::lock, LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SlruSharedData::num_slots, SlruSharedData::page_dirty, SlruSharedData::page_number, SlruSharedData::page_status, pg_atomic_read_u64(), pgstat_count_slru_truncate(), SimpleLruWaitIO(), SlotGetBankNumber, SLRU_PAGE_EMPTY, SLRU_PAGE_VALID, SlruSharedData::slru_stats_idx, SlruInternalWritePage(), SlruScanDirCbDeleteCutoff(), and SlruScanDirectory().

Referenced by asyncQueueAdvanceTail(), CheckPointPredicate(), clog_redo(), commit_ts_redo(), PerformOffsetsTruncation(), test_slru_page_truncate(), TruncateCLOG(), TruncateCommitTs(), and TruncateSUBTRANS().

◆ SimpleLruWaitIO()

static void SimpleLruWaitIO ( SlruCtl  ctl,
int  slotno 
)
static

Definition at line 431 of file slru.c.

432 {
433  SlruShared shared = ctl->shared;
434  int bankno = SlotGetBankNumber(slotno);
435 
436  Assert(shared->page_status[slotno] != SLRU_PAGE_EMPTY);
437 
438  /* See notes at top of file */
439  LWLockRelease(&shared->bank_locks[bankno].lock);
440  LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_SHARED);
441  LWLockRelease(&shared->buffer_locks[slotno].lock);
442  LWLockAcquire(&shared->bank_locks[bankno].lock, LW_EXCLUSIVE);
443 
444  /*
445  * If the slot is still in an io-in-progress state, then either someone
446  * already started a new I/O on the slot, or a previous I/O failed and
447  * neglected to reset the page state. That shouldn't happen, really, but
448  * it seems worth a few extra cycles to check and recover from it. We can
449  * cheaply test for failure by seeing if the buffer lock is still held (we
450  * assume that transaction abort would release the lock).
451  */
452  if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS ||
453  shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS)
454  {
455  if (LWLockConditionalAcquire(&shared->buffer_locks[slotno].lock, LW_SHARED))
456  {
457  /* indeed, the I/O must have failed */
458  if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS)
459  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
460  else /* write_in_progress */
461  {
462  shared->page_status[slotno] = SLRU_PAGE_VALID;
463  shared->page_dirty[slotno] = true;
464  }
465  LWLockRelease(&shared->buffer_locks[slotno].lock);
466  }
467  }
468 }
bool LWLockConditionalAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1341

References Assert, SlruSharedData::bank_locks, SlruSharedData::buffer_locks, ctl, LWLockPadded::lock, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockConditionalAcquire(), LWLockRelease(), SlruSharedData::page_dirty, SlruSharedData::page_status, SlotGetBankNumber, SLRU_PAGE_EMPTY, SLRU_PAGE_READ_IN_PROGRESS, SLRU_PAGE_VALID, and SLRU_PAGE_WRITE_IN_PROGRESS.

Referenced by SimpleLruReadPage(), SimpleLruTruncate(), SlruDeleteSegment(), SlruInternalWritePage(), and SlruSelectLRUPage().

◆ SimpleLruWriteAll()

void SimpleLruWriteAll ( SlruCtl  ctl,
bool  allow_redirtied 
)

Definition at line 1305 of file slru.c.

1306 {
1307  SlruShared shared = ctl->shared;
1308  SlruWriteAllData fdata;
1309  int64 pageno = 0;
1310  int prevbank = SlotGetBankNumber(0);
1311  bool ok;
1312 
1313  /* update the stats counter of flushes */
1315 
1316  /*
1317  * Find and write dirty pages
1318  */
1319  fdata.num_files = 0;
1320 
1321  LWLockAcquire(&shared->bank_locks[prevbank].lock, LW_EXCLUSIVE);
1322 
1323  for (int slotno = 0; slotno < shared->num_slots; slotno++)
1324  {
1325  int curbank = SlotGetBankNumber(slotno);
1326 
1327  /*
1328  * If the current bank lock is not same as the previous bank lock then
1329  * release the previous lock and acquire the new lock.
1330  */
1331  if (curbank != prevbank)
1332  {
1333  LWLockRelease(&shared->bank_locks[prevbank].lock);
1334  LWLockAcquire(&shared->bank_locks[curbank].lock, LW_EXCLUSIVE);
1335  prevbank = curbank;
1336  }
1337 
1338  /* Do nothing if slot is unused */
1339  if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
1340  continue;
1341 
1342  SlruInternalWritePage(ctl, slotno, &fdata);
1343 
1344  /*
1345  * In some places (e.g. checkpoints), we cannot assert that the slot
1346  * is clean now, since another process might have re-dirtied it
1347  * already. That's okay.
1348  */
1349  Assert(allow_redirtied ||
1350  shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
1351  (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1352  !shared->page_dirty[slotno]));
1353  }
1354 
1355  LWLockRelease(&shared->bank_locks[prevbank].lock);
1356 
1357  /*
1358  * Now close any files that were open
1359  */
1360  ok = true;
1361  for (int i = 0; i < fdata.num_files; i++)
1362  {
1363  if (CloseTransientFile(fdata.fd[i]) != 0)
1364  {
1366  slru_errno = errno;
1367  pageno = fdata.segno[i] * SLRU_PAGES_PER_SEGMENT;
1368  ok = false;
1369  }
1370  }
1371  if (!ok)
1373 
1374  /* Ensure that directory entries for new files are on disk. */
1375  if (ctl->sync_handler != SYNC_HANDLER_NONE)
1376  fsync_fname(ctl->Dir, true);
1377 }
void fsync_fname(const char *fname, bool isdir)
Definition: fd.c:756
int i
Definition: isn.c:73
void pgstat_count_slru_flush(int slru_idx)
Definition: pgstat_slru.c:89
int num_files
Definition: slru.c:113
int fd[MAX_WRITEALL_BUFFERS]
Definition: slru.c:114
int64 segno[MAX_WRITEALL_BUFFERS]
Definition: slru.c:115
@ SYNC_HANDLER_NONE
Definition: sync.h:42
#define InvalidTransactionId
Definition: transam.h:31

References Assert, SlruSharedData::bank_locks, CloseTransientFile(), ctl, SlruWriteAllData::fd, fsync_fname(), i, InvalidTransactionId, LWLockPadded::lock, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SlruWriteAllData::num_files, SlruSharedData::num_slots, SlruSharedData::page_dirty, SlruSharedData::page_status, pgstat_count_slru_flush(), SlruWriteAllData::segno, SlotGetBankNumber, SLRU_CLOSE_FAILED, slru_errcause, slru_errno, SLRU_PAGE_EMPTY, SLRU_PAGE_VALID, SLRU_PAGES_PER_SEGMENT, SlruSharedData::slru_stats_idx, SlruInternalWritePage(), SlruReportIOError(), and SYNC_HANDLER_NONE.

Referenced by CheckPointCLOG(), CheckPointCommitTs(), CheckPointMultiXact(), CheckPointPredicate(), CheckPointSUBTRANS(), find_multixact_start(), and test_slru_page_writeall().

◆ SimpleLruWritePage()

void SimpleLruWritePage ( SlruCtl  ctl,
int  slotno 
)

Definition at line 715 of file slru.c.

716 {
717  Assert(ctl->shared->page_status[slotno] != SLRU_PAGE_EMPTY);
718 
719  SlruInternalWritePage(ctl, slotno, NULL);
720 }

References Assert, ctl, SLRU_PAGE_EMPTY, and SlruInternalWritePage().

Referenced by ActivateCommitTs(), BootStrapCLOG(), BootStrapMultiXact(), BootStrapSUBTRANS(), clog_redo(), commit_ts_redo(), MaybeExtendOffsetSlru(), multixact_redo(), and test_slru_page_write().

◆ SimpleLruZeroLSNs()

static void SimpleLruZeroLSNs ( SlruCtl  ctl,
int  slotno 
)
static

Definition at line 414 of file slru.c.

415 {
416  SlruShared shared = ctl->shared;
417 
418  if (shared->lsn_groups_per_page > 0)
419  MemSet(&shared->group_lsn[slotno * shared->lsn_groups_per_page], 0,
420  shared->lsn_groups_per_page * sizeof(XLogRecPtr));
421 }
#define MemSet(start, val, len)
Definition: c.h:1020

References ctl, SlruSharedData::group_lsn, SlruSharedData::lsn_groups_per_page, and MemSet.

Referenced by SimpleLruReadPage(), and SimpleLruZeroPage().

◆ SimpleLruZeroPage()

int SimpleLruZeroPage ( SlruCtl  ctl,
int64  pageno 
)

Definition at line 361 of file slru.c.

362 {
363  SlruShared shared = ctl->shared;
364  int slotno;
365 
367 
368  /* Find a suitable buffer slot for the page */
369  slotno = SlruSelectLRUPage(ctl, pageno);
370  Assert(shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
371  (shared->page_status[slotno] == SLRU_PAGE_VALID &&
372  !shared->page_dirty[slotno]) ||
373  shared->page_number[slotno] == pageno);
374 
375  /* Mark the slot as containing this page */
376  shared->page_number[slotno] = pageno;
377  shared->page_status[slotno] = SLRU_PAGE_VALID;
378  shared->page_dirty[slotno] = true;
379  SlruRecentlyUsed(shared, slotno);
380 
381  /* Set the buffer to zeroes */
382  MemSet(shared->page_buffer[slotno], 0, BLCKSZ);
383 
384  /* Set the LSNs for this new page to zero */
385  SimpleLruZeroLSNs(ctl, slotno);
386 
387  /*
388  * Assume this page is now the latest active page.
389  *
390  * Note that because both this routine and SlruSelectLRUPage run with
391  * ControlLock held, it is not possible for this to be zeroing a page that
392  * SlruSelectLRUPage is going to evict simultaneously. Therefore, there's
393  * no memory barrier here.
394  */
395  pg_atomic_write_u64(&shared->latest_page_number, pageno);
396 
397  /* update the stats counter of zeroed pages */
399 
400  return slotno;
401 }
static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition: atomics.h:480
void pgstat_count_slru_page_zeroed(int slru_idx)
Definition: pgstat_slru.c:59

References Assert, ctl, SlruSharedData::latest_page_number, LW_EXCLUSIVE, LWLockHeldByMeInMode(), MemSet, SlruSharedData::page_buffer, SlruSharedData::page_dirty, SlruSharedData::page_number, SlruSharedData::page_status, pg_atomic_write_u64(), pgstat_count_slru_page_zeroed(), SimpleLruGetBankLock(), SimpleLruZeroLSNs(), SLRU_PAGE_EMPTY, SLRU_PAGE_VALID, SlruSharedData::slru_stats_idx, SlruRecentlyUsed(), and SlruSelectLRUPage().

Referenced by asyncQueueAddEntries(), SerialAdd(), test_slru_page_write(), ZeroCLOGPage(), ZeroCommitTsPage(), ZeroMultiXactMemberPage(), ZeroMultiXactOffsetPage(), and ZeroSUBTRANSPage().

◆ SlruCorrectSegmentFilenameLength()

static bool SlruCorrectSegmentFilenameLength ( SlruCtl  ctl,
size_t  len 
)
inlinestatic

Definition at line 1741 of file slru.c.

1742 {
1743  if (ctl->long_segment_names)
1744  return (len == 15); /* see SlruFileName() */
1745  else
1746 
1747  /*
1748  * Commit 638cf09e76d allowed 5-character lengths. Later commit
1749  * 73c986adde5 allowed 6-character length.
1750  *
1751  * Note: There is an ongoing plan to migrate all SLRUs to 64-bit page
1752  * numbers, and the corresponding 15-character file names, which may
1753  * eventually deprecate the support for 4, 5, and 6-character names.
1754  */
1755  return (len == 4 || len == 5 || len == 6);
1756 }
const void size_t len

References ctl, and len.

Referenced by SlruScanDirectory().

◆ SlruDeleteSegment()

void SlruDeleteSegment ( SlruCtl  ctl,
int64  segno 
)

Definition at line 1509 of file slru.c.

1510 {
1511  SlruShared shared = ctl->shared;
1512  int prevbank = SlotGetBankNumber(0);
1513  bool did_write;
1514 
1515  /* Clean out any possibly existing references to the segment. */
1516  LWLockAcquire(&shared->bank_locks[prevbank].lock, LW_EXCLUSIVE);
1517 restart:
1518  did_write = false;
1519  for (int slotno = 0; slotno < shared->num_slots; slotno++)
1520  {
1521  int pagesegno;
1522  int curbank = SlotGetBankNumber(slotno);
1523 
1524  /*
1525  * If the current bank lock is not same as the previous bank lock then
1526  * release the previous lock and acquire the new lock.
1527  */
1528  if (curbank != prevbank)
1529  {
1530  LWLockRelease(&shared->bank_locks[prevbank].lock);
1531  LWLockAcquire(&shared->bank_locks[curbank].lock, LW_EXCLUSIVE);
1532  prevbank = curbank;
1533  }
1534 
1535  if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
1536  continue;
1537 
1538  pagesegno = shared->page_number[slotno] / SLRU_PAGES_PER_SEGMENT;
1539  /* not the segment we're looking for */
1540  if (pagesegno != segno)
1541  continue;
1542 
1543  /* If page is clean, just change state to EMPTY (expected case). */
1544  if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1545  !shared->page_dirty[slotno])
1546  {
1547  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
1548  continue;
1549  }
1550 
1551  /* Same logic as SimpleLruTruncate() */
1552  if (shared->page_status[slotno] == SLRU_PAGE_VALID)
1553  SlruInternalWritePage(ctl, slotno, NULL);
1554  else
1555  SimpleLruWaitIO(ctl, slotno);
1556 
1557  did_write = true;
1558  }
1559 
1560  /*
1561  * Be extra careful and re-check. The IO functions release the control
1562  * lock, so new pages could have been read in.
1563  */
1564  if (did_write)
1565  goto restart;
1566 
1568 
1569  LWLockRelease(&shared->bank_locks[prevbank].lock);
1570 }
static void SlruInternalDeleteSegment(SlruCtl ctl, int64 segno)
Definition: slru.c:1486

References SlruSharedData::bank_locks, ctl, LWLockPadded::lock, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SlruSharedData::num_slots, SlruSharedData::page_dirty, SlruSharedData::page_number, SlruSharedData::page_status, SlruWriteAllData::segno, SimpleLruWaitIO(), SlotGetBankNumber, SLRU_PAGE_EMPTY, SLRU_PAGE_VALID, SLRU_PAGES_PER_SEGMENT, SlruInternalDeleteSegment(), and SlruInternalWritePage().

Referenced by PerformMembersTruncation(), and test_slru_page_delete().

◆ SlruFileName()

static int SlruFileName ( SlruCtl  ctl,
char *  path,
int64  segno 
)
inlinestatic

Definition at line 76 of file slru.c.

77 {
78  if (ctl->long_segment_names)
79  {
80  /*
81  * We could use 16 characters here but the disadvantage would be that
82  * the SLRU segments will be hard to distinguish from WAL segments.
83  *
84  * For this reason we use 15 characters. It is enough but also means
85  * that in the future we can't decrease SLRU_PAGES_PER_SEGMENT easily.
86  */
87  Assert(segno >= 0 && segno <= INT64CONST(0xFFFFFFFFFFFFFFF));
88  return snprintf(path, MAXPGPATH, "%s/%015llX", ctl->Dir,
89  (long long) segno);
90  }
91  else
92  {
93  /*
94  * Despite the fact that %04X format string is used up to 24 bit
95  * integers are allowed. See SlruCorrectSegmentFilenameLength()
96  */
97  Assert(segno >= 0 && segno <= INT64CONST(0xFFFFFF));
98  return snprintf(path, MAXPGPATH, "%s/%04X", (ctl)->Dir,
99  (unsigned int) segno);
100  }
101 }
#define snprintf
Definition: port.h:238

References Assert, ctl, MAXPGPATH, and snprintf.

Referenced by SimpleLruDoesPhysicalPageExist(), SlruInternalDeleteSegment(), SlruPhysicalReadPage(), SlruPhysicalWritePage(), SlruReportIOError(), and SlruSyncFileTag().

◆ SlruInternalDeleteSegment()

static void SlruInternalDeleteSegment ( SlruCtl  ctl,
int64  segno 
)
static

Definition at line 1486 of file slru.c.

1487 {
1488  char path[MAXPGPATH];
1489 
1490  /* Forget any fsync requests queued for this segment. */
1491  if (ctl->sync_handler != SYNC_HANDLER_NONE)
1492  {
1493  FileTag tag;
1494 
1495  INIT_SLRUFILETAG(tag, ctl->sync_handler, segno);
1497  }
1498 
1499  /* Unlink the file. */
1500  SlruFileName(ctl, path, segno);
1501  ereport(DEBUG2, (errmsg_internal("removing file \"%s\"", path)));
1502  unlink(path);
1503 }
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1159
#define DEBUG2
Definition: elog.h:29
#define INIT_SLRUFILETAG(a, xx_handler, xx_segno)
Definition: slru.c:142
bool RegisterSyncRequest(const FileTag *ftag, SyncRequestType type, bool retryOnError)
Definition: sync.c:580
@ SYNC_FORGET_REQUEST
Definition: sync.h:27

References ctl, DEBUG2, ereport, errmsg_internal(), INIT_SLRUFILETAG, MAXPGPATH, RegisterSyncRequest(), SlruWriteAllData::segno, SlruFileName(), SYNC_FORGET_REQUEST, and SYNC_HANDLER_NONE.

Referenced by SlruDeleteSegment(), SlruScanDirCbDeleteAll(), and SlruScanDirCbDeleteCutoff().

◆ SlruInternalWritePage()

static void SlruInternalWritePage ( SlruCtl  ctl,
int  slotno,
SlruWriteAll  fdata 
)
static

Definition at line 638 of file slru.c.

639 {
640  SlruShared shared = ctl->shared;
641  int64 pageno = shared->page_number[slotno];
642  int bankno = SlotGetBankNumber(slotno);
643  bool ok;
644 
645  Assert(shared->page_status[slotno] != SLRU_PAGE_EMPTY);
647 
648  /* If a write is in progress, wait for it to finish */
649  while (shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS &&
650  shared->page_number[slotno] == pageno)
651  {
652  SimpleLruWaitIO(ctl, slotno);
653  }
654 
655  /*
656  * Do nothing if page is not dirty, or if buffer no longer contains the
657  * same page we were called for.
658  */
659  if (!shared->page_dirty[slotno] ||
660  shared->page_status[slotno] != SLRU_PAGE_VALID ||
661  shared->page_number[slotno] != pageno)
662  return;
663 
664  /*
665  * Mark the slot write-busy, and clear the dirtybit. After this point, a
666  * transaction status update on this page will mark it dirty again.
667  */
668  shared->page_status[slotno] = SLRU_PAGE_WRITE_IN_PROGRESS;
669  shared->page_dirty[slotno] = false;
670 
671  /* Acquire per-buffer lock (cannot deadlock, see notes at top) */
672  LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_EXCLUSIVE);
673 
674  /* Release bank lock while doing I/O */
675  LWLockRelease(&shared->bank_locks[bankno].lock);
676 
677  /* Do the write */
678  ok = SlruPhysicalWritePage(ctl, pageno, slotno, fdata);
679 
680  /* If we failed, and we're in a flush, better close the files */
681  if (!ok && fdata)
682  {
683  for (int i = 0; i < fdata->num_files; i++)
684  CloseTransientFile(fdata->fd[i]);
685  }
686 
687  /* Re-acquire bank lock and update page state */
688  LWLockAcquire(&shared->bank_locks[bankno].lock, LW_EXCLUSIVE);
689 
690  Assert(shared->page_number[slotno] == pageno &&
691  shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS);
692 
693  /* If we failed to write, mark the page dirty again */
694  if (!ok)
695  shared->page_dirty[slotno] = true;
696 
697  shared->page_status[slotno] = SLRU_PAGE_VALID;
698 
699  LWLockRelease(&shared->buffer_locks[slotno].lock);
700 
701  /* Now it's okay to ereport if we failed */
702  if (!ok)
704 
705  /* If part of a checkpoint, count this as a buffer written. */
706  if (fdata)
708 }
static bool SlruPhysicalWritePage(SlruCtl ctl, int64 pageno, int slotno, SlruWriteAll fdata)
Definition: slru.c:859
int ckpt_bufs_written
Definition: xlog.h:165
CheckpointStatsData CheckpointStats
Definition: xlog.c:209

References Assert, SlruSharedData::bank_locks, SlruSharedData::buffer_locks, CheckpointStats, CheckpointStatsData::ckpt_bufs_written, CloseTransientFile(), ctl, SlruWriteAllData::fd, i, InvalidTransactionId, LWLockPadded::lock, LW_EXCLUSIVE, LWLockAcquire(), LWLockHeldByMeInMode(), LWLockRelease(), SlruWriteAllData::num_files, SlruSharedData::page_dirty, SlruSharedData::page_number, SlruSharedData::page_status, SimpleLruGetBankLock(), SimpleLruWaitIO(), SlotGetBankNumber, SLRU_PAGE_EMPTY, SLRU_PAGE_VALID, SLRU_PAGE_WRITE_IN_PROGRESS, SlruPhysicalWritePage(), and SlruReportIOError().

Referenced by SimpleLruTruncate(), SimpleLruWriteAll(), SimpleLruWritePage(), SlruDeleteSegment(), and SlruSelectLRUPage().

◆ SlruMayDeleteSegment()

static bool SlruMayDeleteSegment ( SlruCtl  ctl,
int64  segpage,
int64  cutoffPage 
)
static

Definition at line 1586 of file slru.c.

1587 {
1588  int64 seg_last_page = segpage + SLRU_PAGES_PER_SEGMENT - 1;
1589 
1590  Assert(segpage % SLRU_PAGES_PER_SEGMENT == 0);
1591 
1592  return (ctl->PagePrecedes(segpage, cutoffPage) &&
1593  ctl->PagePrecedes(seg_last_page, cutoffPage));
1594 }

References Assert, ctl, and SLRU_PAGES_PER_SEGMENT.

Referenced by SlruScanDirCbDeleteCutoff(), and SlruScanDirCbReportPresence().

◆ SlruPhysicalReadPage()

static bool SlruPhysicalReadPage ( SlruCtl  ctl,
int64  pageno,
int  slotno 
)
static

Definition at line 787 of file slru.c.

788 {
789  SlruShared shared = ctl->shared;
790  int64 segno = pageno / SLRU_PAGES_PER_SEGMENT;
791  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
792  off_t offset = rpageno * BLCKSZ;
793  char path[MAXPGPATH];
794  int fd;
795 
796  SlruFileName(ctl, path, segno);
797 
798  /*
799  * In a crash-and-restart situation, it's possible for us to receive
800  * commands to set the commit status of transactions whose bits are in
801  * already-truncated segments of the commit log (see notes in
802  * SlruPhysicalWritePage). Hence, if we are InRecovery, allow the case
803  * where the file doesn't exist, and return zeroes instead.
804  */
805  fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
806  if (fd < 0)
807  {
808  if (errno != ENOENT || !InRecovery)
809  {
811  slru_errno = errno;
812  return false;
813  }
814 
815  ereport(LOG,
816  (errmsg("file \"%s\" doesn't exist, reading as zeroes",
817  path)));
818  MemSet(shared->page_buffer[slotno], 0, BLCKSZ);
819  return true;
820  }
821 
822  errno = 0;
823  pgstat_report_wait_start(WAIT_EVENT_SLRU_READ);
824  if (pg_pread(fd, shared->page_buffer[slotno], BLCKSZ, offset) != BLCKSZ)
825  {
828  slru_errno = errno;
830  return false;
831  }
833 
834  if (CloseTransientFile(fd) != 0)
835  {
837  slru_errno = errno;
838  return false;
839  }
840 
841  return true;
842 }
#define pg_pread
Definition: port.h:225
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: wait_event.h:88
static void pgstat_report_wait_end(void)
Definition: wait_event.h:104
bool InRecovery
Definition: xlogutils.c:50

References CloseTransientFile(), ctl, ereport, errmsg(), fd(), InRecovery, LOG, MAXPGPATH, MemSet, OpenTransientFile(), SlruSharedData::page_buffer, PG_BINARY, pg_pread, pgstat_report_wait_end(), pgstat_report_wait_start(), SlruWriteAllData::segno, SLRU_CLOSE_FAILED, slru_errcause, slru_errno, SLRU_OPEN_FAILED, SLRU_PAGES_PER_SEGMENT, SLRU_READ_FAILED, and SlruFileName().

Referenced by SimpleLruReadPage().

◆ SlruPhysicalWritePage()

static bool SlruPhysicalWritePage ( SlruCtl  ctl,
int64  pageno,
int  slotno,
SlruWriteAll  fdata 
)
static

Definition at line 859 of file slru.c.

860 {
861  SlruShared shared = ctl->shared;
862  int64 segno = pageno / SLRU_PAGES_PER_SEGMENT;
863  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
864  off_t offset = rpageno * BLCKSZ;
865  char path[MAXPGPATH];
866  int fd = -1;
867 
868  /* update the stats counter of written pages */
870 
871  /*
872  * Honor the write-WAL-before-data rule, if appropriate, so that we do not
873  * write out data before associated WAL records. This is the same action
874  * performed during FlushBuffer() in the main buffer manager.
875  */
876  if (shared->group_lsn != NULL)
877  {
878  /*
879  * We must determine the largest async-commit LSN for the page. This
880  * is a bit tedious, but since this entire function is a slow path
881  * anyway, it seems better to do this here than to maintain a per-page
882  * LSN variable (which'd need an extra comparison in the
883  * transaction-commit path).
884  */
885  XLogRecPtr max_lsn;
886  int lsnindex;
887 
888  lsnindex = slotno * shared->lsn_groups_per_page;
889  max_lsn = shared->group_lsn[lsnindex++];
890  for (int lsnoff = 1; lsnoff < shared->lsn_groups_per_page; lsnoff++)
891  {
892  XLogRecPtr this_lsn = shared->group_lsn[lsnindex++];
893 
894  if (max_lsn < this_lsn)
895  max_lsn = this_lsn;
896  }
897 
898  if (!XLogRecPtrIsInvalid(max_lsn))
899  {
900  /*
901  * As noted above, elog(ERROR) is not acceptable here, so if
902  * XLogFlush were to fail, we must PANIC. This isn't much of a
903  * restriction because XLogFlush is just about all critical
904  * section anyway, but let's make sure.
905  */
907  XLogFlush(max_lsn);
909  }
910  }
911 
912  /*
913  * During a SimpleLruWriteAll, we may already have the desired file open.
914  */
915  if (fdata)
916  {
917  for (int i = 0; i < fdata->num_files; i++)
918  {
919  if (fdata->segno[i] == segno)
920  {
921  fd = fdata->fd[i];
922  break;
923  }
924  }
925  }
926 
927  if (fd < 0)
928  {
929  /*
930  * If the file doesn't already exist, we should create it. It is
931  * possible for this to need to happen when writing a page that's not
932  * first in its segment; we assume the OS can cope with that. (Note:
933  * it might seem that it'd be okay to create files only when
934  * SimpleLruZeroPage is called for the first page of a segment.
935  * However, if after a crash and restart the REDO logic elects to
936  * replay the log from a checkpoint before the latest one, then it's
937  * possible that we will get commands to set transaction status of
938  * transactions that have already been truncated from the commit log.
939  * Easiest way to deal with that is to accept references to
940  * nonexistent files here and in SlruPhysicalReadPage.)
941  *
942  * Note: it is possible for more than one backend to be executing this
943  * code simultaneously for different pages of the same file. Hence,
944  * don't use O_EXCL or O_TRUNC or anything like that.
945  */
946  SlruFileName(ctl, path, segno);
947  fd = OpenTransientFile(path, O_RDWR | O_CREAT | PG_BINARY);
948  if (fd < 0)
949  {
951  slru_errno = errno;
952  return false;
953  }
954 
955  if (fdata)
956  {
957  if (fdata->num_files < MAX_WRITEALL_BUFFERS)
958  {
959  fdata->fd[fdata->num_files] = fd;
960  fdata->segno[fdata->num_files] = segno;
961  fdata->num_files++;
962  }
963  else
964  {
965  /*
966  * In the unlikely event that we exceed MAX_WRITEALL_BUFFERS,
967  * fall back to treating it as a standalone write.
968  */
969  fdata = NULL;
970  }
971  }
972  }
973 
974  errno = 0;
975  pgstat_report_wait_start(WAIT_EVENT_SLRU_WRITE);
976  if (pg_pwrite(fd, shared->page_buffer[slotno], BLCKSZ, offset) != BLCKSZ)
977  {
979  /* if write didn't set errno, assume problem is no disk space */
980  if (errno == 0)
981  errno = ENOSPC;
983  slru_errno = errno;
984  if (!fdata)
986  return false;
987  }
989 
990  /* Queue up a sync request for the checkpointer. */
991  if (ctl->sync_handler != SYNC_HANDLER_NONE)
992  {
993  FileTag tag;
994 
995  INIT_SLRUFILETAG(tag, ctl->sync_handler, segno);
996  if (!RegisterSyncRequest(&tag, SYNC_REQUEST, false))
997  {
998  /* No space to enqueue sync request. Do it synchronously. */
999  pgstat_report_wait_start(WAIT_EVENT_SLRU_SYNC);
1000  if (pg_fsync(fd) != 0)
1001  {
1004  slru_errno = errno;
1006  return false;
1007  }
1009  }
1010  }
1011 
1012  /* Close file, unless part of flush request. */
1013  if (!fdata)
1014  {
1015  if (CloseTransientFile(fd) != 0)
1016  {
1018  slru_errno = errno;
1019  return false;
1020  }
1021  }
1022 
1023  return true;
1024 }
int pg_fsync(int fd)
Definition: fd.c:386
#define START_CRIT_SECTION()
Definition: miscadmin.h:149
#define END_CRIT_SECTION()
Definition: miscadmin.h:151
void pgstat_count_slru_page_written(int slru_idx)
Definition: pgstat_slru.c:83
#define pg_pwrite
Definition: port.h:226
#define MAX_WRITEALL_BUFFERS
Definition: slru.c:109
@ SYNC_REQUEST
Definition: sync.h:25
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2791
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29

References CloseTransientFile(), ctl, END_CRIT_SECTION, fd(), SlruWriteAllData::fd, SlruSharedData::group_lsn, i, INIT_SLRUFILETAG, SlruSharedData::lsn_groups_per_page, MAX_WRITEALL_BUFFERS, MAXPGPATH, SlruWriteAllData::num_files, OpenTransientFile(), SlruSharedData::page_buffer, PG_BINARY, pg_fsync(), pg_pwrite, pgstat_count_slru_page_written(), pgstat_report_wait_end(), pgstat_report_wait_start(), RegisterSyncRequest(), SlruWriteAllData::segno, SLRU_CLOSE_FAILED, slru_errcause, slru_errno, SLRU_FSYNC_FAILED, SLRU_OPEN_FAILED, SLRU_PAGES_PER_SEGMENT, SlruSharedData::slru_stats_idx, SLRU_WRITE_FAILED, SlruFileName(), START_CRIT_SECTION, SYNC_HANDLER_NONE, SYNC_REQUEST, XLogFlush(), and XLogRecPtrIsInvalid.

Referenced by SlruInternalWritePage().

◆ SlruRecentlyUsed()

static void SlruRecentlyUsed ( SlruShared  shared,
int  slotno 
)
inlinestatic

Definition at line 1106 of file slru.c.

1107 {
1108  int bankno = SlotGetBankNumber(slotno);
1109  int new_lru_count = shared->bank_cur_lru_count[bankno];
1110 
1111  Assert(shared->page_status[slotno] != SLRU_PAGE_EMPTY);
1112 
1113  /*
1114  * The reason for the if-test is that there are often many consecutive
1115  * accesses to the same page (particularly the latest page). By
1116  * suppressing useless increments of bank_cur_lru_count, we reduce the
1117  * probability that old pages' counts will "wrap around" and make them
1118  * appear recently used.
1119  *
1120  * We allow this code to be executed concurrently by multiple processes
1121  * within SimpleLruReadPage_ReadOnly(). As long as int reads and writes
1122  * are atomic, this should not cause any completely-bogus values to enter
1123  * the computation. However, it is possible for either bank_cur_lru_count
1124  * or individual page_lru_count entries to be "reset" to lower values than
1125  * they should have, in case a process is delayed while it executes this
1126  * function. With care in SlruSelectLRUPage(), this does little harm, and
1127  * in any case the absolute worst possible consequence is a nonoptimal
1128  * choice of page to evict. The gain from allowing concurrent reads of
1129  * SLRU pages seems worth it.
1130  */
1131  if (new_lru_count != shared->page_lru_count[slotno])
1132  {
1133  shared->bank_cur_lru_count[bankno] = ++new_lru_count;
1134  shared->page_lru_count[slotno] = new_lru_count;
1135  }
1136 }

References Assert, SlruSharedData::bank_cur_lru_count, SlruSharedData::page_lru_count, SlruSharedData::page_status, SlotGetBankNumber, and SLRU_PAGE_EMPTY.

Referenced by SimpleLruReadPage(), SimpleLruReadPage_ReadOnly(), and SimpleLruZeroPage().

◆ SlruReportIOError()

static void SlruReportIOError ( SlruCtl  ctl,
int64  pageno,
TransactionId  xid 
)
static

Definition at line 1031 of file slru.c.

1032 {
1033  int64 segno = pageno / SLRU_PAGES_PER_SEGMENT;
1034  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
1035  int offset = rpageno * BLCKSZ;
1036  char path[MAXPGPATH];
1037 
1038  SlruFileName(ctl, path, segno);
1039  errno = slru_errno;
1040  switch (slru_errcause)
1041  {
1042  case SLRU_OPEN_FAILED:
1043  ereport(ERROR,
1045  errmsg("could not access status of transaction %u", xid),
1046  errdetail("Could not open file \"%s\": %m.", path)));
1047  break;
1048  case SLRU_SEEK_FAILED:
1049  ereport(ERROR,
1051  errmsg("could not access status of transaction %u", xid),
1052  errdetail("Could not seek in file \"%s\" to offset %d: %m.",
1053  path, offset)));
1054  break;
1055  case SLRU_READ_FAILED:
1056  if (errno)
1057  ereport(ERROR,
1059  errmsg("could not access status of transaction %u", xid),
1060  errdetail("Could not read from file \"%s\" at offset %d: %m.",
1061  path, offset)));
1062  else
1063  ereport(ERROR,
1064  (errmsg("could not access status of transaction %u", xid),
1065  errdetail("Could not read from file \"%s\" at offset %d: read too few bytes.", path, offset)));
1066  break;
1067  case SLRU_WRITE_FAILED:
1068  if (errno)
1069  ereport(ERROR,
1071  errmsg("could not access status of transaction %u", xid),
1072  errdetail("Could not write to file \"%s\" at offset %d: %m.",
1073  path, offset)));
1074  else
1075  ereport(ERROR,
1076  (errmsg("could not access status of transaction %u", xid),
1077  errdetail("Could not write to file \"%s\" at offset %d: wrote too few bytes.",
1078  path, offset)));
1079  break;
1080  case SLRU_FSYNC_FAILED:
1083  errmsg("could not access status of transaction %u", xid),
1084  errdetail("Could not fsync file \"%s\": %m.",
1085  path)));
1086  break;
1087  case SLRU_CLOSE_FAILED:
1088  ereport(ERROR,
1090  errmsg("could not access status of transaction %u", xid),
1091  errdetail("Could not close file \"%s\": %m.",
1092  path)));
1093  break;
1094  default:
1095  /* can't get here, we trust */
1096  elog(ERROR, "unrecognized SimpleLru error cause: %d",
1097  (int) slru_errcause);
1098  break;
1099  }
1100 }
int errcode_for_file_access(void)
Definition: elog.c:882
int errdetail(const char *fmt,...)
Definition: elog.c:1205
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
int data_sync_elevel(int elevel)
Definition: fd.c:3936

References ctl, data_sync_elevel(), elog, ereport, errcode_for_file_access(), errdetail(), errmsg(), ERROR, MAXPGPATH, SlruWriteAllData::segno, SLRU_CLOSE_FAILED, slru_errcause, slru_errno, SLRU_FSYNC_FAILED, SLRU_OPEN_FAILED, SLRU_PAGES_PER_SEGMENT, SLRU_READ_FAILED, SLRU_SEEK_FAILED, SLRU_WRITE_FAILED, and SlruFileName().

Referenced by SimpleLruDoesPhysicalPageExist(), SimpleLruReadPage(), SimpleLruWriteAll(), and SlruInternalWritePage().

◆ SlruScanDirCbDeleteAll()

bool SlruScanDirCbDeleteAll ( SlruCtl  ctl,
char *  filename,
int64  segpage,
void *  data 
)

Definition at line 1727 of file slru.c.

1728 {
1730 
1731  return false; /* keep going */
1732 }

References ctl, SLRU_PAGES_PER_SEGMENT, and SlruInternalDeleteSegment().

Referenced by AsyncShmemInit(), DeactivateCommitTs(), and test_slru_scan_cb().

◆ SlruScanDirCbDeleteCutoff()

static bool SlruScanDirCbDeleteCutoff ( SlruCtl  ctl,
char *  filename,
int64  segpage,
void *  data 
)
static

Definition at line 1711 of file slru.c.

1713 {
1714  int64 cutoffPage = *(int64 *) data;
1715 
1716  if (SlruMayDeleteSegment(ctl, segpage, cutoffPage))
1718 
1719  return false; /* keep going */
1720 }
const void * data
static bool SlruMayDeleteSegment(SlruCtl ctl, int64 segpage, int64 cutoffPage)
Definition: slru.c:1586

References ctl, data, SLRU_PAGES_PER_SEGMENT, SlruInternalDeleteSegment(), and SlruMayDeleteSegment().

Referenced by SimpleLruTruncate().

◆ SlruScanDirCbReportPresence()

bool SlruScanDirCbReportPresence ( SlruCtl  ctl,
char *  filename,
int64  segpage,
void *  data 
)

Definition at line 1695 of file slru.c.

1697 {
1698  int64 cutoffPage = *(int64 *) data;
1699 
1700  if (SlruMayDeleteSegment(ctl, segpage, cutoffPage))
1701  return true; /* found one; don't iterate any more */
1702 
1703  return false; /* keep going */
1704 }

References ctl, data, and SlruMayDeleteSegment().

Referenced by TruncateCLOG(), and TruncateCommitTs().

◆ SlruScanDirectory()

bool SlruScanDirectory ( SlruCtl  ctl,
SlruScanCallback  callback,
void *  data 
)

Definition at line 1774 of file slru.c.

1775 {
1776  bool retval = false;
1777  DIR *cldir;
1778  struct dirent *clde;
1779  int64 segno;
1780  int64 segpage;
1781 
1782  cldir = AllocateDir(ctl->Dir);
1783  while ((clde = ReadDir(cldir, ctl->Dir)) != NULL)
1784  {
1785  size_t len;
1786 
1787  len = strlen(clde->d_name);
1788 
1790  strspn(clde->d_name, "0123456789ABCDEF") == len)
1791  {
1792  segno = strtoi64(clde->d_name, NULL, 16);
1793  segpage = segno * SLRU_PAGES_PER_SEGMENT;
1794 
1795  elog(DEBUG2, "SlruScanDirectory invoking callback on %s/%s",
1796  ctl->Dir, clde->d_name);
1797  retval = callback(ctl, clde->d_name, segpage, data);
1798  if (retval)
1799  break;
1800  }
1801  }
1802  FreeDir(cldir);
1803 
1804  return retval;
1805 }
#define strtoi64(str, endptr, base)
Definition: c.h:1297
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2909
int FreeDir(DIR *dir)
Definition: fd.c:2961
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2843
static bool SlruCorrectSegmentFilenameLength(SlruCtl ctl, size_t len)
Definition: slru.c:1741
Definition: dirent.c:26
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:46

References AllocateDir(), callback(), ctl, dirent::d_name, data, DEBUG2, elog, FreeDir(), len, ReadDir(), SLRU_PAGES_PER_SEGMENT, SlruCorrectSegmentFilenameLength(), and strtoi64.

Referenced by AsyncShmemInit(), DeactivateCommitTs(), SimpleLruTruncate(), test_slru_delete_all(), TruncateCLOG(), TruncateCommitTs(), and TruncateMultiXact().

◆ SlruSelectLRUPage()

static int SlruSelectLRUPage ( SlruCtl  ctl,
int64  pageno 
)
static

Definition at line 1152 of file slru.c.

1153 {
1154  SlruShared shared = ctl->shared;
1155 
1156  /* Outer loop handles restart after I/O */
1157  for (;;)
1158  {
1159  int cur_count;
1160  int bestvalidslot = 0; /* keep compiler quiet */
1161  int best_valid_delta = -1;
1162  int64 best_valid_page_number = 0; /* keep compiler quiet */
1163  int bestinvalidslot = 0; /* keep compiler quiet */
1164  int best_invalid_delta = -1;
1165  int64 best_invalid_page_number = 0; /* keep compiler quiet */
1166  int bankno = pageno & ctl->bank_mask;
1167  int bankstart = bankno * SLRU_BANK_SIZE;
1168  int bankend = bankstart + SLRU_BANK_SIZE;
1169 
1171 
1172  /* See if page already has a buffer assigned */
1173  for (int slotno = 0; slotno < shared->num_slots; slotno++)
1174  {
1175  if (shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
1176  shared->page_number[slotno] == pageno)
1177  return slotno;
1178  }
1179 
1180  /*
1181  * If we find any EMPTY slot, just select that one. Else choose a
1182  * victim page to replace. We normally take the least recently used
1183  * valid page, but we will never take the slot containing
1184  * latest_page_number, even if it appears least recently used. We
1185  * will select a slot that is already I/O busy only if there is no
1186  * other choice: a read-busy slot will not be least recently used once
1187  * the read finishes, and waiting for an I/O on a write-busy slot is
1188  * inferior to just picking some other slot. Testing shows the slot
1189  * we pick instead will often be clean, allowing us to begin a read at
1190  * once.
1191  *
1192  * Normally the page_lru_count values will all be different and so
1193  * there will be a well-defined LRU page. But since we allow
1194  * concurrent execution of SlruRecentlyUsed() within
1195  * SimpleLruReadPage_ReadOnly(), it is possible that multiple pages
1196  * acquire the same lru_count values. In that case we break ties by
1197  * choosing the furthest-back page.
1198  *
1199  * Notice that this next line forcibly advances cur_lru_count to a
1200  * value that is certainly beyond any value that will be in the
1201  * page_lru_count array after the loop finishes. This ensures that
1202  * the next execution of SlruRecentlyUsed will mark the page newly
1203  * used, even if it's for a page that has the current counter value.
1204  * That gets us back on the path to having good data when there are
1205  * multiple pages with the same lru_count.
1206  */
1207  cur_count = (shared->bank_cur_lru_count[bankno])++;
1208  for (int slotno = bankstart; slotno < bankend; slotno++)
1209  {
1210  int this_delta;
1211  int64 this_page_number;
1212 
1213  if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
1214  return slotno;
1215 
1216  this_delta = cur_count - shared->page_lru_count[slotno];
1217  if (this_delta < 0)
1218  {
1219  /*
1220  * Clean up in case shared updates have caused cur_count
1221  * increments to get "lost". We back off the page counts,
1222  * rather than trying to increase cur_count, to avoid any
1223  * question of infinite loops or failure in the presence of
1224  * wrapped-around counts.
1225  */
1226  shared->page_lru_count[slotno] = cur_count;
1227  this_delta = 0;
1228  }
1229 
1230  /*
1231  * If this page is the one most recently zeroed, don't consider it
1232  * an eviction candidate. See comments in SimpleLruZeroPage for an
1233  * explanation about the lack of a memory barrier here.
1234  */
1235  this_page_number = shared->page_number[slotno];
1236  if (this_page_number ==
1238  continue;
1239 
1240  if (shared->page_status[slotno] == SLRU_PAGE_VALID)
1241  {
1242  if (this_delta > best_valid_delta ||
1243  (this_delta == best_valid_delta &&
1244  ctl->PagePrecedes(this_page_number,
1245  best_valid_page_number)))
1246  {
1247  bestvalidslot = slotno;
1248  best_valid_delta = this_delta;
1249  best_valid_page_number = this_page_number;
1250  }
1251  }
1252  else
1253  {
1254  if (this_delta > best_invalid_delta ||
1255  (this_delta == best_invalid_delta &&
1256  ctl->PagePrecedes(this_page_number,
1257  best_invalid_page_number)))
1258  {
1259  bestinvalidslot = slotno;
1260  best_invalid_delta = this_delta;
1261  best_invalid_page_number = this_page_number;
1262  }
1263  }
1264  }
1265 
1266  /*
1267  * If all pages (except possibly the latest one) are I/O busy, we'll
1268  * have to wait for an I/O to complete and then retry. In that
1269  * unhappy case, we choose to wait for the I/O on the least recently
1270  * used slot, on the assumption that it was likely initiated first of
1271  * all the I/Os in progress and may therefore finish first.
1272  */
1273  if (best_valid_delta < 0)
1274  {
1275  SimpleLruWaitIO(ctl, bestinvalidslot);
1276  continue;
1277  }
1278 
1279  /*
1280  * If the selected page is clean, we're set.
1281  */
1282  if (!shared->page_dirty[bestvalidslot])
1283  return bestvalidslot;
1284 
1285  /*
1286  * Write the page.
1287  */
1288  SlruInternalWritePage(ctl, bestvalidslot, NULL);
1289 
1290  /*
1291  * Now loop back and try again. This is the easiest way of dealing
1292  * with corner cases such as the victim page being re-dirtied while we
1293  * wrote it.
1294  */
1295  }
1296 }
bool LWLockHeldByMe(LWLock *lock)
Definition: lwlock.c:1895

References Assert, SlruSharedData::bank_cur_lru_count, ctl, SlruSharedData::latest_page_number, LWLockHeldByMe(), SlruSharedData::num_slots, SlruSharedData::page_dirty, SlruSharedData::page_lru_count, SlruSharedData::page_number, SlruSharedData::page_status, pg_atomic_read_u64(), SimpleLruGetBankLock(), SimpleLruWaitIO(), SLRU_BANK_SIZE, SLRU_PAGE_EMPTY, SLRU_PAGE_VALID, and SlruInternalWritePage().

Referenced by SimpleLruReadPage(), and SimpleLruZeroPage().

◆ SlruSyncFileTag()

int SlruSyncFileTag ( SlruCtl  ctl,
const FileTag ftag,
char *  path 
)

Definition at line 1814 of file slru.c.

1815 {
1816  int fd;
1817  int save_errno;
1818  int result;
1819 
1820  SlruFileName(ctl, path, ftag->segno);
1821 
1822  fd = OpenTransientFile(path, O_RDWR | PG_BINARY);
1823  if (fd < 0)
1824  return -1;
1825 
1826  pgstat_report_wait_start(WAIT_EVENT_SLRU_FLUSH_SYNC);
1827  result = pg_fsync(fd);
1829  save_errno = errno;
1830 
1832 
1833  errno = save_errno;
1834  return result;
1835 }
uint64 segno
Definition: sync.h:55

References CloseTransientFile(), ctl, fd(), OpenTransientFile(), PG_BINARY, pg_fsync(), pgstat_report_wait_end(), pgstat_report_wait_start(), FileTag::segno, and SlruFileName().

Referenced by clogsyncfiletag(), committssyncfiletag(), multixactmemberssyncfiletag(), multixactoffsetssyncfiletag(), and test_slru_page_sync().

Variable Documentation

◆ slru_errcause

◆ slru_errno