PostgreSQL Source Code git master
Loading...
Searching...
No Matches
slru.h File Reference
#include "access/transam.h"
#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 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, const void *opaque_data)
 
int SimpleLruReadPage_ReadOnly (SlruCtl ctl, int64 pageno, const void *opaque_data)
 
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 25 of file slru.h.

◆ SlruPagePrecedesUnitTests

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

Definition at line 196 of file slru.h.

Typedef Documentation

◆ SlruCtl

Definition at line 162 of file slru.h.

◆ SlruCtlData

◆ SlruScanCallback

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

Definition at line 201 of file slru.h.

◆ SlruShared

Definition at line 107 of file slru.h.

◆ SlruSharedData

Enumeration Type Documentation

◆ SlruPageStatus

Enumerator
SLRU_PAGE_EMPTY 
SLRU_PAGE_READ_IN_PROGRESS 
SLRU_PAGE_VALID 
SLRU_PAGE_WRITE_IN_PROGRESS 

Definition at line 33 of file slru.h.

34{
35 SLRU_PAGE_EMPTY, /* buffer is not in use */
36 SLRU_PAGE_READ_IN_PROGRESS, /* page is being read in */
37 SLRU_PAGE_VALID, /* page is valid and not being written */
38 SLRU_PAGE_WRITE_IN_PROGRESS, /* page is being written out */
SlruPageStatus
Definition slru.h:34
@ SLRU_PAGE_VALID
Definition slru.h:37
@ SLRU_PAGE_WRITE_IN_PROGRESS
Definition slru.h:38
@ SLRU_PAGE_READ_IN_PROGRESS
Definition slru.h:36
@ SLRU_PAGE_EMPTY
Definition slru.h:35

Function Documentation

◆ check_slru_buffers()

bool check_slru_buffers ( const char name,
int newval 
)
extern

Definition at line 360 of file slru.c.

361{
362 /* Valid values are multiples of SLRU_BANK_SIZE */
363 if (*newval % SLRU_BANK_SIZE == 0)
364 return true;
365
366 GUC_check_errdetail("\"%s\" must be a multiple of %d.", name,
368 return false;
369}
#define newval
#define GUC_check_errdetail
Definition guc.h:507
#define SLRU_BANK_SIZE
Definition slru.c:144
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 
)
extern

Definition at line 233 of file slru.c.

234{
235 return Min(max - (max % SLRU_BANK_SIZE),
238}
#define Min(x, y)
Definition c.h:1093
#define Max(x, y)
Definition c.h:1087
int NBuffers
Definition globals.c:142
static int fb(int x)

References fb(), Max, Min, NBuffers, and SLRU_BANK_SIZE.

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

◆ SimpleLruDoesPhysicalPageExist()

bool SimpleLruDoesPhysicalPageExist ( SlruCtl  ctl,
int64  pageno 
)
extern

Definition at line 778 of file slru.c.

779{
780 int64 segno = pageno / SLRU_PAGES_PER_SEGMENT;
781 int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
782 int offset = rpageno * BLCKSZ;
783 char path[MAXPGPATH];
784 int fd;
785 bool result;
787
788 /* update the stats counter of checked pages */
789 pgstat_count_slru_blocks_exists(ctl->shared->slru_stats_idx);
790
791 SlruFileName(ctl, path, segno);
792
794 if (fd < 0)
795 {
796 /* expected: file doesn't exist */
797 if (errno == ENOENT)
798 return false;
799
800 /* report error normally */
803 SlruReportIOError(ctl, pageno, NULL);
804 }
805
806 if ((endpos = lseek(fd, 0, SEEK_END)) < 0)
807 {
810 SlruReportIOError(ctl, pageno, NULL);
811 }
812
813 result = endpos >= (off_t) (offset + BLCKSZ);
814
815 if (CloseTransientFile(fd) != 0)
816 {
819 return false;
820 }
821
822 return result;
823}
int64_t int64
Definition c.h:615
#define PG_BINARY
Definition c.h:1376
int CloseTransientFile(int fd)
Definition fd.c:2855
int OpenTransientFile(const char *fileName, int fileFlags)
Definition fd.c:2678
#define MAXPGPATH
#define SLRU_PAGES_PER_SEGMENT
static XLogRecPtr endpos
void pgstat_count_slru_blocks_exists(int slru_idx)
static int fd(const char *x, int i)
tree ctl
Definition radixtree.h:1838
static int SlruFileName(SlruCtl ctl, char *path, int64 segno)
Definition slru.c:92
static void SlruReportIOError(SlruCtl ctl, int64 pageno, const void *opaque_data)
Definition slru.c:1080
static SlruErrorCause slru_errcause
Definition slru.c:175
static int slru_errno
Definition slru.c:176
@ SLRU_SEEK_FAILED
Definition slru.c:168
@ SLRU_OPEN_FAILED
Definition slru.c:167
@ SLRU_CLOSE_FAILED
Definition slru.c:172

References CloseTransientFile(), ctl, endpos, fb(), 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(), 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 
)
extern

Definition at line 254 of file slru.c.

257{
258 SlruShared shared;
259 bool found;
260 int nbanks = nslots / SLRU_BANK_SIZE;
261
263
264 Assert(ctl->PagePrecedes != NULL);
265 Assert(ctl->errdetail_for_io_error != NULL);
266
268 SimpleLruShmemSize(nslots, nlsns),
269 &found);
270
272 {
273 /* Initialize locks and shared memory area */
274 char *ptr;
275 Size offset;
276
277 Assert(!found);
278
279 memset(shared, 0, sizeof(SlruSharedData));
280
281 shared->num_slots = nslots;
282 shared->lsn_groups_per_page = nlsns;
283
285
287
288 ptr = (char *) shared;
289 offset = MAXALIGN(sizeof(SlruSharedData));
290 shared->page_buffer = (char **) (ptr + offset);
291 offset += MAXALIGN(nslots * sizeof(char *));
292 shared->page_status = (SlruPageStatus *) (ptr + offset);
293 offset += MAXALIGN(nslots * sizeof(SlruPageStatus));
294 shared->page_dirty = (bool *) (ptr + offset);
295 offset += MAXALIGN(nslots * sizeof(bool));
296 shared->page_number = (int64 *) (ptr + offset);
297 offset += MAXALIGN(nslots * sizeof(int64));
298 shared->page_lru_count = (int *) (ptr + offset);
299 offset += MAXALIGN(nslots * sizeof(int));
300
301 /* Initialize LWLocks */
302 shared->buffer_locks = (LWLockPadded *) (ptr + offset);
303 offset += MAXALIGN(nslots * sizeof(LWLockPadded));
304 shared->bank_locks = (LWLockPadded *) (ptr + offset);
305 offset += MAXALIGN(nbanks * sizeof(LWLockPadded));
306 shared->bank_cur_lru_count = (int *) (ptr + offset);
307 offset += MAXALIGN(nbanks * sizeof(int));
308
309 if (nlsns > 0)
310 {
311 shared->group_lsn = (XLogRecPtr *) (ptr + offset);
312 offset += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr));
313 }
314
315 ptr += BUFFERALIGN(offset);
316 for (int slotno = 0; slotno < nslots; slotno++)
317 {
320
321 shared->page_buffer[slotno] = ptr;
323 shared->page_dirty[slotno] = false;
324 shared->page_lru_count[slotno] = 0;
325 ptr += BLCKSZ;
326 }
327
328 /* Initialize the slot banks. */
329 for (int bankno = 0; bankno < nbanks; bankno++)
330 {
332 shared->bank_cur_lru_count[bankno] = 0;
333 }
334
335 /* Should fit to estimated shmem size */
336 Assert(ptr - (char *) shared <= SimpleLruShmemSize(nslots, nlsns));
337 }
338 else
339 {
340 Assert(found);
341 Assert(shared->num_slots == nslots);
342 }
343
344 /*
345 * Initialize the unshared control struct, including directory path. We
346 * assume caller set PagePrecedes.
347 */
348 ctl->shared = shared;
349 ctl->sync_handler = sync_handler;
350 ctl->long_segment_names = long_segment_names;
351 ctl->nbanks = nbanks;
352 strlcpy(ctl->Dir, subdir, sizeof(ctl->Dir));
353}
static void pg_atomic_init_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition atomics.h:453
#define MAXALIGN(LEN)
Definition c.h:898
#define BUFFERALIGN(LEN)
Definition c.h:900
#define Assert(condition)
Definition c.h:945
size_t Size
Definition c.h:691
bool IsUnderPostmaster
Definition globals.c:120
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition lwlock.c:699
int pgstat_get_slru_index(const char *name)
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:381
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition slru.c:200
SlruSharedData * SlruShared
Definition slru.h:107
#define SLRU_MAX_ALLOWED_BUFFERS
Definition slru.h:25
int slru_stats_idx
Definition slru.h:104
int64 * page_number
Definition slru.h:59
int num_slots
Definition slru.h:50
LWLockPadded * bank_locks
Definition slru.h:66
int * page_lru_count
Definition slru.h:60
pg_atomic_uint64 latest_page_number
Definition slru.h:101
XLogRecPtr * group_lsn
Definition slru.h:93
int * bank_cur_lru_count
Definition slru.h:83
int lsn_groups_per_page
Definition slru.h:94
SlruPageStatus * page_status
Definition slru.h:57
bool * page_dirty
Definition slru.h:58
LWLockPadded * buffer_locks
Definition slru.h:63
char ** page_buffer
Definition slru.h:56
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, fb(), 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,
const void opaque_data 
)
extern

