PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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 "pgstat.h"
#include "storage/fd.h"
#include "storage/shmem.h"
#include "miscadmin.h"
Include dependency graph for slru.c:

Go to the source code of this file.

Data Structures

struct  SlruFlushData
 

Macros

#define SlruFileName(ctl, path, seg)   snprintf(path, MAXPGPATH, "%s/%04X", (ctl)->Dir, seg)
 
#define MAX_FLUSH_BUFFERS   16
 
#define SlruRecentlyUsed(shared, slotno)
 

Typedefs

typedef struct SlruFlushData SlruFlushData
 
typedef struct SlruFlushDataSlruFlush
 

Enumerations

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

Functions

static void SimpleLruZeroLSNs (SlruCtl ctl, int slotno)
 
static void SimpleLruWaitIO (SlruCtl ctl, int slotno)
 
static void SlruInternalWritePage (SlruCtl ctl, int slotno, SlruFlush fdata)
 
static bool SlruPhysicalReadPage (SlruCtl ctl, int pageno, int slotno)
 
static bool SlruPhysicalWritePage (SlruCtl ctl, int pageno, int slotno, SlruFlush fdata)
 
static void SlruReportIOError (SlruCtl ctl, int pageno, TransactionId xid)
 
static int SlruSelectLRUPage (SlruCtl ctl, int pageno)
 
static bool SlruScanDirCbDeleteCutoff (SlruCtl ctl, char *filename, int segpage, void *data)
 
static void SlruInternalDeleteSegment (SlruCtl ctl, char *filename)
 
Size SimpleLruShmemSize (int nslots, int nlsns)
 
void SimpleLruInit (SlruCtl ctl, const char *name, int nslots, int nlsns, LWLock *ctllock, const char *subdir, int tranche_id)
 
int SimpleLruZeroPage (SlruCtl ctl, int pageno)
 
int SimpleLruReadPage (SlruCtl ctl, int pageno, bool write_ok, TransactionId xid)
 
int SimpleLruReadPage_ReadOnly (SlruCtl ctl, int pageno, TransactionId xid)
 
void SimpleLruWritePage (SlruCtl ctl, int slotno)
 
bool SimpleLruDoesPhysicalPageExist (SlruCtl ctl, int pageno)
 
void SimpleLruFlush (SlruCtl ctl, bool allow_redirtied)
 
void SimpleLruTruncate (SlruCtl ctl, int cutoffPage)
 
void SlruDeleteSegment (SlruCtl ctl, int segno)
 
bool SlruScanDirCbReportPresence (SlruCtl ctl, char *filename, int segpage, void *data)
 
bool SlruScanDirCbDeleteAll (SlruCtl ctl, char *filename, int segpage, void *data)
 
bool SlruScanDirectory (SlruCtl ctl, SlruScanCallback callback, void *data)
 

Variables

static SlruErrorCause slru_errcause
 
static int slru_errno
 

Macro Definition Documentation

#define MAX_FLUSH_BUFFERS   16

Definition at line 73 of file slru.c.

Referenced by SlruPhysicalWritePage().

#define SlruFileName (   ctl,
  path,
  seg 
)    snprintf(path, MAXPGPATH, "%s/%04X", (ctl)->Dir, seg)
#define SlruRecentlyUsed (   shared,
  slotno 
)
Value:
do { \
int new_lru_count = (shared)->cur_lru_count; \
if (new_lru_count != (shared)->page_lru_count[slotno]) { \
(shared)->cur_lru_count = ++new_lru_count; \
(shared)->page_lru_count[slotno] = new_lru_count; \
} \
} while (0)

Definition at line 103 of file slru.c.

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

Typedef Documentation

Definition at line 82 of file slru.c.

Enumeration Type Documentation

Enumerator
SLRU_OPEN_FAILED 
SLRU_SEEK_FAILED 
SLRU_READ_FAILED 
SLRU_WRITE_FAILED 
SLRU_FSYNC_FAILED 
SLRU_CLOSE_FAILED 

Definition at line 113 of file slru.c.

Function Documentation

bool SimpleLruDoesPhysicalPageExist ( SlruCtl  ctl,
int  pageno 
)

Definition at line 586 of file slru.c.

References CloseTransientFile(), endpos, fd(), MAXPGPATH, OpenTransientFile(), PG_BINARY, result, SlruFlushData::segno, slru_errcause, slru_errno, SLRU_OPEN_FAILED, SLRU_PAGES_PER_SEGMENT, SlruFileName, and SlruReportIOError().

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

587 {
588  int segno = pageno / SLRU_PAGES_PER_SEGMENT;
589  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
590  int offset = rpageno * BLCKSZ;
591  char path[MAXPGPATH];
592  int fd;
593  bool result;
594  off_t endpos;
595 
596  SlruFileName(ctl, path, segno);
597 
598  fd = OpenTransientFile(path, O_RDWR | PG_BINARY, S_IRUSR | S_IWUSR);
599  if (fd < 0)
600  {
601  /* expected: file doesn't exist */
602  if (errno == ENOENT)
603  return false;
604 
605  /* report error normally */
607  slru_errno = errno;
608  SlruReportIOError(ctl, pageno, 0);
609  }
610 
611  if ((endpos = lseek(fd, 0, SEEK_END)) < 0)
612  {
614  slru_errno = errno;
615  SlruReportIOError(ctl, pageno, 0);
616  }
617 
618  result = endpos >= (off_t) (offset + BLCKSZ);
619 
620  CloseTransientFile(fd);
621  return result;
622 }
static SlruErrorCause slru_errcause
Definition: slru.c:123
return result
Definition: formatting.c:1633
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:889
#define PG_BINARY
Definition: c.h:1038
static XLogRecPtr endpos
#define MAXPGPATH
int OpenTransientFile(FileName fileName, int fileFlags, int fileMode)
Definition: fd.c:2144
int CloseTransientFile(int fd)
Definition: fd.c:2305
#define SlruFileName(ctl, path, seg)
Definition: slru.c:63
static int slru_errno
Definition: slru.c:124
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:37
void SimpleLruFlush ( SlruCtl  ctl,
bool  allow_redirtied 
)

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

