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  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, 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, 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)
 
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 87 of file slru.c.

Referenced by SlruDeleteSegment(), and SlruPhysicalWritePage().

◆ MAX_WRITEALL_BUFFERS

#define MAX_WRITEALL_BUFFERS   16

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

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

Typedef Documentation

◆ SlruWriteAll

typedef struct SlruWriteAllData* SlruWriteAll

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

Function Documentation

◆ SimpleLruDoesPhysicalPageExist()

bool SimpleLruDoesPhysicalPageExist ( SlruCtl  ctl,
int  pageno 
)

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

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

189 {
190  SlruShared shared;
191  bool found;
192 
193  shared = (SlruShared) ShmemInitStruct(name,
194  SimpleLruShmemSize(nslots, nlsns),
195  &found);
196 
197  if (!IsUnderPostmaster)
198  {
199  /* Initialize locks and shared memory area */
200  char *ptr;
201  Size offset;
202  int slotno;
203 
204  Assert(!found);
205 
206  memset(shared, 0, sizeof(SlruSharedData));
207 
208  shared->ControlLock = ctllock;
209 
210  shared->num_slots = nslots;
211  shared->lsn_groups_per_page = nlsns;
212 
213  shared->cur_lru_count = 0;
214 
215  /* shared->latest_page_number will be set later */
216 
218 
219  ptr = (char *) shared;
220  offset = MAXALIGN(sizeof(SlruSharedData));
221  shared->page_buffer = (char **) (ptr + offset);
222  offset += MAXALIGN(nslots * sizeof(char *));
223  shared->page_status = (SlruPageStatus *) (ptr + offset);
224  offset += MAXALIGN(nslots * sizeof(SlruPageStatus));
225  shared->page_dirty = (bool *) (ptr + offset);
226  offset += MAXALIGN(nslots * sizeof(bool));
227  shared->page_number = (int *) (ptr + offset);
228  offset += MAXALIGN(nslots * sizeof(int));
229  shared->page_lru_count = (int *) (ptr + offset);
230  offset += MAXALIGN(nslots * sizeof(int));
231 
232  /* Initialize LWLocks */
233  shared->buffer_locks = (LWLockPadded *) (ptr + offset);
234  offset += MAXALIGN(nslots * sizeof(LWLockPadded));
235 
236  if (nlsns > 0)
237  {
238  shared->group_lsn = (XLogRecPtr *) (ptr + offset);
239  offset += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr));
240  }
241 
242  ptr += BUFFERALIGN(offset);
243  for (slotno = 0; slotno < nslots; slotno++)
244  {
245  LWLockInitialize(&shared->buffer_locks[slotno].lock,
246  tranche_id);
247 
248  shared->page_buffer[slotno] = ptr;
249  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
250  shared->page_dirty[slotno] = false;
251  shared->page_lru_count[slotno] = 0;
252  ptr += BLCKSZ;
253  }
254 
255  /* Should fit to estimated shmem size */
256  Assert(ptr - (char *) shared <= SimpleLruShmemSize(nslots, nlsns));
257  }
258  else
259  Assert(found);
260 
261  /*
262  * Initialize the unshared control struct, including directory path. We
263  * assume caller set PagePrecedes.
264  */
265  ctl->shared = shared;
266  ctl->sync_handler = sync_handler;
267  strlcpy(ctl->Dir, subdir, sizeof(ctl->Dir));
268 }
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:155
int pgstat_slru_index(const char *name)
Definition: pgstat.c:7139
SlruPageStatus * page_status
Definition: slru.h:65
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:69
XLogRecPtr * group_lsn
Definition: slru.h:79
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition: lwlock.c:745
SlruSharedData * SlruShared
Definition: slru.h:104
char Dir[64]
Definition: slru.h:131
LWLock lock
Definition: lwlock.h:78
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:746
size_t Size
Definition: c.h:474
#define MAXALIGN(LEN)
Definition: c.h:699
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:561
bool * page_dirty
Definition: slru.h:66
SlruShared shared
Definition: slru.h:112
#define BUFFERALIGN(LEN)
Definition: c.h:701

◆ SimpleLruReadPage()

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

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

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

◆ SimpleLruReadPage_ReadOnly()

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

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

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

