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 "miscadmin.h"
#include "pgstat.h"
#include "storage/fd.h"
#include "storage/shmem.h"
Include dependency graph for slru.c:

Go to the source code of this file.

Data Structures

struct  SlruFlushData
 

Macros

#define SlruFileName(ctl, path, seg)   snprintf(path, MAXPGPATH, "%s/%04X", (ctl)->Dir, seg)
 
#define MAX_FLUSH_BUFFERS   16
 
#define SlruRecentlyUsed(shared, slotno)
 

Typedefs

typedef struct SlruFlushData SlruFlushData
 
typedef struct SlruFlushDataSlruFlush
 

Enumerations

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

Functions

static void SimpleLruZeroLSNs (SlruCtl ctl, int slotno)
 
static void SimpleLruWaitIO (SlruCtl ctl, int slotno)
 
static void SlruInternalWritePage (SlruCtl ctl, int slotno, SlruFlush fdata)
 
static bool SlruPhysicalReadPage (SlruCtl ctl, int pageno, int slotno)
 
static bool SlruPhysicalWritePage (SlruCtl ctl, int pageno, int slotno, SlruFlush fdata)
 
static void SlruReportIOError (SlruCtl ctl, int pageno, TransactionId xid)
 
static int SlruSelectLRUPage (SlruCtl ctl, int pageno)
 
static bool SlruScanDirCbDeleteCutoff (SlruCtl ctl, char *filename, int segpage, void *data)
 
static void SlruInternalDeleteSegment (SlruCtl ctl, char *filename)
 
Size SimpleLruShmemSize (int nslots, int nlsns)
 
void SimpleLruInit (SlruCtl ctl, const char *name, int nslots, int nlsns, LWLock *ctllock, const char *subdir, int tranche_id)
 
int SimpleLruZeroPage (SlruCtl ctl, int pageno)
 
int SimpleLruReadPage (SlruCtl ctl, int pageno, bool write_ok, TransactionId xid)
 
int SimpleLruReadPage_ReadOnly (SlruCtl ctl, int pageno, TransactionId xid)
 
void SimpleLruWritePage (SlruCtl ctl, int slotno)
 
bool SimpleLruDoesPhysicalPageExist (SlruCtl ctl, int pageno)
 
void SimpleLruFlush (SlruCtl ctl, bool allow_redirtied)
 
void SimpleLruTruncate (SlruCtl ctl, int cutoffPage)
 
void SlruDeleteSegment (SlruCtl ctl, int segno)
 
bool SlruScanDirCbReportPresence (SlruCtl ctl, char *filename, int segpage, void *data)
 
bool SlruScanDirCbDeleteAll (SlruCtl ctl, char *filename, int segpage, void *data)
 
bool SlruScanDirectory (SlruCtl ctl, SlruScanCallback callback, void *data)
 

Variables

static SlruErrorCause slru_errcause
 
static int slru_errno
 

Macro Definition Documentation

◆ MAX_FLUSH_BUFFERS

#define MAX_FLUSH_BUFFERS   16

Definition at line 72 of file slru.c.

Referenced by SlruPhysicalWritePage().

◆ SlruFileName

#define SlruFileName (   ctl,
  path,
  seg 
)    snprintf(path, MAXPGPATH, "%s/%04X", (ctl)->Dir, seg)

◆ SlruRecentlyUsed

#define SlruRecentlyUsed (   shared,
  slotno 
)
Value:
do { \
int new_lru_count = (shared)->cur_lru_count; \
if (new_lru_count != (shared)->page_lru_count[slotno]) { \
(shared)->cur_lru_count = ++new_lru_count; \
(shared)->page_lru_count[slotno] = new_lru_count; \
} \
} while (0)

Definition at line 102 of file slru.c.

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

Typedef Documentation

◆ SlruFlush

typedef struct SlruFlushData* SlruFlush

Definition at line 81 of file slru.c.

◆ SlruFlushData

typedef struct SlruFlushData SlruFlushData

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

Function Documentation

◆ SimpleLruDoesPhysicalPageExist()

bool SimpleLruDoesPhysicalPageExist ( SlruCtl  ctl,
int  pageno 
)

Definition at line 609 of file slru.c.

References CloseTransientFile(), endpos, SlruFlushData::fd, MAXPGPATH, OpenTransientFile(), PG_BINARY, pgstat_count_slru_page_exists(), SlruFlushData::segno, SlruCtlData::shared, SLRU_CLOSE_FAILED, slru_errcause, slru_errno, SLRU_OPEN_FAILED, SLRU_PAGES_PER_SEGMENT, SLRU_SEEK_FAILED, SlruSharedData::slru_stats_idx, SlruFileName, and SlruReportIOError().

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

610 {
611  int segno = pageno / SLRU_PAGES_PER_SEGMENT;
612  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
613  int offset = rpageno * BLCKSZ;
614  char path[MAXPGPATH];
615  int fd;
616  bool result;
617  off_t endpos;
618 
619  /* update the stats counter of checked pages */
621 
622  SlruFileName(ctl, path, segno);
623 
624  fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
625  if (fd < 0)
626  {
627  /* expected: file doesn't exist */
628  if (errno == ENOENT)
629  return false;
630 
631  /* report error normally */
633  slru_errno = errno;
634  SlruReportIOError(ctl, pageno, 0);
635  }
636 
637  if ((endpos = lseek(fd, 0, SEEK_END)) < 0)
638  {
640  slru_errno = errno;
641  SlruReportIOError(ctl, pageno, 0);
642  }
643 
644  result = endpos >= (off_t) (offset + BLCKSZ);
645 
646  if (CloseTransientFile(fd) != 0)
647  {
649  slru_errno = errno;
650  return false;
651  }
652 
653  return result;
654 }
static SlruErrorCause slru_errcause
Definition: slru.c:122
static int fd(const char *x, int i)
Definition: preproc-init.c:105
static void SlruReportIOError(SlruCtl ctl, int pageno, TransactionId xid)
Definition: slru.c:923
#define PG_BINARY
Definition: c.h:1234
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2370
#define MAXPGPATH
static XLogRecPtr endpos
Definition: pg_receivewal.c:46
int CloseTransientFile(int fd)
Definition: fd.c:2547
void pgstat_count_slru_page_exists(int slru_idx)
Definition: pgstat.c:6755
#define SlruFileName(ctl, path, seg)
Definition: slru.c:62
int slru_stats_idx
Definition: slru.h:100
static int slru_errno
Definition: slru.c:123
SlruShared shared
Definition: slru.h:111
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:33

◆ SimpleLruFlush()

void SimpleLruFlush ( SlruCtl  ctl,
bool  allow_redirtied 
)

Definition at line 1145 of file slru.c.

References Assert, CloseTransientFile(), SlruSharedData::ControlLock, SlruCtlData::do_fsync, SlruFlushData::fd, i, InvalidTransactionId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SlruFlushData::num_files, SlruSharedData::num_slots, SlruSharedData::page_dirty, SlruSharedData::page_status, pg_fsync(), pgstat_count_slru_flush(), pgstat_report_wait_end(), pgstat_report_wait_start(), SlruFlushData::segno, SlruCtlData::shared, SLRU_CLOSE_FAILED, slru_errcause, slru_errno, SLRU_FSYNC_FAILED, SLRU_PAGE_EMPTY, SLRU_PAGE_VALID, SLRU_PAGES_PER_SEGMENT, SlruSharedData::slru_stats_idx, SlruInternalWritePage(), SlruReportIOError(), and WAIT_EVENT_SLRU_FLUSH_SYNC.

Referenced by CheckPointCLOG(), CheckPointCommitTs(), CheckPointMultiXact(), CheckPointPredicate(), CheckPointSUBTRANS(), find_multixact_start(), ShutdownCLOG(), ShutdownCommitTs(), ShutdownMultiXact(), and ShutdownSUBTRANS().

