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 dependency graph for slru.c:

Go to the source code of this file.

Data Structures

struct  SlruWriteAllData
 

Macros

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

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 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, int pageno, int slotno)
 
static bool SlruPhysicalWritePage (SlruCtl ctl, int pageno, int slotno, SlruWriteAll 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, int segno)
 
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, SyncRequestHandler sync_handler)
 
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 SimpleLruWriteAll (SlruCtl ctl, bool allow_redirtied)
 
void SimpleLruTruncate (SlruCtl ctl, int cutoffPage)
 
void SlruDeleteSegment (SlruCtl ctl, int segno)
 
static bool SlruMayDeleteSegment (SlruCtl ctl, int segpage, int cutoffPage)
 
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)
 
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) \
)
Definition: sync.h:50

Definition at line 88 of file slru.c.

Referenced by SlruInternalDeleteSegment(), and SlruPhysicalWritePage().

◆ MAX_WRITEALL_BUFFERS

#define MAX_WRITEALL_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 114 of file slru.c.

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

Typedef Documentation

◆ SlruWriteAll

typedef struct SlruWriteAllData* SlruWriteAll

Definition at line 81 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 124 of file slru.c.

Function Documentation

◆ SimpleLruDoesPhysicalPageExist()

bool SimpleLruDoesPhysicalPageExist ( SlruCtl  ctl,
int  pageno 
)

Definition at line 626 of file slru.c.

References CloseTransientFile(), endpos, SlruWriteAllData::fd, MAXPGPATH, OpenTransientFile(), PG_BINARY, pgstat_count_slru_page_exists(), SlruWriteAllData::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().

627 {
628  int segno = pageno / SLRU_PAGES_PER_SEGMENT;
629  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
630  int offset = rpageno * BLCKSZ;
631  char path[MAXPGPATH];
632  int fd;
633  bool result;
634  off_t endpos;
635 
636  /* update the stats counter of checked pages */
638 
639  SlruFileName(ctl, path, segno);
640 
641  fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
642  if (fd < 0)
643  {
644  /* expected: file doesn't exist */
645  if (errno == ENOENT)
646  return false;
647 
648  /* report error normally */
650  slru_errno = errno;
651  SlruReportIOError(ctl, pageno, 0);
652  }
653 
654  if ((endpos = lseek(fd, 0, SEEK_END)) < 0)
655  {
657  slru_errno = errno;
658  SlruReportIOError(ctl, pageno, 0);
659  }
660 
661  result = endpos >= (off_t) (offset + BLCKSZ);
662 
663  if (CloseTransientFile(fd) != 0)
664  {
666  slru_errno = errno;
667  return false;
668  }
669 
670  return result;
671 }
static SlruErrorCause slru_errcause
Definition: slru.c:134
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:931
#define PG_BINARY
Definition: c.h:1271
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2467
#define MAXPGPATH
static XLogRecPtr endpos
Definition: pg_receivewal.c:48
int CloseTransientFile(int fd)
Definition: fd.c:2644
void pgstat_count_slru_page_exists(int slru_idx)
Definition: pgstat.c:5846
#define SlruFileName(ctl, path, seg)
Definition: slru.c:63
int slru_stats_idx
Definition: slru.h:101
static int slru_errno
Definition: slru.c:135
SlruShared shared
Definition: slru.h:112
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:34

◆ SimpleLruInit()

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

Definition at line 187 of file slru.c.

References Assert, SlruSharedData::buffer_locks, BUFFERALIGN, SlruSharedData::ControlLock, SlruSharedData::cur_lru_count, SlruCtlData::Dir, 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, strlcpy(), and SlruCtlData::sync_handler.

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

190 {
191  SlruShared shared;
192  bool found;
193 
194  shared = (SlruShared) ShmemInitStruct(name,
195  SimpleLruShmemSize(nslots, nlsns),
196  &found);
197 
198  if (!IsUnderPostmaster)
199  {
200  /* Initialize locks and shared memory area */
201  char *ptr;
202  Size offset;
203  int slotno;
204 
205  Assert(!found);
206 
207  memset(shared, 0, sizeof(SlruSharedData));
208 
209  shared->ControlLock = ctllock;
210 
211  shared->num_slots = nslots;
212  shared->lsn_groups_per_page = nlsns;
213 
214  shared->cur_lru_count = 0;
215 
216  /* shared->latest_page_number will be set later */
217 
219 
220  ptr = (char *) shared;
221  offset = MAXALIGN(sizeof(SlruSharedData));
222  shared->page_buffer = (char **) (ptr + offset);
223  offset += MAXALIGN(nslots * sizeof(char *));
224  shared->page_status = (SlruPageStatus *) (ptr + offset);
225  offset += MAXALIGN(nslots * sizeof(SlruPageStatus));
226  shared->page_dirty = (bool *) (ptr + offset);
227  offset += MAXALIGN(nslots * sizeof(bool));
228  shared->page_number = (int *) (ptr + offset);
229  offset += MAXALIGN(nslots * sizeof(int));
230  shared->page_lru_count = (int *) (ptr + offset);
231  offset += MAXALIGN(nslots * sizeof(int));
232 
233  /* Initialize LWLocks */
234  shared->buffer_locks = (LWLockPadded *) (ptr + offset);
235  offset += MAXALIGN(nslots * sizeof(LWLockPadded));
236 
237  if (nlsns > 0)
238  {
239  shared->group_lsn = (XLogRecPtr *) (ptr + offset);
240  offset += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr));
241  }
242 
243  ptr += BUFFERALIGN(offset);
244  for (slotno = 0; slotno < nslots; slotno++)
245  {
246  LWLockInitialize(&shared->buffer_locks[slotno].lock,
247  tranche_id);
248 
249  shared->page_buffer[slotno] = ptr;
250  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
251  shared->page_dirty[slotno] = false;
252  shared->page_lru_count[slotno] = 0;
253  ptr += BLCKSZ;
254  }
255 
256  /* Should fit to estimated shmem size */
257  Assert(ptr - (char *) shared <= SimpleLruShmemSize(nslots, nlsns));
258  }
259  else
260  Assert(found);
261 
262  /*
263  * Initialize the unshared control struct, including directory path. We
264  * assume caller set PagePrecedes.
265  */
266  ctl->shared = shared;
267  ctl->sync_handler = sync_handler;
268  strlcpy(ctl->Dir, subdir, sizeof(ctl->Dir));
269 }
LWLock * ControlLock
Definition: slru.h:55
int * page_number
Definition: slru.h:67
SlruPageStatus
Definition: slru.h:42
char ** page_buffer
Definition: slru.h:64
int cur_lru_count
Definition: slru.h:91
int lsn_groups_per_page
Definition: slru.h:80
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:156
int pgstat_slru_index(const char *name)
Definition: pgstat.c:5779
SlruPageStatus * page_status
Definition: slru.h:65
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:396
bool IsUnderPostmaster
Definition: globals.c:112
LWLockPadded * buffer_locks
Definition: slru.h:69
XLogRecPtr * group_lsn
Definition: slru.h:79
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition: lwlock.c:736
SlruSharedData * SlruShared
Definition: slru.h:104
char Dir[64]
Definition: slru.h:136
LWLock lock
Definition: lwlock.h:57
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
int * page_lru_count
Definition: slru.h:68
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:804
size_t Size
Definition: c.h:540
#define MAXALIGN(LEN)
Definition: c.h:757
SyncRequestHandler sync_handler
Definition: slru.h:118
int slru_stats_idx
Definition: slru.h:101
int num_slots
Definition: slru.h:58
const char * name
Definition: encode.c:515
bool * page_dirty
Definition: slru.h:66
SlruShared shared
Definition: slru.h:112
#define BUFFERALIGN(LEN)
Definition: c.h:759