◆ SimpleLruShmemSize()

Size SimpleLruShmemSize ( int  nslots,
int  nlsns 
)

Definition at line 155 of file slru.c.

References BUFFERALIGN, and MAXALIGN.

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

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

◆ SimpleLruTruncate()

void SimpleLruTruncate ( SlruCtl  ctl,
int  cutoffPage 
)

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

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

◆ SimpleLruWaitIO()

static void SimpleLruWaitIO ( SlruCtl  ctl,
int  slotno 
)
static

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

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

◆ SimpleLruWriteAll()

void SimpleLruWriteAll ( SlruCtl  ctl,
bool  allow_redirtied 
)

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

1156 {
1157  SlruShared shared = ctl->shared;
1158  SlruWriteAllData fdata;
1159  int slotno;
1160  int pageno = 0;
1161  int i;
1162  bool ok;
1163 
1164  /* update the stats counter of flushes */
1166 
1167  /*
1168  * Find and write dirty pages
1169  */
1170  fdata.num_files = 0;
1171 
1173 
1174  for (slotno = 0; slotno < shared->num_slots; slotno++)
1175  {
1176  SlruInternalWritePage(ctl, slotno, &fdata);
1177 
1178  /*
1179  * In some places (e.g. checkpoints), we cannot assert that the slot
1180  * is clean now, since another process might have re-dirtied it
1181  * already. That's okay.
1182  */
1183  Assert(allow_redirtied ||
1184  shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
1185  (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1186  !shared->page_dirty[slotno]));
1187  }
1188 
1189  LWLockRelease(shared->ControlLock);
1190 
1191  /*
1192  * Now close any files that were open
1193  */
1194  ok = true;
1195  for (i = 0; i < fdata.num_files; i++)
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 
1208  /* Ensure that directory entries for new files are on disk. */
1209  if (ctl->sync_handler != SYNC_HANDLER_NONE)
1210  fsync_fname(ctl->Dir, true);
1211 }
LWLock * ControlLock
Definition: slru.h:55
void fsync_fname(const char *fname, bool isdir)
Definition: fd.c:633
static SlruErrorCause slru_errcause
Definition: slru.c:133
void pgstat_count_slru_flush(int slru_idx)
Definition: pgstat.c:7224
static void SlruReportIOError(SlruCtl ctl, int pageno, TransactionId xid)
Definition: slru.c:930
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
int segno[MAX_WRITEALL_BUFFERS]
Definition: slru.c:77
int fd[MAX_WRITEALL_BUFFERS]
Definition: slru.c:76
SlruPageStatus * page_status
Definition: slru.h:65
int num_files
Definition: slru.c:75
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruWriteAll fdata)
Definition: slru.c:538
#define InvalidTransactionId
Definition: transam.h:31
int CloseTransientFile(int fd)
Definition: fd.c:2549
char Dir[64]
Definition: slru.h:131
#define Assert(condition)
Definition: c.h:746
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
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:134
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 613 of file slru.c.

References SlruInternalWritePage().

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

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

◆ SimpleLruZeroLSNs()

static void SimpleLruZeroLSNs ( SlruCtl  ctl,
int  slotno 
)
static

Definition at line 323 of file slru.c.

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

Referenced by SimpleLruReadPage(), and SimpleLruZeroPage().

324 {
325  SlruShared shared = ctl->shared;
326 
327  if (shared->lsn_groups_per_page > 0)
328  MemSet(&shared->group_lsn[slotno * shared->lsn_groups_per_page], 0,
329  shared->lsn_groups_per_page * sizeof(XLogRecPtr));
330 }
#define MemSet(start, val, len)
Definition: c.h:950
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 279 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().

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

◆ SlruDeleteSegment()

void SlruDeleteSegment ( SlruCtl  ctl,
int  segno 
)

Definition at line 1321 of file slru.c.

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

Referenced by PerformMembersTruncation().

