PostgreSQL Source Code  git master
slru.h File Reference
#include "access/xlogdefs.h"
#include "storage/lwlock.h"
#include "storage/sync.h"
Include dependency graph for slru.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  SlruSharedData
 
struct  SlruCtlData
 

Macros

#define SLRU_PAGES_PER_SEGMENT   32
 
#define SlruPagePrecedesUnitTests(ctl, per_page)   do {} while (0)
 

Typedefs

typedef struct SlruSharedData SlruSharedData
 
typedef SlruSharedDataSlruShared
 
typedef struct SlruCtlData SlruCtlData
 
typedef SlruCtlDataSlruCtl
 
typedef bool(* SlruScanCallback) (SlruCtl ctl, char *filename, int64 segpage, void *data)
 

Enumerations

enum  SlruPageStatus { SLRU_PAGE_EMPTY , SLRU_PAGE_READ_IN_PROGRESS , SLRU_PAGE_VALID , SLRU_PAGE_WRITE_IN_PROGRESS }
 

Functions

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, bool long_segment_names)
 
int SimpleLruZeroPage (SlruCtl ctl, int64 pageno)
 
int SimpleLruReadPage (SlruCtl ctl, int64 pageno, bool write_ok, TransactionId xid)
 
int SimpleLruReadPage_ReadOnly (SlruCtl ctl, int64 pageno, TransactionId xid)
 
void SimpleLruWritePage (SlruCtl ctl, int slotno)
 
void SimpleLruWriteAll (SlruCtl ctl, bool allow_redirtied)
 
void SimpleLruTruncate (SlruCtl ctl, int64 cutoffPage)
 
bool SimpleLruDoesPhysicalPageExist (SlruCtl ctl, int64 pageno)
 
bool SlruScanDirectory (SlruCtl ctl, SlruScanCallback callback, void *data)
 
void SlruDeleteSegment (SlruCtl ctl, int64 segno)
 
int SlruSyncFileTag (SlruCtl ctl, const FileTag *ftag, char *path)
 
bool SlruScanDirCbReportPresence (SlruCtl ctl, char *filename, int64 segpage, void *data)
 
bool SlruScanDirCbDeleteAll (SlruCtl ctl, char *filename, int64 segpage, void *data)
 

Macro Definition Documentation

◆ SLRU_PAGES_PER_SEGMENT

#define SLRU_PAGES_PER_SEGMENT   32

Definition at line 34 of file slru.h.

◆ SlruPagePrecedesUnitTests

#define SlruPagePrecedesUnitTests (   ctl,
  per_page 
)    do {} while (0)

Definition at line 168 of file slru.h.

Typedef Documentation

◆ SlruCtl

typedef SlruCtlData* SlruCtl

Definition at line 150 of file slru.h.

◆ SlruCtlData

typedef struct SlruCtlData SlruCtlData

◆ SlruScanCallback

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

Definition at line 173 of file slru.h.

◆ SlruShared

Definition at line 107 of file slru.h.

◆ SlruSharedData

Enumeration Type Documentation

◆ SlruPageStatus

Enumerator
SLRU_PAGE_EMPTY 
SLRU_PAGE_READ_IN_PROGRESS 
SLRU_PAGE_VALID 
SLRU_PAGE_WRITE_IN_PROGRESS 

Definition at line 42 of file slru.h.