◆ SimpleLruReadPage()

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

Definition at line 395 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().

397 {
398  SlruShared shared = ctl->shared;
399 
400  /* Outer loop handles restart if we must wait for someone else's I/O */
401  for (;;)
402  {
403  int slotno;
404  bool ok;
405 
406  /* See if page already is in memory; if not, pick victim slot */
407  slotno = SlruSelectLRUPage(ctl, pageno);
408 
409  /* Did we find the page in memory? */
410  if (shared->page_number[slotno] == pageno &&
411  shared->page_status[slotno] != SLRU_PAGE_EMPTY)
412  {
413  /*
414  * If page is still being read in, we must wait for I/O. Likewise
415  * if the page is being written and the caller said that's not OK.
416  */
417  if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS ||
418  (shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS &&
419  !write_ok))
420  {
421  SimpleLruWaitIO(ctl, slotno);
422  /* Now we must recheck state from the top */
423  continue;
424  }
425  /* Otherwise, it's ready to use */
426  SlruRecentlyUsed(shared, slotno);
427 
428  /* update the stats counter of pages found in the SLRU */
430 
431  return slotno;
432  }
433 
434  /* We found no match; assert we selected a freeable slot */
435  Assert(shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
436  (shared->page_status[slotno] == SLRU_PAGE_VALID &&
437  !shared->page_dirty[slotno]));
438 
439  /* Mark the slot read-busy */
440  shared->page_number[slotno] = pageno;
441  shared->page_status[slotno] = SLRU_PAGE_READ_IN_PROGRESS;
442  shared->page_dirty[slotno] = false;
443 
444  /* Acquire per-buffer lock (cannot deadlock, see notes at top) */
445  LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_EXCLUSIVE);
446 
447  /* Release control lock while doing I/O */
448  LWLockRelease(shared->ControlLock);
449 
450  /* Do the read */
451  ok = SlruPhysicalReadPage(ctl, pageno, slotno);
452 
453  /* Set the LSNs for this newly read-in page to zero */
454  SimpleLruZeroLSNs(ctl, slotno);
455 
456  /* Re-acquire control lock and update page state */
458 
459  Assert(shared->page_number[slotno] == pageno &&
460  shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS &&
461  !shared->page_dirty[slotno]);
462 
463  shared->page_status[slotno] = ok ? SLRU_PAGE_VALID : SLRU_PAGE_EMPTY;
464 
465  LWLockRelease(&shared->buffer_locks[slotno].lock);
466 
467  /* Now it's okay to ereport if we failed */
468  if (!ok)
469  SlruReportIOError(ctl, pageno, xid);
470 
471  SlruRecentlyUsed(shared, slotno);
472 
473  /* update the stats counter of pages not found in SLRU */
475 
476  return slotno;
477  }
478 }
LWLock * ControlLock
Definition: slru.h:55
int * page_number
Definition: slru.h:67
static void SimpleLruZeroLSNs(SlruCtl ctl, int slotno)
Definition: slru.c:324
static void SlruReportIOError(SlruCtl ctl, int pageno, TransactionId xid)
Definition: slru.c:931
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1803
SlruPageStatus * page_status
Definition: slru.h:65
LWLockPadded * buffer_locks
Definition: slru.h:69
void pgstat_count_slru_page_read(int slru_idx)
Definition: pgstat.c:5852
static void SimpleLruWaitIO(SlruCtl ctl, int slotno)
Definition: slru.c:341
LWLock lock
Definition: lwlock.h:57
static bool SlruPhysicalReadPage(SlruCtl ctl, int pageno, int slotno)
Definition: slru.c:684
#define Assert(condition)
Definition: c.h:804
void pgstat_count_slru_page_hit(int slru_idx)
Definition: pgstat.c:5840
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1199
int slru_stats_idx
Definition: slru.h:101
static int SlruSelectLRUPage(SlruCtl ctl, int pageno)
Definition: slru.c:1016
bool * page_dirty
Definition: slru.h:66
SlruShared shared
Definition: slru.h:112
#define SlruRecentlyUsed(shared, slotno)
Definition: slru.c:114

◆ SimpleLruReadPage_ReadOnly()

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

Definition at line 495 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().

496 {
497  SlruShared shared = ctl->shared;
498  int slotno;
499 
500  /* Try to find the page while holding only shared lock */
502 
503  /* See if page is already in a buffer */
504  for (slotno = 0; slotno < shared->num_slots; slotno++)
505  {
506  if (shared->page_number[slotno] == pageno &&
507  shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
508  shared->page_status[slotno] != SLRU_PAGE_READ_IN_PROGRESS)
509  {
510  /* See comments for SlruRecentlyUsed macro */
511  SlruRecentlyUsed(shared, slotno);
512 
513  /* update the stats counter of pages found in the SLRU */
515 
516  return slotno;
517  }
518  }
519 
520  /* No luck, so switch to normal exclusive lock and do regular read */
521  LWLockRelease(shared->ControlLock);
523 
524  return SimpleLruReadPage(ctl, pageno, true, xid);
525 }
LWLock * ControlLock
Definition: slru.h:55
int * page_number
Definition: slru.h:67
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1803
SlruPageStatus * page_status
Definition: slru.h:65
int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok, TransactionId xid)
Definition: slru.c:395
void pgstat_count_slru_page_hit(int slru_idx)
Definition: pgstat.c:5840
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1199
int slru_stats_idx
Definition: slru.h:101
int num_slots
Definition: slru.h:58
SlruShared shared
Definition: slru.h:112
#define SlruRecentlyUsed(shared, slotno)
Definition: slru.c:114