1101 {
1102  SlruShared shared = ctl->shared;
1103  SlruFlushData fdata;
1104  int slotno;
1105  int pageno = 0;
1106  int i;
1107  bool ok;
1108 
1109  /*
1110  * Find and write dirty pages
1111  */
1112  fdata.num_files = 0;
1113 
1115 
1116  for (slotno = 0; slotno < shared->num_slots; slotno++)
1117  {
1118  SlruInternalWritePage(ctl, slotno, &fdata);
1119 
1120  /*
1121  * In some places (e.g. checkpoints), we cannot assert that the slot
1122  * is clean now, since another process might have re-dirtied it
1123  * already. That's okay.
1124  */
1125  Assert(allow_redirtied ||
1126  shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
1127  (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1128  !shared->page_dirty[slotno]));
1129  }
1130 
1131  LWLockRelease(shared->ControlLock);
1132 
1133  /*
1134  * Now fsync and close any files that were open
1135  */
1136  ok = true;
1137  for (i = 0; i < fdata.num_files; i++)
1138  {
1140  if (ctl->do_fsync && pg_fsync(fdata.fd[i]))
1141  {
1143  slru_errno = errno;
1144  pageno = fdata.segno[i] * SLRU_PAGES_PER_SEGMENT;
1145  ok = false;
1146  }
1148 
1149  if (CloseTransientFile(fdata.fd[i]))
1150  {
1152  slru_errno = errno;
1153  pageno = fdata.segno[i] * SLRU_PAGES_PER_SEGMENT;
1154  ok = false;
1155  }
1156  }
1157  if (!ok)
1159 }
LWLock * ControlLock
Definition: slru.h:61
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruFlush fdata)
Definition: slru.c:503
static SlruErrorCause slru_errcause
Definition: slru.c:123
int segno[MAX_FLUSH_BUFFERS]
Definition: slru.c:79
static void SlruReportIOError(SlruCtl ctl, int pageno, TransactionId xid)
Definition: slru.c:889
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1715
SlruPageStatus * page_status
Definition: slru.h:71
#define InvalidTransactionId
Definition: transam.h:31
static void pgstat_report_wait_end(void)
Definition: pgstat.h:1232
bool do_fsync
Definition: slru.h:125
int CloseTransientFile(int fd)
Definition: fd.c:2305
int num_files
Definition: slru.c:77
#define Assert(condition)
Definition: c.h:675
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: pgstat.h:1208
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1111
int num_slots
Definition: slru.h:64
static int slru_errno
Definition: slru.c:124
bool * page_dirty
Definition: slru.h:72
int i
SlruShared shared
Definition: slru.h:119
int pg_fsync(int fd)
Definition: fd.c:333
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:37
int fd[MAX_FLUSH_BUFFERS]
Definition: slru.c:78
void SimpleLruInit ( SlruCtl  ctl,
const char *  name,
int  nslots,
int  nlsns,
LWLock ctllock,
const char *  subdir,
int  tranche_id 
)

Definition at line 165 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, ShmemAlloc(), ShmemInitStruct(), SimpleLruShmemSize(), SLRU_MAX_NAME_LENGTH, SLRU_PAGE_EMPTY, strlcpy(), and StrNCpy.

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

167 {
168  SlruShared shared;
169  bool found;
170 
171  shared = (SlruShared) ShmemInitStruct(name,
172  SimpleLruShmemSize(nslots, nlsns),
173  &found);
174 
175  if (!IsUnderPostmaster)
176  {
177  /* Initialize locks and shared memory area */
178  char *ptr;
179  Size offset;
180  int slotno;
181 
182  Assert(!found);
183 
184  memset(shared, 0, sizeof(SlruSharedData));
185 
186  shared->ControlLock = ctllock;
187 
188  shared->num_slots = nslots;
189  shared->lsn_groups_per_page = nlsns;
190 
191  shared->cur_lru_count = 0;
192 
193  /* shared->latest_page_number will be set later */
194 
195  ptr = (char *) shared;
196  offset = MAXALIGN(sizeof(SlruSharedData));
197  shared->page_buffer = (char **) (ptr + offset);
198  offset += MAXALIGN(nslots * sizeof(char *));
199  shared->page_status = (SlruPageStatus *) (ptr + offset);
200  offset += MAXALIGN(nslots * sizeof(SlruPageStatus));
201  shared->page_dirty = (bool *) (ptr + offset);
202  offset += MAXALIGN(nslots * sizeof(bool));
203  shared->page_number = (int *) (ptr + offset);
204  offset += MAXALIGN(nslots * sizeof(int));
205  shared->page_lru_count = (int *) (ptr + offset);
206  offset += MAXALIGN(nslots * sizeof(int));
207 
208  if (nlsns > 0)
209  {
210  shared->group_lsn = (XLogRecPtr *) (ptr + offset);
211  offset += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr));
212  }
213 
214  /* Initialize LWLocks */
215  shared->buffer_locks = (LWLockPadded *) ShmemAlloc(sizeof(LWLockPadded) * nslots);
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  else
235  Assert(found);
236 
237  /* Register SLRU tranche in the main tranches array */
239  shared->lwlock_tranche_name);
240 
241  /*
242  * Initialize the unshared control struct, including directory path. We
243  * assume caller set PagePrecedes.
244  */
245  ctl->shared = shared;
246  ctl->do_fsync = true; /* default behavior */
247  StrNCpy(ctl->Dir, subdir, sizeof(ctl->Dir));
248 }
LWLock * ControlLock
Definition: slru.h:61
int * page_number
Definition: slru.h:73
SlruPageStatus
Definition: slru.h:48
char ** page_buffer
Definition: slru.h:70
int cur_lru_count
Definition: slru.h:96
int lsn_groups_per_page
Definition: slru.h:85
void * ShmemAlloc(Size size)
Definition: shmem.c:157
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:145
SlruPageStatus * page_status
Definition: slru.h:71
char lwlock_tranche_name[SLRU_MAX_NAME_LENGTH]
Definition: slru.h:107
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:372
bool IsUnderPostmaster
Definition: globals.c:101
LWLockPadded * buffer_locks
Definition: slru.h:108
XLogRecPtr * group_lsn
Definition: slru.h:84
bool do_fsync
Definition: slru.h:125
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition: lwlock.c:667
SlruSharedData * SlruShared
Definition: slru.h:111
char Dir[64]
Definition: slru.h:138
#define SLRU_MAX_NAME_LENGTH
Definition: slru.h:40
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:74
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:675
#define StrNCpy(dst, src, len)
Definition: c.h:830
size_t Size
Definition: c.h:356
#define MAXALIGN(LEN)
Definition: c.h:588
void LWLockRegisterTranche(int tranche_id, char *tranche_name)
Definition: lwlock.c:592
int num_slots
Definition: slru.h:64
const char * name
Definition: encode.c:521
bool * page_dirty
Definition: slru.h:72
SlruShared shared
Definition: slru.h:119
#define BUFFERALIGN(LEN)
Definition: c.h:590
int lwlock_tranche_id
Definition: slru.h:106
int SimpleLruReadPage ( SlruCtl  ctl,
int  pageno,
bool  write_ok,
TransactionId  xid 
)

Definition at line 371 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(), TransactionIdSetPageStatus(), TrimCLOG(), and TrimMultiXact().

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

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

