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

Go to the source code of this file.

Data Structures

struct  SlruSharedData
 
struct  SlruCtlData
 

Macros

#define SLRU_PAGES_PER_SEGMENT   32
 
#define SLRU_MAX_NAME_LENGTH   32
 

Typedefs

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

Enumerations

enum  SlruPageStatus { SLRU_PAGE_EMPTY, SLRU_PAGE_READ_IN_PROGRESS, SLRU_PAGE_VALID, SLRU_PAGE_WRITE_IN_PROGRESS }
 

Functions

Size SimpleLruShmemSize (int nslots, int nlsns)
 
void SimpleLruInit (SlruCtl ctl, const char *name, int nslots, int nlsns, LWLock *ctllock, const char *subdir, int tranche_id)
 
int SimpleLruZeroPage (SlruCtl ctl, int pageno)
 
int SimpleLruReadPage (SlruCtl ctl, int pageno, bool write_ok, TransactionId xid)
 
int SimpleLruReadPage_ReadOnly (SlruCtl ctl, int pageno, TransactionId xid)
 
void SimpleLruWritePage (SlruCtl ctl, int slotno)
 
void SimpleLruFlush (SlruCtl ctl, bool allow_redirtied)
 
void SimpleLruTruncate (SlruCtl ctl, int cutoffPage)
 
bool SimpleLruDoesPhysicalPageExist (SlruCtl ctl, int pageno)
 
bool SlruScanDirectory (SlruCtl ctl, SlruScanCallback callback, void *data)
 
void SlruDeleteSegment (SlruCtl ctl, int segno)
 
bool SlruScanDirCbReportPresence (SlruCtl ctl, char *filename, int segpage, void *data)
 
bool SlruScanDirCbDeleteAll (SlruCtl ctl, char *filename, int segpage, void *data)
 

Macro Definition Documentation

◆ SLRU_MAX_NAME_LENGTH

#define SLRU_MAX_NAME_LENGTH   32

Definition at line 36 of file slru.h.

Referenced by SimpleLruInit().

◆ SLRU_PAGES_PER_SEGMENT

Typedef Documentation

◆ SlruCtl

typedef SlruCtlData* SlruCtl

Definition at line 137 of file slru.h.

◆ SlruCtlData

typedef struct SlruCtlData SlruCtlData

◆ SlruScanCallback

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

Definition at line 153 of file slru.h.

◆ SlruShared

Definition at line 107 of file slru.h.

◆ SlruSharedData

Enumeration Type Documentation

◆ SlruPageStatus

Enumerator
SLRU_PAGE_EMPTY 
SLRU_PAGE_READ_IN_PROGRESS 
SLRU_PAGE_VALID 
SLRU_PAGE_WRITE_IN_PROGRESS 

Definition at line 44 of file slru.h.

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

Function Documentation

◆ SimpleLruDoesPhysicalPageExist()

bool SimpleLruDoesPhysicalPageExist ( SlruCtl  ctl,
int  pageno 
)

Definition at line 589 of file slru.c.

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

590 {
591  int segno = pageno / SLRU_PAGES_PER_SEGMENT;
592  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
593  int offset = rpageno * BLCKSZ;
594  char path[MAXPGPATH];
595  int fd;
596  bool result;
597  off_t endpos;
598 
599  SlruFileName(ctl, path, segno);
600 
601  fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
602  if (fd < 0)
603  {
604  /* expected: file doesn't exist */
605  if (errno == ENOENT)
606  return false;
607 
608  /* report error normally */
610  slru_errno = errno;
611  SlruReportIOError(ctl, pageno, 0);
612  }
613 
614  if ((endpos = lseek(fd, 0, SEEK_END)) < 0)
615  {
617  slru_errno = errno;
618  SlruReportIOError(ctl, pageno, 0);
619  }
620 
621  result = endpos >= (off_t) (offset + BLCKSZ);
622 
623  if (CloseTransientFile(fd) != 0)
624  {
626  slru_errno = errno;
627  return false;
628  }
629 
630  return result;
631 }
static SlruErrorCause slru_errcause
Definition: slru.c:122
static int fd(const char *x, int i)
Definition: preproc-init.c:105
static void SlruReportIOError(SlruCtl ctl, int pageno, TransactionId xid)
Definition: slru.c:897
#define PG_BINARY
Definition: c.h:1216
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2254
#define MAXPGPATH
static XLogRecPtr endpos
Definition: pg_receivewal.c:46
int CloseTransientFile(int fd)
Definition: fd.c:2431
#define SlruFileName(ctl, path, seg)
Definition: slru.c:62
static int slru_errno
Definition: slru.c:123
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:33

