Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

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

Go to the source code of this file.

Data Structures

struct  SlruWriteAllData
 

Macros

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

Typedefs

typedef struct SlruWriteAllData SlruWriteAllData
 
typedef struct SlruWriteAllDataSlruWriteAll
 

Enumerations

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

Functions

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

Variables

static SlruErrorCause slru_errcause
 
static int slru_errno
 

Macro Definition Documentation

◆ INIT_SLRUFILETAG

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

Definition at line 156 of file slru.c.

◆ MAX_WRITEALL_BUFFERS

#define MAX_WRITEALL_BUFFERS   16

Definition at line 123 of file slru.c.

◆ SlotGetBankNumber

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

Definition at line 148 of file slru.c.

◆ SLRU_BANK_BITSHIFT

#define SLRU_BANK_BITSHIFT   4

Definition at line 142 of file slru.c.

◆ SLRU_BANK_SIZE

#define SLRU_BANK_SIZE   (1 << SLRU_BANK_BITSHIFT)

Definition at line 143 of file slru.c.

Typedef Documentation

◆ SlruWriteAll

typedef struct SlruWriteAllData* SlruWriteAll

Definition at line 132 of file slru.c.

◆ SlruWriteAllData

Enumeration Type Documentation

◆ SlruErrorCause

Enumerator
SLRU_OPEN_FAILED 
SLRU_SEEK_FAILED 
SLRU_READ_FAILED 
SLRU_WRITE_FAILED 
SLRU_FSYNC_FAILED 
SLRU_CLOSE_FAILED 

Definition at line 164 of file slru.c.

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

Function Documentation

◆ check_slru_buffers()

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

Definition at line 355 of file slru.c.

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

References GUC_check_errdetail, name, newval, and SLRU_BANK_SIZE.

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

◆ SimpleLruAutotuneBuffers()

int SimpleLruAutotuneBuffers ( int  divisor,
int  max 
)

Definition at line 231 of file slru.c.

232{
233 return Min(max - (max % SLRU_BANK_SIZE),
235 NBuffers / divisor - (NBuffers / divisor) % SLRU_BANK_SIZE));
236}
#define Min(x, y)
Definition: c.h:1003
#define Max(x, y)
Definition: c.h:997
int NBuffers
Definition: globals.c:142

References Max, Min, NBuffers, and SLRU_BANK_SIZE.

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

◆ SimpleLruDoesPhysicalPageExist()

bool SimpleLruDoesPhysicalPageExist ( SlruCtl  ctl,
int64  pageno 
)

Definition at line 771 of file slru.c.

772{
773 int64 segno = pageno / SLRU_PAGES_PER_SEGMENT;
774 int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
775 int offset = rpageno * BLCKSZ;
776 char path[MAXPGPATH];
777 int fd;
778 bool result;
779 off_t endpos;
780
781 /* update the stats counter of checked pages */
782 pgstat_count_slru_blocks_exists(ctl->shared->slru_stats_idx);
783
784 SlruFileName(ctl, path, segno);
785
786 fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
787 if (fd < 0)
788 {
789 /* expected: file doesn't exist */
790 if (errno == ENOENT)
791 return false;
792
793 /* report error normally */
795 slru_errno = errno;
796 SlruReportIOError(ctl, pageno, 0);
797 }
798
799 if ((endpos = lseek(fd, 0, SEEK_END)) < 0)
800 {
802 slru_errno = errno;
803 SlruReportIOError(ctl, pageno, 0);
804 }
805
806 result = endpos >= (off_t) (offset + BLCKSZ);
807
808 if (CloseTransientFile(fd) != 0)
809 {
811 slru_errno = errno;
812 return false;
813 }
814
815 return result;
816}
int64_t int64
Definition: c.h:535
#define PG_BINARY
Definition: c.h:1272
int CloseTransientFile(int fd)
Definition: fd.c:2868
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2691
#define MAXPGPATH
static XLogRecPtr endpos
Definition: pg_receivewal.c:56
void pgstat_count_slru_blocks_exists(int slru_idx)
static int fd(const char *x, int i)
Definition: preproc-init.c:105
tree ctl
Definition: radixtree.h:1838
static int SlruFileName(SlruCtl ctl, char *path, int64 segno)
Definition: slru.c:91
static void SlruReportIOError(SlruCtl ctl, int64 pageno, TransactionId xid)
Definition: slru.c:1073
static SlruErrorCause slru_errcause
Definition: slru.c:174
static int slru_errno
Definition: slru.c:175
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:39

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

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