1146 {
1147  SlruShared shared = ctl->shared;
1148  SlruFlushData fdata;
1149  int slotno;
1150  int pageno = 0;
1151  int i;
1152  bool ok;
1153 
1154  /* update the stats counter of flushes */
1156 
1157  /*
1158  * Find and write dirty pages
1159  */
1160  fdata.num_files = 0;
1161 
1163 
1164  for (slotno = 0; slotno < shared->num_slots; slotno++)
1165  {
1166  SlruInternalWritePage(ctl, slotno, &fdata);
1167 
1168  /*
1169  * In some places (e.g. checkpoints), we cannot assert that the slot
1170  * is clean now, since another process might have re-dirtied it
1171  * already. That's okay.
1172  */
1173  Assert(allow_redirtied ||
1174  shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
1175  (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1176  !shared->page_dirty[slotno]));
1177  }
1178 
1179  LWLockRelease(shared->ControlLock);
1180 
1181  /*
1182  * Now fsync and close any files that were open
1183  */
1184  ok = true;
1185  for (i = 0; i < fdata.num_files; i++)
1186  {
1188  if (ctl->do_fsync && pg_fsync(fdata.fd[i]) != 0)
1189  {
1191  slru_errno = errno;
1192  pageno = fdata.segno[i] * SLRU_PAGES_PER_SEGMENT;
1193  ok = false;
1194  }
1196 
1197  if (CloseTransientFile(fdata.fd[i]) != 0)
1198  {
1200  slru_errno = errno;
1201  pageno = fdata.segno[i] * SLRU_PAGES_PER_SEGMENT;
1202  ok = false;
1203  }
1204  }
1205  if (!ok)
1207 }
LWLock * ControlLock
Definition: slru.h:54
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruFlush fdata)
Definition: slru.c:526
static SlruErrorCause slru_errcause
Definition: slru.c:122
int segno[MAX_FLUSH_BUFFERS]
Definition: slru.c:78
void pgstat_count_slru_flush(int slru_idx)
Definition: pgstat.c:6773
static void SlruReportIOError(SlruCtl ctl, int pageno, TransactionId xid)
Definition: slru.c:923
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
SlruPageStatus * page_status
Definition: slru.h:64
#define InvalidTransactionId
Definition: transam.h:31
static void pgstat_report_wait_end(void)
Definition: pgstat.h:1380
bool do_fsync
Definition: slru.h:117
int CloseTransientFile(int fd)
Definition: fd.c:2547
int num_files
Definition: slru.c:76
#define Assert(condition)
Definition: c.h:738
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: pgstat.h:1356
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
int slru_stats_idx
Definition: slru.h:100
int num_slots
Definition: slru.h:57
static int slru_errno
Definition: slru.c:123
bool * page_dirty
Definition: slru.h:65
int i
SlruShared shared
Definition: slru.h:111
int pg_fsync(int fd)
Definition: fd.c:343
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:33
int fd[MAX_FLUSH_BUFFERS]
Definition: slru.c:77

◆ SimpleLruInit()

void SimpleLruInit ( SlruCtl  ctl,
const char *  name,
int  nslots,
int  nlsns,
LWLock ctllock,
const char *  subdir,
int  tranche_id 
)

Definition at line 175 of file slru.c.

References Assert, SlruSharedData::buffer_locks, BUFFERALIGN, SlruSharedData::ControlLock, SlruSharedData::cur_lru_count, SlruCtlData::Dir, SlruCtlData::do_fsync, SlruSharedData::group_lsn, IsUnderPostmaster, LWLockPadded::lock, SlruSharedData::lsn_groups_per_page, LWLockInitialize(), MAXALIGN, SlruSharedData::num_slots, SlruSharedData::page_buffer, SlruSharedData::page_dirty, SlruSharedData::page_lru_count, SlruSharedData::page_number, SlruSharedData::page_status, pgstat_slru_index(), SlruCtlData::shared, ShmemInitStruct(), SimpleLruShmemSize(), SLRU_PAGE_EMPTY, SlruSharedData::slru_stats_idx, and StrNCpy.

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

177 {
178  SlruShared shared;
179  bool found;
180 
181  shared = (SlruShared) ShmemInitStruct(name,
182  SimpleLruShmemSize(nslots, nlsns),
183  &found);
184 
185  if (!IsUnderPostmaster)
186  {
187  /* Initialize locks and shared memory area */
188  char *ptr;
189  Size offset;
190  int slotno;
191 
192  Assert(!found);
193 
194  memset(shared, 0, sizeof(SlruSharedData));
195 
196  shared->ControlLock = ctllock;
197 
198  shared->num_slots = nslots;
199  shared->lsn_groups_per_page = nlsns;
200 
201  shared->cur_lru_count = 0;
202 
203  /* shared->latest_page_number will be set later */
204 
206 
207  ptr = (char *) shared;
208  offset = MAXALIGN(sizeof(SlruSharedData));
209  shared->page_buffer = (char **) (ptr + offset);
210  offset += MAXALIGN(nslots * sizeof(char *));
211  shared->page_status = (SlruPageStatus *) (ptr + offset);
212  offset += MAXALIGN(nslots * sizeof(SlruPageStatus));
213  shared->page_dirty = (bool *) (ptr + offset);
214  offset += MAXALIGN(nslots * sizeof(bool));
215  shared->page_number = (int *) (ptr + offset);
216  offset += MAXALIGN(nslots * sizeof(int));
217  shared->page_lru_count = (int *) (ptr + offset);
218  offset += MAXALIGN(nslots * sizeof(int));
219 
220  /* Initialize LWLocks */
221  shared->buffer_locks = (LWLockPadded *) (ptr + offset);
222  offset += MAXALIGN(nslots * sizeof(LWLockPadded));
223 
224  if (nlsns > 0)
225  {
226  shared->group_lsn = (XLogRecPtr *) (ptr + offset);
227  offset += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr));
228  }
229 
230  ptr += BUFFERALIGN(offset);
231  for (slotno = 0; slotno < nslots; slotno++)
232  {
233  LWLockInitialize(&shared->buffer_locks[slotno].lock,
234  tranche_id);
235 
236  shared->page_buffer[slotno] = ptr;
237  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
238  shared->page_dirty[slotno] = false;
239  shared->page_lru_count[slotno] = 0;
240  ptr += BLCKSZ;
241  }
242 
243  /* Should fit to estimated shmem size */
244  Assert(ptr - (char *) shared <= SimpleLruShmemSize(nslots, nlsns));
245  }
246  else
247  Assert(found);
248 
249  /*
250  * Initialize the unshared control struct, including directory path. We
251  * assume caller set PagePrecedes.
252  */
253  ctl->shared = shared;
254  ctl->do_fsync = true; /* default behavior */
255  StrNCpy(ctl->Dir, subdir, sizeof(ctl->Dir));
256 }
LWLock * ControlLock
Definition: slru.h:54
int * page_number
Definition: slru.h:66
SlruPageStatus
Definition: slru.h:41
char ** page_buffer
Definition: slru.h:63
int cur_lru_count
Definition: slru.h:90
int lsn_groups_per_page
Definition: slru.h:79
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:144
int pgstat_slru_index(const char *name)
Definition: pgstat.c:6688
SlruPageStatus * page_status
Definition: slru.h:64
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:392
bool IsUnderPostmaster
Definition: globals.c:109
LWLockPadded * buffer_locks
Definition: slru.h:68
XLogRecPtr * group_lsn
Definition: slru.h:78
bool do_fsync
Definition: slru.h:117
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition: lwlock.c:745
SlruSharedData * SlruShared
Definition: slru.h:103
char Dir[64]
Definition: slru.h:130
LWLock lock
Definition: lwlock.h:79
int * page_lru_count
Definition: slru.h:67
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:738
#define StrNCpy(dst, src, len)
Definition: c.h:944
size_t Size
Definition: c.h:466
#define MAXALIGN(LEN)
Definition: c.h:691
int slru_stats_idx
Definition: slru.h:100
int num_slots
Definition: slru.h:57
const char * name
Definition: encode.c:555
bool * page_dirty
Definition: slru.h:65
SlruShared shared
Definition: slru.h:111
#define BUFFERALIGN(LEN)
Definition: c.h:693

◆ SimpleLruReadPage()

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

Definition at line 382 of file slru.c.

References Assert, SlruSharedData::buffer_locks, SlruSharedData::ControlLock, LWLockPadded::lock, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SlruSharedData::page_dirty, SlruSharedData::page_number, SlruSharedData::page_status, pgstat_count_slru_page_hit(), pgstat_count_slru_page_read(), SlruCtlData::shared, 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(), TransactionIdSetPageStatusInternal(), TrimCLOG(), and TrimMultiXact().

