PostgreSQL Source Code  git master
slru.c File Reference
#include "postgres.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include "access/slru.h"
#include "access/transam.h"
#include "access/xlog.h"
#include "access/xlogutils.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "storage/fd.h"
#include "storage/shmem.h"
#include "utils/guc_hooks.h"
Include dependency graph for slru.c:

Go to the source code of this file.

Data Structures

struct  SlruWriteAllData
 

Macros

#define MAX_WRITEALL_BUFFERS   16
 
#define SLRU_BANK_BITSHIFT   4
 
#define SLRU_BANK_SIZE   (1 << SLRU_BANK_BITSHIFT)
 
#define SlotGetBankNumber(slotno)   ((slotno) >> SLRU_BANK_BITSHIFT)
 
#define INIT_SLRUFILETAG(a, xx_handler, xx_segno)
 

Typedefs

typedef struct SlruWriteAllData SlruWriteAllData
 
typedef struct SlruWriteAllDataSlruWriteAll
 

Enumerations

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

Functions

static int SlruFileName (SlruCtl ctl, char *path, int64 segno)
 
static void SimpleLruZeroLSNs (SlruCtl ctl, int slotno)
 
static void SimpleLruWaitIO (SlruCtl ctl, int slotno)
 
static void SlruInternalWritePage (SlruCtl ctl, int slotno, SlruWriteAll fdata)
 
static bool SlruPhysicalReadPage (SlruCtl ctl, int64 pageno, int slotno)
 
static bool SlruPhysicalWritePage (SlruCtl ctl, int64 pageno, int slotno, SlruWriteAll fdata)
 
static void SlruReportIOError (SlruCtl ctl, int64 pageno, TransactionId xid)
 
static int SlruSelectLRUPage (SlruCtl ctl, int64 pageno)
 
static bool SlruScanDirCbDeleteCutoff (SlruCtl ctl, char *filename, int64 segpage, void *data)
 
static void SlruInternalDeleteSegment (SlruCtl ctl, int64 segno)
 
static void SlruRecentlyUsed (SlruShared shared, int slotno)
 
Size SimpleLruShmemSize (int nslots, int nlsns)
 
int SimpleLruAutotuneBuffers (int divisor, int max)
 
void SimpleLruInit (SlruCtl ctl, const char *name, int nslots, int nlsns, const char *subdir, int buffer_tranche_id, int bank_tranche_id, SyncRequestHandler sync_handler, bool long_segment_names)
 
bool check_slru_buffers (const char *name, int *newval)
 
int SimpleLruZeroPage (SlruCtl ctl, int64 pageno)
 
int SimpleLruReadPage (SlruCtl ctl, int64 pageno, bool write_ok, TransactionId xid)
 
int SimpleLruReadPage_ReadOnly (SlruCtl ctl, int64 pageno, TransactionId xid)
 
void SimpleLruWritePage (SlruCtl ctl, int slotno)
 
bool SimpleLruDoesPhysicalPageExist (SlruCtl ctl, int64 pageno)
 
void SimpleLruWriteAll (SlruCtl ctl, bool allow_redirtied)
 
void SimpleLruTruncate (SlruCtl ctl, int64 cutoffPage)
 
void SlruDeleteSegment (SlruCtl ctl, int64 segno)
 
static bool SlruMayDeleteSegment (SlruCtl ctl, int64 segpage, int64 cutoffPage)
 
bool SlruScanDirCbReportPresence (SlruCtl ctl, char *filename, int64 segpage, void *data)
 
bool SlruScanDirCbDeleteAll (SlruCtl ctl, char *filename, int64 segpage, void *data)
 
static bool SlruCorrectSegmentFilenameLength (SlruCtl ctl, size_t len)
 
bool SlruScanDirectory (SlruCtl ctl, SlruScanCallback callback, void *data)
 
int SlruSyncFileTag (SlruCtl ctl, const FileTag *ftag, char *path)
 

Variables

static SlruErrorCause slru_errcause
 
static int slru_errno
 

Macro Definition Documentation

◆ INIT_SLRUFILETAG

#define INIT_SLRUFILETAG (   a,
  xx_handler,
  xx_segno 
)
Value:
( \
memset(&(a), 0, sizeof(FileTag)), \
(a).handler = (xx_handler), \
(a).segno = (xx_segno) \
)
int a
Definition: isn.c:69
Definition: sync.h:51

Definition at line 157 of file slru.c.

◆ MAX_WRITEALL_BUFFERS

#define MAX_WRITEALL_BUFFERS   16

Definition at line 124 of file slru.c.

◆ SlotGetBankNumber

#define SlotGetBankNumber (   slotno)    ((slotno) >> SLRU_BANK_BITSHIFT)

Definition at line 149 of file slru.c.

◆ SLRU_BANK_BITSHIFT

#define SLRU_BANK_BITSHIFT   4

Definition at line 143 of file slru.c.

◆ SLRU_BANK_SIZE

#define SLRU_BANK_SIZE   (1 << SLRU_BANK_BITSHIFT)

Definition at line 144 of file slru.c.

Typedef Documentation

◆ SlruWriteAll

typedef struct SlruWriteAllData* SlruWriteAll

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