1322 {
1323  SlruShared shared = ctl->shared;
1324  int slotno;
1325  char path[MAXPGPATH];
1326  bool did_write;
1327 
1328  /* Clean out any possibly existing references to the segment. */
1330 restart:
1331  did_write = false;
1332  for (slotno = 0; slotno < shared->num_slots; slotno++)
1333  {
1334  int pagesegno = shared->page_number[slotno] / SLRU_PAGES_PER_SEGMENT;
1335 
1336  if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
1337  continue;
1338 
1339  /* not the segment we're looking for */
1340  if (pagesegno != segno)
1341  continue;
1342 
1343  /* If page is clean, just change state to EMPTY (expected case). */
1344  if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1345  !shared->page_dirty[slotno])
1346  {
1347  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
1348  continue;
1349  }
1350 
1351  /* Same logic as SimpleLruTruncate() */
1352  if (shared->page_status[slotno] == SLRU_PAGE_VALID)
1353  SlruInternalWritePage(ctl, slotno, NULL);
1354  else
1355  SimpleLruWaitIO(ctl, slotno);
1356 
1357  did_write = true;
1358  }
1359 
1360  /*
1361  * Be extra careful and re-check. The IO functions release the control
1362  * lock, so new pages could have been read in.
1363  */
1364  if (did_write)
1365  goto restart;
1366 
1367  snprintf(path, MAXPGPATH, "%s/%04X", ctl->Dir, segno);
1368  ereport(DEBUG2,
1369  (errmsg("removing file \"%s\"", path)));
1370 
1371  /*
1372  * Tell the checkpointer to forget any sync requests, before we unlink the
1373  * file.
1374  */
1375  if (ctl->sync_handler != SYNC_HANDLER_NONE)
1376  {
1377  FileTag tag;
1378 
1379  INIT_SLRUFILETAG(tag, ctl->sync_handler, segno);
1381  }
1382 
1383  unlink(path);
1384 
1385  LWLockRelease(shared->ControlLock);
1386 }
LWLock * ControlLock
Definition: slru.h:55
int * page_number
Definition: slru.h:67
#define INIT_SLRUFILETAG(a, xx_handler, xx_segno)
Definition: slru.c:87
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
SlruPageStatus * page_status
Definition: slru.h:65
#define MAXPGPATH
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruWriteAll fdata)
Definition: slru.c:538
#define DEBUG2
Definition: elog.h:24
static void SimpleLruWaitIO(SlruCtl ctl, int slotno)
Definition: slru.c:340
char Dir[64]
Definition: slru.h:131
bool RegisterSyncRequest(const FileTag *ftag, SyncRequestType type, bool retryOnError)
Definition: sync.c:554
#define ereport(elevel,...)
Definition: elog.h:144
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
SyncRequestHandler sync_handler
Definition: slru.h:118
int num_slots
Definition: slru.h:58
int errmsg(const char *fmt,...)
Definition: elog.c:821
bool * page_dirty
Definition: slru.h:66
SlruShared shared
Definition: slru.h:112
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:34
#define snprintf
Definition: port.h:215
Definition: sync.h:50

◆ SlruInternalDeleteSegment()

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

Definition at line 1307 of file slru.c.

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

Referenced by SlruScanDirCbDeleteAll(), and SlruScanDirCbDeleteCutoff().

1308 {
1309  char path[MAXPGPATH];
1310 
1311  snprintf(path, MAXPGPATH, "%s/%s", ctl->Dir, filename);
1312  ereport(DEBUG2,
1313  (errmsg("removing file \"%s\"", path)));
1314  unlink(path);
1315 }
#define MAXPGPATH
#define DEBUG2
Definition: elog.h:24
char Dir[64]
Definition: slru.h:131
#define ereport(elevel,...)
Definition: elog.h:144
static char * filename
Definition: pg_dumpall.c:91
int errmsg(const char *fmt,...)
Definition: elog.c:821
#define snprintf
Definition: port.h:215

◆ SlruInternalWritePage()

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

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

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

◆ SlruPhysicalReadPage()

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

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