384 {
385  SlruShared shared = ctl->shared;
386 
387  /* Outer loop handles restart if we must wait for someone else's I/O */
388  for (;;)
389  {
390  int slotno;
391  bool ok;
392 
393  /* See if page already is in memory; if not, pick victim slot */
394  slotno = SlruSelectLRUPage(ctl, pageno);
395 
396  /* Did we find the page in memory? */
397  if (shared->page_number[slotno] == pageno &&
398  shared->page_status[slotno] != SLRU_PAGE_EMPTY)
399  {
400  /*
401  * If page is still being read in, we must wait for I/O. Likewise
402  * if the page is being written and the caller said that's not OK.
403  */
404  if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS ||
405  (shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS &&
406  !write_ok))
407  {
408  SimpleLruWaitIO(ctl, slotno);
409  /* Now we must recheck state from the top */
410  continue;
411  }
412  /* Otherwise, it's ready to use */
413  SlruRecentlyUsed(shared, slotno);
414 
415  /* update the stats counter of pages found in the SLRU */
417 
418  return slotno;
419  }
420 
421  /* We found no match; assert we selected a freeable slot */
422  Assert(shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
423  (shared->page_status[slotno] == SLRU_PAGE_VALID &&
424  !shared->page_dirty[slotno]));
425 
426  /* Mark the slot read-busy */
427  shared->page_number[slotno] = pageno;
428  shared->page_status[slotno] = SLRU_PAGE_READ_IN_PROGRESS;
429  shared->page_dirty[slotno] = false;
430 
431  /* Acquire per-buffer lock (cannot deadlock, see notes at top) */
432  LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_EXCLUSIVE);
433 
434  /* Release control lock while doing I/O */
435  LWLockRelease(shared->ControlLock);
436 
437  /* Do the read */
438  ok = SlruPhysicalReadPage(ctl, pageno, slotno);
439 
440  /* Set the LSNs for this newly read-in page to zero */
441  SimpleLruZeroLSNs(ctl, slotno);
442 
443  /* Re-acquire control lock and update page state */
445 
446  Assert(shared->page_number[slotno] == pageno &&
447  shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS &&
448  !shared->page_dirty[slotno]);
449 
450  shared->page_status[slotno] = ok ? SLRU_PAGE_VALID : SLRU_PAGE_EMPTY;
451 
452  LWLockRelease(&shared->buffer_locks[slotno].lock);
453 
454  /* Now it's okay to ereport if we failed */
455  if (!ok)
456  SlruReportIOError(ctl, pageno, xid);
457 
458  SlruRecentlyUsed(shared, slotno);
459 
460  /* update the stats counter of pages not found in SLRU */
462 
463  return slotno;
464  }
465 }
LWLock * ControlLock
Definition: slru.h:54
int * page_number
Definition: slru.h:66
static void SimpleLruZeroLSNs(SlruCtl ctl, int slotno)
Definition: slru.c:311
static void SlruReportIOError(SlruCtl ctl, int pageno, TransactionId xid)
Definition: slru.c:923
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
SlruPageStatus * page_status
Definition: slru.h:64
LWLockPadded * buffer_locks
Definition: slru.h:68
void pgstat_count_slru_page_read(int slru_idx)
Definition: pgstat.c:6761
static void SimpleLruWaitIO(SlruCtl ctl, int slotno)
Definition: slru.c:328
LWLock lock
Definition: lwlock.h:79
static bool SlruPhysicalReadPage(SlruCtl ctl, int pageno, int slotno)
Definition: slru.c:667
#define Assert(condition)
Definition: c.h:738
void pgstat_count_slru_page_hit(int slru_idx)
Definition: pgstat.c:6749
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
int slru_stats_idx
Definition: slru.h:100
static int SlruSelectLRUPage(SlruCtl ctl, int pageno)
Definition: slru.c:1008
bool * page_dirty
Definition: slru.h:65
SlruShared shared
Definition: slru.h:111
#define SlruRecentlyUsed(shared, slotno)
Definition: slru.c:102

◆ SimpleLruReadPage_ReadOnly()

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

Definition at line 482 of file slru.c.

References SlruSharedData::ControlLock, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), SlruSharedData::num_slots, SlruSharedData::page_number, SlruSharedData::page_status, pgstat_count_slru_page_hit(), SlruCtlData::shared, SimpleLruReadPage(), SLRU_PAGE_EMPTY, SLRU_PAGE_READ_IN_PROGRESS, SlruSharedData::slru_stats_idx, and SlruRecentlyUsed.

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

483 {
484  SlruShared shared = ctl->shared;
485  int slotno;
486 
487  /* Try to find the page while holding only shared lock */
489 
490  /* See if page is already in a buffer */
491  for (slotno = 0; slotno < shared->num_slots; slotno++)
492  {
493  if (shared->page_number[slotno] == pageno &&
494  shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
495  shared->page_status[slotno] != SLRU_PAGE_READ_IN_PROGRESS)
496  {
497  /* See comments for SlruRecentlyUsed macro */
498  SlruRecentlyUsed(shared, slotno);
499 
500  /* update the stats counter of pages found in the SLRU */
502 
503  return slotno;
504  }
505  }
506 
507  /* No luck, so switch to normal exclusive lock and do regular read */
508  LWLockRelease(shared->ControlLock);
510 
511  return SimpleLruReadPage(ctl, pageno, true, xid);
512 }
LWLock * ControlLock
Definition: slru.h:54
int * page_number
Definition: slru.h:66
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
SlruPageStatus * page_status
Definition: slru.h:64
int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok, TransactionId xid)
Definition: slru.c:382
void pgstat_count_slru_page_hit(int slru_idx)
Definition: pgstat.c:6749
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
int slru_stats_idx
Definition: slru.h:100
int num_slots
Definition: slru.h:57
SlruShared shared
Definition: slru.h:111
#define SlruRecentlyUsed(shared, slotno)
Definition: slru.c:102

◆ SimpleLruShmemSize()

Size SimpleLruShmemSize ( int  nslots,
int  nlsns 
)

Definition at line 144 of file slru.c.

References BUFFERALIGN, and MAXALIGN.

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

145 {
146  Size sz;
147 
148  /* we assume nslots isn't so large as to risk overflow */
149  sz = MAXALIGN(sizeof(SlruSharedData));
150  sz += MAXALIGN(nslots * sizeof(char *)); /* page_buffer[] */
151  sz += MAXALIGN(nslots * sizeof(SlruPageStatus)); /* page_status[] */
152  sz += MAXALIGN(nslots * sizeof(bool)); /* page_dirty[] */
153  sz += MAXALIGN(nslots * sizeof(int)); /* page_number[] */
154  sz += MAXALIGN(nslots * sizeof(int)); /* page_lru_count[] */
155  sz += MAXALIGN(nslots * sizeof(LWLockPadded)); /* buffer_locks[] */
156 
157  if (nlsns > 0)
158  sz += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr)); /* group_lsn[] */
159 
160  return BUFFERALIGN(sz) + BLCKSZ * nslots;
161 }
SlruPageStatus
Definition: slru.h:41
uint64 XLogRecPtr
Definition: xlogdefs.h:21
size_t Size
Definition: c.h:466
#define MAXALIGN(LEN)
Definition: c.h:691
#define BUFFERALIGN(LEN)
Definition: c.h:693

◆ SimpleLruTruncate()

void SimpleLruTruncate ( SlruCtl  ctl,
int  cutoffPage 
)

Definition at line 1213 of file slru.c.

References SlruSharedData::ControlLock, SlruCtlData::Dir, ereport, errmsg(), SlruSharedData::latest_page_number, LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SlruSharedData::num_slots, SlruSharedData::page_dirty, SlruSharedData::page_number, SlruSharedData::page_status, SlruCtlData::PagePrecedes, pgstat_count_slru_truncate(), SlruCtlData::shared, SimpleLruWaitIO(), SLRU_PAGE_EMPTY, SLRU_PAGE_VALID, SLRU_PAGES_PER_SEGMENT, SlruSharedData::slru_stats_idx, SlruInternalWritePage(), SlruScanDirCbDeleteCutoff(), and SlruScanDirectory().

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

