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 340 of file slru.c.

341 {
342  /* Valid values are multiples of SLRU_BANK_SIZE */
343  if (*newval % SLRU_BANK_SIZE == 0)
344  return true;
345 
346  GUC_check_errdetail("\"%s\" must be a multiple of %d", name,
348  return false;
349 }
#define newval
#define GUC_check_errdetail
Definition: guc.h:447
#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 728 of file slru.c.

729 {
730  int64 segno = pageno / SLRU_PAGES_PER_SEGMENT;
731  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
732  int offset = rpageno * BLCKSZ;
733  char path[MAXPGPATH];
734  int fd;
735  bool result;
736  off_t endpos;
737 
738  /* update the stats counter of checked pages */
739  pgstat_count_slru_page_exists(ctl->shared->slru_stats_idx);
740 
741  SlruFileName(ctl, path, segno);
742 
743  fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
744  if (fd < 0)
745  {
746  /* expected: file doesn't exist */
747  if (errno == ENOENT)
748  return false;
749 
750  /* report error normally */
752  slru_errno = errno;
753  SlruReportIOError(ctl, pageno, 0);
754  }
755 
756  if ((endpos = lseek(fd, 0, SEEK_END)) < 0)
757  {
759  slru_errno = errno;
760  SlruReportIOError(ctl, pageno, 0);
761  }
762 
763  result = endpos >= (off_t) (offset + BLCKSZ);
764 
765  if (CloseTransientFile(fd) != 0)
766  {
768  slru_errno = errno;
769  return false;
770  }
771 
772  return result;
773 }
#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:1853
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:1030
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 237 of file slru.c.

240 {
241  SlruShared shared;
242  bool found;
243  int nbanks = nslots / SLRU_BANK_SIZE;
244 
245  Assert(nslots <= SLRU_MAX_ALLOWED_BUFFERS);
246 
247  shared = (SlruShared) ShmemInitStruct(name,
248  SimpleLruShmemSize(nslots, nlsns),
249  &found);
250 
251  if (!IsUnderPostmaster)
252  {
253  /* Initialize locks and shared memory area */
254  char *ptr;
255  Size offset;
256 
257  Assert(!found);
258 
259  memset(shared, 0, sizeof(SlruSharedData));
260 
261  shared->num_slots = nslots;
262  shared->lsn_groups_per_page = nlsns;
263 
265 
267 
268  ptr = (char *) shared;
269  offset = MAXALIGN(sizeof(SlruSharedData));
270  shared->page_buffer = (char **) (ptr + offset);
271  offset += MAXALIGN(nslots * sizeof(char *));
272  shared->page_status = (SlruPageStatus *) (ptr + offset);
273  offset += MAXALIGN(nslots * sizeof(SlruPageStatus));
274  shared->page_dirty = (bool *) (ptr + offset);
275  offset += MAXALIGN(nslots * sizeof(bool));
276  shared->page_number = (int64 *) (ptr + offset);
277  offset += MAXALIGN(nslots * sizeof(int64));
278  shared->page_lru_count = (int *) (ptr + offset);
279  offset += MAXALIGN(nslots * sizeof(int));
280 
281  /* Initialize LWLocks */
282  shared->buffer_locks = (LWLockPadded *) (ptr + offset);
283  offset += MAXALIGN(nslots * sizeof(LWLockPadded));
284  shared->bank_locks = (LWLockPadded *) (ptr + offset);
285  offset += MAXALIGN(nbanks * sizeof(LWLockPadded));
286  shared->bank_cur_lru_count = (int *) (ptr + offset);
287  offset += MAXALIGN(nbanks * sizeof(int));
288 
289  if (nlsns > 0)
290  {
291  shared->group_lsn = (XLogRecPtr *) (ptr + offset);
292  offset += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr));
293  }
294 
295  ptr += BUFFERALIGN(offset);
296  for (int slotno = 0; slotno < nslots; slotno++)
297  {
298  LWLockInitialize(&shared->buffer_locks[slotno].lock,
299  buffer_tranche_id);
300 
301  shared->page_buffer[slotno] = ptr;
302  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
303  shared->page_dirty[slotno] = false;
304  shared->page_lru_count[slotno] = 0;
305  ptr += BLCKSZ;
306  }
307 
308  /* Initialize the slot banks. */
309  for (int bankno = 0; bankno < nbanks; bankno++)
310  {
311  LWLockInitialize(&shared->bank_locks[bankno].lock, bank_tranche_id);
312  shared->bank_cur_lru_count[bankno] = 0;
313  }
314 
315  /* Should fit to estimated shmem size */
316  Assert(ptr - (char *) shared <= SimpleLruShmemSize(nslots, nlsns));
317  }
318  else
319  {
320  Assert(found);
321  Assert(shared->num_slots == nslots);
322  }
323 
324  /*
325  * Initialize the unshared control struct, including directory path. We
326  * assume caller set PagePrecedes.
327  */
328  ctl->shared = shared;
329  ctl->sync_handler = sync_handler;
330  ctl->long_segment_names = long_segment_names;
331  ctl->bank_mask = (nslots / SLRU_BANK_SIZE) - 1;
332  strlcpy(ctl->Dir, subdir, sizeof(ctl->Dir));
333 }
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 487 of file slru.c.

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

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

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 1390 of file slru.c.

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

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 430 of file slru.c.

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

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

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

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 413 of file slru.c.