43 {
44  SLRU_PAGE_EMPTY, /* buffer is not in use */
45  SLRU_PAGE_READ_IN_PROGRESS, /* page is being read in */
46  SLRU_PAGE_VALID, /* page is valid and not being written */
47  SLRU_PAGE_WRITE_IN_PROGRESS, /* page is being written out */
SlruPageStatus
Definition: slru.h:43
@ SLRU_PAGE_VALID
Definition: slru.h:46
@ SLRU_PAGE_WRITE_IN_PROGRESS
Definition: slru.h:47
@ SLRU_PAGE_READ_IN_PROGRESS
Definition: slru.h:45
@ SLRU_PAGE_EMPTY
Definition: slru.h:44

Function Documentation

◆ SimpleLruDoesPhysicalPageExist()

bool SimpleLruDoesPhysicalPageExist ( SlruCtl  ctl,
int64  pageno 
)

Definition at line 661 of file slru.c.

662 {
663  int64 segno = pageno / SLRU_PAGES_PER_SEGMENT;
664  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
665  int offset = rpageno * BLCKSZ;
666  char path[MAXPGPATH];
667  int fd;
668  bool result;
669  off_t endpos;
670 
671  /* update the stats counter of checked pages */
673 
674  SlruFileName(ctl, path, segno);
675 
676  fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
677  if (fd < 0)
678  {
679  /* expected: file doesn't exist */
680  if (errno == ENOENT)
681  return false;
682 
683  /* report error normally */
685  slru_errno = errno;
686  SlruReportIOError(ctl, pageno, 0);
687  }
688 
689  if ((endpos = lseek(fd, 0, SEEK_END)) < 0)
690  {
692  slru_errno = errno;
693  SlruReportIOError(ctl, pageno, 0);
694  }
695 
696  result = endpos >= (off_t) (offset + BLCKSZ);
697 
698  if (CloseTransientFile(fd) != 0)
699  {
701  slru_errno = errno;
702  return false;
703  }
704 
705  return result;
706 }
#define PG_BINARY
Definition: c.h:1262
int CloseTransientFile(int fd)
Definition: fd.c:2809
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2633
#define MAXPGPATH
static XLogRecPtr endpos
Definition: pg_receivewal.c:56
void pgstat_count_slru_page_exists(int slru_idx)
Definition: pgstat_slru.c:71
static int fd(const char *x, int i)
Definition: preproc-init.c:105
static int SlruFileName(SlruCtl ctl, char *path, int64 segno)
Definition: slru.c:65
static void SlruReportIOError(SlruCtl ctl, int64 pageno, TransactionId xid)
Definition: slru.c:966
static SlruErrorCause slru_errcause
Definition: slru.c:160
static int slru_errno
Definition: slru.c:161
@ SLRU_SEEK_FAILED
Definition: slru.c:153
@ SLRU_OPEN_FAILED
Definition: slru.c:152
@ SLRU_CLOSE_FAILED
Definition: slru.c:157
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:34
SlruShared shared
Definition: slru.h:115
int slru_stats_idx
Definition: slru.h:104

References CloseTransientFile(), endpos, 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(), MaybeExtendOffsetSlru(), and test_slru_page_exists().

◆ SimpleLruInit()

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

Definition at line 215 of file slru.c.

218 {
219  SlruShared shared;
220  bool found;
221 
222  shared = (SlruShared) ShmemInitStruct(name,
223  SimpleLruShmemSize(nslots, nlsns),
224  &found);
225 
226  if (!IsUnderPostmaster)
227  {
228  /* Initialize locks and shared memory area */
229  char *ptr;
230  Size offset;
231  int slotno;
232 
233  Assert(!found);
234 
235  memset(shared, 0, sizeof(SlruSharedData));
236 
237  shared->ControlLock = ctllock;
238 
239  shared->num_slots = nslots;
240  shared->lsn_groups_per_page = nlsns;
241 
242  shared->cur_lru_count = 0;
244 
246 
247  ptr = (char *) shared;
248  offset = MAXALIGN(sizeof(SlruSharedData));
249  shared->page_buffer = (char **) (ptr + offset);
250  offset += MAXALIGN(nslots * sizeof(char *));
251  shared->page_status = (SlruPageStatus *) (ptr + offset);
252  offset += MAXALIGN(nslots * sizeof(SlruPageStatus));
253  shared->page_dirty = (bool *) (ptr + offset);
254  offset += MAXALIGN(nslots * sizeof(bool));
255  shared->page_number = (int64 *) (ptr + offset);
256  offset += MAXALIGN(nslots * sizeof(int64));
257  shared->page_lru_count = (int *) (ptr + offset);
258  offset += MAXALIGN(nslots * sizeof(int));
259 
260  /* Initialize LWLocks */
261  shared->buffer_locks = (LWLockPadded *) (ptr + offset);
262  offset += MAXALIGN(nslots * sizeof(LWLockPadded));
263 
264  if (nlsns > 0)
265  {
266  shared->group_lsn = (XLogRecPtr *) (ptr + offset);
267  offset += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr));
268  }
269 
270  ptr += BUFFERALIGN(offset);
271  for (slotno = 0; slotno < nslots; slotno++)
272  {
273  LWLockInitialize(&shared->buffer_locks[slotno].lock,
274  tranche_id);
275 
276  shared->page_buffer[slotno] = ptr;
277  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
278  shared->page_dirty[slotno] = false;
279  shared->page_lru_count[slotno] = 0;
280  ptr += BLCKSZ;
281  }
282 
283  /* Should fit to estimated shmem size */
284  Assert(ptr - (char *) shared <= SimpleLruShmemSize(nslots, nlsns));
285  }
286  else
287  Assert(found);
288 
289  /*
290  * Initialize the unshared control struct, including directory path. We
291  * assume caller set PagePrecedes.
292  */
293  ctl->shared = shared;
294  ctl->sync_handler = sync_handler;
295  ctl->long_segment_names = long_segment_names;
296  strlcpy(ctl->Dir, subdir, sizeof(ctl->Dir));
297 }
static void pg_atomic_init_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition: atomics.h:410
#define MAXALIGN(LEN)
Definition: c.h:800
#define BUFFERALIGN(LEN)
Definition: c.h:802
size_t Size
Definition: c.h:594
bool IsUnderPostmaster
Definition: globals.c:116
Assert(fmt[strlen(fmt) - 1] !='\n')
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition: lwlock.c:703
int pgstat_get_slru_index(const char *name)
Definition: pgstat_slru.c:132
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:388
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:183
SlruSharedData * SlruShared
Definition: slru.h:107
bool long_segment_names
Definition: slru.h:141
SyncRequestHandler sync_handler
Definition: slru.h:121
char Dir[64]
Definition: slru.h:147
int64 * page_number
Definition: slru.h:70
int num_slots
Definition: slru.h:61
int * page_lru_count
Definition: slru.h:71
pg_atomic_uint64 latest_page_number
Definition: slru.h:101
XLogRecPtr * group_lsn
Definition: slru.h:82
int cur_lru_count
Definition: slru.h:94
int lsn_groups_per_page
Definition: slru.h:83
SlruPageStatus * page_status
Definition: slru.h:68
LWLock * ControlLock
Definition: slru.h:58
bool * page_dirty
Definition: slru.h:69
LWLockPadded * buffer_locks
Definition: slru.h:72
char ** page_buffer
Definition: slru.h:67
LWLock lock
Definition: lwlock.h:69
const char * name
uint64 XLogRecPtr
Definition: xlogdefs.h:21