◆ SimpleLruFlush()

void SimpleLruFlush ( SlruCtl  ctl,
bool  allow_redirtied 
)

Definition at line 1119 of file slru.c.

References Assert, CloseTransientFile(), SlruSharedData::ControlLock, SlruCtlData::do_fsync, SlruFlushData::fd, i, InvalidTransactionId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SlruFlushData::num_files, SlruSharedData::num_slots, SlruSharedData::page_dirty, SlruSharedData::page_status, pg_fsync(), pgstat_report_wait_end(), pgstat_report_wait_start(), SlruFlushData::segno, SlruCtlData::shared, SLRU_CLOSE_FAILED, slru_errcause, slru_errno, SLRU_FSYNC_FAILED, SLRU_PAGE_EMPTY, SLRU_PAGE_VALID, SLRU_PAGES_PER_SEGMENT, SlruInternalWritePage(), SlruReportIOError(), and WAIT_EVENT_SLRU_FLUSH_SYNC.

Referenced by CheckPointCLOG(), CheckPointCommitTs(), CheckPointMultiXact(), CheckPointPredicate(), CheckPointSUBTRANS(), find_multixact_start(), ShutdownCLOG(), ShutdownCommitTs(), ShutdownMultiXact(), and ShutdownSUBTRANS().

1120 {
1121  SlruShared shared = ctl->shared;
1122  SlruFlushData fdata;
1123  int slotno;
1124  int pageno = 0;
1125  int i;
1126  bool ok;
1127 
1128  /*
1129  * Find and write dirty pages
1130  */
1131  fdata.num_files = 0;
1132 
1134 
1135  for (slotno = 0; slotno < shared->num_slots; slotno++)
1136  {
1137  SlruInternalWritePage(ctl, slotno, &fdata);
1138 
1139  /*
1140  * In some places (e.g. checkpoints), we cannot assert that the slot
1141  * is clean now, since another process might have re-dirtied it
1142  * already. That's okay.
1143  */
1144  Assert(allow_redirtied ||
1145  shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
1146  (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1147  !shared->page_dirty[slotno]));
1148  }
1149 
1150  LWLockRelease(shared->ControlLock);
1151 
1152  /*
1153  * Now fsync and close any files that were open
1154  */
1155  ok = true;
1156  for (i = 0; i < fdata.num_files; i++)
1157  {
1159  if (ctl->do_fsync && pg_fsync(fdata.fd[i]) != 0)
1160  {
1162  slru_errno = errno;
1163  pageno = fdata.segno[i] * SLRU_PAGES_PER_SEGMENT;
1164  ok = false;
1165  }
1167 
1168  if (CloseTransientFile(fdata.fd[i]) != 0)
1169  {
1171  slru_errno = errno;
1172  pageno = fdata.segno[i] * SLRU_PAGES_PER_SEGMENT;
1173  ok = false;
1174  }
1175  }
1176  if (!ok)
1178 }
LWLock * ControlLock
Definition: slru.h:57
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruFlush fdata)
Definition: slru.c:506
static SlruErrorCause slru_errcause
Definition: slru.c:122
int segno[MAX_FLUSH_BUFFERS]
Definition: slru.c:78
static void SlruReportIOError(SlruCtl ctl, int pageno, TransactionId xid)
Definition: slru.c:897
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
SlruPageStatus * page_status
Definition: slru.h:67
#define InvalidTransactionId
Definition: transam.h:31
static void pgstat_report_wait_end(void)
Definition: pgstat.h:1342
bool do_fsync
Definition: slru.h:121
int CloseTransientFile(int fd)
Definition: fd.c:2431
int num_files
Definition: slru.c:76
#define Assert(condition)
Definition: c.h:733
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: pgstat.h:1318
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
int num_slots
Definition: slru.h:60
static int slru_errno
Definition: slru.c:123
bool * page_dirty
Definition: slru.h:68
int i
SlruShared shared
Definition: slru.h:115
int pg_fsync(int fd)
Definition: fd.c:330
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:33
int fd[MAX_FLUSH_BUFFERS]
Definition: slru.c:77