166 {
SlruErrorCause
Definition: slru.c:166
@ SLRU_WRITE_FAILED
Definition: slru.c:170
@ SLRU_FSYNC_FAILED
Definition: slru.c:171
@ SLRU_SEEK_FAILED
Definition: slru.c:168
@ SLRU_OPEN_FAILED
Definition: slru.c:167
@ SLRU_CLOSE_FAILED
Definition: slru.c:172
@ SLRU_READ_FAILED
Definition: slru.c:169

Function Documentation

◆ check_slru_buffers()

bool check_slru_buffers ( const char *  name,
int *  newval 
)

Definition at line 355 of file slru.c.

356 {
357  /* Valid values are multiples of SLRU_BANK_SIZE */
358  if (*newval % SLRU_BANK_SIZE == 0)
359  return true;
360 
361  GUC_check_errdetail("\"%s\" must be a multiple of %d", name,
363  return false;
364 }
#define newval
#define GUC_check_errdetail
Definition: guc.h:472
#define SLRU_BANK_SIZE
Definition: slru.c:144
const char * name

References GUC_check_errdetail, name, newval, and SLRU_BANK_SIZE.

Referenced by check_commit_ts_buffers(), check_multixact_member_buffers(), check_multixact_offset_buffers(), check_notify_buffers(), check_serial_buffers(), check_subtrans_buffers(), and check_transaction_buffers().

◆ SimpleLruAutotuneBuffers()

int SimpleLruAutotuneBuffers ( int  divisor,
int  max 
)

Definition at line 232 of file slru.c.

233 {
234  return Min(max - (max % SLRU_BANK_SIZE),
236  NBuffers / divisor - (NBuffers / divisor) % SLRU_BANK_SIZE));
237 }
#define Min(x, y)
Definition: c.h:1004
#define Max(x, y)
Definition: c.h:998
int NBuffers
Definition: globals.c:140

References Max, Min, NBuffers, and SLRU_BANK_SIZE.

Referenced by CLOGShmemBuffers(), CommitTsShmemBuffers(), and SUBTRANSShmemBuffers().

◆ SimpleLruDoesPhysicalPageExist()

bool SimpleLruDoesPhysicalPageExist ( SlruCtl  ctl,
int64  pageno 
)

Definition at line 743 of file slru.c.

744 {
745  int64 segno = pageno / SLRU_PAGES_PER_SEGMENT;
746  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
747  int offset = rpageno * BLCKSZ;
748  char path[MAXPGPATH];
749  int fd;
750  bool result;
751  off_t endpos;
752 
753  /* update the stats counter of checked pages */
754  pgstat_count_slru_page_exists(ctl->shared->slru_stats_idx);
755 
756  SlruFileName(ctl, path, segno);
757 
758  fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
759  if (fd < 0)
760  {
761  /* expected: file doesn't exist */
762  if (errno == ENOENT)
763  return false;
764 
765  /* report error normally */
767  slru_errno = errno;
768  SlruReportIOError(ctl, pageno, 0);
769  }
770 
771  if ((endpos = lseek(fd, 0, SEEK_END)) < 0)
772  {
774  slru_errno = errno;
775  SlruReportIOError(ctl, pageno, 0);
776  }
777 
778  result = endpos >= (off_t) (offset + BLCKSZ);
779 
780  if (CloseTransientFile(fd) != 0)
781  {
783  slru_errno = errno;
784  return false;
785  }
786 
787  return result;
788 }
#define PG_BINARY
Definition: c.h:1273
int CloseTransientFile(int fd)
Definition: fd.c:2809
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2633
#define MAXPGPATH
static XLogRecPtr endpos
Definition: pg_receivewal.c:56
void pgstat_count_slru_page_exists(int slru_idx)
Definition: pgstat_slru.c:71
static int fd(const char *x, int i)
Definition: preproc-init.c:105
tree ctl
Definition: radixtree.h:1853
static int SlruFileName(SlruCtl ctl, char *path, int64 segno)
Definition: slru.c:91
static void SlruReportIOError(SlruCtl ctl, int64 pageno, TransactionId xid)
Definition: slru.c:1045
static SlruErrorCause slru_errcause
Definition: slru.c:175
static int slru_errno
Definition: slru.c:176
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:39

References CloseTransientFile(), ctl, endpos, fd(), MAXPGPATH, OpenTransientFile(), PG_BINARY, pgstat_count_slru_page_exists(), SlruWriteAllData::segno, SLRU_CLOSE_FAILED, slru_errcause, slru_errno, SLRU_OPEN_FAILED, SLRU_PAGES_PER_SEGMENT, SLRU_SEEK_FAILED, SlruFileName(), and SlruReportIOError().

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

◆ SimpleLruInit()

void SimpleLruInit ( SlruCtl  ctl,
const char *  name,
int  nslots,
int  nlsns,
const char *  subdir,
int  buffer_tranche_id,
int  bank_tranche_id,
SyncRequestHandler  sync_handler,
bool  long_segment_names 
)

Definition at line 252 of file slru.c.

255 {
256  SlruShared shared;
257  bool found;
258  int nbanks = nslots / SLRU_BANK_SIZE;
259 
260  Assert(nslots <= SLRU_MAX_ALLOWED_BUFFERS);
261 
262  shared = (SlruShared) ShmemInitStruct(name,
263  SimpleLruShmemSize(nslots, nlsns),
264  &found);
265 
266  if (!IsUnderPostmaster)
267  {
268  /* Initialize locks and shared memory area */
269  char *ptr;
270  Size offset;
271 
272  Assert(!found);
273 
274  memset(shared, 0, sizeof(SlruSharedData));
275 
276  shared->num_slots = nslots;
277  shared->lsn_groups_per_page = nlsns;
278 
280 
282 
283  ptr = (char *) shared;
284  offset = MAXALIGN(sizeof(SlruSharedData));
285  shared->page_buffer = (char **) (ptr + offset);
286  offset += MAXALIGN(nslots * sizeof(char *));
287  shared->page_status = (SlruPageStatus *) (ptr + offset);
288  offset += MAXALIGN(nslots * sizeof(SlruPageStatus));
289  shared->page_dirty = (bool *) (ptr + offset);
290  offset += MAXALIGN(nslots * sizeof(bool));
291  shared->page_number = (int64 *) (ptr + offset);
292  offset += MAXALIGN(nslots * sizeof(int64));
293  shared->page_lru_count = (int *) (ptr + offset);
294  offset += MAXALIGN(nslots * sizeof(int));
295 
296  /* Initialize LWLocks */
297  shared->buffer_locks = (LWLockPadded *) (ptr + offset);
298  offset += MAXALIGN(nslots * sizeof(LWLockPadded));
299  shared->bank_locks = (LWLockPadded *) (ptr + offset);
300  offset += MAXALIGN(nbanks * sizeof(LWLockPadded));
301  shared->bank_cur_lru_count = (int *) (ptr + offset);
302  offset += MAXALIGN(nbanks * sizeof(int));
303 
304  if (nlsns > 0)
305  {
306  shared->group_lsn = (XLogRecPtr *) (ptr + offset);
307  offset += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr));
308  }
309 
310  ptr += BUFFERALIGN(offset);
311  for (int slotno = 0; slotno < nslots; slotno++)
312  {
313  LWLockInitialize(&shared->buffer_locks[slotno].lock,
314  buffer_tranche_id);
315 
316  shared->page_buffer[slotno] = ptr;
317  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
318  shared->page_dirty[slotno] = false;
319  shared->page_lru_count[slotno] = 0;
320  ptr += BLCKSZ;
321  }
322 
323  /* Initialize the slot banks. */
324  for (int bankno = 0; bankno < nbanks; bankno++)
325  {
326  LWLockInitialize(&shared->bank_locks[bankno].lock, bank_tranche_id);
327  shared->bank_cur_lru_count[bankno] = 0;
328  }
329 
330  /* Should fit to estimated shmem size */
331  Assert(ptr - (char *) shared <= SimpleLruShmemSize(nslots, nlsns));
332  }
333  else
334  {
335  Assert(found);
336  Assert(shared->num_slots == nslots);
337  }
338 
339  /*
340  * Initialize the unshared control struct, including directory path. We
341  * assume caller set PagePrecedes.
342  */
343  ctl->shared = shared;
344  ctl->sync_handler = sync_handler;
345  ctl->long_segment_names = long_segment_names;
346  ctl->bank_mask = (nslots / SLRU_BANK_SIZE) - 1;
347  strlcpy(ctl->Dir, subdir, sizeof(ctl->Dir));
348 }
static void pg_atomic_init_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition: atomics.h:446
#define MAXALIGN(LEN)
Definition: c.h:811
#define BUFFERALIGN(LEN)
Definition: c.h:813
#define Assert(condition)
Definition: c.h:858
size_t Size
Definition: c.h:605
bool IsUnderPostmaster
Definition: globals.c:118
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition: lwlock.c:707
int pgstat_get_slru_index(const char *name)
Definition: pgstat_slru.c:132
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:387
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:199
SlruSharedData * SlruShared
Definition: slru.h:121
#define SLRU_MAX_ALLOWED_BUFFERS
Definition: slru.h:24
SlruPageStatus
Definition: slru.h:48
@ SLRU_PAGE_EMPTY
Definition: slru.h:49
int slru_stats_idx
Definition: slru.h:118
int64 * page_number
Definition: slru.h:73
int num_slots
Definition: slru.h:64
LWLockPadded * bank_locks
Definition: slru.h:80
int * page_lru_count
Definition: slru.h:74
pg_atomic_uint64 latest_page_number
Definition: slru.h:115
XLogRecPtr * group_lsn
Definition: slru.h:107
int * bank_cur_lru_count
Definition: slru.h:97
int lsn_groups_per_page
Definition: slru.h:108
SlruPageStatus * page_status
Definition: slru.h:71
bool * page_dirty
Definition: slru.h:72
LWLockPadded * buffer_locks
Definition: slru.h:77
char ** page_buffer
Definition: slru.h:70
LWLock lock
Definition: lwlock.h:70
uint64 XLogRecPtr
Definition: xlogdefs.h:21