References Assert(), SlruSharedData::buffer_locks, BUFFERALIGN, SlruSharedData::ControlLock, SlruSharedData::cur_lru_count, SlruCtlData::Dir, SlruSharedData::group_lsn, IsUnderPostmaster, SlruSharedData::latest_page_number, LWLockPadded::lock, SlruCtlData::long_segment_names, SlruSharedData::lsn_groups_per_page, LWLockInitialize(), MAXALIGN, name, SlruSharedData::num_slots, SlruSharedData::page_buffer, SlruSharedData::page_dirty, SlruSharedData::page_lru_count, SlruSharedData::page_number, SlruSharedData::page_status, pg_atomic_init_u64(), pgstat_get_slru_index(), SlruCtlData::shared, ShmemInitStruct(), SimpleLruShmemSize(), SLRU_PAGE_EMPTY, SlruSharedData::slru_stats_idx, strlcpy(), and SlruCtlData::sync_handler.

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

◆ SimpleLruReadPage()

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

Definition at line 430 of file slru.c.

432 {
433  SlruShared shared = ctl->shared;
434 
435  /* Outer loop handles restart if we must wait for someone else's I/O */
436  for (;;)
437  {
438  int slotno;
439  bool ok;
440 
441  /* See if page already is in memory; if not, pick victim slot */
442  slotno = SlruSelectLRUPage(ctl, pageno);
443 
444  /* Did we find the page in memory? */
445  if (shared->page_number[slotno] == pageno &&
446  shared->page_status[slotno] != SLRU_PAGE_EMPTY)
447  {
448  /*
449  * If page is still being read in, we must wait for I/O. Likewise
450  * if the page is being written and the caller said that's not OK.
451  */
452  if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS ||
453  (shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS &&
454  !write_ok))
455  {
456  SimpleLruWaitIO(ctl, slotno);
457  /* Now we must recheck state from the top */
458  continue;
459  }
460  /* Otherwise, it's ready to use */
461  SlruRecentlyUsed(shared, slotno);
462 
463  /* update the stats counter of pages found in the SLRU */
465 
466  return slotno;
467  }
468 
469  /* We found no match; assert we selected a freeable slot */
470  Assert(shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
471  (shared->page_status[slotno] == SLRU_PAGE_VALID &&
472  !shared->page_dirty[slotno]));
473 
474  /* Mark the slot read-busy */
475  shared->page_number[slotno] = pageno;
476  shared->page_status[slotno] = SLRU_PAGE_READ_IN_PROGRESS;
477  shared->page_dirty[slotno] = false;
478 
479  /* Acquire per-buffer lock (cannot deadlock, see notes at top) */
480  LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_EXCLUSIVE);
481 
482  /* Release control lock while doing I/O */
483  LWLockRelease(shared->ControlLock);
484 
485  /* Do the read */
486  ok = SlruPhysicalReadPage(ctl, pageno, slotno);
487 
488  /* Set the LSNs for this newly read-in page to zero */
489  SimpleLruZeroLSNs(ctl, slotno);
490 
491  /* Re-acquire control lock and update page state */
493 
494  Assert(shared->page_number[slotno] == pageno &&
495  shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS &&
496  !shared->page_dirty[slotno]);
497 
498  shared->page_status[slotno] = ok ? SLRU_PAGE_VALID : SLRU_PAGE_EMPTY;
499 
500  LWLockRelease(&shared->buffer_locks[slotno].lock);
501 
502  /* Now it's okay to ereport if we failed */
503  if (!ok)
504  SlruReportIOError(ctl, pageno, xid);
505 
506  SlruRecentlyUsed(shared, slotno);
507 
508  /* update the stats counter of pages not found in SLRU */
510 
511  return slotno;
512  }
513 }
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1168
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781
@ LW_EXCLUSIVE
Definition: lwlock.h:116
void pgstat_count_slru_page_read(int slru_idx)
Definition: pgstat_slru.c:77
void pgstat_count_slru_page_hit(int slru_idx)
Definition: pgstat_slru.c:65
static bool SlruPhysicalReadPage(SlruCtl ctl, int64 pageno, int slotno)
Definition: slru.c:719
#define SlruRecentlyUsed(shared, slotno)
Definition: slru.c:140
static void SimpleLruZeroLSNs(SlruCtl ctl, int slotno)
Definition: slru.c:359
static void SimpleLruWaitIO(SlruCtl ctl, int slotno)
Definition: slru.c:376
static int SlruSelectLRUPage(SlruCtl ctl, int64 pageno)
Definition: slru.c:1051

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(), test_slru_page_read(), TransactionIdSetPageStatusInternal(), TrimCLOG(), and TrimMultiXact().