684 {
685  SlruShared shared = ctl->shared;
686  int segno = pageno / SLRU_PAGES_PER_SEGMENT;
687  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
688  off_t offset = rpageno * BLCKSZ;
689  char path[MAXPGPATH];
690  int fd;
691 
692  SlruFileName(ctl, path, segno);
693 
694  /*
695  * In a crash-and-restart situation, it's possible for us to receive
696  * commands to set the commit status of transactions whose bits are in
697  * already-truncated segments of the commit log (see notes in
698  * SlruPhysicalWritePage). Hence, if we are InRecovery, allow the case
699  * where the file doesn't exist, and return zeroes instead.
700  */
701  fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
702  if (fd < 0)
703  {
704  if (errno != ENOENT || !InRecovery)
705  {
707  slru_errno = errno;
708  return false;
709  }
710 
711  ereport(LOG,
712  (errmsg("file \"%s\" doesn't exist, reading as zeroes",
713  path)));
714  MemSet(shared->page_buffer[slotno], 0, BLCKSZ);
715  return true;
716  }
717 
718  errno = 0;
720  if (pg_pread(fd, shared->page_buffer[slotno], BLCKSZ, offset) != BLCKSZ)
721  {
724  slru_errno = errno;
725  CloseTransientFile(fd);
726  return false;
727  }
729 
730  if (CloseTransientFile(fd) != 0)
731  {
733  slru_errno = errno;
734  return false;
735  }
736 
737  return true;
738 }
char ** page_buffer
Definition: slru.h:64
bool InRecovery
Definition: xlog.c:205
#define MemSet(start, val, len)
Definition: c.h:950
static SlruErrorCause slru_errcause
Definition: slru.c:133
#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:1213
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:2372
#define MAXPGPATH
static void pgstat_report_wait_end(void)
Definition: pgstat.h:1460
int CloseTransientFile(int fd)
Definition: fd.c:2549
#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:1436
static int slru_errno
Definition: slru.c:134
int errmsg(const char *fmt,...)
Definition: elog.c:821
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 755 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().

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

◆ SlruReportIOError()

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

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

931 {
932  int segno = pageno / SLRU_PAGES_PER_SEGMENT;
933  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
934  int offset = rpageno * BLCKSZ;
935  char path[MAXPGPATH];
936 
937  SlruFileName(ctl, path, segno);
938  errno = slru_errno;
939  switch (slru_errcause)
940  {
941  case SLRU_OPEN_FAILED:
942  ereport(ERROR,
944  errmsg("could not access status of transaction %u", xid),
945  errdetail("Could not open file \"%s\": %m.", path)));
946  break;
947  case SLRU_SEEK_FAILED:
948  ereport(ERROR,
950  errmsg("could not access status of transaction %u", xid),
951  errdetail("Could not seek in file \"%s\" to offset %u: %m.",
952  path, offset)));
953  break;
954  case SLRU_READ_FAILED:
955  if (errno)
956  ereport(ERROR,
958  errmsg("could not access status of transaction %u", xid),
959  errdetail("Could not read from file \"%s\" at offset %u: %m.",
960  path, offset)));
961  else
962  ereport(ERROR,
963  (errmsg("could not access status of transaction %u", xid),
964  errdetail("Could not read from file \"%s\" at offset %u: read too few bytes.", path, offset)));
965  break;
966  case SLRU_WRITE_FAILED:
967  if (errno)
968  ereport(ERROR,
970  errmsg("could not access status of transaction %u", xid),
971  errdetail("Could not write to file \"%s\" at offset %u: %m.",
972  path, offset)));
973  else
974  ereport(ERROR,
975  (errmsg("could not access status of transaction %u", xid),
976  errdetail("Could not write to file \"%s\" at offset %u: wrote too few bytes.",
977  path, offset)));
978  break;
979  case SLRU_FSYNC_FAILED:
982  errmsg("could not access status of transaction %u", xid),
983  errdetail("Could not fsync file \"%s\": %m.",
984  path)));
985  break;
986  case SLRU_CLOSE_FAILED:
987  ereport(ERROR,
989  errmsg("could not access status of transaction %u", xid),
990  errdetail("Could not close file \"%s\": %m.",
991  path)));
992  break;
993  default:
994  /* can't get here, we trust */
995  elog(ERROR, "unrecognized SimpleLru error cause: %d",
996  (int) slru_errcause);
997  break;
998  }
999 }
static SlruErrorCause slru_errcause
Definition: slru.c:133
#define ERROR
Definition: elog.h:43
#define MAXPGPATH
int errdetail(const char *fmt,...)
Definition: elog.c:954
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:3603
#define ereport(elevel,...)
Definition: elog.h:144
static int slru_errno
Definition: slru.c:134
int errmsg(const char *fmt,...)
Definition: elog.c:821
#define elog(elevel,...)
Definition: elog.h:214
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:34