◆ SimpleLruInit()

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

Definition at line 164 of file slru.c.

References Assert, SlruSharedData::buffer_locks, BUFFERALIGN, SlruSharedData::ControlLock, SlruSharedData::cur_lru_count, SlruCtlData::Dir, SlruCtlData::do_fsync, SlruSharedData::group_lsn, IsUnderPostmaster, LWLockPadded::lock, SlruSharedData::lsn_groups_per_page, SlruSharedData::lwlock_tranche_id, SlruSharedData::lwlock_tranche_name, LWLockInitialize(), LWLockRegisterTranche(), MAXALIGN, SlruSharedData::num_slots, SlruSharedData::page_buffer, SlruSharedData::page_dirty, SlruSharedData::page_lru_count, SlruSharedData::page_number, SlruSharedData::page_status, SlruCtlData::shared, ShmemInitStruct(), SimpleLruShmemSize(), SLRU_MAX_NAME_LENGTH, SLRU_PAGE_EMPTY, strlcpy(), and StrNCpy.

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

166 {
167  SlruShared shared;
168  bool found;
169 
170  shared = (SlruShared) ShmemInitStruct(name,
171  SimpleLruShmemSize(nslots, nlsns),
172  &found);
173 
174  if (!IsUnderPostmaster)
175  {
176  /* Initialize locks and shared memory area */
177  char *ptr;
178  Size offset;
179  int slotno;
180 
181  Assert(!found);
182 
183  memset(shared, 0, sizeof(SlruSharedData));
184 
185  shared->ControlLock = ctllock;
186 
187  shared->num_slots = nslots;
188  shared->lsn_groups_per_page = nlsns;
189 
190  shared->cur_lru_count = 0;
191 
192  /* shared->latest_page_number will be set later */
193 
194  ptr = (char *) shared;
195  offset = MAXALIGN(sizeof(SlruSharedData));
196  shared->page_buffer = (char **) (ptr + offset);
197  offset += MAXALIGN(nslots * sizeof(char *));
198  shared->page_status = (SlruPageStatus *) (ptr + offset);
199  offset += MAXALIGN(nslots * sizeof(SlruPageStatus));
200  shared->page_dirty = (bool *) (ptr + offset);
201  offset += MAXALIGN(nslots * sizeof(bool));
202  shared->page_number = (int *) (ptr + offset);
203  offset += MAXALIGN(nslots * sizeof(int));
204  shared->page_lru_count = (int *) (ptr + offset);
205  offset += MAXALIGN(nslots * sizeof(int));
206 
207  /* Initialize LWLocks */
208  shared->buffer_locks = (LWLockPadded *) (ptr + offset);
209  offset += MAXALIGN(nslots * sizeof(LWLockPadded));
210 
211  if (nlsns > 0)
212  {
213  shared->group_lsn = (XLogRecPtr *) (ptr + offset);
214  offset += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr));
215  }
216 
217  Assert(strlen(name) + 1 < SLRU_MAX_NAME_LENGTH);
219  shared->lwlock_tranche_id = tranche_id;
220 
221  ptr += BUFFERALIGN(offset);
222  for (slotno = 0; slotno < nslots; slotno++)
223  {
224  LWLockInitialize(&shared->buffer_locks[slotno].lock,
225  shared->lwlock_tranche_id);
226 
227  shared->page_buffer[slotno] = ptr;
228  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
229  shared->page_dirty[slotno] = false;
230  shared->page_lru_count[slotno] = 0;
231  ptr += BLCKSZ;
232  }
233 
234  /* Should fit to estimated shmem size */
235  Assert(ptr - (char *) shared <= SimpleLruShmemSize(nslots, nlsns));
236  }
237  else
238  Assert(found);
239 
240  /* Register SLRU tranche in the main tranches array */
242  shared->lwlock_tranche_name);
243 
244  /*
245  * Initialize the unshared control struct, including directory path. We
246  * assume caller set PagePrecedes.
247  */
248  ctl->shared = shared;
249  ctl->do_fsync = true; /* default behavior */
250  StrNCpy(ctl->Dir, subdir, sizeof(ctl->Dir));
251 }
LWLock * ControlLock
Definition: slru.h:57
int * page_number
Definition: slru.h:69
SlruPageStatus
Definition: slru.h:44
char ** page_buffer
Definition: slru.h:66
int cur_lru_count
Definition: slru.h:92
int lsn_groups_per_page
Definition: slru.h:81
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:144
void LWLockRegisterTranche(int tranche_id, const char *tranche_name)
Definition: lwlock.c:603
SlruPageStatus * page_status
Definition: slru.h:67
char lwlock_tranche_name[SLRU_MAX_NAME_LENGTH]
Definition: slru.h:103
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:372
bool IsUnderPostmaster
Definition: globals.c:109
LWLockPadded * buffer_locks
Definition: slru.h:104
XLogRecPtr * group_lsn
Definition: slru.h:80
bool do_fsync
Definition: slru.h:121
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition: lwlock.c:678
SlruSharedData * SlruShared
Definition: slru.h:107
char Dir[64]
Definition: slru.h:134
#define SLRU_MAX_NAME_LENGTH
Definition: slru.h:36
LWLock lock
Definition: lwlock.h:79
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
int * page_lru_count
Definition: slru.h:70
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:733
#define StrNCpy(dst, src, len)
Definition: c.h:929
size_t Size
Definition: c.h:467
#define MAXALIGN(LEN)
Definition: c.h:686
int num_slots
Definition: slru.h:60
const char * name
Definition: encode.c:521
bool * page_dirty
Definition: slru.h:68
SlruShared shared
Definition: slru.h:115
#define BUFFERALIGN(LEN)
Definition: c.h:688
int lwlock_tranche_id
Definition: slru.h:102