References Assert, SlruSharedData::bank_cur_lru_count, SlruSharedData::bank_locks, SlruSharedData::buffer_locks, BUFFERALIGN, ctl, SlruSharedData::group_lsn, IsUnderPostmaster, SlruSharedData::latest_page_number, LWLockPadded::lock, SlruSharedData::lsn_groups_per_page, LWLockInitialize(), MAXALIGN, name, SlruSharedData::num_slots, SlruSharedData::page_buffer, SlruSharedData::page_dirty, SlruSharedData::page_lru_count, SlruSharedData::page_number, SlruSharedData::page_status, pg_atomic_init_u64(), pgstat_get_slru_index(), ShmemInitStruct(), SimpleLruShmemSize(), SLRU_BANK_SIZE, SLRU_MAX_ALLOWED_BUFFERS, SLRU_PAGE_EMPTY, SlruSharedData::slru_stats_idx, and strlcpy().

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

◆ SimpleLruReadPage()

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

Definition at line 502 of file slru.c.

504 {
505  SlruShared shared = ctl->shared;
506  LWLock *banklock = SimpleLruGetBankLock(ctl, pageno);
507 
509 
510  /* Outer loop handles restart if we must wait for someone else's I/O */
511  for (;;)
512  {
513  int slotno;
514  bool ok;
515 
516  /* See if page already is in memory; if not, pick victim slot */
517  slotno = SlruSelectLRUPage(ctl, pageno);
518 
519  /* Did we find the page in memory? */
520  if (shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
521  shared->page_number[slotno] == pageno)
522  {
523  /*
524  * If page is still being read in, we must wait for I/O. Likewise
525  * if the page is being written and the caller said that's not OK.
526  */
527  if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS ||
528  (shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS &&
529  !write_ok))
530  {
531  SimpleLruWaitIO(ctl, slotno);
532  /* Now we must recheck state from the top */
533  continue;
534  }
535  /* Otherwise, it's ready to use */
536  SlruRecentlyUsed(shared, slotno);
537 
538  /* update the stats counter of pages found in the SLRU */
540 
541  return slotno;
542  }
543 
544  /* We found no match; assert we selected a freeable slot */
545  Assert(shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
546  (shared->page_status[slotno] == SLRU_PAGE_VALID &&
547  !shared->page_dirty[slotno]));
548 
549  /* Mark the slot read-busy */
550  shared->page_number[slotno] = pageno;
551  shared->page_status[slotno] = SLRU_PAGE_READ_IN_PROGRESS;
552  shared->page_dirty[slotno] = false;
553 
554  /* Acquire per-buffer lock (cannot deadlock, see notes at top) */
555  LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_EXCLUSIVE);
556 
557  /* Release bank lock while doing I/O */
558  LWLockRelease(banklock);
559 
560  /* Do the read */
561  ok = SlruPhysicalReadPage(ctl, pageno, slotno);
562 
563  /* Set the LSNs for this newly read-in page to zero */
564  SimpleLruZeroLSNs(ctl, slotno);
565 
566  /* Re-acquire bank control lock and update page state */
567  LWLockAcquire(banklock, LW_EXCLUSIVE);
568 
569  Assert(shared->page_number[slotno] == pageno &&
570  shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS &&
571  !shared->page_dirty[slotno]);
572 
573  shared->page_status[slotno] = ok ? SLRU_PAGE_VALID : SLRU_PAGE_EMPTY;
574 
575  LWLockRelease(&shared->buffer_locks[slotno].lock);
576 
577  /* Now it's okay to ereport if we failed */
578  if (!ok)
579  SlruReportIOError(ctl, pageno, xid);
580 
581  SlruRecentlyUsed(shared, slotno);
582 
583  /* update the stats counter of pages not found in SLRU */
585 
586  return slotno;
587  }
588 }
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1168
bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1937
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781
@ LW_EXCLUSIVE
Definition: lwlock.h:114
void pgstat_count_slru_page_read(int slru_idx)
Definition: pgstat_slru.c:77
void pgstat_count_slru_page_hit(int slru_idx)
Definition: pgstat_slru.c:65
static bool SlruPhysicalReadPage(SlruCtl ctl, int64 pageno, int slotno)
Definition: slru.c:801
static void SimpleLruZeroLSNs(SlruCtl ctl, int slotno)
Definition: slru.c:428
static void SimpleLruWaitIO(SlruCtl ctl, int slotno)
Definition: slru.c:445
static int SlruSelectLRUPage(SlruCtl ctl, int64 pageno)
Definition: slru.c:1166
static void SlruRecentlyUsed(SlruShared shared, int slotno)
Definition: slru.c:1120
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
Definition: slru.h:178
@ SLRU_PAGE_VALID
Definition: slru.h:51
@ SLRU_PAGE_WRITE_IN_PROGRESS
Definition: slru.h:52
@ SLRU_PAGE_READ_IN_PROGRESS
Definition: slru.h:50
Definition: lwlock.h:42