◆ SimpleLruShmemSize()

Size SimpleLruShmemSize ( int  nslots,
int  nlsns 
)

Definition at line 156 of file slru.c.

References BUFFERALIGN, and MAXALIGN.

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

157 {
158  Size sz;
159 
160  /* we assume nslots isn't so large as to risk overflow */
161  sz = MAXALIGN(sizeof(SlruSharedData));
162  sz += MAXALIGN(nslots * sizeof(char *)); /* page_buffer[] */
163  sz += MAXALIGN(nslots * sizeof(SlruPageStatus)); /* page_status[] */
164  sz += MAXALIGN(nslots * sizeof(bool)); /* page_dirty[] */
165  sz += MAXALIGN(nslots * sizeof(int)); /* page_number[] */
166  sz += MAXALIGN(nslots * sizeof(int)); /* page_lru_count[] */
167  sz += MAXALIGN(nslots * sizeof(LWLockPadded)); /* buffer_locks[] */
168 
169  if (nlsns > 0)
170  sz += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr)); /* group_lsn[] */
171 
172  return BUFFERALIGN(sz) + BLCKSZ * nslots;
173 }
SlruPageStatus
Definition: slru.h:42
uint64 XLogRecPtr
Definition: xlogdefs.h:21
size_t Size
Definition: c.h:540
#define MAXALIGN(LEN)
Definition: c.h:757
#define BUFFERALIGN(LEN)
Definition: c.h:759

◆ SimpleLruTruncate()

void SimpleLruTruncate ( SlruCtl  ctl,
int  cutoffPage 
)

Definition at line 1226 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, SlruSharedData::slru_stats_idx, SlruInternalWritePage(), SlruScanDirCbDeleteCutoff(), and SlruScanDirectory().

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

1227 {
1228  SlruShared shared = ctl->shared;
1229  int slotno;
1230 
1231  /* update the stats counter of truncates */
1233 
1234  /*
1235  * Scan shared memory and remove any pages preceding the cutoff page, to
1236  * ensure we won't rewrite them later. (Since this is normally called in
1237  * or just after a checkpoint, any dirty pages should have been flushed
1238  * already ... we're just being extra careful here.)
1239  */
1241 
1242 restart:;
1243 
1244  /*
1245  * While we are holding the lock, make an important safety check: the
1246  * current endpoint page must not be eligible for removal.
1247  */
1248  if (ctl->PagePrecedes(shared->latest_page_number, cutoffPage))
1249  {
1250  LWLockRelease(shared->ControlLock);
1251  ereport(LOG,
1252  (errmsg("could not truncate directory \"%s\": apparent wraparound",
1253  ctl->Dir)));
1254  return;
1255  }
1256 
1257  for (slotno = 0; slotno < shared->num_slots; slotno++)
1258  {
1259  if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
1260  continue;
1261  if (!ctl->PagePrecedes(shared->page_number[slotno], cutoffPage))
1262  continue;
1263 
1264  /*
1265  * If page is clean, just change state to EMPTY (expected case).
1266  */
1267  if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1268  !shared->page_dirty[slotno])
1269  {
1270  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
1271  continue;
1272  }
1273 
1274  /*
1275  * Hmm, we have (or may have) I/O operations acting on the page, so
1276  * we've got to wait for them to finish and then start again. This is
1277  * the same logic as in SlruSelectLRUPage. (XXX if page is dirty,
1278  * wouldn't it be OK to just discard it without writing it?
1279  * SlruMayDeleteSegment() uses a stricter qualification, so we might
1280  * not delete this page in the end; even if we don't delete it, we
1281  * won't have cause to read its data again. For now, keep the logic
1282  * the same as it was.)
1283  */
1284  if (shared->page_status[slotno] == SLRU_PAGE_VALID)
1285  SlruInternalWritePage(ctl, slotno, NULL);
1286  else
1287  SimpleLruWaitIO(ctl, slotno);
1288  goto restart;
1289  }
1290 
1291  LWLockRelease(shared->ControlLock);
1292 
1293  /* Now we can remove the old segment(s) */
1294  (void) SlruScanDirectory(ctl, SlruScanDirCbDeleteCutoff, &cutoffPage);
1295 }
LWLock * ControlLock
Definition: slru.h:55
int * page_number
Definition: slru.h:67
int latest_page_number
Definition: slru.h:98
#define LOG
Definition: elog.h:26
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1803
SlruPageStatus * page_status
Definition: slru.h:65
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruWriteAll fdata)
Definition: slru.c:539
static void SimpleLruWaitIO(SlruCtl ctl, int slotno)
Definition: slru.c:341
static bool SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename, int segpage, void *data)
Definition: slru.c:1515
char Dir[64]
Definition: slru.h:136
void pgstat_count_slru_truncate(int slru_idx)
Definition: pgstat.c:5870
#define ereport(elevel,...)
Definition: elog.h:157
bool SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data)
Definition: slru.c:1553
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1199
int slru_stats_idx
Definition: slru.h:101
int num_slots
Definition: slru.h:58
int errmsg(const char *fmt,...)
Definition: elog.c:909
bool * page_dirty
Definition: slru.h:66
SlruShared shared
Definition: slru.h:112
bool(* PagePrecedes)(int, int)
Definition: slru.h:130

◆ SimpleLruWaitIO()

static void SimpleLruWaitIO ( SlruCtl  ctl,
int  slotno 
)
static

Definition at line 341 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().

342 {
343  SlruShared shared = ctl->shared;
344 
345  /* See notes at top of file */
346  LWLockRelease(shared->ControlLock);
347  LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_SHARED);
348  LWLockRelease(&shared->buffer_locks[slotno].lock);
350 
351  /*
352  * If the slot is still in an io-in-progress state, then either someone
353  * already started a new I/O on the slot, or a previous I/O failed and
354  * neglected to reset the page state. That shouldn't happen, really, but
355  * it seems worth a few extra cycles to check and recover from it. We can
356  * cheaply test for failure by seeing if the buffer lock is still held (we
357  * assume that transaction abort would release the lock).
358  */
359  if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS ||
360  shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS)
361  {
362  if (LWLockConditionalAcquire(&shared->buffer_locks[slotno].lock, LW_SHARED))
363  {
364  /* indeed, the I/O must have failed */
365  if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS)
366  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
367  else /* write_in_progress */
368  {
369  shared->page_status[slotno] = SLRU_PAGE_VALID;
370  shared->page_dirty[slotno] = true;
371  }
372  LWLockRelease(&shared->buffer_locks[slotno].lock);
373  }
374  }
375 }
LWLock * ControlLock
Definition: slru.h:55
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1803
SlruPageStatus * page_status
Definition: slru.h:65
bool LWLockConditionalAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1370
LWLockPadded * buffer_locks
Definition: slru.h:69
LWLock lock
Definition: lwlock.h:57
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1199
bool * page_dirty
Definition: slru.h:66
SlruShared shared
Definition: slru.h:112