◆ SimpleLruReadPage_ReadOnly()

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

Definition at line 530 of file slru.c.

531 {
532  SlruShared shared = ctl->shared;
533  int slotno;
534 
535  /* Try to find the page while holding only shared lock */
537 
538  /* See if page is already in a buffer */
539  for (slotno = 0; slotno < shared->num_slots; slotno++)
540  {
541  if (shared->page_number[slotno] == pageno &&
542  shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
543  shared->page_status[slotno] != SLRU_PAGE_READ_IN_PROGRESS)
544  {
545  /* See comments for SlruRecentlyUsed macro */
546  SlruRecentlyUsed(shared, slotno);
547 
548  /* update the stats counter of pages found in the SLRU */
550 
551  return slotno;
552  }
553  }
554 
555  /* No luck, so switch to normal exclusive lock and do regular read */
556  LWLockRelease(shared->ControlLock);
558 
559  return SimpleLruReadPage(ctl, pageno, true, xid);
560 }
@ LW_SHARED
Definition: lwlock.h:117
int SimpleLruReadPage(SlruCtl ctl, int64 pageno, bool write_ok, TransactionId xid)
Definition: slru.c:430

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(), test_slru_page_readonly(), TransactionIdGetCommitTsData(), and TransactionIdGetStatus().

◆ SimpleLruShmemSize()

Size SimpleLruShmemSize ( int  nslots,
int  nlsns 
)

Definition at line 183 of file slru.c.

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

References BUFFERALIGN, and MAXALIGN.

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

◆ SimpleLruTruncate()

void SimpleLruTruncate ( SlruCtl  ctl,
int64  cutoffPage 
)

Definition at line 1269 of file slru.c.