464 {
465  SlruShared shared = ctl->shared;
466  int slotno;
467 
468  /* Try to find the page while holding only shared lock */
470 
471  /* See if page is already in a buffer */
472  for (slotno = 0; slotno < shared->num_slots; slotno++)
473  {
474  if (shared->page_number[slotno] == pageno &&
475  shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
476  shared->page_status[slotno] != SLRU_PAGE_READ_IN_PROGRESS)
477  {
478  /* See comments for SlruRecentlyUsed macro */
479  SlruRecentlyUsed(shared, slotno);
480  return slotno;
481  }
482  }
483 
484  /* No luck, so switch to normal exclusive lock and do regular read */
485  LWLockRelease(shared->ControlLock);
487 
488  return SimpleLruReadPage(ctl, pageno, true, xid);
489 }
LWLock * ControlLock
Definition: slru.h:61
int * page_number
Definition: slru.h:73
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1715
SlruPageStatus * page_status
Definition: slru.h:71
int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok, TransactionId xid)
Definition: slru.c:371
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1111
int num_slots
Definition: slru.h:64
SlruShared shared
Definition: slru.h:119
#define SlruRecentlyUsed(shared, slotno)
Definition: slru.c:103
Size SimpleLruShmemSize ( int  nslots,
int  nlsns 
)

Definition at line 145 of file slru.c.

References BUFFERALIGN, and MAXALIGN.

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

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

Definition at line 1165 of file slru.c.

References SlruSharedData::ControlLock, SlruCtlData::Dir, ereport, errmsg(), SlruSharedData::latest_page_number, LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), NULL, 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().

1166 {
1167  SlruShared shared = ctl->shared;
1168  int slotno;
1169 
1170  /*
1171  * The cutoff point is the start of the segment containing cutoffPage.
1172  */
1173  cutoffPage -= cutoffPage % SLRU_PAGES_PER_SEGMENT;
1174 
1175  /*
1176  * Scan shared memory and remove any pages preceding the cutoff page, to
1177  * ensure we won't rewrite them later. (Since this is normally called in
1178  * or just after a checkpoint, any dirty pages should have been flushed
1179  * already ... we're just being extra careful here.)
1180  */
1182 
1183 restart:;
1184 
1185  /*
1186  * While we are holding the lock, make an important safety check: the
1187  * planned cutoff point must be <= the current endpoint page. Otherwise we
1188  * have already wrapped around, and proceeding with the truncation would
1189  * risk removing the current segment.
1190  */
1191  if (ctl->PagePrecedes(shared->latest_page_number, cutoffPage))
1192  {
1193  LWLockRelease(shared->ControlLock);
1194  ereport(LOG,
1195  (errmsg("could not truncate directory \"%s\": apparent wraparound",
1196  ctl->Dir)));
1197  return;
1198  }
1199 
1200  for (slotno = 0; slotno < shared->num_slots; slotno++)
1201  {
1202  if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
1203  continue;
1204  if (!ctl->PagePrecedes(shared->page_number[slotno], cutoffPage))
1205  continue;
1206 
1207  /*
1208  * If page is clean, just change state to EMPTY (expected case).
1209  */
1210  if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1211  !shared->page_dirty[slotno])
1212  {
1213  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
1214  continue;
1215  }
1216 
1217  /*
1218  * Hmm, we have (or may have) I/O operations acting on the page, so
1219  * we've got to wait for them to finish and then start again. This is
1220  * the same logic as in SlruSelectLRUPage. (XXX if page is dirty,
1221  * wouldn't it be OK to just discard it without writing it? For now,
1222  * keep the logic the same as it was.)
1223  */
1224  if (shared->page_status[slotno] == SLRU_PAGE_VALID)
1225  SlruInternalWritePage(ctl, slotno, NULL);
1226  else
1227  SimpleLruWaitIO(ctl, slotno);
1228  goto restart;
1229  }
1230 
1231  LWLockRelease(shared->ControlLock);
1232 
1233  /* Now we can remove the old segment(s) */
1234  (void) SlruScanDirectory(ctl, SlruScanDirCbDeleteCutoff, &cutoffPage);
1235 }
LWLock * ControlLock
Definition: slru.h:61
int * page_number
Definition: slru.h:73
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruFlush fdata)
Definition: slru.c:503
int latest_page_number
Definition: slru.h:103
#define LOG
Definition: elog.h:26
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1715
SlruPageStatus * page_status
Definition: slru.h:71
#define ereport(elevel, rest)
Definition: elog.h:122
static void SimpleLruWaitIO(SlruCtl ctl, int slotno)
Definition: slru.c:317
static bool SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename, int segpage, void *data)
Definition: slru.c:1335
char Dir[64]
Definition: slru.h:138
bool(* PagePrecedes)(int, int)
Definition: slru.h:132
#define NULL
Definition: c.h:229
bool SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data)
Definition: slru.c:1373
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1111
int num_slots
Definition: slru.h:64
int errmsg(const char *fmt,...)
Definition: elog.c:797
bool * page_dirty
Definition: slru.h:72
SlruShared shared
Definition: slru.h:119
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:37
static void SimpleLruWaitIO ( SlruCtl  ctl,
int  slotno 
)
static

Definition at line 317 of file slru.c.

References SlruSharedData::buffer_locks, SlruSharedData::ControlLock, LWLockPadded::lock, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockConditionalAcquire(), LWLockRelease(), SlruSharedData::page_dirty, SlruSharedData::page_status, SlruCtlData::shared, SLRU_PAGE_EMPTY, SLRU_PAGE_READ_IN_PROGRESS, SLRU_PAGE_VALID, and SLRU_PAGE_WRITE_IN_PROGRESS.

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

318 {
319  SlruShared shared = ctl->shared;
320 
321  /* See notes at top of file */
322  LWLockRelease(shared->ControlLock);
323  LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_SHARED);
324  LWLockRelease(&shared->buffer_locks[slotno].lock);
326 
327  /*
328  * If the slot is still in an io-in-progress state, then either someone
329  * already started a new I/O on the slot, or a previous I/O failed and
330  * neglected to reset the page state. That shouldn't happen, really, but
331  * it seems worth a few extra cycles to check and recover from it. We can
332  * cheaply test for failure by seeing if the buffer lock is still held (we
333  * assume that transaction abort would release the lock).
334  */
335  if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS ||
336  shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS)
337  {
338  if (LWLockConditionalAcquire(&shared->buffer_locks[slotno].lock, LW_SHARED))
339  {
340  /* indeed, the I/O must have failed */
341  if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS)
342  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
343  else /* write_in_progress */
344  {
345  shared->page_status[slotno] = SLRU_PAGE_VALID;
346  shared->page_dirty[slotno] = true;
347  }
348  LWLockRelease(&shared->buffer_locks[slotno].lock);
349  }
350  }
351 }
LWLock * ControlLock
Definition: slru.h:61
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1715
SlruPageStatus * page_status
Definition: slru.h:71
bool LWLockConditionalAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1283
LWLockPadded * buffer_locks
Definition: slru.h:108
LWLock lock
Definition: lwlock.h:79
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1111
bool * page_dirty
Definition: slru.h:72
SlruShared shared
Definition: slru.h:119
void SimpleLruWritePage ( SlruCtl  ctl,
int  slotno 
)