References Assert, SlruSharedData::buffer_locks, ctl, LWLockPadded::lock, LW_EXCLUSIVE, LWLockAcquire(), LWLockHeldByMeInMode(), LWLockRelease(), SlruSharedData::page_dirty, SlruSharedData::page_number, SlruSharedData::page_status, pgstat_count_slru_page_hit(), pgstat_count_slru_page_read(), SimpleLruGetBankLock(), SimpleLruWaitIO(), SimpleLruZeroLSNs(), SLRU_PAGE_EMPTY, SLRU_PAGE_READ_IN_PROGRESS, SLRU_PAGE_VALID, SLRU_PAGE_WRITE_IN_PROGRESS, SlruSharedData::slru_stats_idx, SlruPhysicalReadPage(), SlruRecentlyUsed(), SlruReportIOError(), and SlruSelectLRUPage().

Referenced by asyncQueueAddEntries(), GetMultiXactIdMembers(), RecordNewMultiXact(), SerialAdd(), SetXidCommitTsInPage(), SimpleLruReadPage_ReadOnly(), SubTransSetParent(), test_slru_page_read(), TransactionIdSetPageStatusInternal(), TrimCLOG(), and TrimMultiXact().

◆ SimpleLruReadPage_ReadOnly()

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

Definition at line 605 of file slru.c.

606 {
607  SlruShared shared = ctl->shared;
608  LWLock *banklock = SimpleLruGetBankLock(ctl, pageno);
609  int bankno = pageno & ctl->bank_mask;
610  int bankstart = bankno * SLRU_BANK_SIZE;
611  int bankend = bankstart + SLRU_BANK_SIZE;
612 
613  /* Try to find the page while holding only shared lock */
614  LWLockAcquire(banklock, LW_SHARED);
615 
616  /* See if page is already in a buffer */
617  for (int slotno = bankstart; slotno < bankend; slotno++)
618  {
619  if (shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
620  shared->page_number[slotno] == pageno &&
621  shared->page_status[slotno] != SLRU_PAGE_READ_IN_PROGRESS)
622  {
623  /* See comments for SlruRecentlyUsed macro */
624  SlruRecentlyUsed(shared, slotno);
625 
626  /* update the stats counter of pages found in the SLRU */
628 
629  return slotno;
630  }
631  }
632 
633  /* No luck, so switch to normal exclusive lock and do regular read */
634  LWLockRelease(banklock);
635  LWLockAcquire(banklock, LW_EXCLUSIVE);
636 
637  return SimpleLruReadPage(ctl, pageno, true, xid);
638 }
@ LW_SHARED
Definition: lwlock.h:115
int SimpleLruReadPage(SlruCtl ctl, int64 pageno, bool write_ok, TransactionId xid)
Definition: slru.c:502

References ctl, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), SlruSharedData::page_number, SlruSharedData::page_status, pgstat_count_slru_page_hit(), SimpleLruGetBankLock(), SimpleLruReadPage(), SLRU_BANK_SIZE, SLRU_PAGE_EMPTY, SLRU_PAGE_READ_IN_PROGRESS, SlruSharedData::slru_stats_idx, and SlruRecentlyUsed().

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

◆ SimpleLruShmemSize()

Size SimpleLruShmemSize ( int  nslots,
int  nlsns 
)

Definition at line 199 of file slru.c.

200 {
201  int nbanks = nslots / SLRU_BANK_SIZE;
202  Size sz;
203 
204  Assert(nslots <= SLRU_MAX_ALLOWED_BUFFERS);
205  Assert(nslots % SLRU_BANK_SIZE == 0);
206 
207  /* we assume nslots isn't so large as to risk overflow */
208  sz = MAXALIGN(sizeof(SlruSharedData));
209  sz += MAXALIGN(nslots * sizeof(char *)); /* page_buffer[] */
210  sz += MAXALIGN(nslots * sizeof(SlruPageStatus)); /* page_status[] */
211  sz += MAXALIGN(nslots * sizeof(bool)); /* page_dirty[] */
212  sz += MAXALIGN(nslots * sizeof(int64)); /* page_number[] */
213  sz += MAXALIGN(nslots * sizeof(int)); /* page_lru_count[] */
214  sz += MAXALIGN(nslots * sizeof(LWLockPadded)); /* buffer_locks[] */
215  sz += MAXALIGN(nbanks * sizeof(LWLockPadded)); /* bank_locks[] */
216  sz += MAXALIGN(nbanks * sizeof(int)); /* bank_cur_lru_count[] */
217 
218  if (nlsns > 0)
219  sz += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr)); /* group_lsn[] */
220 
221  return BUFFERALIGN(sz) + BLCKSZ * nslots;
222 }

