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_MAX_ALLOWED_BUFFERS   ((1024 * 1024 * 1024) / BLCKSZ)
 
#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

static LWLockSimpleLruGetBankLock (SlruCtl ctl, int64 pageno)
 
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)
 
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)
 
bool check_slru_buffers (const char *name, int *newval)
 

Macro Definition Documentation

◆ SLRU_MAX_ALLOWED_BUFFERS

#define SLRU_MAX_ALLOWED_BUFFERS   ((1024 * 1024 * 1024) / BLCKSZ)

Definition at line 24 of file slru.h.

◆ SLRU_PAGES_PER_SEGMENT

#define SLRU_PAGES_PER_SEGMENT   32

Definition at line 39 of file slru.h.

◆ SlruPagePrecedesUnitTests

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

Definition at line 203 of file slru.h.

Typedef Documentation

◆ SlruCtl

typedef SlruCtlData* SlruCtl

Definition at line 170 of file slru.h.

◆ SlruCtlData

typedef struct SlruCtlData SlruCtlData

◆ SlruScanCallback

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

Definition at line 208 of file slru.h.

◆ SlruShared

Definition at line 121 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 47 of file slru.h.

48 {
49  SLRU_PAGE_EMPTY, /* buffer is not in use */
50  SLRU_PAGE_READ_IN_PROGRESS, /* page is being read in */
51  SLRU_PAGE_VALID, /* page is valid and not being written */
52  SLRU_PAGE_WRITE_IN_PROGRESS, /* page is being written out */
SlruPageStatus
Definition: slru.h:48
@ 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
@ SLRU_PAGE_EMPTY
Definition: slru.h:49

Function Documentation

◆ check_slru_buffers()

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

Definition at line 340 of file slru.c.

341 {
342  /* Valid values are multiples of SLRU_BANK_SIZE */
343  if (*newval % SLRU_BANK_SIZE == 0)
344  return true;
345 
346  GUC_check_errdetail("\"%s\" must be a multiple of %d", name,
348  return false;
349 }
#define newval
#define GUC_check_errdetail
Definition: guc.h:447
#define SLRU_BANK_SIZE
Definition: slru.c:129
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 217 of file slru.c.

218 {
219  return Min(max - (max % SLRU_BANK_SIZE),
221  NBuffers / divisor - (NBuffers / divisor) % SLRU_BANK_SIZE));
222 }
#define Min(x, y)
Definition: c.h:1004
#define Max(x, y)
Definition: c.h:998
int NBuffers
Definition: globals.c:139

References Max, Min, NBuffers, and SLRU_BANK_SIZE.

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

◆ SimpleLruDoesPhysicalPageExist()

bool SimpleLruDoesPhysicalPageExist ( SlruCtl  ctl,
int64  pageno 
)

Definition at line 728 of file slru.c.

729 {
730  int64 segno = pageno / SLRU_PAGES_PER_SEGMENT;
731  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
732  int offset = rpageno * BLCKSZ;
733  char path[MAXPGPATH];
734  int fd;
735  bool result;
736  off_t endpos;
737 
738  /* update the stats counter of checked pages */
739  pgstat_count_slru_page_exists(ctl->shared->slru_stats_idx);
740 
741  SlruFileName(ctl, path, segno);
742 
743  fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
744  if (fd < 0)
745  {
746  /* expected: file doesn't exist */
747  if (errno == ENOENT)
748  return false;
749 
750  /* report error normally */
752  slru_errno = errno;
753  SlruReportIOError(ctl, pageno, 0);
754  }
755 
756  if ((endpos = lseek(fd, 0, SEEK_END)) < 0)
757  {
759  slru_errno = errno;
760  SlruReportIOError(ctl, pageno, 0);
761  }
762 
763  result = endpos >= (off_t) (offset + BLCKSZ);
764 
765  if (CloseTransientFile(fd) != 0)
766  {
768  slru_errno = errno;
769  return false;
770  }
771 
772  return result;
773 }
#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:1851
static int SlruFileName(SlruCtl ctl, char *path, int64 segno)
Definition: slru.c:76
static void SlruReportIOError(SlruCtl ctl, int64 pageno, TransactionId xid)
Definition: slru.c:1030
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: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().

◆ SimpleLruGetBankLock()

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

240 {
241  SlruShared shared;
242  bool found;
243  int nbanks = nslots / SLRU_BANK_SIZE;
244 
245  Assert(nslots <= SLRU_MAX_ALLOWED_BUFFERS);
246 
247  shared = (SlruShared) ShmemInitStruct(name,
248  SimpleLruShmemSize(nslots, nlsns),
249  &found);
250 
251  if (!IsUnderPostmaster)
252  {
253  /* Initialize locks and shared memory area */
254  char *ptr;
255  Size offset;
256 
257  Assert(!found);
258 
259  memset(shared, 0, sizeof(SlruSharedData));
260 
261  shared->num_slots = nslots;
262  shared->lsn_groups_per_page = nlsns;
263 
265 
267 
268  ptr = (char *) shared;
269  offset = MAXALIGN(sizeof(SlruSharedData));
270  shared->page_buffer = (char **) (ptr + offset);
271  offset += MAXALIGN(nslots * sizeof(char *));
272  shared->page_status = (SlruPageStatus *) (ptr + offset);
273  offset += MAXALIGN(nslots * sizeof(SlruPageStatus));
274  shared->page_dirty = (bool *) (ptr + offset);
275  offset += MAXALIGN(nslots * sizeof(bool));
276  shared->page_number = (int64 *) (ptr + offset);
277  offset += MAXALIGN(nslots * sizeof(int64));
278  shared->page_lru_count = (int *) (ptr + offset);
279  offset += MAXALIGN(nslots * sizeof(int));
280 
281  /* Initialize LWLocks */
282  shared->buffer_locks = (LWLockPadded *) (ptr + offset);
283  offset += MAXALIGN(nslots * sizeof(LWLockPadded));
284  shared->bank_locks = (LWLockPadded *) (ptr + offset);
285  offset += MAXALIGN(nbanks * sizeof(LWLockPadded));
286  shared->bank_cur_lru_count = (int *) (ptr + offset);
287  offset += MAXALIGN(nbanks * sizeof(int));
288 
289  if (nlsns > 0)
290  {
291  shared->group_lsn = (XLogRecPtr *) (ptr + offset);
292  offset += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr));
293  }
294 
295  ptr += BUFFERALIGN(offset);
296  for (int slotno = 0; slotno < nslots; slotno++)
297  {
298  LWLockInitialize(&shared->buffer_locks[slotno].lock,
299  buffer_tranche_id);
300 
301  shared->page_buffer[slotno] = ptr;
302  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
303  shared->page_dirty[slotno] = false;
304  shared->page_lru_count[slotno] = 0;
305  ptr += BLCKSZ;
306  }
307 
308  /* Initialize the slot banks. */
309  for (int bankno = 0; bankno < nbanks; bankno++)
310  {
311  LWLockInitialize(&shared->bank_locks[bankno].lock, bank_tranche_id);
312  shared->bank_cur_lru_count[bankno] = 0;
313  }
314 
315  /* Should fit to estimated shmem size */
316  Assert(ptr - (char *) shared <= SimpleLruShmemSize(nslots, nlsns));
317  }
318  else
319  {
320  Assert(found);
321  Assert(shared->num_slots == nslots);
322  }
323 
324  /*
325  * Initialize the unshared control struct, including directory path. We
326  * assume caller set PagePrecedes.
327  */
328  ctl->shared = shared;
329  ctl->sync_handler = sync_handler;
330  ctl->long_segment_names = long_segment_names;
331  ctl->bank_mask = (nslots / SLRU_BANK_SIZE) - 1;
332  strlcpy(ctl->Dir, subdir, sizeof(ctl->Dir));
333 }
static void pg_atomic_init_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition: atomics.h:448
#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:117
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition: lwlock.c:709
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:184
SlruSharedData * SlruShared
Definition: slru.h:121
#define SLRU_MAX_ALLOWED_BUFFERS
Definition: slru.h:24
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 487 of file slru.c.