◆ SimpleLruReadPage()

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

Definition at line 374 of file slru.c.

References Assert, SlruSharedData::buffer_locks, SlruSharedData::ControlLock, LWLockPadded::lock, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SlruSharedData::page_dirty, SlruSharedData::page_number, SlruSharedData::page_status, SlruCtlData::shared, SimpleLruWaitIO(), SimpleLruZeroLSNs(), SLRU_PAGE_EMPTY, SLRU_PAGE_READ_IN_PROGRESS, SLRU_PAGE_VALID, SLRU_PAGE_WRITE_IN_PROGRESS, SlruPhysicalReadPage(), SlruRecentlyUsed, SlruReportIOError(), and SlruSelectLRUPage().

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

376 {
377  SlruShared shared = ctl->shared;
378 
379  /* Outer loop handles restart if we must wait for someone else's I/O */
380  for (;;)
381  {
382  int slotno;
383  bool ok;
384 
385  /* See if page already is in memory; if not, pick victim slot */
386  slotno = SlruSelectLRUPage(ctl, pageno);
387 
388  /* Did we find the page in memory? */
389  if (shared->page_number[slotno] == pageno &&
390  shared->page_status[slotno] != SLRU_PAGE_EMPTY)
391  {
392  /*
393  * If page is still being read in, we must wait for I/O. Likewise
394  * if the page is being written and the caller said that's not OK.
395  */
396  if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS ||
397  (shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS &&
398  !write_ok))
399  {
400  SimpleLruWaitIO(ctl, slotno);
401  /* Now we must recheck state from the top */
402  continue;
403  }
404  /* Otherwise, it's ready to use */
405  SlruRecentlyUsed(shared, slotno);
406  return slotno;
407  }
408 
409  /* We found no match; assert we selected a freeable slot */
410  Assert(shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
411  (shared->page_status[slotno] == SLRU_PAGE_VALID &&
412  !shared->page_dirty[slotno]));
413 
414  /* Mark the slot read-busy */
415  shared->page_number[slotno] = pageno;
416  shared->page_status[slotno] = SLRU_PAGE_READ_IN_PROGRESS;
417  shared->page_dirty[slotno] = false;
418 
419  /* Acquire per-buffer lock (cannot deadlock, see notes at top) */
420  LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_EXCLUSIVE);
421 
422  /* Release control lock while doing I/O */
423  LWLockRelease(shared->ControlLock);
424 
425  /* Do the read */
426  ok = SlruPhysicalReadPage(ctl, pageno, slotno);
427 
428  /* Set the LSNs for this newly read-in page to zero */
429  SimpleLruZeroLSNs(ctl, slotno);
430 
431  /* Re-acquire control lock and update page state */
433 
434  Assert(shared->page_number[slotno] == pageno &&
435  shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS &&
436  !shared->page_dirty[slotno]);
437 
438  shared->page_status[slotno] = ok ? SLRU_PAGE_VALID : SLRU_PAGE_EMPTY;
439 
440  LWLockRelease(&shared->buffer_locks[slotno].lock);
441 
442  /* Now it's okay to ereport if we failed */
443  if (!ok)
444  SlruReportIOError(ctl, pageno, xid);
445 
446  SlruRecentlyUsed(shared, slotno);
447  return slotno;
448  }
449 }
LWLock * ControlLock
Definition: slru.h:57
int * page_number
Definition: slru.h:69
static void SimpleLruZeroLSNs(SlruCtl ctl, int slotno)
Definition: slru.c:303
static void SlruReportIOError(SlruCtl ctl, int pageno, TransactionId xid)
Definition: slru.c:897
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
SlruPageStatus * page_status
Definition: slru.h:67
LWLockPadded * buffer_locks
Definition: slru.h:104
static void SimpleLruWaitIO(SlruCtl ctl, int slotno)
Definition: slru.c:320
LWLock lock
Definition: lwlock.h:79
static bool SlruPhysicalReadPage(SlruCtl ctl, int pageno, int slotno)
Definition: slru.c:644
#define Assert(condition)
Definition: c.h:733
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
static int SlruSelectLRUPage(SlruCtl ctl, int pageno)
Definition: slru.c:982
bool * page_dirty
Definition: slru.h:68
SlruShared shared
Definition: slru.h:115
#define SlruRecentlyUsed(shared, slotno)
Definition: slru.c:102