References Assert, BUFFERALIGN, MAXALIGN, SLRU_BANK_SIZE, and SLRU_MAX_ALLOWED_BUFFERS.

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

◆ SimpleLruTruncate()

void SimpleLruTruncate ( SlruCtl  ctl,
int64  cutoffPage 
)

Definition at line 1405 of file slru.c.

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

References SlruSharedData::bank_locks, ctl, ereport, errmsg(), SlruSharedData::latest_page_number, LWLockPadded::lock, LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SlruSharedData::num_slots, SlruSharedData::page_dirty, SlruSharedData::page_number, SlruSharedData::page_status, pg_atomic_read_u64(), pgstat_count_slru_truncate(), SimpleLruWaitIO(), SlotGetBankNumber, SLRU_PAGE_EMPTY, SLRU_PAGE_VALID, SlruSharedData::slru_stats_idx, SlruInternalWritePage(), SlruScanDirCbDeleteCutoff(), and SlruScanDirectory().

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

◆ SimpleLruWaitIO()

static void SimpleLruWaitIO ( SlruCtl  ctl,
int  slotno 
)
static

Definition at line 445 of file slru.c.

446 {
447  SlruShared shared = ctl->shared;
448  int bankno = SlotGetBankNumber(slotno);
449 
450  Assert(shared->page_status[slotno] != SLRU_PAGE_EMPTY);
451 
452  /* See notes at top of file */
453  LWLockRelease(&shared->bank_locks[bankno].lock);
454  LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_SHARED);
455  LWLockRelease(&shared->buffer_locks[slotno].lock);
456  LWLockAcquire(&shared->bank_locks[bankno].lock, LW_EXCLUSIVE);
457 
458  /*
459  * If the slot is still in an io-in-progress state, then either someone
460  * already started a new I/O on the slot, or a previous I/O failed and
461  * neglected to reset the page state. That shouldn't happen, really, but
462  * it seems worth a few extra cycles to check and recover from it. We can
463  * cheaply test for failure by seeing if the buffer lock is still held (we
464  * assume that transaction abort would release the lock).
465  */
466  if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS ||
467  shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS)
468  {
469  if (LWLockConditionalAcquire(&shared->buffer_locks[slotno].lock, LW_SHARED))
470  {
471  /* indeed, the I/O must have failed */
472  if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS)
473  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
474  else /* write_in_progress */
475  {
476  shared->page_status[slotno] = SLRU_PAGE_VALID;
477  shared->page_dirty[slotno] = true;
478  }
479  LWLockRelease(&shared->buffer_locks[slotno].lock);
480  }
481  }
482 }
bool LWLockConditionalAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1339

References Assert, SlruSharedData::bank_locks, SlruSharedData::buffer_locks, ctl, LWLockPadded::lock, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockConditionalAcquire(), LWLockRelease(), SlruSharedData::page_dirty, SlruSharedData::page_status, SlotGetBankNumber, SLRU_PAGE_EMPTY, SLRU_PAGE_READ_IN_PROGRESS, SLRU_PAGE_VALID, and SLRU_PAGE_WRITE_IN_PROGRESS.

Referenced by SimpleLruReadPage(), SimpleLruTruncate(), SlruDeleteSegment(), SlruInternalWritePage(), and SlruSelectLRUPage().

◆ SimpleLruWriteAll()

void SimpleLruWriteAll ( SlruCtl  ctl,
bool  allow_redirtied 
)

Definition at line 1319 of file slru.c.

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

References Assert, SlruSharedData::bank_locks, CloseTransientFile(), ctl, SlruWriteAllData::fd, fsync_fname(), i, InvalidTransactionId, LWLockPadded::lock, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SlruWriteAllData::num_files, SlruSharedData::num_slots, SlruSharedData::page_dirty, SlruSharedData::page_status, pgstat_count_slru_flush(), SlruWriteAllData::segno, SlotGetBankNumber, SLRU_CLOSE_FAILED, slru_errcause, slru_errno, SLRU_PAGE_EMPTY, SLRU_PAGE_VALID, SLRU_PAGES_PER_SEGMENT, SlruSharedData::slru_stats_idx, SlruInternalWritePage(), SlruReportIOError(), and SYNC_HANDLER_NONE.

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

◆ SimpleLruWritePage()

void SimpleLruWritePage ( SlruCtl  ctl,
int  slotno 
)

Definition at line 729 of file slru.c.

730 {
731  Assert(ctl->shared->page_status[slotno] != SLRU_PAGE_EMPTY);
732 
733  SlruInternalWritePage(ctl, slotno, NULL);
734 }

References Assert, ctl, SLRU_PAGE_EMPTY, and SlruInternalWritePage().

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

◆ SimpleLruZeroLSNs()

static void SimpleLruZeroLSNs ( SlruCtl  ctl,
int  slotno 
)
static

Definition at line 428 of file slru.c.

429 {
430  SlruShared shared = ctl->shared;
431 
432  if (shared->lsn_groups_per_page > 0)
433  MemSet(&shared->group_lsn[slotno * shared->lsn_groups_per_page], 0,
434  shared->lsn_groups_per_page * sizeof(XLogRecPtr));
435 }
#define MemSet(start, val, len)
Definition: c.h:1020

References ctl, SlruSharedData::group_lsn, SlruSharedData::lsn_groups_per_page, and MemSet.

Referenced by SimpleLruReadPage(), and SimpleLruZeroPage().

◆ SimpleLruZeroPage()

int SimpleLruZeroPage ( SlruCtl  ctl,
int64  pageno 
)

Definition at line 375 of file slru.c.