◆ SimpleLruInit()

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

Definition at line 252 of file slru.c.

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

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

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

◆ SimpleLruReadPage()

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

Definition at line 527 of file slru.c.

529{
530 SlruShared shared = ctl->shared;
531 LWLock *banklock = SimpleLruGetBankLock(ctl, pageno);
532
534
535 /* Outer loop handles restart if we must wait for someone else's I/O */
536 for (;;)
537 {
538 int slotno;
539 bool ok;
540
541 /* See if page already is in memory; if not, pick victim slot */
542 slotno = SlruSelectLRUPage(ctl, pageno);
543
544 /* Did we find the page in memory? */
545 if (shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
546 shared->page_number[slotno] == pageno)
547 {
548 /*
549 * If page is still being read in, we must wait for I/O. Likewise
550 * if the page is being written and the caller said that's not OK.
551 */
552 if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS ||
553 (shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS &&
554 !write_ok))
555 {
556 SimpleLruWaitIO(ctl, slotno);
557 /* Now we must recheck state from the top */
558 continue;
559 }
560 /* Otherwise, it's ready to use */
561 SlruRecentlyUsed(shared, slotno);
562
563 /* update the stats counter of pages found in the SLRU */
565
566 return slotno;
567 }
568
569 /* We found no match; assert we selected a freeable slot */
570 Assert(shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
571 (shared->page_status[slotno] == SLRU_PAGE_VALID &&
572 !shared->page_dirty[slotno]));
573
574 /* Mark the slot read-busy */
575 shared->page_number[slotno] = pageno;
576 shared->page_status[slotno] = SLRU_PAGE_READ_IN_PROGRESS;
577 shared->page_dirty[slotno] = false;
578
579 /* Acquire per-buffer lock (cannot deadlock, see notes at top) */
580 LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_EXCLUSIVE);
581
582 /* Release bank lock while doing I/O */
583 LWLockRelease(banklock);
584
585 /* Do the read */
586 ok = SlruPhysicalReadPage(ctl, pageno, slotno);
587
588 /* Set the LSNs for this newly read-in page to zero */
589 SimpleLruZeroLSNs(ctl, slotno);
590
591 /* Re-acquire bank control lock and update page state */
592 LWLockAcquire(banklock, LW_EXCLUSIVE);
593
594 Assert(shared->page_number[slotno] == pageno &&
595 shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS &&
596 !shared->page_dirty[slotno]);
597
598 shared->page_status[slotno] = ok ? SLRU_PAGE_VALID : SLRU_PAGE_EMPTY;
599
600 LWLockRelease(&shared->buffer_locks[slotno].lock);
601
602 /* Now it's okay to ereport if we failed */
603 if (!ok)
604 SlruReportIOError(ctl, pageno, xid);
605
606 SlruRecentlyUsed(shared, slotno);
607
608 /* update the stats counter of pages not found in SLRU */
610
611 return slotno;
612 }
613}
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1174
bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:2021
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1894
@ LW_EXCLUSIVE
Definition: lwlock.h:112
void pgstat_count_slru_blocks_hit(int slru_idx)
void pgstat_count_slru_blocks_read(int slru_idx)
static bool SlruPhysicalReadPage(SlruCtl ctl, int64 pageno, int slotno)
Definition: slru.c:829
static void SimpleLruZeroLSNs(SlruCtl ctl, int slotno)
Definition: slru.c:428
static void SimpleLruWaitIO(SlruCtl ctl, int slotno)
Definition: slru.c:470
static int SlruSelectLRUPage(SlruCtl ctl, int64 pageno)
Definition: slru.c:1194
static void SlruRecentlyUsed(SlruShared shared, int slotno)
Definition: slru.c:1148
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
Definition: slru.h:175
@ SLRU_PAGE_VALID
Definition: slru.h:51
@ SLRU_PAGE_WRITE_IN_PROGRESS
Definition: slru.h:52
@ SLRU_PAGE_READ_IN_PROGRESS
Definition: slru.h:50
Definition: lwlock.h:42

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

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

◆ SimpleLruReadPage_ReadOnly()

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

Definition at line 630 of file slru.c.

