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 "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 72 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 102 of file slru.c.

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

Typedef Documentation

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

Function Documentation

bool SimpleLruDoesPhysicalPageExist ( SlruCtl  ctl,
int  pageno 
)

Definition at line 585 of file slru.c.

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

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

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

Definition at line 1090 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(), 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(), and SlruReportIOError().

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

1091 {
1092  SlruShared shared = ctl->shared;
1093  SlruFlushData fdata;
1094  int slotno;
1095  int pageno = 0;
1096  int i;
1097  bool ok;
1098 
1099  /*
1100  * Find and write dirty pages
1101  */
1102  fdata.num_files = 0;
1103 
1105 
1106  for (slotno = 0; slotno < shared->num_slots; slotno++)
1107  {
1108  SlruInternalWritePage(ctl, slotno, &fdata);
1109 
1110  /*
1111  * In some places (e.g. checkpoints), we cannot assert that the slot
1112  * is clean now, since another process might have re-dirtied it
1113  * already. That's okay.
1114  */
1115  Assert(allow_redirtied ||
1116  shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
1117  (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1118  !shared->page_dirty[slotno]));
1119  }
1120 
1121  LWLockRelease(shared->ControlLock);
1122 
1123  /*
1124  * Now fsync and close any files that were open
1125  */
1126  ok = true;
1127  for (i = 0; i < fdata.num_files; i++)
1128  {
1129  if (ctl->do_fsync && pg_fsync(fdata.fd[i]))
1130  {
1132  slru_errno = errno;
1133  pageno = fdata.segno[i] * SLRU_PAGES_PER_SEGMENT;
1134  ok = false;
1135  }
1136 
1137  if (CloseTransientFile(fdata.fd[i]))
1138  {
1140  slru_errno = errno;
1141  pageno = fdata.segno[i] * SLRU_PAGES_PER_SEGMENT;
1142  ok = false;
1143  }
1144  }
1145  if (!ok)
1147 }
LWLock * ControlLock
Definition: slru.h:61
static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruFlush fdata)
Definition: slru.c:502
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:879
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
SlruPageStatus * page_status
Definition: slru.h:71
#define InvalidTransactionId
Definition: transam.h:31
bool do_fsync
Definition: slru.h:125
int CloseTransientFile(int fd)
Definition: fd.c:2254
int num_files
Definition: slru.c:76
#define Assert(condition)
Definition: c.h:671
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
int num_slots
Definition: slru.h:64
static int slru_errno
Definition: slru.c:123
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:77
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, ShmemAlloc(), 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  if (nlsns > 0)
208  {
209  shared->group_lsn = (XLogRecPtr *) (ptr + offset);
210  offset += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr));
211  }
212 
213  /* Initialize LWLocks */
214  shared->buffer_locks = (LWLockPadded *) ShmemAlloc(sizeof(LWLockPadded) * nslots);
215 
216  Assert(strlen(name) + 1 < SLRU_MAX_NAME_LENGTH);
218  shared->lwlock_tranche_id = tranche_id;
219 
220  ptr += BUFFERALIGN(offset);
221  for (slotno = 0; slotno < nslots; slotno++)
222  {
223  LWLockInitialize(&shared->buffer_locks[slotno].lock,
224  shared->lwlock_tranche_id);
225 
226  shared->page_buffer[slotno] = ptr;
227  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
228  shared->page_dirty[slotno] = false;
229  shared->page_lru_count[slotno] = 0;
230  ptr += BLCKSZ;
231  }
232  }
233  else
234  Assert(found);
235 
236  /* Register SLRU tranche in the main tranches array */
238  shared->lwlock_tranche_name);
239 
240  /*
241  * Initialize the unshared control struct, including directory path. We
242  * assume caller set PagePrecedes.
243  */
244  ctl->shared = shared;
245  ctl->do_fsync = true; /* default behavior */
246  StrNCpy(ctl->Dir, subdir, sizeof(ctl->Dir));
247 }
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:144
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:100
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:666
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:671
#define StrNCpy(dst, src, len)
Definition: c.h:826
size_t Size
Definition: c.h:353
#define MAXALIGN(LEN)
Definition: c.h:584
void LWLockRegisterTranche(int tranche_id, char *tranche_name)
Definition: lwlock.c:591
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:586
int lwlock_tranche_id
Definition: slru.h:106
int SimpleLruReadPage ( SlruCtl  ctl,
int  pageno,
bool  write_ok,
TransactionId  xid 
)

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

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

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

