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

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

Go to the source code of this file.

Data Structures

struct  SlruSharedData
 
struct  SlruCtlData
 

Macros

#define SLRU_MAX_ALLOWED_BUFFERS   ((1024 * 1024 * 1024) / BLCKSZ)
 
#define SLRU_PAGES_PER_SEGMENT   32
 
#define SlruPagePrecedesUnitTests(ctl, per_page)   do {} while (0)
 

Typedefs

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

Enumerations

enum  SlruPageStatus { SLRU_PAGE_EMPTY , SLRU_PAGE_READ_IN_PROGRESS , SLRU_PAGE_VALID , SLRU_PAGE_WRITE_IN_PROGRESS }
 

Functions

static LWLockSimpleLruGetBankLock (SlruCtl ctl, int64 pageno)
 
Size SimpleLruShmemSize (int nslots, int nlsns)
 
int SimpleLruAutotuneBuffers (int divisor, int max)
 
void SimpleLruInit (SlruCtl ctl, const char *name, int nslots, int nlsns, const char *subdir, int buffer_tranche_id, int bank_tranche_id, SyncRequestHandler sync_handler, bool long_segment_names)
 
int SimpleLruZeroPage (SlruCtl ctl, int64 pageno)
 
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)
 
void SimpleLruWriteAll (SlruCtl ctl, bool allow_redirtied)
 
void SimpleLruTruncate (SlruCtl ctl, int64 cutoffPage)
 
bool SimpleLruDoesPhysicalPageExist (SlruCtl ctl, int64 pageno)
 
bool SlruScanDirectory (SlruCtl ctl, SlruScanCallback callback, void *data)
 
void SlruDeleteSegment (SlruCtl ctl, int64 segno)
 
int SlruSyncFileTag (SlruCtl ctl, const FileTag *ftag, char *path)
 
bool SlruScanDirCbReportPresence (SlruCtl ctl, char *filename, int64 segpage, void *data)
 
bool SlruScanDirCbDeleteAll (SlruCtl ctl, char *filename, int64 segpage, void *data)
 
bool check_slru_buffers (const char *name, int *newval)
 

Macro Definition Documentation

◆ SLRU_MAX_ALLOWED_BUFFERS

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

Definition at line 24 of file slru.h.

◆ SLRU_PAGES_PER_SEGMENT

#define SLRU_PAGES_PER_SEGMENT   32

Definition at line 39 of file slru.h.

◆ SlruPagePrecedesUnitTests

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

Definition at line 200 of file slru.h.

Typedef Documentation

◆ SlruCtl

typedef SlruCtlData* SlruCtl

Definition at line 166 of file slru.h.

◆ SlruCtlData

typedef struct SlruCtlData SlruCtlData

◆ SlruScanCallback

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

Definition at line 205 of file slru.h.

◆ SlruShared

Definition at line 121 of file slru.h.

◆ SlruSharedData

Enumeration Type Documentation

◆ SlruPageStatus

Enumerator
SLRU_PAGE_EMPTY 
SLRU_PAGE_READ_IN_PROGRESS 
SLRU_PAGE_VALID 
SLRU_PAGE_WRITE_IN_PROGRESS 

Definition at line 47 of file slru.h.

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

Function Documentation

◆ check_slru_buffers()

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

Definition at line 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:1004
#define Max(x, y)
Definition: c.h:998
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:536
#define PG_BINARY
Definition: c.h:1273
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
@ SLRU_SEEK_FAILED
Definition: slru.c:167
@ SLRU_OPEN_FAILED
Definition: slru.c:166
@ SLRU_CLOSE_FAILED
Definition: slru.c:171
#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().

◆ SimpleLruGetBankLock()

◆ SimpleLruInit()

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

Definition at line 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:811
#define BUFFERALIGN(LEN)
Definition: c.h:813
size_t Size
Definition: c.h:611
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
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
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().

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

◆ 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
#define MemSet(start, val, len)
Definition: c.h:1020
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().

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

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

◆ 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}
const void * data
static bool SlruMayDeleteSegment(SlruCtl ctl, int64 segpage, int64 cutoffPage)
Definition: slru.c:1628

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}
#define DEBUG2
Definition: elog.h:29
#define elog(elevel,...)
Definition: elog.h:226
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
const void size_t len
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().

◆ 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}
int pg_fsync(int fd)
Definition: fd.c:386
uint64 segno
Definition: sync.h:55
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: wait_event.h:69
static void pgstat_report_wait_end(void)
Definition: wait_event.h:85

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