376 {
377  SlruShared shared = ctl->shared;
378  int slotno;
379 
381 
382  /* Find a suitable buffer slot for the page */
383  slotno = SlruSelectLRUPage(ctl, pageno);
384  Assert(shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
385  (shared->page_status[slotno] == SLRU_PAGE_VALID &&
386  !shared->page_dirty[slotno]) ||
387  shared->page_number[slotno] == pageno);
388 
389  /* Mark the slot as containing this page */
390  shared->page_number[slotno] = pageno;
391  shared->page_status[slotno] = SLRU_PAGE_VALID;
392  shared->page_dirty[slotno] = true;
393  SlruRecentlyUsed(shared, slotno);
394 
395  /* Set the buffer to zeroes */
396  MemSet(shared->page_buffer[slotno], 0, BLCKSZ);
397 
398  /* Set the LSNs for this new page to zero */
399  SimpleLruZeroLSNs(ctl, slotno);
400 
401  /*
402  * Assume this page is now the latest active page.
403  *
404  * Note that because both this routine and SlruSelectLRUPage run with
405  * ControlLock held, it is not possible for this to be zeroing a page that
406  * SlruSelectLRUPage is going to evict simultaneously. Therefore, there's
407  * no memory barrier here.
408  */
409  pg_atomic_write_u64(&shared->latest_page_number, pageno);
410 
411  /* update the stats counter of zeroed pages */
413 
414  return slotno;
415 }
static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition: atomics.h:478
void pgstat_count_slru_page_zeroed(int slru_idx)
Definition: pgstat_slru.c:59

References Assert, ctl, SlruSharedData::latest_page_number, LW_EXCLUSIVE, LWLockHeldByMeInMode(), MemSet, SlruSharedData::page_buffer, SlruSharedData::page_dirty, SlruSharedData::page_number, SlruSharedData::page_status, pg_atomic_write_u64(), pgstat_count_slru_page_zeroed(), SimpleLruGetBankLock(), SimpleLruZeroLSNs(), SLRU_PAGE_EMPTY, SLRU_PAGE_VALID, SlruSharedData::slru_stats_idx, SlruRecentlyUsed(), and SlruSelectLRUPage().

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

◆ SlruCorrectSegmentFilenameLength()

static bool SlruCorrectSegmentFilenameLength ( SlruCtl  ctl,
size_t  len 
)
inlinestatic

Definition at line 1755 of file slru.c.

1756 {
1757  if (ctl->long_segment_names)
1758  return (len == 15); /* see SlruFileName() */
1759  else
1760 
1761  /*
1762  * Commit 638cf09e76d allowed 5-character lengths. Later commit
1763  * 73c986adde5 allowed 6-character length.
1764  *
1765  * Note: There is an ongoing plan to migrate all SLRUs to 64-bit page
1766  * numbers, and the corresponding 15-character file names, which may
1767  * eventually deprecate the support for 4, 5, and 6-character names.
1768  */
1769  return (len == 4 || len == 5 || len == 6);
1770 }
const void size_t len

References ctl, and len.

Referenced by SlruScanDirectory().

◆ SlruDeleteSegment()

void SlruDeleteSegment ( SlruCtl  ctl,
int64  segno 
)

Definition at line 1523 of file slru.c.

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

References SlruSharedData::bank_locks, ctl, LWLockPadded::lock, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SlruSharedData::num_slots, SlruSharedData::page_dirty, SlruSharedData::page_number, SlruSharedData::page_status, SlruWriteAllData::segno, SimpleLruWaitIO(), SlotGetBankNumber, SLRU_PAGE_EMPTY, SLRU_PAGE_VALID, SLRU_PAGES_PER_SEGMENT, SlruInternalDeleteSegment(), and SlruInternalWritePage().

Referenced by PerformMembersTruncation(), and test_slru_page_delete().

◆ SlruFileName()

static int SlruFileName ( SlruCtl  ctl,
char *  path,
int64  segno 
)
inlinestatic

Definition at line 91 of file slru.c.

92 {
93  if (ctl->long_segment_names)
94  {
95  /*
96  * We could use 16 characters here but the disadvantage would be that
97  * the SLRU segments will be hard to distinguish from WAL segments.
98  *
99  * For this reason we use 15 characters. It is enough but also means
100  * that in the future we can't decrease SLRU_PAGES_PER_SEGMENT easily.
101  */
102  Assert(segno >= 0 && segno <= INT64CONST(0xFFFFFFFFFFFFFFF));
103  return snprintf(path, MAXPGPATH, "%s/%015llX", ctl->Dir,
104  (long long) segno);
105  }
106  else
107  {
108  /*
109  * Despite the fact that %04X format string is used up to 24 bit
110  * integers are allowed. See SlruCorrectSegmentFilenameLength()
111  */
112  Assert(segno >= 0 && segno <= INT64CONST(0xFFFFFF));
113  return snprintf(path, MAXPGPATH, "%s/%04X", (ctl)->Dir,
114  (unsigned int) segno);
115  }
116 }
#define snprintf
Definition: port.h:238

References Assert, ctl, MAXPGPATH, and snprintf.

Referenced by SimpleLruDoesPhysicalPageExist(), SlruInternalDeleteSegment(), SlruPhysicalReadPage(), SlruPhysicalWritePage(), SlruReportIOError(), and SlruSyncFileTag().

◆ SlruInternalDeleteSegment()

static void SlruInternalDeleteSegment ( SlruCtl  ctl,
int64  segno 
)
static

Definition at line 1500 of file slru.c.

1501 {
1502  char path[MAXPGPATH];
1503 
1504  /* Forget any fsync requests queued for this segment. */
1505  if (ctl->sync_handler != SYNC_HANDLER_NONE)
1506  {
1507  FileTag tag;
1508 
1509  INIT_SLRUFILETAG(tag, ctl->sync_handler, segno);
1511  }
1512 
1513  /* Unlink the file. */
1514  SlruFileName(ctl, path, segno);
1515  ereport(DEBUG2, (errmsg_internal("removing file \"%s\"", path)));
1516  unlink(path);
1517 }
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1157
#define DEBUG2
Definition: elog.h:29
#define INIT_SLRUFILETAG(a, xx_handler, xx_segno)
Definition: slru.c:157
bool RegisterSyncRequest(const FileTag *ftag, SyncRequestType type, bool retryOnError)
Definition: sync.c:580
@ SYNC_FORGET_REQUEST
Definition: sync.h:27

References ctl, DEBUG2, ereport, errmsg_internal(), INIT_SLRUFILETAG, MAXPGPATH, RegisterSyncRequest(), SlruWriteAllData::segno, SlruFileName(), SYNC_FORGET_REQUEST, and SYNC_HANDLER_NONE.

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

◆ SlruInternalWritePage()

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

Definition at line 652 of file slru.c.

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