◆ SimpleLruReadPage_ReadOnly()

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

Definition at line 466 of file slru.c.

References SlruSharedData::ControlLock, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), SlruSharedData::num_slots, SlruSharedData::page_number, SlruSharedData::page_status, SlruCtlData::shared, SimpleLruReadPage(), SLRU_PAGE_EMPTY, SLRU_PAGE_READ_IN_PROGRESS, and SlruRecentlyUsed.

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

467 {
468  SlruShared shared = ctl->shared;
469  int slotno;
470 
471  /* Try to find the page while holding only shared lock */
473 
474  /* See if page is already in a buffer */
475  for (slotno = 0; slotno < shared->num_slots; slotno++)
476  {
477  if (shared->page_number[slotno] == pageno &&
478  shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
479  shared->page_status[slotno] != SLRU_PAGE_READ_IN_PROGRESS)
480  {
481  /* See comments for SlruRecentlyUsed macro */
482  SlruRecentlyUsed(shared, slotno);
483  return slotno;
484  }
485  }
486 
487  /* No luck, so switch to normal exclusive lock and do regular read */
488  LWLockRelease(shared->ControlLock);
490 
491  return SimpleLruReadPage(ctl, pageno, true, xid);
492 }
LWLock * ControlLock
Definition: slru.h:57
int * page_number
Definition: slru.h:69
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
SlruPageStatus * page_status
Definition: slru.h:67
int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok, TransactionId xid)
Definition: slru.c:374
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
int num_slots
Definition: slru.h:60
SlruShared shared
Definition: slru.h:115
#define SlruRecentlyUsed(shared, slotno)
Definition: slru.c:102

◆ SimpleLruShmemSize()

Size SimpleLruShmemSize ( int  nslots,
int  nlsns 
)

Definition at line 144 of file slru.c.

References BUFFERALIGN, and MAXALIGN.

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

145 {
146  Size sz;
147 
148  /* we assume nslots isn't so large as to risk overflow */
149  sz = MAXALIGN(sizeof(SlruSharedData));
150  sz += MAXALIGN(nslots * sizeof(char *)); /* page_buffer[] */
151  sz += MAXALIGN(nslots * sizeof(SlruPageStatus)); /* page_status[] */
152  sz += MAXALIGN(nslots * sizeof(bool)); /* page_dirty[] */
153  sz += MAXALIGN(nslots * sizeof(int)); /* page_number[] */
154  sz += MAXALIGN(nslots * sizeof(int)); /* page_lru_count[] */
155  sz += MAXALIGN(nslots * sizeof(LWLockPadded)); /* buffer_locks[] */
156 
157  if (nlsns > 0)
158  sz += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr)); /* group_lsn[] */
159 
160  return BUFFERALIGN(sz) + BLCKSZ * nslots;
161 }
SlruPageStatus
Definition: slru.h:44
uint64 XLogRecPtr
Definition: xlogdefs.h:21
size_t Size
Definition: c.h:467
#define MAXALIGN(LEN)
Definition: c.h:686
#define BUFFERALIGN(LEN)
Definition: c.h:688