1214 {
1215  SlruShared shared = ctl->shared;
1216  int slotno;
1217 
1218  /* update the stats counter of truncates */
1220 
1221  /*
1222  * The cutoff point is the start of the segment containing cutoffPage.
1223  */
1224  cutoffPage -= cutoffPage % SLRU_PAGES_PER_SEGMENT;
1225 
1226  /*
1227  * Scan shared memory and remove any pages preceding the cutoff page, to
1228  * ensure we won't rewrite them later. (Since this is normally called in
1229  * or just after a checkpoint, any dirty pages should have been flushed
1230  * already ... we're just being extra careful here.)
1231  */
1233 
1234 restart:;
1235 
1236  /*
1237  * While we are holding the lock, make an important safety check: the
1238  * planned cutoff point must be <= the current endpoint page. Otherwise we
1239  * have already wrapped around, and proceeding with the truncation would
1240  * risk removing the current segment.
1241  */
1242  if (ctl->PagePrecedes(shared->latest_page_number, cutoffPage))
1243  {
1244  LWLockRelease(shared->ControlLock);
1245  ereport(LOG,
1246  (errmsg("could not truncate directory \"%s\": apparent wraparound",
1247  ctl->Dir)));
1248  return;
1249  }
1250 
1251  for (slotno = 0; slotno < shared->num_slots; slotno++)
1252  {
1253  if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
1254  continue;
1255  if (!ctl->PagePrecedes(shared->page_number[slotno], cutoffPage))
1256  continue;
1257 
1258  /*
1259  * If page is clean, just change state to EMPTY (expected case).
1260  */
1261  if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1262  !shared->page_dirty[slotno])
1263  {
1264  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
1265  continue;
1266  }
1267 
1268  /*
1269  * Hmm, we have (or may have) I/O operations acting on the page, so
1270  * we've got to wait for them to finish and then start again. This is
1271  * the same logic as in SlruSelectLRUPage. (XXX if page is dirty,
1272  * wouldn't it be OK to just discard it without writing it? For now,
1273  * keep the logic the same as it was.)
1274  */
1275  if (shared->page_status[slotno] == SLRU_PAGE_VALID)
1276  SlruInternalWritePage(ctl, slotno, NULL);
1277  else
1278  SimpleLruWaitIO(ctl, slotno);
1279  goto restart;
1280  }
1281 
1282  LWLockRelease(shared->ControlLock);
1283 
1284  /* Now we can remove the old segment(s) */
1285  (void) SlruScanDirectory(ctl, SlruScanDirCbDeleteCutoff, &cutoffPage);
1286 }
LWLock * ControlLock
Definition: slru.h:54
int * page_number
Definition: slru.h:66
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruFlush fdata)
Definition: slru.c:526
int latest_page_number
Definition: slru.h:97
#define LOG
Definition: elog.h:26
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
SlruPageStatus * page_status
Definition: slru.h:64
static void SimpleLruWaitIO(SlruCtl ctl, int slotno)
Definition: slru.c:328
static bool SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename, int segpage, void *data)
Definition: slru.c:1386
char Dir[64]
Definition: slru.h:130
void pgstat_count_slru_truncate(int slru_idx)
Definition: pgstat.c:6779
#define ereport(elevel,...)
Definition: elog.h:144
bool SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data)
Definition: slru.c:1424
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
int slru_stats_idx
Definition: slru.h:100
int num_slots
Definition: slru.h:57
int errmsg(const char *fmt,...)
Definition: elog.c:824
bool * page_dirty
Definition: slru.h:65
SlruShared shared
Definition: slru.h:111
bool(* PagePrecedes)(int, int)
Definition: slru.h:124
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:33

◆ SimpleLruWaitIO()

static void SimpleLruWaitIO ( SlruCtl  ctl,
int  slotno 
)
static

Definition at line 328 of file slru.c.

References SlruSharedData::buffer_locks, SlruSharedData::ControlLock, LWLockPadded::lock, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockConditionalAcquire(), LWLockRelease(), SlruSharedData::page_dirty, SlruSharedData::page_status, SlruCtlData::shared, 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().

329 {
330  SlruShared shared = ctl->shared;
331 
332  /* See notes at top of file */
333  LWLockRelease(shared->ControlLock);
334  LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_SHARED);
335  LWLockRelease(&shared->buffer_locks[slotno].lock);
337 
338  /*
339  * If the slot is still in an io-in-progress state, then either someone
340  * already started a new I/O on the slot, or a previous I/O failed and
341  * neglected to reset the page state. That shouldn't happen, really, but
342  * it seems worth a few extra cycles to check and recover from it. We can
343  * cheaply test for failure by seeing if the buffer lock is still held (we
344  * assume that transaction abort would release the lock).
345  */
346  if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS ||
347  shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS)
348  {
349  if (LWLockConditionalAcquire(&shared->buffer_locks[slotno].lock, LW_SHARED))
350  {
351  /* indeed, the I/O must have failed */
352  if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS)
353  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
354  else /* write_in_progress */
355  {
356  shared->page_status[slotno] = SLRU_PAGE_VALID;
357  shared->page_dirty[slotno] = true;
358  }
359  LWLockRelease(&shared->buffer_locks[slotno].lock);
360  }
361  }
362 }
LWLock * ControlLock
Definition: slru.h:54
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
SlruPageStatus * page_status
Definition: slru.h:64
bool LWLockConditionalAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1380
LWLockPadded * buffer_locks
Definition: slru.h:68
LWLock lock
Definition: lwlock.h:79
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
bool * page_dirty
Definition: slru.h:65
SlruShared shared
Definition: slru.h:111

◆ SimpleLruWritePage()

void SimpleLruWritePage ( SlruCtl  ctl,
int  slotno 
)

Definition at line 597 of file slru.c.

References SlruInternalWritePage().

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

598 {
599  SlruInternalWritePage(ctl, slotno, NULL);
600 }
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruFlush fdata)
Definition: slru.c:526

◆ SimpleLruZeroLSNs()

static void SimpleLruZeroLSNs ( SlruCtl  ctl,
int  slotno 
)
static

Definition at line 311 of file slru.c.

References SlruSharedData::group_lsn, SlruSharedData::lsn_groups_per_page, MemSet, and SlruCtlData::shared.

Referenced by SimpleLruReadPage(), and SimpleLruZeroPage().

312 {
313  SlruShared shared = ctl->shared;
314 
315  if (shared->lsn_groups_per_page > 0)
316  MemSet(&shared->group_lsn[slotno * shared->lsn_groups_per_page], 0,
317  shared->lsn_groups_per_page * sizeof(XLogRecPtr));
318 }
#define MemSet(start, val, len)
Definition: c.h:971
int lsn_groups_per_page
Definition: slru.h:79
XLogRecPtr * group_lsn
Definition: slru.h:78
uint64 XLogRecPtr
Definition: xlogdefs.h:21
SlruShared shared
Definition: slru.h:111

◆ SimpleLruZeroPage()

int SimpleLruZeroPage ( SlruCtl  ctl,
int  pageno 
)

Definition at line 267 of file slru.c.

References Assert, SlruSharedData::latest_page_number, MemSet, SlruSharedData::page_buffer, SlruSharedData::page_dirty, SlruSharedData::page_number, SlruSharedData::page_status, pgstat_count_slru_page_zeroed(), SlruCtlData::shared, SimpleLruZeroLSNs(), SLRU_PAGE_EMPTY, SLRU_PAGE_VALID, SlruSharedData::slru_stats_idx, SlruRecentlyUsed, and SlruSelectLRUPage().

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