◆ SimpleLruWriteAll()

void SimpleLruWriteAll ( SlruCtl  ctl,
bool  allow_redirtied 
)

Definition at line 1156 of file slru.c.

References Assert, CloseTransientFile(), SlruSharedData::ControlLock, SlruCtlData::Dir, SlruWriteAllData::fd, fsync_fname(), i, InvalidTransactionId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SlruWriteAllData::num_files, SlruSharedData::num_slots, SlruSharedData::page_dirty, SlruSharedData::page_status, pgstat_count_slru_flush(), SlruWriteAllData::segno, SlruCtlData::shared, SLRU_CLOSE_FAILED, slru_errcause, slru_errno, SLRU_PAGE_EMPTY, SLRU_PAGE_VALID, SLRU_PAGES_PER_SEGMENT, SlruSharedData::slru_stats_idx, SlruInternalWritePage(), SlruReportIOError(), SlruCtlData::sync_handler, and SYNC_HANDLER_NONE.

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

1157 {
1158  SlruShared shared = ctl->shared;
1159  SlruWriteAllData fdata;
1160  int slotno;
1161  int pageno = 0;
1162  int i;
1163  bool ok;
1164 
1165  /* update the stats counter of flushes */
1167 
1168  /*
1169  * Find and write dirty pages
1170  */
1171  fdata.num_files = 0;
1172 
1174 
1175  for (slotno = 0; slotno < shared->num_slots; slotno++)
1176  {
1177  SlruInternalWritePage(ctl, slotno, &fdata);
1178 
1179  /*
1180  * In some places (e.g. checkpoints), we cannot assert that the slot
1181  * is clean now, since another process might have re-dirtied it
1182  * already. That's okay.
1183  */
1184  Assert(allow_redirtied ||
1185  shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
1186  (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1187  !shared->page_dirty[slotno]));
1188  }
1189 
1190  LWLockRelease(shared->ControlLock);
1191 
1192  /*
1193  * Now close any files that were open
1194  */
1195  ok = true;
1196  for (i = 0; i < fdata.num_files; i++)
1197  {
1198  if (CloseTransientFile(fdata.fd[i]) != 0)
1199  {
1201  slru_errno = errno;
1202  pageno = fdata.segno[i] * SLRU_PAGES_PER_SEGMENT;
1203  ok = false;
1204  }
1205  }
1206  if (!ok)
1208 
1209  /* Ensure that directory entries for new files are on disk. */
1210  if (ctl->sync_handler != SYNC_HANDLER_NONE)
1211  fsync_fname(ctl->Dir, true);
1212 }
LWLock * ControlLock
Definition: slru.h:55
void fsync_fname(const char *fname, bool isdir)
Definition: fd.c:666
static SlruErrorCause slru_errcause
Definition: slru.c:134
void pgstat_count_slru_flush(int slru_idx)
Definition: pgstat.c:5864
static void SlruReportIOError(SlruCtl ctl, int pageno, TransactionId xid)
Definition: slru.c:931
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1803
int segno[MAX_WRITEALL_BUFFERS]
Definition: slru.c:78
int fd[MAX_WRITEALL_BUFFERS]
Definition: slru.c:77
SlruPageStatus * page_status
Definition: slru.h:65
int num_files
Definition: slru.c:76
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruWriteAll fdata)
Definition: slru.c:539
#define InvalidTransactionId
Definition: transam.h:31
int CloseTransientFile(int fd)
Definition: fd.c:2644
char Dir[64]
Definition: slru.h:136
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1199
SyncRequestHandler sync_handler
Definition: slru.h:118
int slru_stats_idx
Definition: slru.h:101
int num_slots
Definition: slru.h:58
static int slru_errno
Definition: slru.c:135
bool * page_dirty
Definition: slru.h:66
int i
SlruShared shared
Definition: slru.h:112
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:34

◆ SimpleLruWritePage()

void SimpleLruWritePage ( SlruCtl  ctl,
int  slotno 
)

Definition at line 614 of file slru.c.

References SlruInternalWritePage().

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

615 {
616  SlruInternalWritePage(ctl, slotno, NULL);
617 }
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruWriteAll fdata)
Definition: slru.c:539

◆ SimpleLruZeroLSNs()

static void SimpleLruZeroLSNs ( SlruCtl  ctl,
int  slotno 
)
static

Definition at line 324 of file slru.c.

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

Referenced by SimpleLruReadPage(), and SimpleLruZeroPage().

325 {
326  SlruShared shared = ctl->shared;
327 
328  if (shared->lsn_groups_per_page > 0)
329  MemSet(&shared->group_lsn[slotno * shared->lsn_groups_per_page], 0,
330  shared->lsn_groups_per_page * sizeof(XLogRecPtr));
331 }
#define MemSet(start, val, len)
Definition: c.h:1008
int lsn_groups_per_page
Definition: slru.h:80
XLogRecPtr * group_lsn
Definition: slru.h:79
uint64 XLogRecPtr
Definition: xlogdefs.h:21
SlruShared shared
Definition: slru.h:112

◆ SimpleLruZeroPage()

int SimpleLruZeroPage ( SlruCtl  ctl,
int  pageno 
)

Definition at line 280 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().

281 {
282  SlruShared shared = ctl->shared;
283  int slotno;
284 
285  /* Find a suitable buffer slot for the page */
286  slotno = SlruSelectLRUPage(ctl, pageno);
287  Assert(shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
288  (shared->page_status[slotno] == SLRU_PAGE_VALID &&
289  !shared->page_dirty[slotno]) ||
290  shared->page_number[slotno] == pageno);
291 
292  /* Mark the slot as containing this page */
293  shared->page_number[slotno] = pageno;
294  shared->page_status[slotno] = SLRU_PAGE_VALID;
295  shared->page_dirty[slotno] = true;
296  SlruRecentlyUsed(shared, slotno);
297 
298  /* Set the buffer to zeroes */
299  MemSet(shared->page_buffer[slotno], 0, BLCKSZ);
300 
301  /* Set the LSNs for this new page to zero */
302  SimpleLruZeroLSNs(ctl, slotno);
303 
304  /* Assume this page is now the latest active page */
305  shared->latest_page_number = pageno;
306 
307  /* update the stats counter of zeroed pages */
309 
310  return slotno;
311 }
int * page_number
Definition: slru.h:67
int latest_page_number
Definition: slru.h:98
char ** page_buffer
Definition: slru.h:64
#define MemSet(start, val, len)
Definition: c.h:1008
static void SimpleLruZeroLSNs(SlruCtl ctl, int slotno)
Definition: slru.c:324
SlruPageStatus * page_status
Definition: slru.h:65
void pgstat_count_slru_page_zeroed(int slru_idx)
Definition: pgstat.c:5834
#define Assert(condition)
Definition: c.h:804
int slru_stats_idx
Definition: slru.h:101
static int SlruSelectLRUPage(SlruCtl ctl, int pageno)
Definition: slru.c:1016
bool * page_dirty
Definition: slru.h:66
SlruShared shared
Definition: slru.h:112
#define SlruRecentlyUsed(shared, slotno)
Definition: slru.c:114