Definition at line 574 of file slru.c.

References NULL, and SlruInternalWritePage().

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

575 {
576  SlruInternalWritePage(ctl, slotno, NULL);
577 }
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruFlush fdata)
Definition: slru.c:503
#define NULL
Definition: c.h:229
static void SimpleLruZeroLSNs ( SlruCtl  ctl,
int  slotno 
)
static

Definition at line 300 of file slru.c.

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

Referenced by SimpleLruReadPage(), and SimpleLruZeroPage().

301 {
302  SlruShared shared = ctl->shared;
303 
304  if (shared->lsn_groups_per_page > 0)
305  MemSet(&shared->group_lsn[slotno * shared->lsn_groups_per_page], 0,
306  shared->lsn_groups_per_page * sizeof(XLogRecPtr));
307 }
#define MemSet(start, val, len)
Definition: c.h:857
int lsn_groups_per_page
Definition: slru.h:85
XLogRecPtr * group_lsn
Definition: slru.h:84
uint64 XLogRecPtr
Definition: xlogdefs.h:21
SlruShared shared
Definition: slru.h:119
int SimpleLruZeroPage ( SlruCtl  ctl,
int  pageno 
)

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

260 {
261  SlruShared shared = ctl->shared;
262  int slotno;
263 
264  /* Find a suitable buffer slot for the page */
265  slotno = SlruSelectLRUPage(ctl, pageno);
266  Assert(shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
267  (shared->page_status[slotno] == SLRU_PAGE_VALID &&
268  !shared->page_dirty[slotno]) ||
269  shared->page_number[slotno] == pageno);
270 
271  /* Mark the slot as containing this page */
272  shared->page_number[slotno] = pageno;
273  shared->page_status[slotno] = SLRU_PAGE_VALID;
274  shared->page_dirty[slotno] = true;
275  SlruRecentlyUsed(shared, slotno);
276 
277  /* Set the buffer to zeroes */
278  MemSet(shared->page_buffer[slotno], 0, BLCKSZ);
279 
280  /* Set the LSNs for this new page to zero */
281  SimpleLruZeroLSNs(ctl, slotno);
282 
283  /* Assume this page is now the latest active page */
284  shared->latest_page_number = pageno;
285 
286  return slotno;
287 }
int * page_number
Definition: slru.h:73
int latest_page_number
Definition: slru.h:103
char ** page_buffer
Definition: slru.h:70
#define MemSet(start, val, len)
Definition: c.h:857
static void SimpleLruZeroLSNs(SlruCtl ctl, int slotno)
Definition: slru.c:300
SlruPageStatus * page_status
Definition: slru.h:71
#define Assert(condition)
Definition: c.h:675
static int SlruSelectLRUPage(SlruCtl ctl, int pageno)
Definition: slru.c:963
bool * page_dirty
Definition: slru.h:72
SlruShared shared
Definition: slru.h:119
#define SlruRecentlyUsed(shared, slotno)
Definition: slru.c:103
void SlruDeleteSegment ( SlruCtl  ctl,
int  segno 
)

Definition at line 1258 of file slru.c.

References SlruSharedData::ControlLock, DEBUG2, SlruCtlData::Dir, ereport, errmsg(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MAXPGPATH, NULL, 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(), snprintf(), and unlink().

Referenced by PerformMembersTruncation().

1259 {
1260  SlruShared shared = ctl->shared;
1261  int slotno;
1262  char path[MAXPGPATH];
1263  bool did_write;
1264 
1265  /* Clean out any possibly existing references to the segment. */
1267 restart:
1268  did_write = false;
1269  for (slotno = 0; slotno < shared->num_slots; slotno++)
1270  {
1271  int pagesegno = shared->page_number[slotno] / SLRU_PAGES_PER_SEGMENT;
1272 
1273  if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
1274  continue;
1275 
1276  /* not the segment we're looking for */
1277  if (pagesegno != segno)
1278  continue;
1279 
1280  /* If page is clean, just change state to EMPTY (expected case). */
1281  if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1282  !shared->page_dirty[slotno])
1283  {
1284  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
1285  continue;
1286  }
1287 
1288  /* Same logic as SimpleLruTruncate() */
1289  if (shared->page_status[slotno] == SLRU_PAGE_VALID)
1290  SlruInternalWritePage(ctl, slotno, NULL);
1291  else
1292  SimpleLruWaitIO(ctl, slotno);
1293 
1294  did_write = true;
1295  }
1296 
1297  /*
1298  * Be extra careful and re-check. The IO functions release the control
1299  * lock, so new pages could have been read in.
1300  */
1301  if (did_write)
1302  goto restart;
1303 
1304  snprintf(path, MAXPGPATH, "%s/%04X", ctl->Dir, segno);
1305  ereport(DEBUG2,
1306  (errmsg("removing file \"%s\"", path)));
1307  unlink(path);
1308 
1309  LWLockRelease(shared->ControlLock);
1310 }
LWLock * ControlLock
Definition: slru.h:61
int * page_number
Definition: slru.h:73
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruFlush fdata)
Definition: slru.c:503
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1715
SlruPageStatus * page_status
Definition: slru.h:71
#define MAXPGPATH
#define DEBUG2
Definition: elog.h:24
int unlink(const char *filename)
#define ereport(elevel, rest)
Definition: elog.h:122
static void SimpleLruWaitIO(SlruCtl ctl, int slotno)
Definition: slru.c:317
char Dir[64]
Definition: slru.h:138
#define NULL
Definition: c.h:229
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1111
int num_slots
Definition: slru.h:64
int errmsg(const char *fmt,...)
Definition: elog.c:797
bool * page_dirty
Definition: slru.h:72
SlruShared shared
Definition: slru.h:119
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:37
static void SlruInternalDeleteSegment ( SlruCtl  ctl,
char *  filename 
)
static

Definition at line 1244 of file slru.c.

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

Referenced by SlruScanDirCbDeleteAll(), and SlruScanDirCbDeleteCutoff().

1245 {
1246  char path[MAXPGPATH];
1247 
1248  snprintf(path, MAXPGPATH, "%s/%s", ctl->Dir, filename);
1249  ereport(DEBUG2,
1250  (errmsg("removing file \"%s\"", path)));
1251  unlink(path);
1252 }
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define MAXPGPATH
#define DEBUG2
Definition: elog.h:24
int unlink(const char *filename)
#define ereport(elevel, rest)
Definition: elog.h:122
char Dir[64]
Definition: slru.h:138
static char * filename
Definition: pg_dumpall.c:89
int errmsg(const char *fmt,...)
Definition: elog.c:797
static void SlruInternalWritePage ( SlruCtl  ctl,
int  slotno,
SlruFlush  fdata 
)
static