Definition at line 533 of file slru.c.

535{
536 SlruShared shared = ctl->shared;
538
540
541 /* Outer loop handles restart if we must wait for someone else's I/O */
542 for (;;)
543 {
544 int slotno;
545 bool ok;
546
547 /* See if page already is in memory; if not, pick victim slot */
548 slotno = SlruSelectLRUPage(ctl, pageno);
549
550 /* Did we find the page in memory? */
551 if (shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
552 shared->page_number[slotno] == pageno)
553 {
554 /*
555 * If page is still being read in, we must wait for I/O. Likewise
556 * if the page is being written and the caller said that's not OK.
557 */
560 !write_ok))
561 {
563 /* Now we must recheck state from the top */
564 continue;
565 }
566 /* Otherwise, it's ready to use */
567 SlruRecentlyUsed(shared, slotno);
568
569 /* update the stats counter of pages found in the SLRU */
571
572 return slotno;
573 }
574
575 /* We found no match; assert we selected a freeable slot */
577 (shared->page_status[slotno] == SLRU_PAGE_VALID &&
578 !shared->page_dirty[slotno]));
579
580 /* Mark the slot read-busy */
581 shared->page_number[slotno] = pageno;
583 shared->page_dirty[slotno] = false;
584
585 /* Acquire per-buffer lock (cannot deadlock, see notes at top) */
587
588 /* Release bank lock while doing I/O */
590
591 /* Do the read */
592 ok = SlruPhysicalReadPage(ctl, pageno, slotno);
593
594 /* Set the LSNs for this newly read-in page to zero */
596
597 /* Re-acquire bank control lock and update page state */
599
600 Assert(shared->page_number[slotno] == pageno &&
602 !shared->page_dirty[slotno]);
603
605
607
608 /* Now it's okay to ereport if we failed */
609 if (!ok)
611
612 SlruRecentlyUsed(shared, slotno);
613
614 /* update the stats counter of pages not found in SLRU */
616
617 return slotno;
618 }
619}
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1177
bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1956
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1794
@ 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:836
static void SimpleLruZeroLSNs(SlruCtl ctl, int slotno)
Definition slru.c:433
static void SimpleLruWaitIO(SlruCtl ctl, int slotno)
Definition slru.c:475
static int SlruSelectLRUPage(SlruCtl ctl, int64 pageno)
Definition slru.c:1202
static void SlruRecentlyUsed(SlruShared shared, int slotno)
Definition slru.c:1156
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
Definition slru.h:171