References Assert, SlruSharedData::bank_locks, SlruSharedData::buffer_locks, CheckpointStats, CheckpointStatsData::ckpt_bufs_written, CloseTransientFile(), ctl, SlruWriteAllData::fd, i, InvalidTransactionId, LWLockPadded::lock, LW_EXCLUSIVE, LWLockAcquire(), LWLockHeldByMeInMode(), LWLockRelease(), SlruWriteAllData::num_files, SlruSharedData::page_dirty, SlruSharedData::page_number, SlruSharedData::page_status, SimpleLruGetBankLock(), SimpleLruWaitIO(), SlotGetBankNumber, SLRU_PAGE_EMPTY, SLRU_PAGE_VALID, SLRU_PAGE_WRITE_IN_PROGRESS, SlruPhysicalWritePage(), and SlruReportIOError().

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

◆ SlruMayDeleteSegment()

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

Definition at line 1600 of file slru.c.

1601 {
1602  int64 seg_last_page = segpage + SLRU_PAGES_PER_SEGMENT - 1;
1603 
1604  Assert(segpage % SLRU_PAGES_PER_SEGMENT == 0);
1605 
1606  return (ctl->PagePrecedes(segpage, cutoffPage) &&
1607  ctl->PagePrecedes(seg_last_page, cutoffPage));
1608 }

References Assert, ctl, and SLRU_PAGES_PER_SEGMENT.

Referenced by SlruScanDirCbDeleteCutoff(), and SlruScanDirCbReportPresence().

◆ SlruPhysicalReadPage()

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

Definition at line 801 of file slru.c.

802 {
803  SlruShared shared = ctl->shared;
804  int64 segno = pageno / SLRU_PAGES_PER_SEGMENT;
805  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
806  off_t offset = rpageno * BLCKSZ;
807  char path[MAXPGPATH];
808  int fd;
809 
810  SlruFileName(ctl, path, segno);
811 
812  /*
813  * In a crash-and-restart situation, it's possible for us to receive
814  * commands to set the commit status of transactions whose bits are in
815  * already-truncated segments of the commit log (see notes in
816  * SlruPhysicalWritePage). Hence, if we are InRecovery, allow the case
817  * where the file doesn't exist, and return zeroes instead.
818  */
819  fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
820  if (fd < 0)
821  {
822  if (errno != ENOENT || !InRecovery)
823  {
825  slru_errno = errno;
826  return false;
827  }
828 
829  ereport(LOG,
830  (errmsg("file \"%s\" doesn't exist, reading as zeroes",
831  path)));
832  MemSet(shared->page_buffer[slotno], 0, BLCKSZ);
833  return true;
834  }
835 
836  errno = 0;
837  pgstat_report_wait_start(WAIT_EVENT_SLRU_READ);
838  if (pg_pread(fd, shared->page_buffer[slotno], BLCKSZ, offset) != BLCKSZ)
839  {
842  slru_errno = errno;
844  return false;
845  }
847 
848  if (CloseTransientFile(fd) != 0)
849  {
851  slru_errno = errno;
852  return false;
853  }
854 
855  return true;
856 }
#define pg_pread
Definition: port.h:225
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: wait_event.h:85
static void pgstat_report_wait_end(void)
Definition: wait_event.h:101
bool InRecovery
Definition: xlogutils.c:50

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

Referenced by SimpleLruReadPage().

◆ SlruPhysicalWritePage()

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

Definition at line 873 of file slru.c.

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

References CloseTransientFile(), ctl, END_CRIT_SECTION, fd(), SlruWriteAllData::fd, SlruSharedData::group_lsn, i, INIT_SLRUFILETAG, SlruSharedData::lsn_groups_per_page, MAX_WRITEALL_BUFFERS, MAXPGPATH, SlruWriteAllData::num_files, OpenTransientFile(), SlruSharedData::page_buffer, PG_BINARY, pg_fsync(), pg_pwrite, pgstat_count_slru_page_written(), pgstat_report_wait_end(), pgstat_report_wait_start(), RegisterSyncRequest(), SlruWriteAllData::segno, SLRU_CLOSE_FAILED, slru_errcause, slru_errno, SLRU_FSYNC_FAILED, SLRU_OPEN_FAILED, SLRU_PAGES_PER_SEGMENT, SlruSharedData::slru_stats_idx, SLRU_WRITE_FAILED, SlruFileName(), START_CRIT_SECTION, SYNC_HANDLER_NONE, SYNC_REQUEST, XLogFlush(), and XLogRecPtrIsInvalid.

Referenced by SlruInternalWritePage().

◆ SlruRecentlyUsed()

static void SlruRecentlyUsed ( SlruShared  shared,
int  slotno 
)
inlinestatic

Definition at line 1120 of file slru.c.

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

References Assert, SlruSharedData::bank_cur_lru_count, SlruSharedData::page_lru_count, SlruSharedData::page_status, SlotGetBankNumber, and SLRU_PAGE_EMPTY.

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

◆ SlruReportIOError()

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

Definition at line 1045 of file slru.c.

1046 {
1047  int64 segno = pageno / SLRU_PAGES_PER_SEGMENT;
1048  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
1049  int offset = rpageno * BLCKSZ;
1050  char path[MAXPGPATH];
1051 
1052  SlruFileName(ctl, path, segno);
1053  errno = slru_errno;
1054  switch (slru_errcause)
1055  {
1056  case SLRU_OPEN_FAILED:
1057  ereport(ERROR,
1059  errmsg("could not access status of transaction %u", xid),
1060  errdetail("Could not open file \"%s\": %m.", path)));
1061  break;
1062  case SLRU_SEEK_FAILED:
1063  ereport(ERROR,
1065  errmsg("could not access status of transaction %u", xid),
1066  errdetail("Could not seek in file \"%s\" to offset %d: %m.",
1067  path, offset)));
1068  break;
1069  case SLRU_READ_FAILED:
1070  if (errno)
1071  ereport(ERROR,
1073  errmsg("could not access status of transaction %u", xid),
1074  errdetail("Could not read from file \"%s\" at offset %d: %m.",
1075  path, offset)));
1076  else
1077  ereport(ERROR,
1078  (errmsg("could not access status of transaction %u", xid),
1079  errdetail("Could not read from file \"%s\" at offset %d: read too few bytes.", path, offset)));
1080  break;
1081  case SLRU_WRITE_FAILED:
1082  if (errno)
1083  ereport(ERROR,
1085  errmsg("could not access status of transaction %u", xid),
1086  errdetail("Could not write to file \"%s\" at offset %d: %m.",
1087  path, offset)));
1088  else
1089  ereport(ERROR,
1090  (errmsg("could not access status of transaction %u", xid),
1091  errdetail("Could not write to file \"%s\" at offset %d: wrote too few bytes.",
1092  path, offset)));
1093  break;
1094  case SLRU_FSYNC_FAILED:
1097  errmsg("could not access status of transaction %u", xid),
1098  errdetail("Could not fsync file \"%s\": %m.",
1099  path)));
1100  break;
1101  case SLRU_CLOSE_FAILED:
1102  ereport(ERROR,
1104  errmsg("could not access status of transaction %u", xid),
1105  errdetail("Could not close file \"%s\": %m.",
1106  path)));
1107  break;
1108  default:
1109  /* can't get here, we trust */
1110  elog(ERROR, "unrecognized SimpleLru error cause: %d",
1111  (int) slru_errcause);
1112  break;
1113  }
1114 }
int errcode_for_file_access(void)
Definition: elog.c:876
int errdetail(const char *fmt,...)
Definition: elog.c:1203
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
int data_sync_elevel(int elevel)
Definition: fd.c:3936