463 {
464  SlruShared shared = ctl->shared;
465  int slotno;
466 
467  /* Try to find the page while holding only shared lock */
469 
470  /* See if page is already in a buffer */
471  for (slotno = 0; slotno < shared->num_slots; slotno++)
472  {
473  if (shared->page_number[slotno] == pageno &&
474  shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
475  shared->page_status[slotno] != SLRU_PAGE_READ_IN_PROGRESS)
476  {
477  /* See comments for SlruRecentlyUsed macro */
478  SlruRecentlyUsed(shared, slotno);
479  return slotno;
480  }
481  }
482 
483  /* No luck, so switch to normal exclusive lock and do regular read */
484  LWLockRelease(shared->ControlLock);
486 
487  return SimpleLruReadPage(ctl, pageno, true, xid);
488 }
LWLock * ControlLock
Definition: slru.h:61
int * page_number
Definition: slru.h:73
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
SlruPageStatus * page_status
Definition: slru.h:71
int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok, TransactionId xid)
Definition: slru.c:370
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
int num_slots
Definition: slru.h:64
SlruShared shared
Definition: slru.h:119
#define SlruRecentlyUsed(shared, slotno)
Definition: slru.c:102
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:48
uint64 XLogRecPtr
Definition: xlogdefs.h:21
size_t Size
Definition: c.h:353
#define MAXALIGN(LEN)
Definition: c.h:584
#define BUFFERALIGN(LEN)
Definition: c.h:586
void SimpleLruTruncate ( SlruCtl  ctl,
int  cutoffPage 
)

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

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

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

Definition at line 573 of file slru.c.

References NULL, and SlruInternalWritePage().

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

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

Definition at line 299 of file slru.c.

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

Referenced by SimpleLruReadPage(), and SimpleLruZeroPage().

300 {
301  SlruShared shared = ctl->shared;
302 
303  if (shared->lsn_groups_per_page > 0)
304  MemSet(&shared->group_lsn[slotno * shared->lsn_groups_per_page], 0,
305  shared->lsn_groups_per_page * sizeof(XLogRecPtr));
306 }
#define MemSet(start, val, len)
Definition: c.h:853
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 258 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().

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

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

1247 {
1248  SlruShared shared = ctl->shared;
1249  int slotno;
1250  char path[MAXPGPATH];
1251  bool did_write;
1252 
1253  /* Clean out any possibly existing references to the segment. */
1255 restart:
1256  did_write = false;
1257  for (slotno = 0; slotno < shared->num_slots; slotno++)
1258  {
1259  int pagesegno = shared->page_number[slotno] / SLRU_PAGES_PER_SEGMENT;
1260 
1261  if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
1262  continue;
1263 
1264  /* not the segment we're looking for */
1265  if (pagesegno != segno)
1266  continue;
1267 
1268  /* If page is clean, just change state to EMPTY (expected case). */
1269  if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1270  !shared->page_dirty[slotno])
1271  {
1272  shared->page_status[slotno] = SLRU_PAGE_EMPTY;
1273  continue;
1274  }
1275 
1276  /* Same logic as SimpleLruTruncate() */
1277  if (shared->page_status[slotno] == SLRU_PAGE_VALID)
1278  SlruInternalWritePage(ctl, slotno, NULL);
1279  else
1280  SimpleLruWaitIO(ctl, slotno);
1281 
1282  did_write = true;
1283  }
1284 
1285  /*
1286  * Be extra careful and re-check. The IO functions release the control
1287  * lock, so new pages could have been read in.
1288  */
1289  if (did_write)
1290  goto restart;
1291 
1292  snprintf(path, MAXPGPATH, "%s/%04X", ctl->Dir, segno);
1293  ereport(DEBUG2,
1294  (errmsg("removing file \"%s\"", path)));
1295  unlink(path);
1296 
1297  LWLockRelease(shared->ControlLock);
1298 }
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:502
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
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:316
char Dir[64]
Definition: slru.h:138
#define NULL
Definition: c.h:226
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
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 1232 of file slru.c.

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

Referenced by SlruScanDirCbDeleteAll(), and SlruScanDirCbDeleteCutoff().