631{
632 SlruShared shared = ctl->shared;
633 LWLock *banklock = SimpleLruGetBankLock(ctl, pageno);
634 int bankno = pageno % ctl->nbanks;
635 int bankstart = bankno * SLRU_BANK_SIZE;
636 int bankend = bankstart + SLRU_BANK_SIZE;
637
638 /* Try to find the page while holding only shared lock */
639 LWLockAcquire(banklock, LW_SHARED);
640
641 /* See if page is already in a buffer */
642 for (int slotno = bankstart; slotno < bankend; slotno++)
643 {
644 if (shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
645 shared->page_number[slotno] == pageno &&
646 shared->page_status[slotno] != SLRU_PAGE_READ_IN_PROGRESS)
647 {
648 /* See comments for SlruRecentlyUsed() */
649 SlruRecentlyUsed(shared, slotno);
650
651 /* update the stats counter of pages found in the SLRU */
653
654 return slotno;
655 }
656 }
657
658 /* No luck, so switch to normal exclusive lock and do regular read */
659 LWLockRelease(banklock);
660 LWLockAcquire(banklock, LW_EXCLUSIVE);
661
662 return SimpleLruReadPage(ctl, pageno, true, xid);
663}
@ LW_SHARED
Definition: lwlock.h:113
int SimpleLruReadPage(SlruCtl ctl, int64 pageno, bool write_ok, TransactionId xid)
Definition: slru.c:527

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

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

◆ SimpleLruShmemSize()

Size SimpleLruShmemSize ( int  nslots,
int  nlsns 
)

Definition at line 198 of file slru.c.

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

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

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

◆ SimpleLruTruncate()

void SimpleLruTruncate ( SlruCtl  ctl,
int64  cutoffPage 
)

Definition at line 1433 of file slru.c.

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

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

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

◆ SimpleLruWaitIO()

static void SimpleLruWaitIO ( SlruCtl  ctl,
int  slotno 
)
static

Definition at line 470 of file slru.c.

471{
472 SlruShared shared = ctl->shared;
473 int bankno = SlotGetBankNumber(slotno);
474
475 Assert(shared->page_status[slotno] != SLRU_PAGE_EMPTY);
476
477 /* See notes at top of file */
478 LWLockRelease(&shared->bank_locks[bankno].lock);
479 LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_SHARED);
480 LWLockRelease(&shared->buffer_locks[slotno].lock);
481 LWLockAcquire(&shared->bank_locks[bankno].lock, LW_EXCLUSIVE);
482
483 /*
484 * If the slot is still in an io-in-progress state, then either someone
485 * already started a new I/O on the slot, or a previous I/O failed and
486 * neglected to reset the page state. That shouldn't happen, really, but
487 * it seems worth a few extra cycles to check and recover from it. We can
488 * cheaply test for failure by seeing if the buffer lock is still held (we
489 * assume that transaction abort would release the lock).
490 */
491 if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS ||
492 shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS)
493 {
495 {
496 /* indeed, the I/O must have failed */
497 if (shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS)
498 shared->page_status[slotno] = SLRU_PAGE_EMPTY;
499 else /* write_in_progress */
500 {
501 shared->page_status[slotno] = SLRU_PAGE_VALID;
502 shared->page_dirty[slotno] = true;
503 }
504 LWLockRelease(&shared->buffer_locks[slotno].lock);
505 }
506 }
507}
bool LWLockConditionalAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1345

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

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

◆ SimpleLruWriteAll()

void SimpleLruWriteAll ( SlruCtl  ctl,
bool  allow_redirtied 
)

Definition at line 1347 of file slru.c.