◆ SimpleLruTruncate()

void SimpleLruTruncate ( SlruCtl  ctl,
int  cutoffPage 
)

Definition at line 1184 of file slru.c.

References SlruSharedData::ControlLock, SlruCtlData::Dir, ereport, errmsg(), SlruSharedData::latest_page_number, LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SlruSharedData::num_slots, SlruSharedData::page_dirty, SlruSharedData::page_number, SlruSharedData::page_status, SlruCtlData::PagePrecedes, SlruCtlData::shared, SimpleLruWaitIO(), SLRU_PAGE_EMPTY, SLRU_PAGE_VALID, SLRU_PAGES_PER_SEGMENT, SlruInternalWritePage(), SlruScanDirCbDeleteCutoff(), and SlruScanDirectory().

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

1185 {
1186  SlruShared shared = ctl->shared;
1187  int slotno;
1188 
1189  /*
1190  * The cutoff point is the start of the segment containing cutoffPage.
1191  */
1192  cutoffPage -= cutoffPage % SLRU_PAGES_PER_SEGMENT;
1193 
1194  /*
1195  * Scan shared memory and remove any pages preceding the cutoff page, to
1196  * ensure we won't rewrite them later. (Since this is normally called in
1197  * or just after a checkpoint, any dirty pages should have been flushed
1198  * already ... we're just being extra careful here.)
1199  */
1201 
1202 restart:;
1203 
1204  /*
1205  * While we are holding the lock, make an important safety check: the
1206  * planned cutoff point must be <= the current endpoint page. Otherwise we
1207  * have already wrapped around, and proceeding with the truncation would
1208  * risk removing the current segment.
1209  */
1210  if (ctl->PagePrecedes(shared->latest_page_number, cutoffPage))
1211  {
1212  LWLockRelease(shared->ControlLock);
1213  ereport(LOG,
1214  (errmsg("could not truncate directory \"%s\": apparent wraparound",
1215  ctl->Dir)));
1216  return;
1217  }
1218 
1219  for (slotno = 0; slotno < shared->num_slots; slotno++)
1220  {
1221  if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
1222  continue;
1223  if (!ctl->PagePrecedes(shared->page_number[slotno], cutoffPage))
1224  continue;
1225 
1226  /*
1227  * If page is clean, just change state to EMPTY (expected case).
1228  */
1229  if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1230  !shared->page_dirty[slotno])
1231  {
1232  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
1233  continue;
1234  }
1235 
1236  /*
1237  * Hmm, we have (or may have) I/O operations acting on the page, so
1238  * we've got to wait for them to finish and then start again. This is
1239  * the same logic as in SlruSelectLRUPage. (XXX if page is dirty,
1240  * wouldn't it be OK to just discard it without writing it? For now,
1241  * keep the logic the same as it was.)
1242  */
1243  if (shared->page_status[slotno] == SLRU_PAGE_VALID)
1244  SlruInternalWritePage(ctl, slotno, NULL);
1245  else
1246  SimpleLruWaitIO(ctl, slotno);
1247  goto restart;
1248  }
1249 
1250  LWLockRelease(shared->ControlLock);
1251 
1252  /* Now we can remove the old segment(s) */
1253  (void) SlruScanDirectory(ctl, SlruScanDirCbDeleteCutoff, &cutoffPage);
1254 }
LWLock * ControlLock
Definition: slru.h:57
int * page_number
Definition: slru.h:69
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruFlush fdata)
Definition: slru.c:506
int latest_page_number
Definition: slru.h:99
#define LOG
Definition: elog.h:26
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
SlruPageStatus * page_status
Definition: slru.h:67
#define ereport(elevel, rest)
Definition: elog.h:141
static void SimpleLruWaitIO(SlruCtl ctl, int slotno)
Definition: slru.c:320
static bool SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename, int segpage, void *data)
Definition: slru.c:1354
char Dir[64]
Definition: slru.h:134
bool SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data)
Definition: slru.c:1392
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
int num_slots
Definition: slru.h:60
int errmsg(const char *fmt,...)
Definition: elog.c:822
bool * page_dirty
Definition: slru.h:68
SlruShared shared
Definition: slru.h:115
bool(* PagePrecedes)(int, int)
Definition: slru.h:128
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:33