1270 {
1271  SlruShared shared = ctl->shared;
1272 
1273  /* update the stats counter of truncates */
1275 
1276  /*
1277  * Scan shared memory and remove any pages preceding the cutoff page, to
1278  * ensure we won't rewrite them later. (Since this is normally called in
1279  * or just after a checkpoint, any dirty pages should have been flushed
1280  * already ... we're just being extra careful here.)
1281  */
1283 
1284 restart:
1285 
1286  /*
1287  * An important safety check: the current endpoint page must not be
1288  * eligible for removal. This check is just a backstop against wraparound
1289  * bugs elsewhere in SLRU handling, so we don't care if we read a slightly
1290  * outdated value; therefore we don't add a memory barrier.
1291  */
1293  cutoffPage))
1294  {
1295  LWLockRelease(shared->ControlLock);
1296  ereport(LOG,
1297  (errmsg("could not truncate directory \"%s\": apparent wraparound",
1298  ctl->Dir)));
1299  return;
1300  }
1301 
1302  for (int slotno = 0; slotno < shared->num_slots; slotno++)
1303  {
1304  if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
1305  continue;
1306  if (!ctl->PagePrecedes(shared->page_number[slotno], cutoffPage))
1307  continue;
1308 
1309  /*
1310  * If page is clean, just change state to EMPTY (expected case).
1311  */
1312  if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1313  !shared->page_dirty[slotno])
1314  {
1315  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
1316  continue;
1317  }
1318 
1319  /*
1320  * Hmm, we have (or may have) I/O operations acting on the page, so
1321  * we've got to wait for them to finish and then start again. This is
1322  * the same logic as in SlruSelectLRUPage. (XXX if page is dirty,
1323  * wouldn't it be OK to just discard it without writing it?
1324  * SlruMayDeleteSegment() uses a stricter qualification, so we might
1325  * not delete this page in the end; even if we don't delete it, we
1326  * won't have cause to read its data again. For now, keep the logic
1327  * the same as it was.)
1328  */
1329  if (shared->page_status[slotno] == SLRU_PAGE_VALID)
1330  SlruInternalWritePage(ctl, slotno, NULL);
1331  else
1332  SimpleLruWaitIO(ctl, slotno);
1333  goto restart;
1334  }
1335 
1336  LWLockRelease(shared->ControlLock);
1337 
1338  /* Now we can remove the old segment(s) */
1339  (void) SlruScanDirectory(ctl, SlruScanDirCbDeleteCutoff, &cutoffPage);
1340 }
static uint64 pg_atomic_read_u64(volatile pg_atomic_uint64 *ptr)
Definition: atomics.h:424
int errmsg(const char *fmt,...)
Definition: elog.c:1075
#define LOG
Definition: elog.h:31
#define ereport(elevel,...)
Definition: elog.h:149
void pgstat_count_slru_truncate(int slru_idx)
Definition: pgstat_slru.c:95
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruWriteAll fdata)
Definition: slru.c:574
bool SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data)
Definition: slru.c:1624
static bool SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename, int64 segpage, void *data)
Definition: slru.c:1561
bool(* PagePrecedes)(int64, int64)
Definition: slru.h:133

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, pg_atomic_read_u64(), 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(), test_slru_page_truncate(), TruncateCLOG(), TruncateCommitTs(), and TruncateSUBTRANS().

◆ SimpleLruWriteAll()

void SimpleLruWriteAll ( SlruCtl  ctl,
bool  allow_redirtied 
)

Definition at line 1199 of file slru.c.

1200 {
1201  SlruShared shared = ctl->shared;
1202  SlruWriteAllData fdata;
1203  int slotno;
1204  int64 pageno = 0;
1205  int i;
1206  bool ok;
1207 
1208  /* update the stats counter of flushes */
1210 
1211  /*
1212  * Find and write dirty pages
1213  */
1214  fdata.num_files = 0;
1215 
1217 
1218  for (slotno = 0; slotno < shared->num_slots; slotno++)
1219  {
1220  SlruInternalWritePage(ctl, slotno, &fdata);
1221 
1222  /*
1223  * In some places (e.g. checkpoints), we cannot assert that the slot
1224  * is clean now, since another process might have re-dirtied it
1225  * already. That's okay.
1226  */
1227  Assert(allow_redirtied ||
1228  shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
1229  (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1230  !shared->page_dirty[slotno]));
1231  }
1232 
1233  LWLockRelease(shared->ControlLock);
1234 
1235  /*
1236  * Now close any files that were open
1237  */
1238  ok = true;
1239  for (i = 0; i < fdata.num_files; i++)
1240  {
1241  if (CloseTransientFile(fdata.fd[i]) != 0)
1242  {
1244  slru_errno = errno;
1245  pageno = fdata.segno[i] * SLRU_PAGES_PER_SEGMENT;
1246  ok = false;
1247  }
1248  }
1249  if (!ok)
1251 
1252  /* Ensure that directory entries for new files are on disk. */
1253  if (ctl->sync_handler != SYNC_HANDLER_NONE)
1254  fsync_fname(ctl->Dir, true);
1255 }
void fsync_fname(const char *fname, bool isdir)
Definition: fd.c:756
int i
Definition: isn.c:73
void pgstat_count_slru_flush(int slru_idx)
Definition: pgstat_slru.c:89
int num_files
Definition: slru.c:102
int fd[MAX_WRITEALL_BUFFERS]
Definition: slru.c:103
int64 segno[MAX_WRITEALL_BUFFERS]
Definition: slru.c:104
@ SYNC_HANDLER_NONE
Definition: sync.h:42
#define InvalidTransactionId
Definition: transam.h:31

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(), find_multixact_start(), and test_slru_page_writeall().