268 {
269  SlruShared shared = ctl->shared;
270  int slotno;
271 
272  /* Find a suitable buffer slot for the page */
273  slotno = SlruSelectLRUPage(ctl, pageno);
274  Assert(shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
275  (shared->page_status[slotno] == SLRU_PAGE_VALID &&
276  !shared->page_dirty[slotno]) ||
277  shared->page_number[slotno] == pageno);
278 
279  /* Mark the slot as containing this page */
280  shared->page_number[slotno] = pageno;
281  shared->page_status[slotno] = SLRU_PAGE_VALID;
282  shared->page_dirty[slotno] = true;
283  SlruRecentlyUsed(shared, slotno);
284 
285  /* Set the buffer to zeroes */
286  MemSet(shared->page_buffer[slotno], 0, BLCKSZ);
287 
288  /* Set the LSNs for this new page to zero */
289  SimpleLruZeroLSNs(ctl, slotno);
290 
291  /* Assume this page is now the latest active page */
292  shared->latest_page_number = pageno;
293 
294  /* update the stats counter of zeroed pages */
296 
297  return slotno;
298 }
int * page_number
Definition: slru.h:66
int latest_page_number
Definition: slru.h:97
char ** page_buffer
Definition: slru.h:63
#define MemSet(start, val, len)
Definition: c.h:971
static void SimpleLruZeroLSNs(SlruCtl ctl, int slotno)
Definition: slru.c:311
SlruPageStatus * page_status
Definition: slru.h:64
void pgstat_count_slru_page_zeroed(int slru_idx)
Definition: pgstat.c:6743
#define Assert(condition)
Definition: c.h:738
int slru_stats_idx
Definition: slru.h:100
static int SlruSelectLRUPage(SlruCtl ctl, int pageno)
Definition: slru.c:1008
bool * page_dirty
Definition: slru.h:65
SlruShared shared
Definition: slru.h:111
#define SlruRecentlyUsed(shared, slotno)
Definition: slru.c:102

◆ SlruDeleteSegment()

void SlruDeleteSegment ( SlruCtl  ctl,
int  segno 
)

Definition at line 1309 of file slru.c.

References SlruSharedData::ControlLock, DEBUG2, SlruCtlData::Dir, ereport, errmsg(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MAXPGPATH, SlruSharedData::num_slots, SlruSharedData::page_dirty, SlruSharedData::page_number, SlruSharedData::page_status, SlruCtlData::shared, SimpleLruWaitIO(), SLRU_PAGE_EMPTY, SLRU_PAGE_VALID, SLRU_PAGES_PER_SEGMENT, SlruInternalWritePage(), and snprintf.

Referenced by PerformMembersTruncation().

1310 {
1311  SlruShared shared = ctl->shared;
1312  int slotno;
1313  char path[MAXPGPATH];
1314  bool did_write;
1315 
1316  /* Clean out any possibly existing references to the segment. */
1318 restart:
1319  did_write = false;
1320  for (slotno = 0; slotno < shared->num_slots; slotno++)
1321  {
1322  int pagesegno = shared->page_number[slotno] / SLRU_PAGES_PER_SEGMENT;
1323 
1324  if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
1325  continue;
1326 
1327  /* not the segment we're looking for */
1328  if (pagesegno != segno)
1329  continue;
1330 
1331  /* If page is clean, just change state to EMPTY (expected case). */
1332  if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1333  !shared->page_dirty[slotno])
1334  {
1335  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
1336  continue;
1337  }
1338 
1339  /* Same logic as SimpleLruTruncate() */
1340  if (shared->page_status[slotno] == SLRU_PAGE_VALID)
1341  SlruInternalWritePage(ctl, slotno, NULL);
1342  else
1343  SimpleLruWaitIO(ctl, slotno);
1344 
1345  did_write = true;
1346  }
1347 
1348  /*
1349  * Be extra careful and re-check. The IO functions release the control
1350  * lock, so new pages could have been read in.
1351  */
1352  if (did_write)
1353  goto restart;
1354 
1355  snprintf(path, MAXPGPATH, "%s/%04X", ctl->Dir, segno);
1356  ereport(DEBUG2,
1357  (errmsg("removing file \"%s\"", path)));
1358  unlink(path);
1359 
1360  LWLockRelease(shared->ControlLock);
1361 }
LWLock * ControlLock
Definition: slru.h:54
int * page_number
Definition: slru.h:66
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruFlush fdata)
Definition: slru.c:526
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
SlruPageStatus * page_status
Definition: slru.h:64
#define MAXPGPATH
#define DEBUG2
Definition: elog.h:24
static void SimpleLruWaitIO(SlruCtl ctl, int slotno)
Definition: slru.c:328
char Dir[64]
Definition: slru.h:130
#define ereport(elevel,...)
Definition: elog.h:144
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
int num_slots
Definition: slru.h:57
int errmsg(const char *fmt,...)
Definition: elog.c:824
bool * page_dirty
Definition: slru.h:65
SlruShared shared
Definition: slru.h:111
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:33
#define snprintf
Definition: port.h:193

◆ SlruInternalDeleteSegment()

static void SlruInternalDeleteSegment ( SlruCtl  ctl,
char *  filename 
)
static

Definition at line 1295 of file slru.c.

References DEBUG2, SlruCtlData::Dir, ereport, errmsg(), MAXPGPATH, and snprintf.

Referenced by SlruScanDirCbDeleteAll(), and SlruScanDirCbDeleteCutoff().

1296 {
1297  char path[MAXPGPATH];
1298 
1299  snprintf(path, MAXPGPATH, "%s/%s", ctl->Dir, filename);
1300  ereport(DEBUG2,
1301  (errmsg("removing file \"%s\"", path)));
1302  unlink(path);
1303 }
#define MAXPGPATH
#define DEBUG2
Definition: elog.h:24
char Dir[64]
Definition: slru.h:130
#define ereport(elevel,...)
Definition: elog.h:144
static char * filename
Definition: pg_dumpall.c:90
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define snprintf
Definition: port.h:193

◆ SlruInternalWritePage()

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

Definition at line 526 of file slru.c.

References Assert, SlruSharedData::buffer_locks, CloseTransientFile(), SlruSharedData::ControlLock, SlruFlushData::fd, i, InvalidTransactionId, LWLockPadded::lock, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SlruFlushData::num_files, SlruSharedData::page_dirty, SlruSharedData::page_number, SlruSharedData::page_status, SlruCtlData::shared, SimpleLruWaitIO(), SLRU_PAGE_VALID, SLRU_PAGE_WRITE_IN_PROGRESS, SlruPhysicalWritePage(), and SlruReportIOError().

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

527 {
528  SlruShared shared = ctl->shared;
529  int pageno = shared->page_number[slotno];
530  bool ok;
531 
532  /* If a write is in progress, wait for it to finish */
533  while (shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS &&
534  shared->page_number[slotno] == pageno)
535  {
536  SimpleLruWaitIO(ctl, slotno);
537  }
538 
539  /*
540  * Do nothing if page is not dirty, or if buffer no longer contains the
541  * same page we were called for.
542  */
543  if (!shared->page_dirty[slotno] ||
544  shared->page_status[slotno] != SLRU_PAGE_VALID ||
545  shared->page_number[slotno] != pageno)
546  return;
547 
548  /*
549  * Mark the slot write-busy, and clear the dirtybit. After this point, a
550  * transaction status update on this page will mark it dirty again.
551  */
552  shared->page_status[slotno] = SLRU_PAGE_WRITE_IN_PROGRESS;
553  shared->page_dirty[slotno] = false;
554 
555  /* Acquire per-buffer lock (cannot deadlock, see notes at top) */
556  LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_EXCLUSIVE);
557 
558  /* Release control lock while doing I/O */
559  LWLockRelease(shared->ControlLock);
560 
561  /* Do the write */
562  ok = SlruPhysicalWritePage(ctl, pageno, slotno, fdata);
563 
564  /* If we failed, and we're in a flush, better close the files */
565  if (!ok && fdata)
566  {
567  int i;
568 
569  for (i = 0; i < fdata->num_files; i++)
570  CloseTransientFile(fdata->fd[i]);
571  }
572 
573  /* Re-acquire control lock and update page state */
575 
576  Assert(shared->page_number[slotno] == pageno &&
577  shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS);
578 
579  /* If we failed to write, mark the page dirty again */
580  if (!ok)
581  shared->page_dirty[slotno] = true;
582 
583  shared->page_status[slotno] = SLRU_PAGE_VALID;
584 
585  LWLockRelease(&shared->buffer_locks[slotno].lock);
586 
587  /* Now it's okay to ereport if we failed */
588  if (!ok)
590 }
LWLock * ControlLock
Definition: slru.h:54
int * page_number
Definition: slru.h:66
static bool SlruPhysicalWritePage(SlruCtl ctl, int pageno, int slotno, SlruFlush fdata)
Definition: slru.c:747
static void SlruReportIOError(SlruCtl ctl, int pageno, TransactionId xid)
Definition: slru.c:923
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
SlruPageStatus * page_status
Definition: slru.h:64
LWLockPadded * buffer_locks
Definition: slru.h:68
#define InvalidTransactionId
Definition: transam.h:31
static void SimpleLruWaitIO(SlruCtl ctl, int slotno)
Definition: slru.c:328
int CloseTransientFile(int fd)
Definition: fd.c:2547
int num_files
Definition: slru.c:76
LWLock lock
Definition: lwlock.h:79
#define Assert(condition)
Definition: c.h:738
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
bool * page_dirty
Definition: slru.h:65
int i
SlruShared shared
Definition: slru.h:111
int fd[MAX_FLUSH_BUFFERS]
Definition: slru.c:77