489 {
490  SlruShared shared = ctl->shared;
491  LWLock *banklock = SimpleLruGetBankLock(ctl, pageno);
492 
494 
495  /* Outer loop handles restart if we must wait for someone else's I/O */
496  for (;;)
497  {
498  int slotno;
499  bool ok;
500 
501  /* See if page already is in memory; if not, pick victim slot */
502  slotno = SlruSelectLRUPage(ctl, pageno);
503 
504  /* Did we find the page in memory? */
505  if (shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
506  shared->page_number[slotno] == pageno)
507  {
508  /*
509  * If page is still being read in, we must wait for I/O. Likewise
510  * if the page is being written and the caller said that's not OK.
511  */
512  if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS ||
513  (shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS &&
514  !write_ok))
515  {
516  SimpleLruWaitIO(ctl, slotno);
517  /* Now we must recheck state from the top */
518  continue;
519  }
520  /* Otherwise, it's ready to use */
521  SlruRecentlyUsed(shared, slotno);
522 
523  /* update the stats counter of pages found in the SLRU */
525 
526  return slotno;
527  }
528 
529  /* We found no match; assert we selected a freeable slot */
530  Assert(shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
531  (shared->page_status[slotno] == SLRU_PAGE_VALID &&
532  !shared->page_dirty[slotno]));
533 
534  /* Mark the slot read-busy */
535  shared->page_number[slotno] = pageno;
536  shared->page_status[slotno] = SLRU_PAGE_READ_IN_PROGRESS;
537  shared->page_dirty[slotno] = false;
538 
539  /* Acquire per-buffer lock (cannot deadlock, see notes at top) */
540  LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_EXCLUSIVE);
541 
542  /* Release bank lock while doing I/O */
543  LWLockRelease(banklock);
544 
545  /* Do the read */
546  ok = SlruPhysicalReadPage(ctl, pageno, slotno);
547 
548  /* Set the LSNs for this newly read-in page to zero */
549  SimpleLruZeroLSNs(ctl, slotno);
550 
551  /* Re-acquire bank control lock and update page state */
552  LWLockAcquire(banklock, LW_EXCLUSIVE);
553 
554  Assert(shared->page_number[slotno] == pageno &&
555  shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS &&
556  !shared->page_dirty[slotno]);
557 
558  shared->page_status[slotno] = ok ? SLRU_PAGE_VALID : SLRU_PAGE_EMPTY;
559 
560  LWLockRelease(&shared->buffer_locks[slotno].lock);
561 
562  /* Now it's okay to ereport if we failed */
563  if (!ok)
564  SlruReportIOError(ctl, pageno, xid);
565 
566  SlruRecentlyUsed(shared, slotno);
567 
568  /* update the stats counter of pages not found in SLRU */
570 
571  return slotno;
572  }
573 }
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1170
bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1939
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1783
@ 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:786
static void SimpleLruZeroLSNs(SlruCtl ctl, int slotno)
Definition: slru.c:413
static void SimpleLruWaitIO(SlruCtl ctl, int slotno)
Definition: slru.c:430
static int SlruSelectLRUPage(SlruCtl ctl, int64 pageno)
Definition: slru.c:1151
static void SlruRecentlyUsed(SlruShared shared, int slotno)
Definition: slru.c:1105
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
Definition: slru.h:179
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 590 of file slru.c.