◆ SlruDeleteSegment()

void SlruDeleteSegment ( SlruCtl  ctl,
int  segno 
)

Definition at line 1327 of file slru.c.

References SlruSharedData::ControlLock, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), 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, SlruInternalDeleteSegment(), and SlruInternalWritePage().

Referenced by PerformMembersTruncation().

1328 {
1329  SlruShared shared = ctl->shared;
1330  int slotno;
1331  bool did_write;
1332 
1333  /* Clean out any possibly existing references to the segment. */
1335 restart:
1336  did_write = false;
1337  for (slotno = 0; slotno < shared->num_slots; slotno++)
1338  {
1339  int pagesegno = shared->page_number[slotno] / SLRU_PAGES_PER_SEGMENT;
1340 
1341  if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
1342  continue;
1343 
1344  /* not the segment we're looking for */
1345  if (pagesegno != segno)
1346  continue;
1347 
1348  /* If page is clean, just change state to EMPTY (expected case). */
1349  if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1350  !shared->page_dirty[slotno])
1351  {
1352  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
1353  continue;
1354  }
1355 
1356  /* Same logic as SimpleLruTruncate() */
1357  if (shared->page_status[slotno] == SLRU_PAGE_VALID)
1358  SlruInternalWritePage(ctl, slotno, NULL);
1359  else
1360  SimpleLruWaitIO(ctl, slotno);
1361 
1362  did_write = true;
1363  }
1364 
1365  /*
1366  * Be extra careful and re-check. The IO functions release the control
1367  * lock, so new pages could have been read in.
1368  */
1369  if (did_write)
1370  goto restart;
1371 
1372  SlruInternalDeleteSegment(ctl, segno);
1373 
1374  LWLockRelease(shared->ControlLock);
1375 }
LWLock * ControlLock
Definition: slru.h:55
int * page_number
Definition: slru.h:67
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1803
SlruPageStatus * page_status
Definition: slru.h:65
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruWriteAll fdata)
Definition: slru.c:539
static void SimpleLruWaitIO(SlruCtl ctl, int slotno)
Definition: slru.c:341
static void SlruInternalDeleteSegment(SlruCtl ctl, int segno)
Definition: slru.c:1304
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1199
int num_slots
Definition: slru.h:58
bool * page_dirty
Definition: slru.h:66
SlruShared shared
Definition: slru.h:112
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:34

◆ SlruInternalDeleteSegment()

static void SlruInternalDeleteSegment ( SlruCtl  ctl,
int  segno 
)
static

Definition at line 1304 of file slru.c.

References DEBUG2, ereport, errmsg_internal(), INIT_SLRUFILETAG, MAXPGPATH, RegisterSyncRequest(), SlruFileName, SYNC_FORGET_REQUEST, SlruCtlData::sync_handler, and SYNC_HANDLER_NONE.

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

1305 {
1306  char path[MAXPGPATH];
1307 
1308  /* Forget any fsync requests queued for this segment. */
1309  if (ctl->sync_handler != SYNC_HANDLER_NONE)
1310  {
1311  FileTag tag;
1312 
1313  INIT_SLRUFILETAG(tag, ctl->sync_handler, segno);
1315  }
1316 
1317  /* Unlink the file. */
1318  SlruFileName(ctl, path, segno);
1319  ereport(DEBUG2, (errmsg_internal("removing file \"%s\"", path)));
1320  unlink(path);
1321 }
#define INIT_SLRUFILETAG(a, xx_handler, xx_segno)
Definition: slru.c:88
#define MAXPGPATH
#define DEBUG2
Definition: elog.h:24
#define SlruFileName(ctl, path, seg)
Definition: slru.c:63
bool RegisterSyncRequest(const FileTag *ftag, SyncRequestType type, bool retryOnError)
Definition: sync.c:553
#define ereport(elevel,...)
Definition: elog.h:157
int errmsg_internal(const char *fmt,...)
Definition: elog.c:996
SyncRequestHandler sync_handler
Definition: slru.h:118
Definition: sync.h:50

◆ SlruInternalWritePage()

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

Definition at line 539 of file slru.c.

References Assert, SlruSharedData::buffer_locks, CheckpointStats, CheckpointStatsData::ckpt_bufs_written, CloseTransientFile(), SlruSharedData::ControlLock, SlruWriteAllData::fd, i, InvalidTransactionId, LWLockPadded::lock, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SlruWriteAllData::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 SimpleLruTruncate(), SimpleLruWriteAll(), SimpleLruWritePage(), SlruDeleteSegment(), and SlruSelectLRUPage().