414 {
415  SlruShared shared = ctl->shared;
416 
417  if (shared->lsn_groups_per_page > 0)
418  MemSet(&shared->group_lsn[slotno * shared->lsn_groups_per_page], 0,
419  shared->lsn_groups_per_page * sizeof(XLogRecPtr));
420 }
#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 360 of file slru.c.

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

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

References ctl, and len.

Referenced by SlruScanDirectory().

◆ SlruDeleteSegment()

void SlruDeleteSegment ( SlruCtl  ctl,
int64  segno 
)

Definition at line 1508 of file slru.c.

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

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 1485 of file slru.c.

1486 {
1487  char path[MAXPGPATH];
1488 
1489  /* Forget any fsync requests queued for this segment. */
1490  if (ctl->sync_handler != SYNC_HANDLER_NONE)
1491  {
1492  FileTag tag;
1493 
1494  INIT_SLRUFILETAG(tag, ctl->sync_handler, segno);
1496  }
1497 
1498  /* Unlink the file. */
1499  SlruFileName(ctl, path, segno);
1500  ereport(DEBUG2, (errmsg_internal("removing file \"%s\"", path)));
1501  unlink(path);
1502 }
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1157
#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 637 of file slru.c.

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

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

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 786 of file slru.c.

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

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

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

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 1030 of file slru.c.

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

1727 {
1729 
1730  return false; /* keep going */
1731 }

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 1710 of file slru.c.

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

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 1694 of file slru.c.

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

References ctl, data, and SlruMayDeleteSegment().

Referenced by TruncateCLOG(), and TruncateCommitTs().

◆ SlruScanDirectory()

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

Definition at line 1773 of file slru.c.

1774 {
1775  bool retval = false;
1776  DIR *cldir;
1777  struct dirent *clde;
1778  int64 segno;
1779  int64 segpage;
1780 
1781  cldir = AllocateDir(ctl->Dir);
1782  while ((clde = ReadDir(cldir, ctl->Dir)) != NULL)
1783  {
1784  size_t len;
1785 
1786  len = strlen(clde->d_name);
1787 
1789  strspn(clde->d_name, "0123456789ABCDEF") == len)
1790  {
1791  segno = strtoi64(clde->d_name, NULL, 16);
1792  segpage = segno * SLRU_PAGES_PER_SEGMENT;
1793 
1794  elog(DEBUG2, "SlruScanDirectory invoking callback on %s/%s",
1795  ctl->Dir, clde->d_name);
1796  retval = callback(ctl, clde->d_name, segpage, data);
1797  if (retval)
1798  break;
1799  }
1800  }
1801  FreeDir(cldir);
1802 
1803  return retval;
1804 }
#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:1740
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 1151 of file slru.c.

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

1814 {
1815  int fd;
1816  int save_errno;
1817  int result;
1818 
1819  SlruFileName(ctl, path, ftag->segno);
1820 
1821  fd = OpenTransientFile(path, O_RDWR | PG_BINARY);
1822  if (fd < 0)
1823  return -1;
1824 
1825  pgstat_report_wait_start(WAIT_EVENT_SLRU_FLUSH_SYNC);
1826  result = pg_fsync(fd);
1828  save_errno = errno;
1829 
1831 
1832  errno = save_errno;
1833  return result;
1834 }
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