◆ SlruPhysicalReadPage()

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

Definition at line 667 of file slru.c.

References CloseTransientFile(), ereport, errmsg(), SlruFlushData::fd, InRecovery, LOG, MAXPGPATH, MemSet, OpenTransientFile(), SlruSharedData::page_buffer, PG_BINARY, pgstat_report_wait_end(), pgstat_report_wait_start(), read, SlruFlushData::segno, SlruCtlData::shared, SLRU_CLOSE_FAILED, slru_errcause, slru_errno, SLRU_OPEN_FAILED, SLRU_PAGES_PER_SEGMENT, SLRU_READ_FAILED, SLRU_SEEK_FAILED, SlruFileName, and WAIT_EVENT_SLRU_READ.

Referenced by SimpleLruReadPage().

668 {
669  SlruShared shared = ctl->shared;
670  int segno = pageno / SLRU_PAGES_PER_SEGMENT;
671  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
672  int offset = rpageno * BLCKSZ;
673  char path[MAXPGPATH];
674  int fd;
675 
676  SlruFileName(ctl, path, segno);
677 
678  /*
679  * In a crash-and-restart situation, it's possible for us to receive
680  * commands to set the commit status of transactions whose bits are in
681  * already-truncated segments of the commit log (see notes in
682  * SlruPhysicalWritePage). Hence, if we are InRecovery, allow the case
683  * where the file doesn't exist, and return zeroes instead.
684  */
685  fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
686  if (fd < 0)
687  {
688  if (errno != ENOENT || !InRecovery)
689  {
691  slru_errno = errno;
692  return false;
693  }
694 
695  ereport(LOG,
696  (errmsg("file \"%s\" doesn't exist, reading as zeroes",
697  path)));
698  MemSet(shared->page_buffer[slotno], 0, BLCKSZ);
699  return true;
700  }
701 
702  if (lseek(fd, (off_t) offset, SEEK_SET) < 0)
703  {
705  slru_errno = errno;
706  CloseTransientFile(fd);
707  return false;
708  }
709 
710  errno = 0;
712  if (read(fd, shared->page_buffer[slotno], BLCKSZ) != BLCKSZ)
713  {
716  slru_errno = errno;
717  CloseTransientFile(fd);
718  return false;
719  }
721 
722  if (CloseTransientFile(fd) != 0)
723  {
725  slru_errno = errno;
726  return false;
727  }
728 
729  return true;
730 }
char ** page_buffer
Definition: slru.h:63
bool InRecovery
Definition: xlog.c:204
#define MemSet(start, val, len)
Definition: c.h:971
static SlruErrorCause slru_errcause
Definition: slru.c:122
#define LOG
Definition: elog.h:26
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define PG_BINARY
Definition: c.h:1234
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2370
#define MAXPGPATH
static void pgstat_report_wait_end(void)
Definition: pgstat.h:1380
int CloseTransientFile(int fd)
Definition: fd.c:2547
#define SlruFileName(ctl, path, seg)
Definition: slru.c:62
#define ereport(elevel,...)
Definition: elog.h:144
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: pgstat.h:1356
static int slru_errno
Definition: slru.c:123
int errmsg(const char *fmt,...)
Definition: elog.c:824
SlruShared shared
Definition: slru.h:111
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:33
#define read(a, b, c)
Definition: win32.h:13

◆ SlruPhysicalWritePage()

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

Definition at line 747 of file slru.c.

References CloseTransientFile(), SlruCtlData::do_fsync, END_CRIT_SECTION, SlruFlushData::fd, SlruSharedData::group_lsn, i, SlruSharedData::lsn_groups_per_page, MAX_FLUSH_BUFFERS, MAXPGPATH, SlruFlushData::num_files, OpenTransientFile(), SlruSharedData::page_buffer, PG_BINARY, pg_fsync(), pgstat_count_slru_page_written(), pgstat_report_wait_end(), pgstat_report_wait_start(), SlruFlushData::segno, SlruCtlData::shared, SLRU_CLOSE_FAILED, slru_errcause, slru_errno, SLRU_FSYNC_FAILED, SLRU_OPEN_FAILED, SLRU_PAGES_PER_SEGMENT, SLRU_SEEK_FAILED, SlruSharedData::slru_stats_idx, SLRU_WRITE_FAILED, SlruFileName, START_CRIT_SECTION, WAIT_EVENT_SLRU_SYNC, WAIT_EVENT_SLRU_WRITE, write, XLogFlush(), and XLogRecPtrIsInvalid.

Referenced by SlruInternalWritePage().