540 {
541  SlruShared shared = ctl->shared;
542  int pageno = shared->page_number[slotno];
543  bool ok;
544 
545  /* If a write is in progress, wait for it to finish */
546  while (shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS &&
547  shared->page_number[slotno] == pageno)
548  {
549  SimpleLruWaitIO(ctl, slotno);
550  }
551 
552  /*
553  * Do nothing if page is not dirty, or if buffer no longer contains the
554  * same page we were called for.
555  */
556  if (!shared->page_dirty[slotno] ||
557  shared->page_status[slotno] != SLRU_PAGE_VALID ||
558  shared->page_number[slotno] != pageno)
559  return;
560 
561  /*
562  * Mark the slot write-busy, and clear the dirtybit. After this point, a
563  * transaction status update on this page will mark it dirty again.
564  */
565  shared->page_status[slotno] = SLRU_PAGE_WRITE_IN_PROGRESS;
566  shared->page_dirty[slotno] = false;
567 
568  /* Acquire per-buffer lock (cannot deadlock, see notes at top) */
569  LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_EXCLUSIVE);
570 
571  /* Release control lock while doing I/O */
572  LWLockRelease(shared->ControlLock);
573 
574  /* Do the write */
575  ok = SlruPhysicalWritePage(ctl, pageno, slotno, fdata);
576 
577  /* If we failed, and we're in a flush, better close the files */
578  if (!ok && fdata)
579  {
580  int i;
581 
582  for (i = 0; i < fdata->num_files; i++)
583  CloseTransientFile(fdata->fd[i]);
584  }
585 
586  /* Re-acquire control lock and update page state */
588 
589  Assert(shared->page_number[slotno] == pageno &&
590  shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS);
591 
592  /* If we failed to write, mark the page dirty again */
593  if (!ok)
594  shared->page_dirty[slotno] = true;
595 
596  shared->page_status[slotno] = SLRU_PAGE_VALID;
597 
598  LWLockRelease(&shared->buffer_locks[slotno].lock);
599 
600  /* Now it's okay to ereport if we failed */
601  if (!ok)
603 
604  /* If part of a checkpoint, count this as a buffer written. */
605  if (fdata)
607 }
LWLock * ControlLock
Definition: slru.h:55
int * page_number
Definition: slru.h:67
static void SlruReportIOError(SlruCtl ctl, int pageno, TransactionId xid)
Definition: slru.c:931
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1803
int fd[MAX_WRITEALL_BUFFERS]
Definition: slru.c:77
SlruPageStatus * page_status
Definition: slru.h:65
int num_files
Definition: slru.c:76
LWLockPadded * buffer_locks
Definition: slru.h:69
#define InvalidTransactionId
Definition: transam.h:31
static bool SlruPhysicalWritePage(SlruCtl ctl, int pageno, int slotno, SlruWriteAll fdata)
Definition: slru.c:756
static void SimpleLruWaitIO(SlruCtl ctl, int slotno)
Definition: slru.c:341
int CloseTransientFile(int fd)
Definition: fd.c:2644
int ckpt_bufs_written
Definition: xlog.h:227
LWLock lock
Definition: lwlock.h:57
#define Assert(condition)
Definition: c.h:804
CheckpointStatsData CheckpointStats
Definition: xlog.c:188
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1199
bool * page_dirty
Definition: slru.h:66
int i
SlruShared shared
Definition: slru.h:112

◆ SlruMayDeleteSegment()

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

Definition at line 1391 of file slru.c.

References Assert, SlruCtlData::PagePrecedes, SLRU_PAGES_PER_SEGMENT, SlruPagePrecedesUnitTests, TransactionIdFollowsOrEquals(), and TransactionIdPrecedes().

Referenced by SlruScanDirCbDeleteCutoff(), and SlruScanDirCbReportPresence().

1392 {
1393  int seg_last_page = segpage + SLRU_PAGES_PER_SEGMENT - 1;
1394 
1395  Assert(segpage % SLRU_PAGES_PER_SEGMENT == 0);
1396 
1397  return (ctl->PagePrecedes(segpage, cutoffPage) &&
1398  ctl->PagePrecedes(seg_last_page, cutoffPage));
1399 }
#define Assert(condition)
Definition: c.h:804
bool(* PagePrecedes)(int, int)
Definition: slru.h:130
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:34

◆ SlruPhysicalReadPage()

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

Definition at line 684 of file slru.c.

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

Referenced by SimpleLruReadPage().

685 {
686  SlruShared shared = ctl->shared;
687  int segno = pageno / SLRU_PAGES_PER_SEGMENT;
688  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
689  off_t offset = rpageno * BLCKSZ;
690  char path[MAXPGPATH];
691  int fd;
692 
693  SlruFileName(ctl, path, segno);
694 
695  /*
696  * In a crash-and-restart situation, it's possible for us to receive
697  * commands to set the commit status of transactions whose bits are in
698  * already-truncated segments of the commit log (see notes in
699  * SlruPhysicalWritePage). Hence, if we are InRecovery, allow the case
700  * where the file doesn't exist, and return zeroes instead.
701  */
702  fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
703  if (fd < 0)
704  {
705  if (errno != ENOENT || !InRecovery)
706  {
708  slru_errno = errno;
709  return false;
710  }
711 
712  ereport(LOG,
713  (errmsg("file \"%s\" doesn't exist, reading as zeroes",
714  path)));
715  MemSet(shared->page_buffer[slotno], 0, BLCKSZ);
716  return true;
717  }
718 
719  errno = 0;
721  if (pg_pread(fd, shared->page_buffer[slotno], BLCKSZ, offset) != BLCKSZ)
722  {
725  slru_errno = errno;
726  CloseTransientFile(fd);
727  return false;
728  }
730 
731  if (CloseTransientFile(fd) != 0)
732  {
734  slru_errno = errno;
735  return false;
736  }
737 
738  return true;
739 }
static void pgstat_report_wait_end(void)
Definition: wait_event.h:278
char ** page_buffer
Definition: slru.h:64
#define MemSet(start, val, len)
Definition: c.h:1008
static SlruErrorCause slru_errcause
Definition: slru.c:134
#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:1271
ssize_t pg_pread(int fd, void *buf, size_t nbyte, off_t offset)
Definition: pread.c:27
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2467
#define MAXPGPATH
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: wait_event.h:262
int CloseTransientFile(int fd)
Definition: fd.c:2644
#define SlruFileName(ctl, path, seg)
Definition: slru.c:63
#define ereport(elevel,...)
Definition: elog.h:157
bool InRecovery
Definition: xlogutils.c:52
static int slru_errno
Definition: slru.c:135
int errmsg(const char *fmt,...)
Definition: elog.c:909
SlruShared shared
Definition: slru.h:112
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:34

◆ SlruPhysicalWritePage()

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

Definition at line 756 of file slru.c.

References CloseTransientFile(), END_CRIT_SECTION, 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, SlruCtlData::shared, 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, SlruCtlData::sync_handler, SYNC_HANDLER_NONE, SYNC_REQUEST, WAIT_EVENT_SLRU_SYNC, WAIT_EVENT_SLRU_WRITE, XLogFlush(), and XLogRecPtrIsInvalid.

Referenced by SlruInternalWritePage().