◆ SimpleLruWritePage()

void SimpleLruWritePage ( SlruCtl  ctl,
int  slotno 
)

Definition at line 577 of file slru.c.

References SlruInternalWritePage().

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

578 {
579  SlruInternalWritePage(ctl, slotno, NULL);
580 }
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruFlush fdata)
Definition: slru.c:506

◆ SimpleLruZeroPage()

int SimpleLruZeroPage ( SlruCtl  ctl,
int  pageno 
)

Definition at line 262 of file slru.c.

References Assert, SlruSharedData::latest_page_number, MemSet, SlruSharedData::page_buffer, SlruSharedData::page_dirty, SlruSharedData::page_number, SlruSharedData::page_status, SlruCtlData::shared, SimpleLruZeroLSNs(), SLRU_PAGE_EMPTY, SLRU_PAGE_VALID, SlruRecentlyUsed, and SlruSelectLRUPage().

Referenced by asyncQueueAddEntries(), AsyncShmemInit(), OldSerXidAdd(), ZeroCLOGPage(), ZeroCommitTsPage(), ZeroMultiXactMemberPage(), ZeroMultiXactOffsetPage(), and ZeroSUBTRANSPage().

263 {
264  SlruShared shared = ctl->shared;
265  int slotno;
266 
267  /* Find a suitable buffer slot for the page */
268  slotno = SlruSelectLRUPage(ctl, pageno);
269  Assert(shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
270  (shared->page_status[slotno] == SLRU_PAGE_VALID &&
271  !shared->page_dirty[slotno]) ||
272  shared->page_number[slotno] == pageno);
273 
274  /* Mark the slot as containing this page */
275  shared->page_number[slotno] = pageno;
276  shared->page_status[slotno] = SLRU_PAGE_VALID;
277  shared->page_dirty[slotno] = true;
278  SlruRecentlyUsed(shared, slotno);
279 
280  /* Set the buffer to zeroes */
281  MemSet(shared->page_buffer[slotno], 0, BLCKSZ);
282 
283  /* Set the LSNs for this new page to zero */
284  SimpleLruZeroLSNs(ctl, slotno);
285 
286  /* Assume this page is now the latest active page */
287  shared->latest_page_number = pageno;
288 
289  return slotno;
290 }
int * page_number
Definition: slru.h:69
int latest_page_number
Definition: slru.h:99
char ** page_buffer
Definition: slru.h:66
#define MemSet(start, val, len)
Definition: c.h:956
static void SimpleLruZeroLSNs(SlruCtl ctl, int slotno)
Definition: slru.c:303
SlruPageStatus * page_status
Definition: slru.h:67
#define Assert(condition)
Definition: c.h:733
static int SlruSelectLRUPage(SlruCtl ctl, int pageno)
Definition: slru.c:982
bool * page_dirty
Definition: slru.h:68
SlruShared shared
Definition: slru.h:115
#define SlruRecentlyUsed(shared, slotno)
Definition: slru.c:102

◆ SlruDeleteSegment()

void SlruDeleteSegment ( SlruCtl  ctl,
int  segno 
)

Definition at line 1277 of file slru.c.

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

Referenced by PerformMembersTruncation().