References Assert, SlruSharedData::buffer_locks, ctl, fb(), 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 AsyncNotifyFreezeXids(), 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,
const void opaque_data 
)
extern

Definition at line 637 of file slru.c.

638{
639 SlruShared shared = ctl->shared;
641 int bankno = pageno % ctl->nbanks;
644
645 /* Try to find the page while holding only shared lock */
647
648 /* See if page is already in a buffer */
649 for (int slotno = bankstart; slotno < bankend; slotno++)
650 {
651 if (shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
652 shared->page_number[slotno] == pageno &&
654 {
655 /* See comments for SlruRecentlyUsed() */
656 SlruRecentlyUsed(shared, slotno);
657
658 /* update the stats counter of pages found in the SLRU */
660
661 return slotno;
662 }
663 }
664
665 /* No luck, so switch to normal exclusive lock and do regular read */
668
669 return SimpleLruReadPage(ctl, pageno, true, opaque_data);
670}
@ LW_SHARED
Definition lwlock.h:113
int SimpleLruReadPage(SlruCtl ctl, int64 pageno, bool write_ok, const void *opaque_data)
Definition slru.c:533

References ctl, fb(), 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 asyncQueueProcessPageEntries(), find_multixact_start(), SerialGetMinConflictCommitSeqNo(), SubTransGetParent(), test_slru_page_readonly(), TransactionIdGetCommitTsData(), and TransactionIdGetStatus().

◆ SimpleLruShmemSize()

Size SimpleLruShmemSize ( int  nslots,
int  nlsns 
)
extern

Definition at line 200 of file slru.c.

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

References Assert, BUFFERALIGN, fb(), 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 
)
extern