1348{
1349 SlruShared shared = ctl->shared;
1350 SlruWriteAllData fdata;
1351 int64 pageno = 0;
1352 int prevbank = SlotGetBankNumber(0);
1353 bool ok;
1354
1355 /* update the stats counter of flushes */
1357
1358 /*
1359 * Find and write dirty pages
1360 */
1361 fdata.num_files = 0;
1362
1363 LWLockAcquire(&shared->bank_locks[prevbank].lock, LW_EXCLUSIVE);
1364
1365 for (int slotno = 0; slotno < shared->num_slots; slotno++)
1366 {
1367 int curbank = SlotGetBankNumber(slotno);
1368
1369 /*
1370 * If the current bank lock is not same as the previous bank lock then
1371 * release the previous lock and acquire the new lock.
1372 */
1373 if (curbank != prevbank)
1374 {
1375 LWLockRelease(&shared->bank_locks[prevbank].lock);
1376 LWLockAcquire(&shared->bank_locks[curbank].lock, LW_EXCLUSIVE);
1377 prevbank = curbank;
1378 }
1379
1380 /* Do nothing if slot is unused */
1381 if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
1382 continue;
1383
1384 SlruInternalWritePage(ctl, slotno, &fdata);
1385
1386 /*
1387 * In some places (e.g. checkpoints), we cannot assert that the slot
1388 * is clean now, since another process might have re-dirtied it
1389 * already. That's okay.
1390 */
1391 Assert(allow_redirtied ||
1392 shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
1393 (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1394 !shared->page_dirty[slotno]));
1395 }
1396
1397 LWLockRelease(&shared->bank_locks[prevbank].lock);
1398
1399 /*
1400 * Now close any files that were open
1401 */
1402 ok = true;
1403 for (int i = 0; i < fdata.num_files; i++)
1404 {
1405 if (CloseTransientFile(fdata.fd[i]) != 0)
1406 {
1408 slru_errno = errno;
1409 pageno = fdata.segno[i] * SLRU_PAGES_PER_SEGMENT;
1410 ok = false;
1411 }
1412 }
1413 if (!ok)
1415
1416 /* Ensure that directory entries for new files are on disk. */
1417 if (ctl->sync_handler != SYNC_HANDLER_NONE)
1418 fsync_fname(ctl->Dir, true);
1419}
void fsync_fname(const char *fname, bool isdir)
Definition: fd.c:753
int i
Definition: isn.c:77
void pgstat_count_slru_flush(int slru_idx)
int num_files
Definition: slru.c:127
int fd[MAX_WRITEALL_BUFFERS]
Definition: slru.c:128
int64 segno[MAX_WRITEALL_BUFFERS]
Definition: slru.c:129
@ SYNC_HANDLER_NONE
Definition: sync.h:42
#define InvalidTransactionId
Definition: transam.h:31

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

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

◆ SimpleLruWritePage()

void SimpleLruWritePage ( SlruCtl  ctl,
int  slotno 
)

Definition at line 757 of file slru.c.

758{
759 Assert(ctl->shared->page_status[slotno] != SLRU_PAGE_EMPTY);
760
761 SlruInternalWritePage(ctl, slotno, NULL);
762}

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

Referenced by MaybeExtendOffsetSlru(), SimpleLruZeroAndWritePage(), and test_slru_page_write().

◆ SimpleLruZeroAndWritePage()

void SimpleLruZeroAndWritePage ( SlruCtl  ctl,
int64  pageno 
)

Definition at line 444 of file slru.c.

445{
446 int slotno;
447 LWLock *lock;
448
449 lock = SimpleLruGetBankLock(ctl, pageno);
451
452 /* Create and zero the page */
453 slotno = SimpleLruZeroPage(ctl, pageno);
454
455 /* Make sure it's written out */
456 SimpleLruWritePage(ctl, slotno);
457 Assert(!ctl->shared->page_dirty[slotno]);
458
459 LWLockRelease(lock);
460}
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:757
int SimpleLruZeroPage(SlruCtl ctl, int64 pageno)
Definition: slru.c:375

References Assert(), ctl, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SimpleLruGetBankLock(), SimpleLruWritePage(), and SimpleLruZeroPage().

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

◆ SimpleLruZeroLSNs()

static void SimpleLruZeroLSNs ( SlruCtl  ctl,
int  slotno 
)
static

Definition at line 428 of file slru.c.

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

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

Referenced by SimpleLruReadPage(), and SimpleLruZeroPage().

◆ SimpleLruZeroPage()

int SimpleLruZeroPage ( SlruCtl  ctl,
int64  pageno 
)

Definition at line 375 of file slru.c.

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

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

Referenced by asyncQueueAddEntries(), ExtendCLOG(), ExtendCommitTs(), ExtendMultiXactMember(), ExtendMultiXactOffset(), ExtendSUBTRANS(), MaybeExtendOffsetSlru(), SerialAdd(), SimpleLruZeroAndWritePage(), StartupSUBTRANS(), and test_slru_page_write().

◆ SlruCorrectSegmentFilenameLength()

static bool SlruCorrectSegmentFilenameLength ( SlruCtl  ctl,
size_t  len 
)
inlinestatic

Definition at line 1783 of file slru.c.