1233 {
1234  char path[MAXPGPATH];
1235 
1236  snprintf(path, MAXPGPATH, "%s/%s", ctl->Dir, filename);
1237  ereport(DEBUG2,
1238  (errmsg("removing file \"%s\"", path)));
1239  unlink(path);
1240 }
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:80
int errmsg(const char *fmt,...)
Definition: elog.c:797
static void SlruInternalWritePage ( SlruCtl  ctl,
int  slotno,
SlruFlush  fdata 
)
static

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

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

Definition at line 634 of file slru.c.

References CloseTransientFile(), ereport, errmsg(), fd(), InRecovery, LOG, MAXPGPATH, MemSet, OpenTransientFile(), SlruSharedData::page_buffer, PG_BINARY, 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, and SlruFileName.

Referenced by SimpleLruReadPage().

635 {
636  SlruShared shared = ctl->shared;
637  int segno = pageno / SLRU_PAGES_PER_SEGMENT;
638  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
639  int offset = rpageno * BLCKSZ;
640  char path[MAXPGPATH];
641  int fd;
642 
643  SlruFileName(ctl, path, segno);
644 
645  /*
646  * In a crash-and-restart situation, it's possible for us to receive
647  * commands to set the commit status of transactions whose bits are in
648  * already-truncated segments of the commit log (see notes in
649  * SlruPhysicalWritePage). Hence, if we are InRecovery, allow the case
650  * where the file doesn't exist, and return zeroes instead.
651  */
652  fd = OpenTransientFile(path, O_RDWR | PG_BINARY, S_IRUSR | S_IWUSR);
653  if (fd < 0)
654  {
655  if (errno != ENOENT || !InRecovery)
656  {
658  slru_errno = errno;
659  return false;
660  }
661 
662  ereport(LOG,
663  (errmsg("file \"%s\" doesn't exist, reading as zeroes",
664  path)));
665  MemSet(shared->page_buffer[slotno], 0, BLCKSZ);
666  return true;
667  }
668 
669  if (lseek(fd, (off_t) offset, SEEK_SET) < 0)
670  {
672  slru_errno = errno;
673  CloseTransientFile(fd);
674  return false;
675  }
676 
677  errno = 0;
678  if (read(fd, shared->page_buffer[slotno], BLCKSZ) != BLCKSZ)
679  {
681  slru_errno = errno;
682  CloseTransientFile(fd);
683  return false;
684  }
685 
686  if (CloseTransientFile(fd))
687  {
689  slru_errno = errno;
690  return false;
691  }
692 
693  return true;
694 }
char ** page_buffer
Definition: slru.h:70
bool InRecovery
Definition: xlog.c:191
#define MemSet(start, val, len)
Definition: c.h:853
static SlruErrorCause slru_errcause
Definition: slru.c:122
#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:2093
#define ereport(elevel, rest)
Definition: elog.h:122
int CloseTransientFile(int fd)
Definition: fd.c:2254
#define SlruFileName(ctl, path, seg)
Definition: slru.c:62
static int slru_errno
Definition: slru.c:123
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:18
static bool SlruPhysicalWritePage ( SlruCtl  ctl,
int  pageno,
int  slotno,
SlruFlush  fdata 
)
static

Definition at line 711 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(), 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, write, XLogFlush(), and XLogRecPtrIsInvalid.

Referenced by SlruInternalWritePage().

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

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