Definition at line 503 of file slru.c.

References Assert, SlruSharedData::buffer_locks, CloseTransientFile(), SlruSharedData::ControlLock, SlruFlushData::fd, i, InvalidTransactionId, LWLockPadded::lock, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SlruFlushData::num_files, SlruSharedData::page_dirty, SlruSharedData::page_number, SlruSharedData::page_status, SlruCtlData::shared, SimpleLruWaitIO(), SLRU_PAGE_VALID, SLRU_PAGE_WRITE_IN_PROGRESS, SlruPhysicalWritePage(), and SlruReportIOError().

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

504 {
505  SlruShared shared = ctl->shared;
506  int pageno = shared->page_number[slotno];
507  bool ok;
508 
509  /* If a write is in progress, wait for it to finish */
510  while (shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS &&
511  shared->page_number[slotno] == pageno)
512  {
513  SimpleLruWaitIO(ctl, slotno);
514  }
515 
516  /*
517  * Do nothing if page is not dirty, or if buffer no longer contains the
518  * same page we were called for.
519  */
520  if (!shared->page_dirty[slotno] ||
521  shared->page_status[slotno] != SLRU_PAGE_VALID ||
522  shared->page_number[slotno] != pageno)
523  return;
524 
525  /*
526  * Mark the slot write-busy, and clear the dirtybit. After this point, a
527  * transaction status update on this page will mark it dirty again.
528  */
529  shared->page_status[slotno] = SLRU_PAGE_WRITE_IN_PROGRESS;
530  shared->page_dirty[slotno] = false;
531 
532  /* Acquire per-buffer lock (cannot deadlock, see notes at top) */
533  LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_EXCLUSIVE);
534 
535  /* Release control lock while doing I/O */
536  LWLockRelease(shared->ControlLock);
537 
538  /* Do the write */
539  ok = SlruPhysicalWritePage(ctl, pageno, slotno, fdata);
540 
541  /* If we failed, and we're in a flush, better close the files */
542  if (!ok && fdata)
543  {
544  int i;
545 
546  for (i = 0; i < fdata->num_files; i++)
547  CloseTransientFile(fdata->fd[i]);
548  }
549 
550  /* Re-acquire control lock and update page state */
552 
553  Assert(shared->page_number[slotno] == pageno &&
554  shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS);
555 
556  /* If we failed to write, mark the page dirty again */
557  if (!ok)
558  shared->page_dirty[slotno] = true;
559 
560  shared->page_status[slotno] = SLRU_PAGE_VALID;
561 
562  LWLockRelease(&shared->buffer_locks[slotno].lock);
563 
564  /* Now it's okay to ereport if we failed */
565  if (!ok)
567 }
LWLock * ControlLock
Definition: slru.h:61
int * page_number
Definition: slru.h:73
static bool SlruPhysicalWritePage(SlruCtl ctl, int pageno, int slotno, SlruFlush fdata)
Definition: slru.c:715
static void SlruReportIOError(SlruCtl ctl, int pageno, TransactionId xid)
Definition: slru.c:889
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1715
SlruPageStatus * page_status
Definition: slru.h:71
LWLockPadded * buffer_locks
Definition: slru.h:108
#define InvalidTransactionId
Definition: transam.h:31
static void SimpleLruWaitIO(SlruCtl ctl, int slotno)
Definition: slru.c:317
int CloseTransientFile(int fd)
Definition: fd.c:2305
int num_files
Definition: slru.c:77
LWLock lock
Definition: lwlock.h:79
#define Assert(condition)
Definition: c.h:675
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1111
bool * page_dirty
Definition: slru.h:72
int i
SlruShared shared
Definition: slru.h:119
int fd[MAX_FLUSH_BUFFERS]
Definition: slru.c:78
static bool SlruPhysicalReadPage ( SlruCtl  ctl,
int  pageno,
int  slotno 
)
static

Definition at line 635 of file slru.c.

References CloseTransientFile(), ereport, errmsg(), fd(), InRecovery, LOG, MAXPGPATH, MemSet, OpenTransientFile(), SlruSharedData::page_buffer, PG_BINARY, pgstat_report_wait_end(), pgstat_report_wait_start(), read, SlruFlushData::segno, SlruCtlData::shared, SLRU_CLOSE_FAILED, slru_errcause, slru_errno, SLRU_OPEN_FAILED, SLRU_PAGES_PER_SEGMENT, SLRU_READ_FAILED, SLRU_SEEK_FAILED, SlruFileName, and WAIT_EVENT_SLRU_READ.

Referenced by SimpleLruReadPage().

636 {
637  SlruShared shared = ctl->shared;
638  int segno = pageno / SLRU_PAGES_PER_SEGMENT;
639  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
640  int offset = rpageno * BLCKSZ;
641  char path[MAXPGPATH];
642  int fd;
643 
644  SlruFileName(ctl, path, segno);
645 
646  /*
647  * In a crash-and-restart situation, it's possible for us to receive
648  * commands to set the commit status of transactions whose bits are in
649  * already-truncated segments of the commit log (see notes in
650  * SlruPhysicalWritePage). Hence, if we are InRecovery, allow the case
651  * where the file doesn't exist, and return zeroes instead.
652  */
653  fd = OpenTransientFile(path, O_RDWR | PG_BINARY, S_IRUSR | S_IWUSR);
654  if (fd < 0)
655  {
656  if (errno != ENOENT || !InRecovery)
657  {
659  slru_errno = errno;
660  return false;
661  }
662 
663  ereport(LOG,
664  (errmsg("file \"%s\" doesn't exist, reading as zeroes",
665  path)));
666  MemSet(shared->page_buffer[slotno], 0, BLCKSZ);
667  return true;
668  }
669 
670  if (lseek(fd, (off_t) offset, SEEK_SET) < 0)
671  {
673  slru_errno = errno;
674  CloseTransientFile(fd);
675  return false;
676  }
677 
678  errno = 0;
680  if (read(fd, shared->page_buffer[slotno], BLCKSZ) != BLCKSZ)
681  {
684  slru_errno = errno;
685  CloseTransientFile(fd);
686  return false;
687  }
689 
690  if (CloseTransientFile(fd))
691  {
693  slru_errno = errno;
694  return false;
695  }
696 
697  return true;
698 }
char ** page_buffer
Definition: slru.h:70
bool InRecovery
Definition: xlog.c:192
#define MemSet(start, val, len)
Definition: c.h:857
static SlruErrorCause slru_errcause
Definition: slru.c:123
#define LOG
Definition: elog.h:26
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define PG_BINARY
Definition: c.h:1038
#define MAXPGPATH
int OpenTransientFile(FileName fileName, int fileFlags, int fileMode)
Definition: fd.c:2144
static void pgstat_report_wait_end(void)
Definition: pgstat.h:1232
#define ereport(elevel, rest)
Definition: elog.h:122
int CloseTransientFile(int fd)
Definition: fd.c:2305
#define SlruFileName(ctl, path, seg)
Definition: slru.c:63
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: pgstat.h:1208
static int slru_errno
Definition: slru.c:124
int errmsg(const char *fmt,...)
Definition: elog.c:797
SlruShared shared
Definition: slru.h:119
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:37
#define read(a, b, c)
Definition: win32.h:13
static bool SlruPhysicalWritePage ( SlruCtl  ctl,
int  pageno,
int  slotno,
SlruFlush  fdata 
)
static