1784{
1785 if (ctl->long_segment_names)
1786 return (len == 15); /* see SlruFileName() */
1787 else
1788
1789 /*
1790 * Commit 638cf09e76d allowed 5-character lengths. Later commit
1791 * 73c986adde5 allowed 6-character length.
1792 *
1793 * Note: There is an ongoing plan to migrate all SLRUs to 64-bit page
1794 * numbers, and the corresponding 15-character file names, which may
1795 * eventually deprecate the support for 4, 5, and 6-character names.
1796 */
1797 return (len == 4 || len == 5 || len == 6);
1798}
const void size_t len

References ctl, and len.

Referenced by SlruScanDirectory().

◆ SlruDeleteSegment()

void SlruDeleteSegment ( SlruCtl  ctl,
int64  segno 
)

Definition at line 1551 of file slru.c.

1552{
1553 SlruShared shared = ctl->shared;
1554 int prevbank = SlotGetBankNumber(0);
1555 bool did_write;
1556
1557 /* Clean out any possibly existing references to the segment. */
1558 LWLockAcquire(&shared->bank_locks[prevbank].lock, LW_EXCLUSIVE);
1559restart:
1560 did_write = false;
1561 for (int slotno = 0; slotno < shared->num_slots; slotno++)
1562 {
1563 int64 pagesegno;
1564 int curbank = SlotGetBankNumber(slotno);
1565
1566 /*
1567 * If the current bank lock is not same as the previous bank lock then
1568 * release the previous lock and acquire the new lock.
1569 */
1570 if (curbank != prevbank)
1571 {
1572 LWLockRelease(&shared->bank_locks[prevbank].lock);
1573 LWLockAcquire(&shared->bank_locks[curbank].lock, LW_EXCLUSIVE);
1574 prevbank = curbank;
1575 }
1576
1577 if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
1578 continue;
1579
1580 pagesegno = shared->page_number[slotno] / SLRU_PAGES_PER_SEGMENT;
1581 /* not the segment we're looking for */
1582 if (pagesegno != segno)
1583 continue;
1584
1585 /* If page is clean, just change state to EMPTY (expected case). */
1586 if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1587 !shared->page_dirty[slotno])
1588 {
1589 shared->page_status[slotno] = SLRU_PAGE_EMPTY;
1590 continue;
1591 }
1592
1593 /* Same logic as SimpleLruTruncate() */
1594 if (shared->page_status[slotno] == SLRU_PAGE_VALID)
1595 SlruInternalWritePage(ctl, slotno, NULL);
1596 else
1597 SimpleLruWaitIO(ctl, slotno);
1598
1599 did_write = true;
1600 }
1601
1602 /*
1603 * Be extra careful and re-check. The IO functions release the control
1604 * lock, so new pages could have been read in.
1605 */
1606 if (did_write)
1607 goto restart;
1608
1610
1611 LWLockRelease(&shared->bank_locks[prevbank].lock);
1612}
static void SlruInternalDeleteSegment(SlruCtl ctl, int64 segno)
Definition: slru.c:1528

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

Referenced by PerformMembersTruncation(), and test_slru_page_delete().

◆ SlruFileName()

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

Definition at line 91 of file slru.c.

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

References Assert(), ctl, INT64CONST, MAXPGPATH, and snprintf.

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

◆ SlruInternalDeleteSegment()

static void SlruInternalDeleteSegment ( SlruCtl  ctl,
int64  segno 
)
static

Definition at line 1528 of file slru.c.

1529{
1530 char path[MAXPGPATH];
1531
1532 /* Forget any fsync requests queued for this segment. */
1533 if (ctl->sync_handler != SYNC_HANDLER_NONE)
1534 {
1535 FileTag tag;
1536
1537 INIT_SLRUFILETAG(tag, ctl->sync_handler, segno);
1539 }
1540
1541 /* Unlink the file. */
1542 SlruFileName(ctl, path, segno);
1543 ereport(DEBUG2, (errmsg_internal("removing file \"%s\"", path)));
1544 unlink(path);
1545}
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1161
#define DEBUG2
Definition: elog.h:29
#define INIT_SLRUFILETAG(a, xx_handler, xx_segno)
Definition: slru.c:156
bool RegisterSyncRequest(const FileTag *ftag, SyncRequestType type, bool retryOnError)
Definition: sync.c:580
@ SYNC_FORGET_REQUEST
Definition: sync.h:27

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

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

◆ SlruInternalWritePage()

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

Definition at line 677 of file slru.c.