591 {
592  SlruShared shared = ctl->shared;
593  LWLock *banklock = SimpleLruGetBankLock(ctl, pageno);
594  int bankno = pageno & ctl->bank_mask;
595  int bankstart = bankno * SLRU_BANK_SIZE;
596  int bankend = bankstart + SLRU_BANK_SIZE;
597 
598  /* Try to find the page while holding only shared lock */
599  LWLockAcquire(banklock, LW_SHARED);
600 
601  /* See if page is already in a buffer */
602  for (int slotno = bankstart; slotno < bankend; slotno++)
603  {
604  if (shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
605  shared->page_number[slotno] == pageno &&
606  shared->page_status[slotno] != SLRU_PAGE_READ_IN_PROGRESS)
607  {
608  /* See comments for SlruRecentlyUsed macro */
609  SlruRecentlyUsed(shared, slotno);
610 
611  /* update the stats counter of pages found in the SLRU */
613 
614  return slotno;
615  }
616  }
617 
618  /* No luck, so switch to normal exclusive lock and do regular read */
619  LWLockRelease(banklock);
620  LWLockAcquire(banklock, LW_EXCLUSIVE);
621 
622  return SimpleLruReadPage(ctl, pageno, true, xid);
623 }
@ LW_SHARED
Definition: lwlock.h:115
int SimpleLruReadPage(SlruCtl ctl, int64 pageno, bool write_ok, TransactionId xid)
Definition: slru.c:487

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

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

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

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

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

◆ SimpleLruWriteAll()

void SimpleLruWriteAll ( SlruCtl  ctl,
bool  allow_redirtied 
)

Definition at line 1304 of file slru.c.

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

715 {
716  Assert(ctl->shared->page_status[slotno] != SLRU_PAGE_EMPTY);
717 
718  SlruInternalWritePage(ctl, slotno, NULL);
719 }

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

◆ SimpleLruZeroPage()

int SimpleLruZeroPage ( SlruCtl  ctl,
int64  pageno 
)