757 {
758  SlruShared shared = ctl->shared;
759  int segno = pageno / SLRU_PAGES_PER_SEGMENT;
760  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
761  off_t offset = rpageno * BLCKSZ;
762  char path[MAXPGPATH];
763  int fd = -1;
764 
765  /* update the stats counter of written pages */
767 
768  /*
769  * Honor the write-WAL-before-data rule, if appropriate, so that we do not
770  * write out data before associated WAL records. This is the same action
771  * performed during FlushBuffer() in the main buffer manager.
772  */
773  if (shared->group_lsn != NULL)
774  {
775  /*
776  * We must determine the largest async-commit LSN for the page. This
777  * is a bit tedious, but since this entire function is a slow path
778  * anyway, it seems better to do this here than to maintain a per-page
779  * LSN variable (which'd need an extra comparison in the
780  * transaction-commit path).
781  */
782  XLogRecPtr max_lsn;
783  int lsnindex,
784  lsnoff;
785 
786  lsnindex = slotno * shared->lsn_groups_per_page;
787  max_lsn = shared->group_lsn[lsnindex++];
788  for (lsnoff = 1; lsnoff < shared->lsn_groups_per_page; lsnoff++)
789  {
790  XLogRecPtr this_lsn = shared->group_lsn[lsnindex++];
791 
792  if (max_lsn < this_lsn)
793  max_lsn = this_lsn;
794  }
795 
796  if (!XLogRecPtrIsInvalid(max_lsn))
797  {
798  /*
799  * As noted above, elog(ERROR) is not acceptable here, so if
800  * XLogFlush were to fail, we must PANIC. This isn't much of a
801  * restriction because XLogFlush is just about all critical
802  * section anyway, but let's make sure.
803  */
805  XLogFlush(max_lsn);
807  }
808  }
809 
810  /*
811  * During a WriteAll, we may already have the desired file open.
812  */
813  if (fdata)
814  {
815  int i;
816 
817  for (i = 0; i < fdata->num_files; i++)
818  {
819  if (fdata->segno[i] == segno)
820  {
821  fd = fdata->fd[i];
822  break;
823  }
824  }
825  }
826 
827  if (fd < 0)
828  {
829  /*
830  * If the file doesn't already exist, we should create it. It is
831  * possible for this to need to happen when writing a page that's not
832  * first in its segment; we assume the OS can cope with that. (Note:
833  * it might seem that it'd be okay to create files only when
834  * SimpleLruZeroPage is called for the first page of a segment.
835  * However, if after a crash and restart the REDO logic elects to
836  * replay the log from a checkpoint before the latest one, then it's
837  * possible that we will get commands to set transaction status of
838  * transactions that have already been truncated from the commit log.
839  * Easiest way to deal with that is to accept references to
840  * nonexistent files here and in SlruPhysicalReadPage.)
841  *
842  * Note: it is possible for more than one backend to be executing this
843  * code simultaneously for different pages of the same file. Hence,
844  * don't use O_EXCL or O_TRUNC or anything like that.
845  */
846  SlruFileName(ctl, path, segno);
847  fd = OpenTransientFile(path, O_RDWR | O_CREAT | PG_BINARY);
848  if (fd < 0)
849  {
851  slru_errno = errno;
852  return false;
853  }
854 
855  if (fdata)
856  {
857  if (fdata->num_files < MAX_WRITEALL_BUFFERS)
858  {
859  fdata->fd[fdata->num_files] = fd;
860  fdata->segno[fdata->num_files] = segno;
861  fdata->num_files++;
862  }
863  else
864  {
865  /*
866  * In the unlikely event that we exceed MAX_FLUSH_BUFFERS,
867  * fall back to treating it as a standalone write.
868  */
869  fdata = NULL;
870  }
871  }
872  }
873 
874  errno = 0;
876  if (pg_pwrite(fd, shared->page_buffer[slotno], BLCKSZ, offset) != 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  /* Queue up a sync request for the checkpointer. */
891  if (ctl->sync_handler != SYNC_HANDLER_NONE)
892  {
893  FileTag tag;
894 
895  INIT_SLRUFILETAG(tag, ctl->sync_handler, segno);
896  if (!RegisterSyncRequest(&tag, SYNC_REQUEST, false))
897  {
898  /* No space to enqueue sync request. Do it synchronously. */
900  if (pg_fsync(fd) != 0)
901  {
904  slru_errno = errno;
905  CloseTransientFile(fd);
906  return false;
907  }
909  }
910  }
911 
912  /* Close file, unless part of flush request. */
913  if (!fdata)
914  {
915  if (CloseTransientFile(fd) != 0)
916  {
918  slru_errno = errno;
919  return false;
920  }
921  }
922 
923  return true;
924 }
static void pgstat_report_wait_end(void)
Definition: wait_event.h:278
#define INIT_SLRUFILETAG(a, xx_handler, xx_segno)
Definition: slru.c:88
char ** page_buffer
Definition: slru.h:64
#define END_CRIT_SECTION()
Definition: miscadmin.h:149
#define START_CRIT_SECTION()
Definition: miscadmin.h:147
static SlruErrorCause slru_errcause
Definition: slru.c:134
int lsn_groups_per_page
Definition: slru.h:80
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2860
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define PG_BINARY
Definition: c.h:1271
ssize_t pg_pwrite(int fd, const void *buf, size_t nbyte, off_t offset)
Definition: pwrite.c:27
int segno[MAX_WRITEALL_BUFFERS]
Definition: slru.c:78
int fd[MAX_WRITEALL_BUFFERS]
Definition: slru.c:77
int num_files
Definition: slru.c:76
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2467
#define MAX_WRITEALL_BUFFERS
Definition: slru.c:72
#define MAXPGPATH
XLogRecPtr * group_lsn
Definition: slru.h:79
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: wait_event.h:262
int CloseTransientFile(int fd)
Definition: fd.c:2644
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29
#define SlruFileName(ctl, path, seg)
Definition: slru.c:63
bool RegisterSyncRequest(const FileTag *ftag, SyncRequestType type, bool retryOnError)
Definition: sync.c:553
uint64 XLogRecPtr
Definition: xlogdefs.h:21
SyncRequestHandler sync_handler
Definition: slru.h:118
int slru_stats_idx
Definition: slru.h:101
static int slru_errno
Definition: slru.c:135
int i
SlruShared shared
Definition: slru.h:112
int pg_fsync(int fd)
Definition: fd.c:352
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:34
Definition: sync.h:50
void pgstat_count_slru_page_written(int slru_idx)
Definition: pgstat.c:5858

◆ SlruReportIOError()

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

Definition at line 931 of file slru.c.

References 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().

932 {
933  int segno = pageno / SLRU_PAGES_PER_SEGMENT;
934  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
935  int offset = rpageno * BLCKSZ;
936  char path[MAXPGPATH];
937 
938  SlruFileName(ctl, path, segno);
939  errno = slru_errno;
940  switch (slru_errcause)
941  {
942  case SLRU_OPEN_FAILED:
943  ereport(ERROR,
945  errmsg("could not access status of transaction %u", xid),
946  errdetail("Could not open file \"%s\": %m.", path)));
947  break;
948  case SLRU_SEEK_FAILED:
949  ereport(ERROR,
951  errmsg("could not access status of transaction %u", xid),
952  errdetail("Could not seek in file \"%s\" to offset %u: %m.",
953  path, offset)));
954  break;
955  case SLRU_READ_FAILED:
956  if (errno)
957  ereport(ERROR,
959  errmsg("could not access status of transaction %u", xid),
960  errdetail("Could not read from file \"%s\" at offset %u: %m.",
961  path, offset)));
962  else
963  ereport(ERROR,
964  (errmsg("could not access status of transaction %u", xid),
965  errdetail("Could not read from file \"%s\" at offset %u: read too few bytes.", path, offset)));
966  break;
967  case SLRU_WRITE_FAILED:
968  if (errno)
969  ereport(ERROR,
971  errmsg("could not access status of transaction %u", xid),
972  errdetail("Could not write to file \"%s\" at offset %u: %m.",
973  path, offset)));
974  else
975  ereport(ERROR,
976  (errmsg("could not access status of transaction %u", xid),
977  errdetail("Could not write to file \"%s\" at offset %u: wrote too few bytes.",
978  path, offset)));
979  break;
980  case SLRU_FSYNC_FAILED:
983  errmsg("could not access status of transaction %u", xid),
984  errdetail("Could not fsync file \"%s\": %m.",
985  path)));
986  break;
987  case SLRU_CLOSE_FAILED:
988  ereport(ERROR,
990  errmsg("could not access status of transaction %u", xid),
991  errdetail("Could not close file \"%s\": %m.",
992  path)));
993  break;
994  default:
995  /* can't get here, we trust */
996  elog(ERROR, "unrecognized SimpleLru error cause: %d",
997  (int) slru_errcause);
998  break;
999  }
1000 }
static SlruErrorCause slru_errcause
Definition: slru.c:134
#define ERROR
Definition: elog.h:46
#define MAXPGPATH
int errdetail(const char *fmt,...)
Definition: elog.c:1042
int errcode_for_file_access(void)
Definition: elog.c:721
#define SlruFileName(ctl, path, seg)
Definition: slru.c:63
int data_sync_elevel(int elevel)
Definition: fd.c:3758
#define ereport(elevel,...)
Definition: elog.h:157
static int slru_errno
Definition: slru.c:135
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:34