◆ SimpleLruWritePage()

void SimpleLruWritePage ( SlruCtl  ctl,
int  slotno 
)

◆ SimpleLruZeroPage()

int SimpleLruZeroPage ( SlruCtl  ctl,
int64  pageno 
)

Definition at line 308 of file slru.c.

309 {
310  SlruShared shared = ctl->shared;
311  int slotno;
312 
313  /* Find a suitable buffer slot for the page */
314  slotno = SlruSelectLRUPage(ctl, pageno);
315  Assert(shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
316  (shared->page_status[slotno] == SLRU_PAGE_VALID &&
317  !shared->page_dirty[slotno]) ||
318  shared->page_number[slotno] == pageno);
319 
320  /* Mark the slot as containing this page */
321  shared->page_number[slotno] = pageno;
322  shared->page_status[slotno] = SLRU_PAGE_VALID;
323  shared->page_dirty[slotno] = true;
324  SlruRecentlyUsed(shared, slotno);
325 
326  /* Set the buffer to zeroes */
327  MemSet(shared->page_buffer[slotno], 0, BLCKSZ);
328 
329  /* Set the LSNs for this new page to zero */
330  SimpleLruZeroLSNs(ctl, slotno);
331 
332  /*
333  * Assume this page is now the latest active page.
334  *
335  * Note that because both this routine and SlruSelectLRUPage run with
336  * ControlLock held, it is not possible for this to be zeroing a page that
337  * SlruSelectLRUPage is going to evict simultaneously. Therefore, there's
338  * no memory barrier here.
339  */
340  pg_atomic_write_u64(&shared->latest_page_number, pageno);
341 
342  /* update the stats counter of zeroed pages */
344 
345  return slotno;
346 }
static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition: atomics.h:433
#define MemSet(start, val, len)
Definition: c.h:1009
void pgstat_count_slru_page_zeroed(int slru_idx)
Definition: pgstat_slru.c:59

References Assert(), SlruSharedData::latest_page_number, MemSet, SlruSharedData::page_buffer, SlruSharedData::page_dirty, SlruSharedData::page_number, SlruSharedData::page_status, pg_atomic_write_u64(), 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(), test_slru_page_write(), ZeroCLOGPage(), ZeroCommitTsPage(), ZeroMultiXactMemberPage(), ZeroMultiXactOffsetPage(), and ZeroSUBTRANSPage().

◆ SlruDeleteSegment()

void SlruDeleteSegment ( SlruCtl  ctl,
int64  segno 
)

Definition at line 1372 of file slru.c.

1373 {
1374  SlruShared shared = ctl->shared;
1375  int slotno;
1376  bool did_write;
1377 
1378  /* Clean out any possibly existing references to the segment. */
1380 restart:
1381  did_write = false;
1382  for (slotno = 0; slotno < shared->num_slots; slotno++)
1383  {
1384  int pagesegno = shared->page_number[slotno] / SLRU_PAGES_PER_SEGMENT;
1385 
1386  if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
1387  continue;
1388 
1389  /* not the segment we're looking for */
1390  if (pagesegno != segno)
1391  continue;
1392 
1393  /* If page is clean, just change state to EMPTY (expected case). */
1394  if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1395  !shared->page_dirty[slotno])
1396  {
1397  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
1398  continue;
1399  }
1400 
1401  /* Same logic as SimpleLruTruncate() */
1402  if (shared->page_status[slotno] == SLRU_PAGE_VALID)
1403  SlruInternalWritePage(ctl, slotno, NULL);
1404  else
1405  SimpleLruWaitIO(ctl, slotno);
1406 
1407  did_write = true;
1408  }
1409 
1410  /*
1411  * Be extra careful and re-check. The IO functions release the control
1412  * lock, so new pages could have been read in.
1413  */
1414  if (did_write)
1415  goto restart;
1416 
1417  SlruInternalDeleteSegment(ctl, segno);
1418 
1419  LWLockRelease(shared->ControlLock);
1420 }
static void SlruInternalDeleteSegment(SlruCtl ctl, int64 segno)
Definition: slru.c:1349