Definition at line 360 of file slru.c.

361 {
362  SlruShared shared = ctl->shared;
363  int slotno;
364 
366 
367  /* Find a suitable buffer slot for the page */
368  slotno = SlruSelectLRUPage(ctl, pageno);
369  Assert(shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
370  (shared->page_status[slotno] == SLRU_PAGE_VALID &&
371  !shared->page_dirty[slotno]) ||
372  shared->page_number[slotno] == pageno);
373 
374  /* Mark the slot as containing this page */
375  shared->page_number[slotno] = pageno;
376  shared->page_status[slotno] = SLRU_PAGE_VALID;
377  shared->page_dirty[slotno] = true;
378  SlruRecentlyUsed(shared, slotno);
379 
380  /* Set the buffer to zeroes */
381  MemSet(shared->page_buffer[slotno], 0, BLCKSZ);
382 
383  /* Set the LSNs for this new page to zero */
384  SimpleLruZeroLSNs(ctl, slotno);
385 
386  /*
387  * Assume this page is now the latest active page.
388  *
389  * Note that because both this routine and SlruSelectLRUPage run with
390  * ControlLock held, it is not possible for this to be zeroing a page that
391  * SlruSelectLRUPage is going to evict simultaneously. Therefore, there's
392  * no memory barrier here.
393  */
394  pg_atomic_write_u64(&shared->latest_page_number, pageno);
395 
396  /* update the stats counter of zeroed pages */
398 
399  return slotno;
400 }
static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition: atomics.h:480
#define MemSet(start, val, len)
Definition: c.h:1020
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().

◆ SlruDeleteSegment()

void SlruDeleteSegment ( SlruCtl  ctl,
int64  segno 
)

Definition at line 1508 of file slru.c.

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

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

◆ SlruScanDirCbDeleteAll()

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

Definition at line 1726 of file slru.c.

1727 {
1729 
1730  return false; /* keep going */
1731 }

References ctl, 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 1694 of file slru.c.

1696 {
1697  int64 cutoffPage = *(int64 *) data;
1698 
1699  if (SlruMayDeleteSegment(ctl, segpage, cutoffPage))
1700  return true; /* found one; don't iterate any more */
1701 
1702  return false; /* keep going */
1703 }
const void * data
static bool SlruMayDeleteSegment(SlruCtl ctl, int64 segpage, int64 cutoffPage)
Definition: slru.c:1585

References ctl, data, and SlruMayDeleteSegment().

Referenced by TruncateCLOG(), and TruncateCommitTs().

◆ SlruScanDirectory()

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

Definition at line 1773 of file slru.c.

1774 {
1775  bool retval = false;
1776  DIR *cldir;
1777  struct dirent *clde;
1778  int64 segno;
1779  int64 segpage;
1780 
1781  cldir = AllocateDir(ctl->Dir);
1782  while ((clde = ReadDir(cldir, ctl->Dir)) != NULL)
1783  {
1784  size_t len;
1785 
1786  len = strlen(clde->d_name);
1787 
1789  strspn(clde->d_name, "0123456789ABCDEF") == len)
1790  {
1791  segno = strtoi64(clde->d_name, NULL, 16);
1792  segpage = segno * SLRU_PAGES_PER_SEGMENT;
1793 
1794  elog(DEBUG2, "SlruScanDirectory invoking callback on %s/%s",
1795  ctl->Dir, clde->d_name);
1796  retval = callback(ctl, clde->d_name, segpage, data);
1797  if (retval)
1798  break;
1799  }
1800  }
1801  FreeDir(cldir);
1802 
1803  return retval;
1804 }
#define strtoi64(str, endptr, base)
Definition: c.h:1297
#define DEBUG2
Definition: elog.h:29
#define elog(elevel,...)
Definition: elog.h:224
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:1740
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().

◆ SlruSyncFileTag()

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

Definition at line 1813 of file slru.c.

1814 {
1815  int fd;
1816  int save_errno;
1817  int result;
1818 
1819  SlruFileName(ctl, path, ftag->segno);
1820 
1821  fd = OpenTransientFile(path, O_RDWR | PG_BINARY);
1822  if (fd < 0)
1823  return -1;
1824 
1825  pgstat_report_wait_start(WAIT_EVENT_SLRU_FLUSH_SYNC);
1826  result = pg_fsync(fd);
1828  save_errno = errno;
1829 
1831 
1832  errno = save_errno;
1833  return result;
1834 }
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:82
static void pgstat_report_wait_end(void)
Definition: wait_event.h:98

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