Definition at line 715 of file slru.c.

References CloseTransientFile(), SlruCtlData::do_fsync, END_CRIT_SECTION, SlruFlushData::fd, fd(), SlruSharedData::group_lsn, i, SlruSharedData::lsn_groups_per_page, MAX_FLUSH_BUFFERS, MAXPGPATH, NULL, SlruFlushData::num_files, OpenTransientFile(), SlruSharedData::page_buffer, PG_BINARY, 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_OPEN_FAILED, SLRU_PAGES_PER_SEGMENT, SLRU_SEEK_FAILED, SLRU_WRITE_FAILED, SlruFileName, START_CRIT_SECTION, WAIT_EVENT_SLRU_SYNC, WAIT_EVENT_SLRU_WRITE, write, XLogFlush(), and XLogRecPtrIsInvalid.

Referenced by SlruInternalWritePage().

716 {
717  SlruShared shared = ctl->shared;
718  int segno = pageno / SLRU_PAGES_PER_SEGMENT;
719  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
720  int offset = rpageno * BLCKSZ;
721  char path[MAXPGPATH];
722  int fd = -1;
723 
724  /*
725  * Honor the write-WAL-before-data rule, if appropriate, so that we do not
726  * write out data before associated WAL records. This is the same action
727  * performed during FlushBuffer() in the main buffer manager.
728  */
729  if (shared->group_lsn != NULL)
730  {
731  /*
732  * We must determine the largest async-commit LSN for the page. This
733  * is a bit tedious, but since this entire function is a slow path
734  * anyway, it seems better to do this here than to maintain a per-page
735  * LSN variable (which'd need an extra comparison in the
736  * transaction-commit path).
737  */
738  XLogRecPtr max_lsn;
739  int lsnindex,
740  lsnoff;
741 
742  lsnindex = slotno * shared->lsn_groups_per_page;
743  max_lsn = shared->group_lsn[lsnindex++];
744  for (lsnoff = 1; lsnoff < shared->lsn_groups_per_page; lsnoff++)
745  {
746  XLogRecPtr this_lsn = shared->group_lsn[lsnindex++];
747 
748  if (max_lsn < this_lsn)
749  max_lsn = this_lsn;
750  }
751 
752  if (!XLogRecPtrIsInvalid(max_lsn))
753  {
754  /*
755  * As noted above, elog(ERROR) is not acceptable here, so if
756  * XLogFlush were to fail, we must PANIC. This isn't much of a
757  * restriction because XLogFlush is just about all critical
758  * section anyway, but let's make sure.
759  */
761  XLogFlush(max_lsn);
763  }
764  }
765 
766  /*
767  * During a Flush, we may already have the desired file open.
768  */
769  if (fdata)
770  {
771  int i;
772 
773  for (i = 0; i < fdata->num_files; i++)
774  {
775  if (fdata->segno[i] == segno)
776  {
777  fd = fdata->fd[i];
778  break;
779  }
780  }
781  }
782 
783  if (fd < 0)
784  {
785  /*
786  * If the file doesn't already exist, we should create it. It is
787  * possible for this to need to happen when writing a page that's not
788  * first in its segment; we assume the OS can cope with that. (Note:
789  * it might seem that it'd be okay to create files only when
790  * SimpleLruZeroPage is called for the first page of a segment.
791  * However, if after a crash and restart the REDO logic elects to
792  * replay the log from a checkpoint before the latest one, then it's
793  * possible that we will get commands to set transaction status of
794  * transactions that have already been truncated from the commit log.
795  * Easiest way to deal with that is to accept references to
796  * nonexistent files here and in SlruPhysicalReadPage.)
797  *
798  * Note: it is possible for more than one backend to be executing this
799  * code simultaneously for different pages of the same file. Hence,
800  * don't use O_EXCL or O_TRUNC or anything like that.
801  */
802  SlruFileName(ctl, path, segno);
803  fd = OpenTransientFile(path, O_RDWR | O_CREAT | PG_BINARY,
804  S_IRUSR | S_IWUSR);
805  if (fd < 0)
806  {
808  slru_errno = errno;
809  return false;
810  }
811 
812  if (fdata)
813  {
814  if (fdata->num_files < MAX_FLUSH_BUFFERS)
815  {
816  fdata->fd[fdata->num_files] = fd;
817  fdata->segno[fdata->num_files] = segno;
818  fdata->num_files++;
819  }
820  else
821  {
822  /*
823  * In the unlikely event that we exceed MAX_FLUSH_BUFFERS,
824  * fall back to treating it as a standalone write.
825  */
826  fdata = NULL;
827  }
828  }
829  }
830 
831  if (lseek(fd, (off_t) offset, SEEK_SET) < 0)
832  {
834  slru_errno = errno;
835  if (!fdata)
836  CloseTransientFile(fd);
837  return false;
838  }
839 
840  errno = 0;
842  if (write(fd, shared->page_buffer[slotno], BLCKSZ) != BLCKSZ)
843  {
845  /* if write didn't set errno, assume problem is no disk space */
846  if (errno == 0)
847  errno = ENOSPC;
849  slru_errno = errno;
850  if (!fdata)
851  CloseTransientFile(fd);
852  return false;
853  }
855 
856  /*
857  * If not part of Flush, need to fsync now. We assume this happens
858  * infrequently enough that it's not a performance issue.
859  */
860  if (!fdata)
861  {
863  if (ctl->do_fsync && pg_fsync(fd))
864  {
867  slru_errno = errno;
868  CloseTransientFile(fd);
869  return false;
870  }
872 
873  if (CloseTransientFile(fd))
874  {
876  slru_errno = errno;
877  return false;
878  }
879  }
880 
881  return true;
882 }
#define write(a, b, c)
Definition: win32.h:14
char ** page_buffer
Definition: slru.h:70
#define END_CRIT_SECTION()
Definition: miscadmin.h:135
#define START_CRIT_SECTION()
Definition: miscadmin.h:133
static SlruErrorCause slru_errcause
Definition: slru.c:123
int lsn_groups_per_page
Definition: slru.h:85
int segno[MAX_FLUSH_BUFFERS]
Definition: slru.c:79
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2757
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define PG_BINARY
Definition: c.h:1038
#define MAXPGPATH
#define MAX_FLUSH_BUFFERS
Definition: slru.c:73
int OpenTransientFile(FileName fileName, int fileFlags, int fileMode)
Definition: fd.c:2144
XLogRecPtr * group_lsn
Definition: slru.h:84
static void pgstat_report_wait_end(void)
Definition: pgstat.h:1232
bool do_fsync
Definition: slru.h:125
int CloseTransientFile(int fd)
Definition: fd.c:2305
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29
#define SlruFileName(ctl, path, seg)
Definition: slru.c:63
int num_files
Definition: slru.c:77
#define NULL
Definition: c.h:229
uint64 XLogRecPtr
Definition: xlogdefs.h:21
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: pgstat.h:1208
static int slru_errno
Definition: slru.c:124
int i
SlruShared shared
Definition: slru.h:119
int pg_fsync(int fd)
Definition: fd.c:333
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:37
int fd[MAX_FLUSH_BUFFERS]
Definition: slru.c:78
static void SlruReportIOError ( SlruCtl  ctl,
int  pageno,
TransactionId  xid 
)
static