◆ SlruScanDirCbDeleteAll()

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

Definition at line 1426 of file slru.c.

References SlruInternalDeleteSegment().

Referenced by AsyncShmemInit(), and DeactivateCommitTs().

1427 {
1429 
1430  return false; /* keep going */
1431 }
static void SlruInternalDeleteSegment(SlruCtl ctl, char *filename)
Definition: slru.c:1307
static char * filename
Definition: pg_dumpall.c:91

◆ SlruScanDirCbDeleteCutoff()

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

Definition at line 1411 of file slru.c.

References SlruCtlData::PagePrecedes, and SlruInternalDeleteSegment().

Referenced by SimpleLruTruncate().

1412 {
1413  int cutoffPage = *(int *) data;
1414 
1415  if (ctl->PagePrecedes(segpage, cutoffPage))
1417 
1418  return false; /* keep going */
1419 }
static void SlruInternalDeleteSegment(SlruCtl ctl, char *filename)
Definition: slru.c:1307
static char * filename
Definition: pg_dumpall.c:91
bool(* PagePrecedes)(int, int)
Definition: slru.h:125

◆ SlruScanDirCbReportPresence()

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

Definition at line 1394 of file slru.c.

References SlruCtlData::PagePrecedes, and SLRU_PAGES_PER_SEGMENT.

Referenced by TruncateCLOG(), and TruncateCommitTs().

1395 {
1396  int cutoffPage = *(int *) data;
1397 
1398  cutoffPage -= cutoffPage % SLRU_PAGES_PER_SEGMENT;
1399 
1400  if (ctl->PagePrecedes(segpage, cutoffPage))
1401  return true; /* found one; don't iterate any more */
1402 
1403  return false; /* keep going */
1404 }
bool(* PagePrecedes)(int, int)
Definition: slru.h:125
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:34

◆ SlruScanDirectory()

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

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

1450 {
1451  bool retval = false;
1452  DIR *cldir;
1453  struct dirent *clde;
1454  int segno;
1455  int segpage;
1456 
1457  cldir = AllocateDir(ctl->Dir);
1458  while ((clde = ReadDir(cldir, ctl->Dir)) != NULL)
1459  {
1460  size_t len;
1461 
1462  len = strlen(clde->d_name);
1463 
1464  if ((len == 4 || len == 5 || len == 6) &&
1465  strspn(clde->d_name, "0123456789ABCDEF") == len)
1466  {
1467  segno = (int) strtol(clde->d_name, NULL, 16);
1468  segpage = segno * SLRU_PAGES_PER_SEGMENT;
1469 
1470  elog(DEBUG2, "SlruScanDirectory invoking callback on %s/%s",
1471  ctl->Dir, clde->d_name);
1472  retval = callback(ctl, clde->d_name, segpage, data);
1473  if (retval)
1474  break;
1475  }
1476  }
1477  FreeDir(cldir);
1478 
1479  return retval;
1480 }
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:2583
char Dir[64]
Definition: slru.h:131
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2649
#define elog(elevel,...)
Definition: elog.h:214
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:2701

◆ SlruSelectLRUPage()

static int SlruSelectLRUPage ( SlruCtl  ctl,
int  pageno 
)
static

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

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

◆ SlruSyncFileTag()

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

Definition at line 1489 of file slru.c.

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

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

1490 {
1491  int fd;
1492  int save_errno;
1493  int result;
1494 
1495  SlruFileName(ctl, path, ftag->segno);
1496 
1497  fd = OpenTransientFile(path, O_RDWR | PG_BINARY);
1498  if (fd < 0)
1499  return -1;
1500 
1501  result = pg_fsync(fd);
1502  save_errno = errno;
1503 
1504  CloseTransientFile(fd);
1505 
1506  errno = save_errno;
1507  return result;
1508 }
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:1213
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2372
int CloseTransientFile(int fd)
Definition: fd.c:2549
#define SlruFileName(ctl, path, seg)
Definition: slru.c:62
int pg_fsync(int fd)
Definition: fd.c:346

Variable Documentation

◆ slru_errcause

◆ slru_errno