References SlruSharedData::ControlLock, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SlruSharedData::num_slots, SlruSharedData::page_dirty, SlruSharedData::page_number, SlruSharedData::page_status, SlruWriteAllData::segno, SlruCtlData::shared, SimpleLruWaitIO(), SLRU_PAGE_EMPTY, SLRU_PAGE_VALID, SLRU_PAGES_PER_SEGMENT, SlruInternalDeleteSegment(), and SlruInternalWritePage().

Referenced by PerformMembersTruncation(), and test_slru_page_delete().

◆ SlruScanDirCbDeleteAll()

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

Definition at line 1577 of file slru.c.

1578 {
1580 
1581  return false; /* keep going */
1582 }

References SLRU_PAGES_PER_SEGMENT, and SlruInternalDeleteSegment().

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

◆ SlruScanDirCbReportPresence()

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

Definition at line 1545 of file slru.c.

1547 {
1548  int64 cutoffPage = *(int64 *) data;
1549 
1550  if (SlruMayDeleteSegment(ctl, segpage, cutoffPage))
1551  return true; /* found one; don't iterate any more */
1552 
1553  return false; /* keep going */
1554 }
const void * data
static bool SlruMayDeleteSegment(SlruCtl ctl, int64 segpage, int64 cutoffPage)
Definition: slru.c:1436

References data, and SlruMayDeleteSegment().

Referenced by TruncateCLOG(), and TruncateCommitTs().

◆ SlruScanDirectory()

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

Definition at line 1624 of file slru.c.

1625 {
1626  bool retval = false;
1627  DIR *cldir;
1628  struct dirent *clde;
1629  int64 segno;
1630  int64 segpage;
1631 
1632  cldir = AllocateDir(ctl->Dir);
1633  while ((clde = ReadDir(cldir, ctl->Dir)) != NULL)
1634  {
1635  size_t len;
1636 
1637  len = strlen(clde->d_name);
1638 
1640  strspn(clde->d_name, "0123456789ABCDEF") == len)
1641  {
1642  segno = strtoi64(clde->d_name, NULL, 16);
1643  segpage = segno * SLRU_PAGES_PER_SEGMENT;
1644 
1645  elog(DEBUG2, "SlruScanDirectory invoking callback on %s/%s",
1646  ctl->Dir, clde->d_name);
1647  retval = callback(ctl, clde->d_name, segpage, data);
1648  if (retval)
1649  break;
1650  }
1651  }
1652  FreeDir(cldir);
1653 
1654  return retval;
1655 }
#define strtoi64(str, endptr, base)
Definition: c.h:1286
#define DEBUG2
Definition: elog.h:29
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2909
int FreeDir(DIR *dir)
Definition: fd.c:2961
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2843
const void size_t len
static bool SlruCorrectSegmentFilenameLength(SlruCtl ctl, size_t len)
Definition: slru.c:1591
Definition: dirent.c:26
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:46

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

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

◆ SlruSyncFileTag()

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

Definition at line 1664 of file slru.c.

1665 {
1666  int fd;
1667  int save_errno;
1668  int result;
1669 
1670  SlruFileName(ctl, path, ftag->segno);
1671 
1672  fd = OpenTransientFile(path, O_RDWR | PG_BINARY);
1673  if (fd < 0)
1674  return -1;
1675 
1676  pgstat_report_wait_start(WAIT_EVENT_SLRU_FLUSH_SYNC);
1677  result = pg_fsync(fd);
1679  save_errno = errno;
1680 
1682 
1683  errno = save_errno;
1684  return result;
1685 }
int pg_fsync(int fd)
Definition: fd.c:386
uint64 segno
Definition: sync.h:55
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: wait_event.h:88
static void pgstat_report_wait_end(void)
Definition: wait_event.h:104

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

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