Definition at line 889 of file slru.c.

References elog, ereport, errcode_for_file_access(), errdetail(), errmsg(), ERROR, MAXPGPATH, SlruFlushData::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(), SimpleLruFlush(), SimpleLruReadPage(), and SlruInternalWritePage().

890 {
891  int segno = pageno / SLRU_PAGES_PER_SEGMENT;
892  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
893  int offset = rpageno * BLCKSZ;
894  char path[MAXPGPATH];
895 
896  SlruFileName(ctl, path, segno);
897  errno = slru_errno;
898  switch (slru_errcause)
899  {
900  case SLRU_OPEN_FAILED:
901  ereport(ERROR,
903  errmsg("could not access status of transaction %u", xid),
904  errdetail("Could not open file \"%s\": %m.", path)));
905  break;
906  case SLRU_SEEK_FAILED:
907  ereport(ERROR,
909  errmsg("could not access status of transaction %u", xid),
910  errdetail("Could not seek in file \"%s\" to offset %u: %m.",
911  path, offset)));
912  break;
913  case SLRU_READ_FAILED:
914  ereport(ERROR,
916  errmsg("could not access status of transaction %u", xid),
917  errdetail("Could not read from file \"%s\" at offset %u: %m.",
918  path, offset)));
919  break;
920  case SLRU_WRITE_FAILED:
921  ereport(ERROR,
923  errmsg("could not access status of transaction %u", xid),
924  errdetail("Could not write to file \"%s\" at offset %u: %m.",
925  path, offset)));
926  break;
927  case SLRU_FSYNC_FAILED:
928  ereport(ERROR,
930  errmsg("could not access status of transaction %u", xid),
931  errdetail("Could not fsync file \"%s\": %m.",
932  path)));
933  break;
934  case SLRU_CLOSE_FAILED:
935  ereport(ERROR,
937  errmsg("could not access status of transaction %u", xid),
938  errdetail("Could not close file \"%s\": %m.",
939  path)));
940  break;
941  default:
942  /* can't get here, we trust */
943  elog(ERROR, "unrecognized SimpleLru error cause: %d",
944  (int) slru_errcause);
945  break;
946  }
947 }
static SlruErrorCause slru_errcause
Definition: slru.c:123
#define ERROR
Definition: elog.h:43
#define MAXPGPATH
int errdetail(const char *fmt,...)
Definition: elog.c:873
int errcode_for_file_access(void)
Definition: elog.c:598
#define ereport(elevel, rest)
Definition: elog.h:122
#define SlruFileName(ctl, path, seg)
Definition: slru.c:63
static int slru_errno
Definition: slru.c:124
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:37
bool SlruScanDirCbDeleteAll ( SlruCtl  ctl,
char *  filename,
int  segpage,
void *  data 
)

Definition at line 1350 of file slru.c.

References SlruInternalDeleteSegment().

Referenced by AsyncShmemInit(), and DeactivateCommitTs().

1351 {
1353 
1354  return false; /* keep going */
1355 }
static void SlruInternalDeleteSegment(SlruCtl ctl, char *filename)
Definition: slru.c:1244
static char * filename
Definition: pg_dumpall.c:89
static bool SlruScanDirCbDeleteCutoff ( SlruCtl  ctl,
char *  filename,
int  segpage,
void *  data 
)
static

Definition at line 1335 of file slru.c.

References SlruCtlData::PagePrecedes, and SlruInternalDeleteSegment().

Referenced by SimpleLruTruncate().

1336 {
1337  int cutoffPage = *(int *) data;
1338 
1339  if (ctl->PagePrecedes(segpage, cutoffPage))
1341 
1342  return false; /* keep going */
1343 }
static void SlruInternalDeleteSegment(SlruCtl ctl, char *filename)
Definition: slru.c:1244
bool(* PagePrecedes)(int, int)
Definition: slru.h:132
static char * filename
Definition: pg_dumpall.c:89
bool SlruScanDirCbReportPresence ( SlruCtl  ctl,
char *  filename,
int  segpage,
void *  data 
)

Definition at line 1318 of file slru.c.

References SlruCtlData::PagePrecedes, and SLRU_PAGES_PER_SEGMENT.

Referenced by TruncateCLOG(), and TruncateCommitTs().

1319 {
1320  int cutoffPage = *(int *) data;
1321 
1322  cutoffPage -= cutoffPage % SLRU_PAGES_PER_SEGMENT;
1323 
1324  if (ctl->PagePrecedes(segpage, cutoffPage))
1325  return true; /* found one; don't iterate any more */
1326 
1327  return false; /* keep going */
1328 }
bool(* PagePrecedes)(int, int)
Definition: slru.h:132
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:37
bool SlruScanDirectory ( SlruCtl  ctl,
SlruScanCallback  callback,
void *  data 
)

Definition at line 1373 of file slru.c.

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

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

1374 {
1375  bool retval = false;
1376  DIR *cldir;
1377  struct dirent *clde;
1378  int segno;
1379  int segpage;
1380 
1381  cldir = AllocateDir(ctl->Dir);
1382  while ((clde = ReadDir(cldir, ctl->Dir)) != NULL)
1383  {
1384  size_t len;
1385 
1386  len = strlen(clde->d_name);
1387 
1388  if ((len == 4 || len == 5 || len == 6) &&
1389  strspn(clde->d_name, "0123456789ABCDEF") == len)
1390  {
1391  segno = (int) strtol(clde->d_name, NULL, 16);
1392  segpage = segno * SLRU_PAGES_PER_SEGMENT;
1393 
1394  elog(DEBUG2, "SlruScanDirectory invoking callback on %s/%s",
1395  ctl->Dir, clde->d_name);
1396  retval = callback(ctl, clde->d_name, segpage, data);
1397  if (retval)
1398  break;
1399  }
1400  }
1401  FreeDir(cldir);
1402 
1403  return retval;
1404 }
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:2335
char Dir[64]
Definition: slru.h:138
#define NULL
Definition: c.h:229
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2401
char d_name[MAX_PATH]
Definition: dirent.h:14
#define elog
Definition: elog.h:219
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:37
int FreeDir(DIR *dir)
Definition: fd.c:2444
static int SlruSelectLRUPage ( SlruCtl  ctl,
int  pageno 
)
static