1278 {
1279  SlruShared shared = ctl->shared;
1280  int slotno;
1281  char path[MAXPGPATH];
1282  bool did_write;
1283 
1284  /* Clean out any possibly existing references to the segment. */
1286 restart:
1287  did_write = false;
1288  for (slotno = 0; slotno < shared->num_slots; slotno++)
1289  {
1290  int pagesegno = shared->page_number[slotno] / SLRU_PAGES_PER_SEGMENT;
1291 
1292  if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
1293  continue;
1294 
1295  /* not the segment we're looking for */
1296  if (pagesegno != segno)
1297  continue;
1298 
1299  /* If page is clean, just change state to EMPTY (expected case). */
1300  if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1301  !shared->page_dirty[slotno])
1302  {
1303  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
1304  continue;
1305  }
1306 
1307  /* Same logic as SimpleLruTruncate() */
1308  if (shared->page_status[slotno] == SLRU_PAGE_VALID)
1309  SlruInternalWritePage(ctl, slotno, NULL);
1310  else
1311  SimpleLruWaitIO(ctl, slotno);
1312 
1313  did_write = true;
1314  }
1315 
1316  /*
1317  * Be extra careful and re-check. The IO functions release the control
1318  * lock, so new pages could have been read in.
1319  */
1320  if (did_write)
1321  goto restart;
1322 
1323  snprintf(path, MAXPGPATH, "%s/%04X", ctl->Dir, segno);
1324  ereport(DEBUG2,
1325  (errmsg("removing file \"%s\"", path)));
1326  unlink(path);
1327 
1328  LWLockRelease(shared->ControlLock);
1329 }
LWLock * ControlLock
Definition: slru.h:57
int * page_number
Definition: slru.h:69
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruFlush fdata)
Definition: slru.c:506
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
SlruPageStatus * page_status
Definition: slru.h:67
#define MAXPGPATH
#define DEBUG2
Definition: elog.h:24
#define ereport(elevel, rest)
Definition: elog.h:141
static void SimpleLruWaitIO(SlruCtl ctl, int slotno)
Definition: slru.c:320
char Dir[64]
Definition: slru.h:134
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
int num_slots
Definition: slru.h:60
int errmsg(const char *fmt,...)
Definition: elog.c:822
bool * page_dirty
Definition: slru.h:68
SlruShared shared
Definition: slru.h:115
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:33
#define snprintf
Definition: port.h:192

◆ SlruScanDirCbDeleteAll()

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

Definition at line 1369 of file slru.c.

References SlruInternalDeleteSegment().

Referenced by AsyncShmemInit(), and DeactivateCommitTs().

1370 {
1372 
1373  return false; /* keep going */
1374 }
static void SlruInternalDeleteSegment(SlruCtl ctl, char *filename)
Definition: slru.c:1263
static char * filename
Definition: pg_dumpall.c:90

◆ SlruScanDirCbReportPresence()

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

Definition at line 1337 of file slru.c.

References SlruCtlData::PagePrecedes, and SLRU_PAGES_PER_SEGMENT.

Referenced by TruncateCLOG(), and TruncateCommitTs().

1338 {
1339  int cutoffPage = *(int *) data;
1340 
1341  cutoffPage -= cutoffPage % SLRU_PAGES_PER_SEGMENT;
1342 
1343  if (ctl->PagePrecedes(segpage, cutoffPage))
1344  return true; /* found one; don't iterate any more */
1345 
1346  return false; /* keep going */
1347 }
bool(* PagePrecedes)(int, int)
Definition: slru.h:128
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:33

◆ SlruScanDirectory()

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

Definition at line 1392 of file slru.c.

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

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

1393 {
1394  bool retval = false;
1395  DIR *cldir;
1396  struct dirent *clde;
1397  int segno;
1398  int segpage;
1399 
1400  cldir = AllocateDir(ctl->Dir);
1401  while ((clde = ReadDir(cldir, ctl->Dir)) != NULL)
1402  {
1403  size_t len;
1404 
1405  len = strlen(clde->d_name);
1406 
1407  if ((len == 4 || len == 5 || len == 6) &&
1408  strspn(clde->d_name, "0123456789ABCDEF") == len)
1409  {
1410  segno = (int) strtol(clde->d_name, NULL, 16);
1411  segpage = segno * SLRU_PAGES_PER_SEGMENT;
1412 
1413  elog(DEBUG2, "SlruScanDirectory invoking callback on %s/%s",
1414  ctl->Dir, clde->d_name);
1415  retval = callback(ctl, clde->d_name, segpage, data);
1416  if (retval)
1417  break;
1418  }
1419  }
1420  FreeDir(cldir);
1421 
1422  return retval;
1423 }
Definition: dirent.h:9
Definition: dirent.c:25
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:48
#define DEBUG2
Definition: elog.h:24
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2465
char Dir[64]
Definition: slru.h:134
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2531
#define elog(elevel,...)
Definition: elog.h:228
char d_name[MAX_PATH]
Definition: dirent.h:14
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:33
int FreeDir(DIR *dir)
Definition: fd.c:2583