678{
679 SlruShared shared = ctl->shared;
680 int64 pageno = shared->page_number[slotno];
681 int bankno = SlotGetBankNumber(slotno);
682 bool ok;
683
684 Assert(shared->page_status[slotno] != SLRU_PAGE_EMPTY);
686
687 /* If a write is in progress, wait for it to finish */
688 while (shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS &&
689 shared->page_number[slotno] == pageno)
690 {
691 SimpleLruWaitIO(ctl, slotno);
692 }
693
694 /*
695 * Do nothing if page is not dirty, or if buffer no longer contains the
696 * same page we were called for.
697 */
698 if (!shared->page_dirty[slotno] ||
699 shared->page_status[slotno] != SLRU_PAGE_VALID ||
700 shared->page_number[slotno] != pageno)
701 return;
702
703 /*
704 * Mark the slot write-busy, and clear the dirtybit. After this point, a
705 * transaction status update on this page will mark it dirty again.
706 */
708 shared->page_dirty[slotno] = false;
709
710 /* Acquire per-buffer lock (cannot deadlock, see notes at top) */
711 LWLockAcquire(&shared->buffer_locks[slotno].lock, LW_EXCLUSIVE);
712
713 /* Release bank lock while doing I/O */
714 LWLockRelease(&shared->bank_locks[bankno].lock);
715
716 /* Do the write */
717 ok = SlruPhysicalWritePage(ctl, pageno, slotno, fdata);
718
719 /* If we failed, and we're in a flush, better close the files */
720 if (!ok && fdata)
721 {
722 for (int i = 0; i < fdata->num_files; i++)
723 CloseTransientFile(fdata->fd[i]);
724 }
725
726 /* Re-acquire bank lock and update page state */
727 LWLockAcquire(&shared->bank_locks[bankno].lock, LW_EXCLUSIVE);
728
729 Assert(shared->page_number[slotno] == pageno &&
730 shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS);
731
732 /* If we failed to write, mark the page dirty again */
733 if (!ok)
734 shared->page_dirty[slotno] = true;
735
736 shared->page_status[slotno] = SLRU_PAGE_VALID;
737
738 LWLockRelease(&shared->buffer_locks[slotno].lock);
739
740 /* Now it's okay to ereport if we failed */
741 if (!ok)
743
744 /* If part of a checkpoint, count this as a SLRU buffer written. */
745 if (fdata)
746 {
749 }
750}
PgStat_CheckpointerStats PendingCheckpointerStats
static bool SlruPhysicalWritePage(SlruCtl ctl, int64 pageno, int slotno, SlruWriteAll fdata)
Definition: slru.c:901
int ckpt_slru_written
Definition: xlog.h:168
PgStat_Counter slru_written
Definition: pgstat.h:265
CheckpointStatsData CheckpointStats
Definition: xlog.c:210

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

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

◆ SlruMayDeleteSegment()

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

Definition at line 1628 of file slru.c.

1629{
1630 int64 seg_last_page = segpage + SLRU_PAGES_PER_SEGMENT - 1;
1631
1632 Assert(segpage % SLRU_PAGES_PER_SEGMENT == 0);
1633
1634 return (ctl->PagePrecedes(segpage, cutoffPage) &&
1635 ctl->PagePrecedes(seg_last_page, cutoffPage));
1636}

References Assert(), ctl, and SLRU_PAGES_PER_SEGMENT.

Referenced by SlruScanDirCbDeleteCutoff(), and SlruScanDirCbReportPresence().

◆ SlruPhysicalReadPage()

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

Definition at line 829 of file slru.c.

830{
831 SlruShared shared = ctl->shared;
832 int64 segno = pageno / SLRU_PAGES_PER_SEGMENT;
833 int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
834 off_t offset = rpageno * BLCKSZ;
835 char path[MAXPGPATH];
836 int fd;
837
838 SlruFileName(ctl, path, segno);
839
840 /*
841 * In a crash-and-restart situation, it's possible for us to receive
842 * commands to set the commit status of transactions whose bits are in
843 * already-truncated segments of the commit log (see notes in
844 * SlruPhysicalWritePage). Hence, if we are InRecovery, allow the case
845 * where the file doesn't exist, and return zeroes instead.
846 */
847 fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
848 if (fd < 0)
849 {
850 if (errno != ENOENT || !InRecovery)
851 {
853 slru_errno = errno;
854 return false;
855 }
856
857 ereport(LOG,
858 (errmsg("file \"%s\" doesn't exist, reading as zeroes",
859 path)));
860 MemSet(shared->page_buffer[slotno], 0, BLCKSZ);
861 return true;
862 }
863
864 errno = 0;
865 pgstat_report_wait_start(WAIT_EVENT_SLRU_READ);
866 if (pg_pread(fd, shared->page_buffer[slotno], BLCKSZ, offset) != BLCKSZ)
867 {
870 slru_errno = errno;
872 return false;
873 }
875
876 if (CloseTransientFile(fd) != 0)
877 {
879 slru_errno = errno;
880 return false;
881 }
882
883 return true;
884}
#define pg_pread
Definition: port.h:226
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: wait_event.h:69
static void pgstat_report_wait_end(void)
Definition: wait_event.h:85
bool InRecovery
Definition: xlogutils.c:50

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