References ctl, data_sync_elevel(), elog, ereport, errcode_for_file_access(), errdetail(), errmsg(), ERROR, MAXPGPATH, SlruWriteAllData::segno, SLRU_CLOSE_FAILED, slru_errcause, slru_errno, SLRU_FSYNC_FAILED, SLRU_OPEN_FAILED, SLRU_PAGES_PER_SEGMENT, SLRU_READ_FAILED, SLRU_SEEK_FAILED, SLRU_WRITE_FAILED, and SlruFileName().

Referenced by SimpleLruDoesPhysicalPageExist(), SimpleLruReadPage(), SimpleLruWriteAll(), and SlruInternalWritePage().

◆ SlruScanDirCbDeleteAll()

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

Definition at line 1741 of file slru.c.

1742 {
1744 
1745  return false; /* keep going */
1746 }

References ctl, SLRU_PAGES_PER_SEGMENT, and SlruInternalDeleteSegment().

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

◆ SlruScanDirCbDeleteCutoff()

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

Definition at line 1725 of file slru.c.

1727 {
1728  int64 cutoffPage = *(int64 *) data;
1729 
1730  if (SlruMayDeleteSegment(ctl, segpage, cutoffPage))
1732 
1733  return false; /* keep going */
1734 }
const void * data
static bool SlruMayDeleteSegment(SlruCtl ctl, int64 segpage, int64 cutoffPage)
Definition: slru.c:1600

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

Referenced by SimpleLruTruncate().

◆ SlruScanDirCbReportPresence()

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

Definition at line 1709 of file slru.c.

1711 {
1712  int64 cutoffPage = *(int64 *) data;
1713 
1714  if (SlruMayDeleteSegment(ctl, segpage, cutoffPage))
1715  return true; /* found one; don't iterate any more */
1716 
1717  return false; /* keep going */
1718 }

References ctl, data, and SlruMayDeleteSegment().

Referenced by TruncateCLOG(), and TruncateCommitTs().

◆ SlruScanDirectory()

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

Definition at line 1788 of file slru.c.

1789 {
1790  bool retval = false;
1791  DIR *cldir;
1792  struct dirent *clde;
1793  int64 segno;
1794  int64 segpage;
1795 
1796  cldir = AllocateDir(ctl->Dir);
1797  while ((clde = ReadDir(cldir, ctl->Dir)) != NULL)
1798  {
1799  size_t len;
1800 
1801  len = strlen(clde->d_name);
1802 
1804  strspn(clde->d_name, "0123456789ABCDEF") == len)
1805  {
1806  segno = strtoi64(clde->d_name, NULL, 16);
1807  segpage = segno * SLRU_PAGES_PER_SEGMENT;
1808 
1809  elog(DEBUG2, "SlruScanDirectory invoking callback on %s/%s",
1810  ctl->Dir, clde->d_name);
1811  retval = callback(ctl, clde->d_name, segpage, data);
1812  if (retval)
1813  break;
1814  }
1815  }
1816  FreeDir(cldir);
1817 
1818  return retval;
1819 }
#define strtoi64(str, endptr, base)
Definition: c.h:1297
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2909
int FreeDir(DIR *dir)
Definition: fd.c:2961
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2843
static bool SlruCorrectSegmentFilenameLength(SlruCtl ctl, size_t len)
Definition: slru.c:1755
Definition: dirent.c:26
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:46

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

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

◆ SlruSelectLRUPage()

static int SlruSelectLRUPage ( SlruCtl  ctl,
int64  pageno 
)
static

Definition at line 1166 of file slru.c.

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

References Assert, SlruSharedData::bank_cur_lru_count, ctl, SlruSharedData::latest_page_number, LWLockHeldByMe(), SlruSharedData::num_slots, SlruSharedData::page_dirty, SlruSharedData::page_lru_count, SlruSharedData::page_number, SlruSharedData::page_status, pg_atomic_read_u64(), SimpleLruGetBankLock(), SimpleLruWaitIO(), SLRU_BANK_SIZE, SLRU_PAGE_EMPTY, SLRU_PAGE_VALID, and SlruInternalWritePage().

Referenced by SimpleLruReadPage(), and SimpleLruZeroPage().

◆ SlruSyncFileTag()

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

Definition at line 1828 of file slru.c.

1829 {
1830  int fd;
1831  int save_errno;
1832  int result;
1833 
1834  SlruFileName(ctl, path, ftag->segno);
1835 
1836  fd = OpenTransientFile(path, O_RDWR | PG_BINARY);
1837  if (fd < 0)
1838  return -1;
1839 
1840  pgstat_report_wait_start(WAIT_EVENT_SLRU_FLUSH_SYNC);
1841  result = pg_fsync(fd);
1843  save_errno = errno;
1844 
1846 
1847  errno = save_errno;
1848  return result;
1849 }
uint64 segno
Definition: sync.h:55

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

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

Variable Documentation

◆ slru_errcause

◆ slru_errno