Definition at line 1441 of file slru.c.

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

References SlruSharedData::bank_locks, ctl, ereport, errmsg, fb(), 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(), PerformMembersTruncation(), PerformOffsetsTruncation(), test_slru_page_truncate(), TruncateCLOG(), TruncateCommitTs(), and TruncateSUBTRANS().

◆ SimpleLruWriteAll()

void SimpleLruWriteAll ( SlruCtl  ctl,
bool  allow_redirtied 
)
extern

Definition at line 1355 of file slru.c.

1356{
1357 SlruShared shared = ctl->shared;
1359 int64 pageno = 0;
1360 int prevbank = SlotGetBankNumber(0);
1361 bool ok;
1362
1363 /* update the stats counter of flushes */
1365
1366 /*
1367 * Find and write dirty pages
1368 */
1369 fdata.num_files = 0;
1370
1372
1373 for (int slotno = 0; slotno < shared->num_slots; slotno++)
1374 {
1376
1377 /*
1378 * If the current bank lock is not same as the previous bank lock then
1379 * release the previous lock and acquire the new lock.
1380 */
1381 if (curbank != prevbank)
1382 {
1385 prevbank = curbank;
1386 }
1387
1388 /* Do nothing if slot is unused */
1389 if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
1390 continue;
1391
1393
1394 /*
1395 * In some places (e.g. checkpoints), we cannot assert that the slot
1396 * is clean now, since another process might have re-dirtied it
1397 * already. That's okay.
1398 */
1400 shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
1401 (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1402 !shared->page_dirty[slotno]));
1403 }
1404
1406
1407 /*
1408 * Now close any files that were open
1409 */
1410 ok = true;
1411 for (int i = 0; i < fdata.num_files; i++)
1412 {
1413 if (CloseTransientFile(fdata.fd[i]) != 0)
1414 {
1416 slru_errno = errno;
1417 pageno = fdata.segno[i] * SLRU_PAGES_PER_SEGMENT;
1418 ok = false;
1419 }
1420 }
1421 if (!ok)
1422 SlruReportIOError(ctl, pageno, NULL);
1423
1424 /* Ensure that directory entries for new files are on disk. */
1425 if (ctl->sync_handler != SYNC_HANDLER_NONE)
1426 fsync_fname(ctl->Dir, true);
1427}
void fsync_fname(const char *fname, bool isdir)
Definition fd.c:757
int i
Definition isn.c:77
void pgstat_count_slru_flush(int slru_idx)
@ SYNC_HANDLER_NONE
Definition sync.h:42

References Assert, SlruSharedData::bank_locks, CloseTransientFile(), ctl, fb(), fsync_fname(), i, LWLockPadded::lock, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SlruSharedData::num_slots, SlruSharedData::page_dirty, SlruSharedData::page_status, pgstat_count_slru_flush(), 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 
)
extern