748 {
749  SlruShared shared = ctl->shared;
750  int segno = pageno / SLRU_PAGES_PER_SEGMENT;
751  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
752  int offset = rpageno * BLCKSZ;
753  char path[MAXPGPATH];
754  int fd = -1;
755 
756  /* update the stats counter of written pages */
758 
759  /*
760  * Honor the write-WAL-before-data rule, if appropriate, so that we do not
761  * write out data before associated WAL records. This is the same action
762  * performed during FlushBuffer() in the main buffer manager.
763  */
764  if (shared->group_lsn != NULL)
765  {
766  /*
767  * We must determine the largest async-commit LSN for the page. This
768  * is a bit tedious, but since this entire function is a slow path
769  * anyway, it seems better to do this here than to maintain a per-page
770  * LSN variable (which'd need an extra comparison in the
771  * transaction-commit path).
772  */
773  XLogRecPtr max_lsn;
774  int lsnindex,
775  lsnoff;
776 
777  lsnindex = slotno * shared->lsn_groups_per_page;
778  max_lsn = shared->group_lsn[lsnindex++];
779  for (lsnoff = 1; lsnoff < shared->lsn_groups_per_page; lsnoff++)
780  {
781  XLogRecPtr this_lsn = shared->group_lsn[lsnindex++];
782 
783  if (max_lsn < this_lsn)
784  max_lsn = this_lsn;
785  }
786 
787  if (!XLogRecPtrIsInvalid(max_lsn))
788  {
789  /*
790  * As noted above, elog(ERROR) is not acceptable here, so if
791  * XLogFlush were to fail, we must PANIC. This isn't much of a
792  * restriction because XLogFlush is just about all critical
793  * section anyway, but let's make sure.
794  */
796  XLogFlush(max_lsn);
798  }
799  }
800 
801  /*
802  * During a Flush, we may already have the desired file open.
803  */
804  if (fdata)
805  {
806  int i;
807 
808  for (i = 0; i < fdata->num_files; i++)
809  {
810  if (fdata->segno[i] == segno)
811  {
812  fd = fdata->fd[i];
813  break;
814  }
815  }
816  }
817 
818  if (fd < 0)
819  {
820  /*
821  * If the file doesn't already exist, we should create it. It is
822  * possible for this to need to happen when writing a page that's not
823  * first in its segment; we assume the OS can cope with that. (Note:
824  * it might seem that it'd be okay to create files only when
825  * SimpleLruZeroPage is called for the first page of a segment.
826  * However, if after a crash and restart the REDO logic elects to
827  * replay the log from a checkpoint before the latest one, then it's
828  * possible that we will get commands to set transaction status of
829  * transactions that have already been truncated from the commit log.
830  * Easiest way to deal with that is to accept references to
831  * nonexistent files here and in SlruPhysicalReadPage.)
832  *
833  * Note: it is possible for more than one backend to be executing this
834  * code simultaneously for different pages of the same file. Hence,
835  * don't use O_EXCL or O_TRUNC or anything like that.
836  */
837  SlruFileName(ctl, path, segno);
838  fd = OpenTransientFile(path, O_RDWR | O_CREAT | PG_BINARY);
839  if (fd < 0)
840  {
842  slru_errno = errno;
843  return false;
844  }
845 
846  if (fdata)
847  {
848  if (fdata->num_files < MAX_FLUSH_BUFFERS)
849  {
850  fdata->fd[fdata->num_files] = fd;
851  fdata->segno[fdata->num_files] = segno;
852  fdata->num_files++;
853  }
854  else
855  {
856  /*
857  * In the unlikely event that we exceed MAX_FLUSH_BUFFERS,
858  * fall back to treating it as a standalone write.
859  */
860  fdata = NULL;
861  }
862  }
863  }
864 
865  if (lseek(fd, (off_t) offset, SEEK_SET) < 0)
866  {
868  slru_errno = errno;
869  if (!fdata)
870  CloseTransientFile(fd);
871  return false;
872  }
873 
874  errno = 0;
876  if (write(fd, shared->page_buffer[slotno], BLCKSZ) != BLCKSZ)
877  {
879  /* if write didn't set errno, assume problem is no disk space */
880  if (errno == 0)
881  errno = ENOSPC;
883  slru_errno = errno;
884  if (!fdata)
885  CloseTransientFile(fd);
886  return false;
887  }
889 
890  /*
891  * If not part of Flush, need to fsync now. We assume this happens
892  * infrequently enough that it's not a performance issue.
893  */
894  if (!fdata)
895  {
897  if (ctl->do_fsync && pg_fsync(fd) != 0)
898  {
901  slru_errno = errno;
902  CloseTransientFile(fd);
903  return false;
904  }
906 
907  if (CloseTransientFile(fd) != 0)
908  {
910  slru_errno = errno;
911  return false;
912  }
913  }
914 
915  return true;
916 }
#define write(a, b, c)
Definition: win32.h:14
char ** page_buffer
Definition: slru.h:63
#define END_CRIT_SECTION()
Definition: miscadmin.h:134
#define START_CRIT_SECTION()
Definition: miscadmin.h:132
static SlruErrorCause slru_errcause
Definition: slru.c:122
int lsn_groups_per_page
Definition: slru.h:79
int segno[MAX_FLUSH_BUFFERS]
Definition: slru.c:78
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2844
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define PG_BINARY
Definition: c.h:1234
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2370
#define MAXPGPATH
#define MAX_FLUSH_BUFFERS
Definition: slru.c:72
XLogRecPtr * group_lsn
Definition: slru.h:78
static void pgstat_report_wait_end(void)
Definition: pgstat.h:1380
bool do_fsync
Definition: slru.h:117
int CloseTransientFile(int fd)
Definition: fd.c:2547
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29
#define SlruFileName(ctl, path, seg)
Definition: slru.c:62
int num_files
Definition: slru.c:76
uint64 XLogRecPtr
Definition: xlogdefs.h:21
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: pgstat.h:1356
int slru_stats_idx
Definition: slru.h:100
static int slru_errno
Definition: slru.c:123
int i
SlruShared shared
Definition: slru.h:111
int pg_fsync(int fd)
Definition: fd.c:343
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:33
void pgstat_count_slru_page_written(int slru_idx)
Definition: pgstat.c:6767
int fd[MAX_FLUSH_BUFFERS]
Definition: slru.c:77

◆ SlruReportIOError()

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

Definition at line 923 of file slru.c.

References data_sync_elevel(), elog, ereport, errcode_for_file_access(), errdetail(), errmsg(), ERROR, MAXPGPATH, SlruFlushData::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(), SimpleLruFlush(), SimpleLruReadPage(), and SlruInternalWritePage().

924 {
925  int segno = pageno / SLRU_PAGES_PER_SEGMENT;
926  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
927  int offset = rpageno * BLCKSZ;
928  char path[MAXPGPATH];
929 
930  SlruFileName(ctl, path, segno);
931  errno = slru_errno;
932  switch (slru_errcause)
933  {
934  case SLRU_OPEN_FAILED:
935  ereport(ERROR,
937  errmsg("could not access status of transaction %u", xid),
938  errdetail("Could not open file \"%s\": %m.", path)));
939  break;
940  case SLRU_SEEK_FAILED:
941  ereport(ERROR,
943  errmsg("could not access status of transaction %u", xid),
944  errdetail("Could not seek in file \"%s\" to offset %u: %m.",
945  path, offset)));
946  break;
947  case SLRU_READ_FAILED:
948  if (errno)
949  ereport(ERROR,
951  errmsg("could not access status of transaction %u", xid),
952  errdetail("Could not read from file \"%s\" at offset %u: %m.",
953  path, offset)));
954  else
955  ereport(ERROR,
956  (errmsg("could not access status of transaction %u", xid),
957  errdetail("Could not read from file \"%s\" at offset %u: read too few bytes.", path, offset)));
958  break;
959  case SLRU_WRITE_FAILED:
960  if (errno)
961  ereport(ERROR,
963  errmsg("could not access status of transaction %u", xid),
964  errdetail("Could not write to file \"%s\" at offset %u: %m.",
965  path, offset)));
966  else
967  ereport(ERROR,
968  (errmsg("could not access status of transaction %u", xid),
969  errdetail("Could not write to file \"%s\" at offset %u: wrote too few bytes.",
970  path, offset)));
971  break;
972  case SLRU_FSYNC_FAILED:
975  errmsg("could not access status of transaction %u", xid),
976  errdetail("Could not fsync file \"%s\": %m.",
977  path)));
978  break;
979  case SLRU_CLOSE_FAILED:
980  ereport(ERROR,
982  errmsg("could not access status of transaction %u", xid),
983  errdetail("Could not close file \"%s\": %m.",
984  path)));
985  break;
986  default:
987  /* can't get here, we trust */
988  elog(ERROR, "unrecognized SimpleLru error cause: %d",
989  (int) slru_errcause);
990  break;
991  }
992 }
static SlruErrorCause slru_errcause
Definition: slru.c:122
#define ERROR
Definition: elog.h:43
#define MAXPGPATH
int errdetail(const char *fmt,...)
Definition: elog.c:957
int errcode_for_file_access(void)
Definition: elog.c:633
#define SlruFileName(ctl, path, seg)
Definition: slru.c:62
int data_sync_elevel(int elevel)
Definition: fd.c:3597
#define ereport(elevel,...)
Definition: elog.h:144
static int slru_errno
Definition: slru.c:123
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:33

◆ SlruScanDirCbDeleteAll()

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

Definition at line 1401 of file slru.c.

References SlruInternalDeleteSegment().

Referenced by AsyncShmemInit(), and DeactivateCommitTs().

1402 {
1404 
1405  return false; /* keep going */
1406 }
static void SlruInternalDeleteSegment(SlruCtl ctl, char *filename)
Definition: slru.c:1295
static char * filename
Definition: pg_dumpall.c:90

◆ SlruScanDirCbDeleteCutoff()

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

Definition at line 1386 of file slru.c.

References SlruCtlData::PagePrecedes, and SlruInternalDeleteSegment().

Referenced by SimpleLruTruncate().

1387 {
1388  int cutoffPage = *(int *) data;
1389 
1390  if (ctl->PagePrecedes(segpage, cutoffPage))
1392 
1393  return false; /* keep going */
1394 }
static void SlruInternalDeleteSegment(SlruCtl ctl, char *filename)
Definition: slru.c:1295
static char * filename
Definition: pg_dumpall.c:90
bool(* PagePrecedes)(int, int)
Definition: slru.h:124

◆ SlruScanDirCbReportPresence()

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

Definition at line 1369 of file slru.c.

References SlruCtlData::PagePrecedes, and SLRU_PAGES_PER_SEGMENT.

Referenced by TruncateCLOG(), and TruncateCommitTs().

1370 {
1371  int cutoffPage = *(int *) data;
1372 
1373  cutoffPage -= cutoffPage % SLRU_PAGES_PER_SEGMENT;
1374 
1375  if (ctl->PagePrecedes(segpage, cutoffPage))
1376  return true; /* found one; don't iterate any more */
1377 
1378  return false; /* keep going */
1379 }
bool(* PagePrecedes)(int, int)
Definition: slru.h:124
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:33