880 {
881  int segno = pageno / SLRU_PAGES_PER_SEGMENT;
882  int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
883  int offset = rpageno * BLCKSZ;
884  char path[MAXPGPATH];
885 
886  SlruFileName(ctl, path, segno);
887  errno = slru_errno;
888  switch (slru_errcause)
889  {
890  case SLRU_OPEN_FAILED:
891  ereport(ERROR,
893  errmsg("could not access status of transaction %u", xid),
894  errdetail("Could not open file \"%s\": %m.", path)));
895  break;
896  case SLRU_SEEK_FAILED:
897  ereport(ERROR,
899  errmsg("could not access status of transaction %u", xid),
900  errdetail("Could not seek in file \"%s\" to offset %u: %m.",
901  path, offset)));
902  break;
903  case SLRU_READ_FAILED:
904  ereport(ERROR,
906  errmsg("could not access status of transaction %u", xid),
907  errdetail("Could not read from file \"%s\" at offset %u: %m.",
908  path, offset)));
909  break;
910  case SLRU_WRITE_FAILED:
911  ereport(ERROR,
913  errmsg("could not access status of transaction %u", xid),
914  errdetail("Could not write to file \"%s\" at offset %u: %m.",
915  path, offset)));
916  break;
917  case SLRU_FSYNC_FAILED:
918  ereport(ERROR,
920  errmsg("could not access status of transaction %u", xid),
921  errdetail("Could not fsync file \"%s\": %m.",
922  path)));
923  break;
924  case SLRU_CLOSE_FAILED:
925  ereport(ERROR,
927  errmsg("could not access status of transaction %u", xid),
928  errdetail("Could not close file \"%s\": %m.",
929  path)));
930  break;
931  default:
932  /* can't get here, we trust */
933  elog(ERROR, "unrecognized SimpleLru error cause: %d",
934  (int) slru_errcause);
935  break;
936  }
937 }
static SlruErrorCause slru_errcause
Definition: slru.c:122
#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:62
static int slru_errno
Definition: slru.c:123
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 1338 of file slru.c.

References SlruInternalDeleteSegment().

Referenced by AsyncShmemInit(), and DeactivateCommitTs().

1339 {
1341 
1342  return false; /* keep going */
1343 }
static void SlruInternalDeleteSegment(SlruCtl ctl, char *filename)
Definition: slru.c:1232
static char * filename
Definition: pg_dumpall.c:80
static bool SlruScanDirCbDeleteCutoff ( SlruCtl  ctl,
char *  filename,
int  segpage,
void *  data 
)
static

Definition at line 1323 of file slru.c.

References SlruCtlData::PagePrecedes, and SlruInternalDeleteSegment().

Referenced by SimpleLruTruncate().

1324 {
1325  int cutoffPage = *(int *) data;
1326 
1327  if (ctl->PagePrecedes(segpage, cutoffPage))
1329 
1330  return false; /* keep going */
1331 }
static void SlruInternalDeleteSegment(SlruCtl ctl, char *filename)
Definition: slru.c:1232
bool(* PagePrecedes)(int, int)
Definition: slru.h:132
static char * filename
Definition: pg_dumpall.c:80
bool SlruScanDirCbReportPresence ( SlruCtl  ctl,
char *  filename,
int  segpage,
void *  data 
)

Definition at line 1306 of file slru.c.

References SlruCtlData::PagePrecedes, and SLRU_PAGES_PER_SEGMENT.

Referenced by TruncateCLOG(), and TruncateCommitTs().

1307 {
1308  int cutoffPage = *(int *) data;
1309 
1310  cutoffPage -= cutoffPage % SLRU_PAGES_PER_SEGMENT;
1311 
1312  if (ctl->PagePrecedes(segpage, cutoffPage))
1313  return true; /* found one; don't iterate any more */
1314 
1315  return false; /* keep going */
1316 }
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 1361 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().

1362 {
1363  bool retval = false;
1364  DIR *cldir;
1365  struct dirent *clde;
1366  int segno;
1367  int segpage;
1368 
1369  cldir = AllocateDir(ctl->Dir);
1370  while ((clde = ReadDir(cldir, ctl->Dir)) != NULL)
1371  {
1372  size_t len;
1373 
1374  len = strlen(clde->d_name);
1375 
1376  if ((len == 4 || len == 5 || len == 6) &&
1377  strspn(clde->d_name, "0123456789ABCDEF") == len)
1378  {
1379  segno = (int) strtol(clde->d_name, NULL, 16);
1380  segpage = segno * SLRU_PAGES_PER_SEGMENT;
1381 
1382  elog(DEBUG2, "SlruScanDirectory invoking callback on %s/%s",
1383  ctl->Dir, clde->d_name);
1384  retval = callback(ctl, clde->d_name, segpage, data);
1385  if (retval)
1386  break;
1387  }
1388  }
1389  FreeDir(cldir);
1390 
1391  return retval;
1392 }
Definition: dirent.h:9
Definition: dirent.c:25
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:49
#define DEBUG2
Definition: elog.h:24
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2284
char Dir[64]
Definition: slru.h:138
#define NULL
Definition: c.h:226
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2350
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:2393
static int SlruSelectLRUPage ( SlruCtl  ctl,
int  pageno 
)
static

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

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