◆ SlruScanDirCbDeleteAll()

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

Definition at line 1530 of file slru.c.

References SLRU_PAGES_PER_SEGMENT, and SlruInternalDeleteSegment().

Referenced by AsyncShmemInit(), and DeactivateCommitTs().

1531 {
1533 
1534  return false; /* keep going */
1535 }
static void SlruInternalDeleteSegment(SlruCtl ctl, int segno)
Definition: slru.c:1304
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:34

◆ SlruScanDirCbDeleteCutoff()

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

Definition at line 1515 of file slru.c.

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

Referenced by SimpleLruTruncate().

1516 {
1517  int cutoffPage = *(int *) data;
1518 
1519  if (SlruMayDeleteSegment(ctl, segpage, cutoffPage))
1521 
1522  return false; /* keep going */
1523 }
static void SlruInternalDeleteSegment(SlruCtl ctl, int segno)
Definition: slru.c:1304
static bool SlruMayDeleteSegment(SlruCtl ctl, int segpage, int cutoffPage)
Definition: slru.c:1391
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:34

◆ SlruScanDirCbReportPresence()

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

Definition at line 1500 of file slru.c.

References SlruMayDeleteSegment().

Referenced by TruncateCLOG(), and TruncateCommitTs().

1501 {
1502  int cutoffPage = *(int *) data;
1503 
1504  if (SlruMayDeleteSegment(ctl, segpage, cutoffPage))
1505  return true; /* found one; don't iterate any more */
1506 
1507  return false; /* keep going */
1508 }
static bool SlruMayDeleteSegment(SlruCtl ctl, int segpage, int cutoffPage)
Definition: slru.c:1391

◆ SlruScanDirectory()

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

Definition at line 1553 of file slru.c.

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

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

1554 {
1555  bool retval = false;
1556  DIR *cldir;
1557  struct dirent *clde;
1558  int segno;
1559  int segpage;
1560 
1561  cldir = AllocateDir(ctl->Dir);
1562  while ((clde = ReadDir(cldir, ctl->Dir)) != NULL)
1563  {
1564  size_t len;
1565 
1566  len = strlen(clde->d_name);
1567 
1568  if ((len == 4 || len == 5 || len == 6) &&
1569  strspn(clde->d_name, "0123456789ABCDEF") == len)
1570  {
1571  segno = (int) strtol(clde->d_name, NULL, 16);
1572  segpage = segno * SLRU_PAGES_PER_SEGMENT;
1573 
1574  elog(DEBUG2, "SlruScanDirectory invoking callback on %s/%s",
1575  ctl->Dir, clde->d_name);
1576  retval = callback(ctl, clde->d_name, segpage, data);
1577  if (retval)
1578  break;
1579  }
1580  }
1581  FreeDir(cldir);
1582 
1583  return retval;
1584 }
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:2678
char Dir[64]
Definition: slru.h:136
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2744
#define elog(elevel,...)
Definition: elog.h:232
char d_name[MAX_PATH]
Definition: dirent.h:15
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:34
int FreeDir(DIR *dir)
Definition: fd.c:2796

◆ SlruSelectLRUPage()

static int SlruSelectLRUPage ( SlruCtl  ctl,
int  pageno 
)
static

Definition at line 1016 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().

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

◆ SlruSyncFileTag()

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

Definition at line 1593 of file slru.c.

References CloseTransientFile(), SlruWriteAllData::fd, OpenTransientFile(), PG_BINARY, pg_fsync(), FileTag::segno, and SlruFileName.

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

1594 {
1595  int fd;
1596  int save_errno;
1597  int result;
1598 
1599  SlruFileName(ctl, path, ftag->segno);
1600 
1601  fd = OpenTransientFile(path, O_RDWR | PG_BINARY);
1602  if (fd < 0)
1603  return -1;
1604 
1605  result = pg_fsync(fd);
1606  save_errno = errno;
1607 
1608  CloseTransientFile(fd);
1609 
1610  errno = save_errno;
1611  return result;
1612 }
uint32 segno
Definition: sync.h:55
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define PG_BINARY
Definition: c.h:1271
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2467
int CloseTransientFile(int fd)
Definition: fd.c:2644
#define SlruFileName(ctl, path, seg)
Definition: slru.c:63
int pg_fsync(int fd)
Definition: fd.c:352

Variable Documentation

◆ slru_errcause

◆ slru_errno