◆ SlruScanDirectory()

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

Definition at line 1424 of file slru.c.

References AllocateDir(), callback(), dirent::d_name, DEBUG2, SlruCtlData::Dir, elog, FreeDir(), ReadDir(), SlruFlushData::segno, and SLRU_PAGES_PER_SEGMENT.

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

1425 {
1426  bool retval = false;
1427  DIR *cldir;
1428  struct dirent *clde;
1429  int segno;
1430  int segpage;
1431 
1432  cldir = AllocateDir(ctl->Dir);
1433  while ((clde = ReadDir(cldir, ctl->Dir)) != NULL)
1434  {
1435  size_t len;
1436 
1437  len = strlen(clde->d_name);
1438 
1439  if ((len == 4 || len == 5 || len == 6) &&
1440  strspn(clde->d_name, "0123456789ABCDEF") == len)
1441  {
1442  segno = (int) strtol(clde->d_name, NULL, 16);
1443  segpage = segno * SLRU_PAGES_PER_SEGMENT;
1444 
1445  elog(DEBUG2, "SlruScanDirectory invoking callback on %s/%s",
1446  ctl->Dir, clde->d_name);
1447  retval = callback(ctl, clde->d_name, segpage, data);
1448  if (retval)
1449  break;
1450  }
1451  }
1452  FreeDir(cldir);
1453 
1454  return retval;
1455 }
Definition: dirent.h:9
Definition: dirent.c:25
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:48
#define DEBUG2
Definition: elog.h:24
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2581
char Dir[64]
Definition: slru.h:130
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2647
#define elog(elevel,...)
Definition: elog.h:214
char d_name[MAX_PATH]
Definition: dirent.h:14
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:33
int FreeDir(DIR *dir)
Definition: fd.c:2699

◆ SlruSelectLRUPage()

static int SlruSelectLRUPage ( SlruCtl  ctl,
int  pageno 
)
static

Definition at line 1008 of file slru.c.

References SlruSharedData::cur_lru_count, SlruSharedData::latest_page_number, SlruSharedData::num_slots, SlruSharedData::page_dirty, SlruSharedData::page_lru_count, SlruSharedData::page_number, SlruSharedData::page_status, SlruCtlData::PagePrecedes, SlruCtlData::shared, SimpleLruWaitIO(), SLRU_PAGE_EMPTY, SLRU_PAGE_VALID, and SlruInternalWritePage().

Referenced by SimpleLruReadPage(), and SimpleLruZeroPage().

1009 {
1010  SlruShared shared = ctl->shared;
1011 
1012  /* Outer loop handles restart after I/O */
1013  for (;;)
1014  {
1015  int slotno;
1016  int cur_count;
1017  int bestvalidslot = 0; /* keep compiler quiet */
1018  int best_valid_delta = -1;
1019  int best_valid_page_number = 0; /* keep compiler quiet */
1020  int bestinvalidslot = 0; /* keep compiler quiet */
1021  int best_invalid_delta = -1;
1022  int best_invalid_page_number = 0; /* keep compiler quiet */
1023 
1024  /* See if page already has a buffer assigned */
1025  for (slotno = 0; slotno < shared->num_slots; slotno++)
1026  {
1027  if (shared->page_number[slotno] == pageno &&
1028  shared->page_status[slotno] != SLRU_PAGE_EMPTY)
1029  return slotno;
1030  }
1031 
1032  /*
1033  * If we find any EMPTY slot, just select that one. Else choose a
1034  * victim page to replace. We normally take the least recently used
1035  * valid page, but we will never take the slot containing
1036  * latest_page_number, even if it appears least recently used. We
1037  * will select a slot that is already I/O busy only if there is no
1038  * other choice: a read-busy slot will not be least recently used once
1039  * the read finishes, and waiting for an I/O on a write-busy slot is
1040  * inferior to just picking some other slot. Testing shows the slot
1041  * we pick instead will often be clean, allowing us to begin a read at
1042  * once.
1043  *
1044  * Normally the page_lru_count values will all be different and so
1045  * there will be a well-defined LRU page. But since we allow
1046  * concurrent execution of SlruRecentlyUsed() within
1047  * SimpleLruReadPage_ReadOnly(), it is possible that multiple pages
1048  * acquire the same lru_count values. In that case we break ties by
1049  * choosing the furthest-back page.
1050  *
1051  * Notice that this next line forcibly advances cur_lru_count to a
1052  * value that is certainly beyond any value that will be in the
1053  * page_lru_count array after the loop finishes. This ensures that
1054  * the next execution of SlruRecentlyUsed will mark the page newly
1055  * used, even if it's for a page that has the current counter value.
1056  * That gets us back on the path to having good data when there are
1057  * multiple pages with the same lru_count.
1058  */
1059  cur_count = (shared->cur_lru_count)++;
1060  for (slotno = 0; slotno < shared->num_slots; slotno++)
1061  {
1062  int this_delta;
1063  int this_page_number;
1064 
1065  if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
1066  return slotno;
1067  this_delta = cur_count - shared->page_lru_count[slotno];
1068  if (this_delta < 0)
1069  {
1070  /*
1071  * Clean up in case shared updates have caused cur_count
1072  * increments to get "lost". We back off the page counts,
1073  * rather than trying to increase cur_count, to avoid any
1074  * question of infinite loops or failure in the presence of
1075  * wrapped-around counts.
1076  */
1077  shared->page_lru_count[slotno] = cur_count;
1078  this_delta = 0;
1079  }
1080  this_page_number = shared->page_number[slotno];
1081  if (this_page_number == shared->latest_page_number)
1082  continue;
1083  if (shared->page_status[slotno] == SLRU_PAGE_VALID)
1084  {
1085  if (this_delta > best_valid_delta ||
1086  (this_delta == best_valid_delta &&
1087  ctl->PagePrecedes(this_page_number,
1088  best_valid_page_number)))
1089  {
1090  bestvalidslot = slotno;
1091  best_valid_delta = this_delta;
1092  best_valid_page_number = this_page_number;
1093  }
1094  }
1095  else
1096  {
1097  if (this_delta > best_invalid_delta ||
1098  (this_delta == best_invalid_delta &&
1099  ctl->PagePrecedes(this_page_number,
1100  best_invalid_page_number)))
1101  {
1102  bestinvalidslot = slotno;
1103  best_invalid_delta = this_delta;
1104  best_invalid_page_number = this_page_number;
1105  }
1106  }
1107  }
1108 
1109  /*
1110  * If all pages (except possibly the latest one) are I/O busy, we'll
1111  * have to wait for an I/O to complete and then retry. In that
1112  * unhappy case, we choose to wait for the I/O on the least recently
1113  * used slot, on the assumption that it was likely initiated first of
1114  * all the I/Os in progress and may therefore finish first.
1115  */
1116  if (best_valid_delta < 0)
1117  {
1118  SimpleLruWaitIO(ctl, bestinvalidslot);
1119  continue;
1120  }
1121 
1122  /*
1123  * If the selected page is clean, we're set.
1124  */
1125  if (!shared->page_dirty[bestvalidslot])
1126  return bestvalidslot;
1127 
1128  /*
1129  * Write the page.
1130  */
1131  SlruInternalWritePage(ctl, bestvalidslot, NULL);
1132 
1133  /*
1134  * Now loop back and try again. This is the easiest way of dealing
1135  * with corner cases such as the victim page being re-dirtied while we
1136  * wrote it.
1137  */
1138  }
1139 }
int * page_number
Definition: slru.h:66
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruFlush fdata)
Definition: slru.c:526
int latest_page_number
Definition: slru.h:97
int cur_lru_count
Definition: slru.h:90
SlruPageStatus * page_status
Definition: slru.h:64
static void SimpleLruWaitIO(SlruCtl ctl, int slotno)
Definition: slru.c:328
int * page_lru_count
Definition: slru.h:67
int num_slots
Definition: slru.h:57
bool * page_dirty
Definition: slru.h:65
SlruShared shared
Definition: slru.h:111
bool(* PagePrecedes)(int, int)
Definition: slru.h:124

Variable Documentation

◆ slru_errcause

◆ slru_errno

int slru_errno
static