Definition at line 963 of file slru.c.

References SlruSharedData::cur_lru_count, SlruSharedData::latest_page_number, NULL, SlruSharedData::num_slots, SlruSharedData::page_dirty, SlruSharedData::page_lru_count, SlruSharedData::page_number, SlruSharedData::page_status, SlruCtlData::PagePrecedes, SlruCtlData::shared, SimpleLruWaitIO(), SLRU_PAGE_EMPTY, SLRU_PAGE_VALID, and SlruInternalWritePage().

Referenced by SimpleLruReadPage(), and SimpleLruZeroPage().

964 {
965  SlruShared shared = ctl->shared;
966 
967  /* Outer loop handles restart after I/O */
968  for (;;)
969  {
970  int slotno;
971  int cur_count;
972  int bestvalidslot = 0; /* keep compiler quiet */
973  int best_valid_delta = -1;
974  int best_valid_page_number = 0; /* keep compiler quiet */
975  int bestinvalidslot = 0; /* keep compiler quiet */
976  int best_invalid_delta = -1;
977  int best_invalid_page_number = 0; /* keep compiler quiet */
978 
979  /* See if page already has a buffer assigned */
980  for (slotno = 0; slotno < shared->num_slots; slotno++)
981  {
982  if (shared->page_number[slotno] == pageno &&
983  shared->page_status[slotno] != SLRU_PAGE_EMPTY)
984  return slotno;
985  }
986 
987  /*
988  * If we find any EMPTY slot, just select that one. Else choose a
989  * victim page to replace. We normally take the least recently used
990  * valid page, but we will never take the slot containing
991  * latest_page_number, even if it appears least recently used. We
992  * will select a slot that is already I/O busy only if there is no
993  * other choice: a read-busy slot will not be least recently used once
994  * the read finishes, and waiting for an I/O on a write-busy slot is
995  * inferior to just picking some other slot. Testing shows the slot
996  * we pick instead will often be clean, allowing us to begin a read at
997  * once.
998  *
999  * Normally the page_lru_count values will all be different and so
1000  * there will be a well-defined LRU page. But since we allow
1001  * concurrent execution of SlruRecentlyUsed() within
1002  * SimpleLruReadPage_ReadOnly(), it is possible that multiple pages
1003  * acquire the same lru_count values. In that case we break ties by
1004  * choosing the furthest-back page.
1005  *
1006  * Notice that this next line forcibly advances cur_lru_count to a
1007  * value that is certainly beyond any value that will be in the
1008  * page_lru_count array after the loop finishes. This ensures that
1009  * the next execution of SlruRecentlyUsed will mark the page newly
1010  * used, even if it's for a page that has the current counter value.
1011  * That gets us back on the path to having good data when there are
1012  * multiple pages with the same lru_count.
1013  */
1014  cur_count = (shared->cur_lru_count)++;
1015  for (slotno = 0; slotno < shared->num_slots; slotno++)
1016  {
1017  int this_delta;
1018  int this_page_number;
1019 
1020  if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
1021  return slotno;
1022  this_delta = cur_count - shared->page_lru_count[slotno];
1023  if (this_delta < 0)
1024  {
1025  /*
1026  * Clean up in case shared updates have caused cur_count
1027  * increments to get "lost". We back off the page counts,
1028  * rather than trying to increase cur_count, to avoid any
1029  * question of infinite loops or failure in the presence of
1030  * wrapped-around counts.
1031  */
1032  shared->page_lru_count[slotno] = cur_count;
1033  this_delta = 0;
1034  }
1035  this_page_number = shared->page_number[slotno];
1036  if (this_page_number == shared->latest_page_number)
1037  continue;
1038  if (shared->page_status[slotno] == SLRU_PAGE_VALID)
1039  {
1040  if (this_delta > best_valid_delta ||
1041  (this_delta == best_valid_delta &&
1042  ctl->PagePrecedes(this_page_number,
1043  best_valid_page_number)))
1044  {
1045  bestvalidslot = slotno;
1046  best_valid_delta = this_delta;
1047  best_valid_page_number = this_page_number;
1048  }
1049  }
1050  else
1051  {
1052  if (this_delta > best_invalid_delta ||
1053  (this_delta == best_invalid_delta &&
1054  ctl->PagePrecedes(this_page_number,
1055  best_invalid_page_number)))
1056  {
1057  bestinvalidslot = slotno;
1058  best_invalid_delta = this_delta;
1059  best_invalid_page_number = this_page_number;
1060  }
1061  }
1062  }
1063 
1064  /*
1065  * If all pages (except possibly the latest one) are I/O busy, we'll
1066  * have to wait for an I/O to complete and then retry. In that
1067  * unhappy case, we choose to wait for the I/O on the least recently
1068  * used slot, on the assumption that it was likely initiated first of
1069  * all the I/Os in progress and may therefore finish first.
1070  */
1071  if (best_valid_delta < 0)
1072  {
1073  SimpleLruWaitIO(ctl, bestinvalidslot);
1074  continue;
1075  }
1076 
1077  /*
1078  * If the selected page is clean, we're set.
1079  */
1080  if (!shared->page_dirty[bestvalidslot])
1081  return bestvalidslot;
1082 
1083  /*
1084  * Write the page.
1085  */
1086  SlruInternalWritePage(ctl, bestvalidslot, NULL);
1087 
1088  /*
1089  * Now loop back and try again. This is the easiest way of dealing
1090  * with corner cases such as the victim page being re-dirtied while we
1091  * wrote it.
1092  */
1093  }
1094 }
int * page_number
Definition: slru.h:73
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruFlush fdata)
Definition: slru.c:503
int latest_page_number
Definition: slru.h:103
int cur_lru_count
Definition: slru.h:96
SlruPageStatus * page_status
Definition: slru.h:71
static void SimpleLruWaitIO(SlruCtl ctl, int slotno)
Definition: slru.c:317
bool(* PagePrecedes)(int, int)
Definition: slru.h:132
int * page_lru_count
Definition: slru.h:74
#define NULL
Definition: c.h:229
int num_slots
Definition: slru.h:64
bool * page_dirty
Definition: slru.h:72
SlruShared shared
Definition: slru.h:119

Variable Documentation

int slru_errno
static