Referenced by SimpleLruReadPage().

◆ SlruPhysicalWritePage()

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

Definition at line 901 of file slru.c.

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

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

Referenced by SlruInternalWritePage().

◆ SlruRecentlyUsed()

static void SlruRecentlyUsed ( SlruShared  shared,
int  slotno 
)
inlinestatic

Definition at line 1148 of file slru.c.

1149{
1150 int bankno = SlotGetBankNumber(slotno);
1151 int new_lru_count = shared->bank_cur_lru_count[bankno];
1152
1153 Assert(shared->page_status[slotno] != SLRU_PAGE_EMPTY);
1154
1155 /*
1156 * The reason for the if-test is that there are often many consecutive
1157 * accesses to the same page (particularly the latest page). By
1158 * suppressing useless increments of bank_cur_lru_count, we reduce the
1159 * probability that old pages' counts will "wrap around" and make them
1160 * appear recently used.
1161 *
1162 * We allow this code to be executed concurrently by multiple processes
1163 * within SimpleLruReadPage_ReadOnly(). As long as int reads and writes
1164 * are atomic, this should not cause any completely-bogus values to enter
1165 * the computation. However, it is possible for either bank_cur_lru_count
1166 * or individual page_lru_count entries to be "reset" to lower values than
1167 * they should have, in case a process is delayed while it executes this
1168 * function. With care in SlruSelectLRUPage(), this does little harm, and
1169 * in any case the absolute worst possible consequence is a nonoptimal
1170 * choice of page to evict. The gain from allowing concurrent reads of
1171 * SLRU pages seems worth it.
1172 */
1173 if (new_lru_count != shared->page_lru_count[slotno])
1174 {
1175 shared->bank_cur_lru_count[bankno] = ++new_lru_count;
1176 shared->page_lru_count[slotno] = new_lru_count;
1177 }
1178}

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

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

◆ SlruReportIOError()

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

Definition at line 1073 of file slru.c.

1074{
1075 int64 segno = pageno / SLRU_PAGES_PER_SEGMENT;
1076 int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
1077 int offset = rpageno * BLCKSZ;
1078 char path[MAXPGPATH];
1079
1080 SlruFileName(ctl, path, segno);
1081 errno = slru_errno;
1082 switch (slru_errcause)
1083 {
1084 case SLRU_OPEN_FAILED:
1085 ereport(ERROR,
1087 errmsg("could not access status of transaction %u", xid),
1088 errdetail("Could not open file \"%s\": %m.", path)));
1089 break;
1090 case SLRU_SEEK_FAILED:
1091 ereport(ERROR,
1093 errmsg("could not access status of transaction %u", xid),
1094 errdetail("Could not seek in file \"%s\" to offset %d: %m.",
1095 path, offset)));
1096 break;
1097 case SLRU_READ_FAILED:
1098 if (errno)
1099 ereport(ERROR,
1101 errmsg("could not access status of transaction %u", xid),
1102 errdetail("Could not read from file \"%s\" at offset %d: %m.",
1103 path, offset)));
1104 else
1105 ereport(ERROR,
1106 (errmsg("could not access status of transaction %u", xid),
1107 errdetail("Could not read from file \"%s\" at offset %d: read too few bytes.", path, offset)));
1108 break;
1109 case SLRU_WRITE_FAILED:
1110 if (errno)
1111 ereport(ERROR,
1113 errmsg("could not access status of transaction %u", xid),
1114 errdetail("Could not write to file \"%s\" at offset %d: %m.",
1115 path, offset)));
1116 else
1117 ereport(ERROR,
1118 (errmsg("could not access status of transaction %u", xid),
1119 errdetail("Could not write to file \"%s\" at offset %d: wrote too few bytes.",
1120 path, offset)));
1121 break;
1122 case SLRU_FSYNC_FAILED:
1125 errmsg("could not access status of transaction %u", xid),
1126 errdetail("Could not fsync file \"%s\": %m.",
1127 path)));
1128 break;
1129 case SLRU_CLOSE_FAILED:
1130 ereport(ERROR,
1132 errmsg("could not access status of transaction %u", xid),
1133 errdetail("Could not close file \"%s\": %m.",
1134 path)));
1135 break;
1136 default:
1137 /* can't get here, we trust */
1138 elog(ERROR, "unrecognized SimpleLru error cause: %d",
1139 (int) slru_errcause);
1140 break;
1141 }
1142}
int errcode_for_file_access(void)
Definition: elog.c:877
int errdetail(const char *fmt,...)
Definition: elog.c:1207
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
int data_sync_elevel(int elevel)
Definition: fd.c:3998

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

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