Definition at line 764 of file slru.c.

765{
766 Assert(ctl->shared->page_status[slotno] != SLRU_PAGE_EMPTY);
767
769}

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

Referenced by SimpleLruZeroAndWritePage(), and test_slru_page_write().

◆ SimpleLruZeroAndWritePage()

void SimpleLruZeroAndWritePage ( SlruCtl  ctl,
int64  pageno 
)
extern

Definition at line 449 of file slru.c.

450{
451 int slotno;
452 LWLock *lock;
453
454 lock = SimpleLruGetBankLock(ctl, pageno);
456
457 /* Create and zero the page */
458 slotno = SimpleLruZeroPage(ctl, pageno);
459
460 /* Make sure it's written out */
462 Assert(!ctl->shared->page_dirty[slotno]);
463
464 LWLockRelease(lock);
465}
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition slru.c:764
int SimpleLruZeroPage(SlruCtl ctl, int64 pageno)
Definition slru.c:380

References Assert, ctl, fb(), 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 
)
extern

Definition at line 380 of file slru.c.

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

References Assert, ctl, fb(), 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(), SerialAdd(), SimpleLruZeroAndWritePage(), StartupSUBTRANS(), test_slru_page_write(), and TrimMultiXact().

◆ SlruDeleteSegment()

void SlruDeleteSegment ( SlruCtl  ctl,
int64  segno 
)
extern

Definition at line 1559 of file slru.c.

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

References SlruSharedData::bank_locks, ctl, fb(), 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 test_slru_page_delete().

◆ SlruScanDirCbDeleteAll()

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

Definition at line 1777 of file slru.c.

1778{
1780
1781 return false; /* keep going */
1782}

References ctl, fb(), 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 
)
extern

Definition at line 1745 of file slru.c.

1747{
1748 int64 cutoffPage = *(int64 *) data;
1749
1751 return true; /* found one; don't iterate any more */
1752
1753 return false; /* keep going */
1754}
const void * data
static bool SlruMayDeleteSegment(SlruCtl ctl, int64 segpage, int64 cutoffPage)
Definition slru.c:1636

References ctl, data, fb(), and SlruMayDeleteSegment().

Referenced by TruncateCLOG(), and TruncateCommitTs().

◆ SlruScanDirectory()

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

Definition at line 1824 of file slru.c.

1825{
1826 bool retval = false;
1827 DIR *cldir;
1828 struct dirent *clde;
1829 int64 segno;
1830 int64 segpage;
1831
1832 cldir = AllocateDir(ctl->Dir);
1833 while ((clde = ReadDir(cldir, ctl->Dir)) != NULL)
1834 {
1835 size_t len;
1836
1837 len = strlen(clde->d_name);
1838
1840 strspn(clde->d_name, "0123456789ABCDEF") == len)
1841 {
1842 segno = strtoi64(clde->d_name, NULL, 16);
1844
1845 elog(DEBUG2, "SlruScanDirectory invoking callback on %s/%s",
1846 ctl->Dir, clde->d_name);
1847 retval = callback(ctl, clde->d_name, segpage, data);
1848 if (retval)
1849 break;
1850 }
1851 }
1852 FreeDir(cldir);
1853
1854 return retval;
1855}
#define DEBUG2
Definition elog.h:29
#define elog(elevel,...)
Definition elog.h:226
int FreeDir(DIR *dir)
Definition fd.c:3009
DIR * AllocateDir(const char *dirname)
Definition fd.c:2891
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition fd.c:2957
const void size_t len
static bool SlruCorrectSegmentFilenameLength(SlruCtl ctl, size_t len)
Definition slru.c:1791
Definition dirent.c:26
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)

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

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

◆ SlruSyncFileTag()

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

Definition at line 1864 of file slru.c.

1865{
1866 int fd;
1867 int save_errno;
1868 int result;
1869
1870 SlruFileName(ctl, path, ftag->segno);
1871
1873 if (fd < 0)
1874 return -1;
1875
1877 result = pg_fsync(fd);
1879 save_errno = errno;
1880
1882
1883 errno = save_errno;
1884 return result;
1885}
int pg_fsync(int fd)
Definition fd.c:390
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, fb(), 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().