◆ SlruScanDirCbDeleteAll()

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

Definition at line 1769 of file slru.c.

1770{
1772
1773 return false; /* keep going */
1774}

References ctl, SLRU_PAGES_PER_SEGMENT, and SlruInternalDeleteSegment().

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

◆ SlruScanDirCbDeleteCutoff()

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

Definition at line 1753 of file slru.c.

1755{
1756 int64 cutoffPage = *(int64 *) data;
1757
1758 if (SlruMayDeleteSegment(ctl, segpage, cutoffPage))
1760
1761 return false; /* keep going */
1762}
const void * data
static bool SlruMayDeleteSegment(SlruCtl ctl, int64 segpage, int64 cutoffPage)
Definition: slru.c:1628

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

Referenced by SimpleLruTruncate().

◆ SlruScanDirCbReportPresence()

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

Definition at line 1737 of file slru.c.

1739{
1740 int64 cutoffPage = *(int64 *) data;
1741
1742 if (SlruMayDeleteSegment(ctl, segpage, cutoffPage))
1743 return true; /* found one; don't iterate any more */
1744
1745 return false; /* keep going */
1746}

References ctl, data, and SlruMayDeleteSegment().

Referenced by TruncateCLOG(), and TruncateCommitTs().

◆ SlruScanDirectory()

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

Definition at line 1816 of file slru.c.

1817{
1818 bool retval = false;
1819 DIR *cldir;
1820 struct dirent *clde;
1821 int64 segno;
1822 int64 segpage;
1823
1824 cldir = AllocateDir(ctl->Dir);
1825 while ((clde = ReadDir(cldir, ctl->Dir)) != NULL)
1826 {
1827 size_t len;
1828
1829 len = strlen(clde->d_name);
1830
1832 strspn(clde->d_name, "0123456789ABCDEF") == len)
1833 {
1834 segno = strtoi64(clde->d_name, NULL, 16);
1835 segpage = segno * SLRU_PAGES_PER_SEGMENT;
1836
1837 elog(DEBUG2, "SlruScanDirectory invoking callback on %s/%s",
1838 ctl->Dir, clde->d_name);
1839 retval = callback(ctl, clde->d_name, segpage, data);
1840 if (retval)
1841 break;
1842 }
1843 }
1844 FreeDir(cldir);
1845
1846 return retval;
1847}
int FreeDir(DIR *dir)
Definition: fd.c:3022
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2904
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2970
static bool SlruCorrectSegmentFilenameLength(SlruCtl ctl, size_t len)
Definition: slru.c:1783
Definition: dirent.c:26
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:46

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

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

◆ SlruSelectLRUPage()

static int SlruSelectLRUPage ( SlruCtl  ctl,
int64  pageno 
)
static

Definition at line 1194 of file slru.c.

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

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

Referenced by SimpleLruReadPage(), and SimpleLruZeroPage().

◆ SlruSyncFileTag()

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

Definition at line 1856 of file slru.c.

1857{
1858 int fd;
1859 int save_errno;
1860 int result;
1861
1862 SlruFileName(ctl, path, ftag->segno);
1863
1864 fd = OpenTransientFile(path, O_RDWR | PG_BINARY);
1865 if (fd < 0)
1866 return -1;
1867
1868 pgstat_report_wait_start(WAIT_EVENT_SLRU_FLUSH_SYNC);
1869 result = pg_fsync(fd);
1871 save_errno = errno;
1872
1874
1875 errno = save_errno;
1876 return result;
1877}
uint64 segno
Definition: sync.h:55

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

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

Variable Documentation

◆ slru_errcause

◆ slru_errno