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/shmem.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  SlruOpts
 
struct  SlruDesc
 

Macros

#define SLRU_MAX_ALLOWED_BUFFERS   ((1024 * 1024 * 1024) / BLCKSZ)
 
#define SimpleLruRequest(...)    SimpleLruRequestWithOpts(&(SlruOpts){__VA_ARGS__})
 
#define SlruPagePrecedesUnitTests(ctl, per_page)   do {} while (0)
 

Typedefs

typedef struct SlruSharedData SlruSharedData
 
typedef SlruSharedDataSlruShared
 
typedef struct SlruDesc SlruDesc
 
typedef struct SlruOpts SlruOpts
 
typedef bool(* SlruScanCallback) (SlruDesc *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 (SlruDesc *ctl, int64 pageno)
 
void SimpleLruRequestWithOpts (const SlruOpts *options)
 
int SimpleLruAutotuneBuffers (int divisor, int max)
 
int SimpleLruZeroPage (SlruDesc *ctl, int64 pageno)
 
void SimpleLruZeroAndWritePage (SlruDesc *ctl, int64 pageno)
 
int SimpleLruReadPage (SlruDesc *ctl, int64 pageno, bool write_ok, const void *opaque_data)
 
int SimpleLruReadPage_ReadOnly (SlruDesc *ctl, int64 pageno, const void *opaque_data)
 
void SimpleLruWritePage (SlruDesc *ctl, int slotno)
 
void SimpleLruWriteAll (SlruDesc *ctl, bool allow_redirtied)
 
void SimpleLruTruncate (SlruDesc *ctl, int64 cutoffPage)
 
bool SimpleLruDoesPhysicalPageExist (SlruDesc *ctl, int64 pageno)
 
bool SlruScanDirectory (SlruDesc *ctl, SlruScanCallback callback, void *data)
 
void SlruDeleteSegment (SlruDesc *ctl, int64 segno)
 
int SlruSyncFileTag (SlruDesc *ctl, const FileTag *ftag, char *path)
 
bool SlruScanDirCbReportPresence (SlruDesc *ctl, char *filename, int64 segpage, void *data)
 
bool SlruScanDirCbDeleteAll (SlruDesc *ctl, char *filename, int64 segpage, void *data)
 
bool check_slru_buffers (const char *name, int *newval)
 
void shmem_slru_init (void *location, ShmemStructOpts *base_options)
 
void shmem_slru_attach (void *location, ShmemStructOpts *base_options)
 

Macro Definition Documentation

◆ SimpleLruRequest

#define SimpleLruRequest (   ...)     SimpleLruRequestWithOpts(&(SlruOpts){__VA_ARGS__})

Definition at line 218 of file slru.h.

219 {__VA_ARGS__})
static int fb(int x)

◆ SLRU_MAX_ALLOWED_BUFFERS

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

Definition at line 26 of file slru.h.

◆ SlruPagePrecedesUnitTests

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

Definition at line 233 of file slru.h.

Typedef Documentation

◆ SlruDesc

Definition at line 110 of file slru.h.

◆ SlruOpts

◆ SlruScanCallback

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

Definition at line 238 of file slru.h.

◆ SlruShared

Definition at line 108 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 34 of file slru.h.

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

Function Documentation

◆ check_slru_buffers()

bool check_slru_buffers ( const char name,
int newval 
)
extern

Definition at line 377 of file slru.c.

378{
379 /* Valid values are multiples of SLRU_BANK_SIZE */
380 if (*newval % SLRU_BANK_SIZE == 0)
381 return true;
382
383 GUC_check_errdetail("\"%s\" must be a multiple of %d.", name,
385 return false;
386}
#define newval
#define GUC_check_errdetail
Definition guc.h:507
#define SLRU_BANK_SIZE
Definition slru.c:146
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().

◆ shmem_slru_attach()

void shmem_slru_attach ( void location,
ShmemStructOpts base_options 
)
extern

Definition at line 359 of file slru.c.

360{
362 SlruDesc *desc = (SlruDesc *) options->desc;
363 int nslots = options->nslots;
364 int nbanks = nslots / SLRU_BANK_SIZE;
365
366 desc->shared = (SlruShared) location;
367 desc->nbanks = nbanks;
368 memcpy(&desc->options, options, sizeof(SlruOpts));
369}
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
SlruSharedData * SlruShared
Definition slru.h:108

References fb(), memcpy(), SlruDesc::nbanks, SlruDesc::options, SlruDesc::shared, and SLRU_BANK_SIZE.

Referenced by AttachShmemIndexEntry().

◆ shmem_slru_init()

void shmem_slru_init ( void location,
ShmemStructOpts base_options 
)
extern

Definition at line 267 of file slru.c.

268{
270 SlruDesc *desc = (SlruDesc *) options->desc;
271 char namebuf[NAMEDATALEN];
272 SlruShared shared;
273 int nslots = options->nslots;
274 int nbanks = nslots / SLRU_BANK_SIZE;
275 int nlsns = options->nlsns;
276 char *ptr;
277 Size offset;
278
279 shared = (SlruShared) location;
280 desc->shared = shared;
281 desc->nbanks = nbanks;
282 memcpy(&desc->options, options, sizeof(SlruOpts));
283
284 /* assign new tranche IDs, if not given */
285 if (desc->options.buffer_tranche_id == 0)
286 {
287 snprintf(namebuf, sizeof(namebuf), "%s buffer", desc->options.name);
288 desc->options.buffer_tranche_id = LWLockNewTrancheId(namebuf);
289 }
290 if (desc->options.bank_tranche_id == 0)
291 {
292 snprintf(namebuf, sizeof(namebuf), "%s bank", desc->options.name);
293 desc->options.bank_tranche_id = LWLockNewTrancheId(namebuf);
294 }
295
297
298 memset(shared, 0, sizeof(SlruSharedData));
299
300 shared->num_slots = nslots;
301 shared->lsn_groups_per_page = nlsns;
302
304
305 shared->slru_stats_idx = pgstat_get_slru_index(desc->options.name);
306
307 ptr = (char *) shared;
308 offset = MAXALIGN(sizeof(SlruSharedData));
309 shared->page_buffer = (char **) (ptr + offset);
310 offset += MAXALIGN(nslots * sizeof(char *));
311 shared->page_status = (SlruPageStatus *) (ptr + offset);
312 offset += MAXALIGN(nslots * sizeof(SlruPageStatus));
313 shared->page_dirty = (bool *) (ptr + offset);
314 offset += MAXALIGN(nslots * sizeof(bool));
315 shared->page_number = (int64 *) (ptr + offset);
316 offset += MAXALIGN(nslots * sizeof(int64));
317 shared->page_lru_count = (int *) (ptr + offset);
318 offset += MAXALIGN(nslots * sizeof(int));
319
320 /* Initialize LWLocks */
321 shared->buffer_locks = (LWLockPadded *) (ptr + offset);
322 offset += MAXALIGN(nslots * sizeof(LWLockPadded));
323 shared->bank_locks = (LWLockPadded *) (ptr + offset);
324 offset += MAXALIGN(nbanks * sizeof(LWLockPadded));
325 shared->bank_cur_lru_count = (int *) (ptr + offset);
326 offset += MAXALIGN(nbanks * sizeof(int));
327
328 if (nlsns > 0)
329 {
330 shared->group_lsn = (XLogRecPtr *) (ptr + offset);
331 offset += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr));
332 }
333
334 ptr += BUFFERALIGN(offset);
335 for (int slotno = 0; slotno < nslots; slotno++)
336 {
338 desc->options.buffer_tranche_id);
339
340 shared->page_buffer[slotno] = ptr;
342 shared->page_dirty[slotno] = false;
343 shared->page_lru_count[slotno] = 0;
344 ptr += BLCKSZ;
345 }
346
347 /* Initialize the slot banks. */
348 for (int bankno = 0; bankno < nbanks; bankno++)
349 {
350 LWLockInitialize(&shared->bank_locks[bankno].lock, desc->options.bank_tranche_id);
351 shared->bank_cur_lru_count[bankno] = 0;
352 }
353
354 /* Should fit to estimated shmem size */
355 Assert(ptr - (char *) shared <= SimpleLruShmemSize(nslots, nlsns));
356}
static void pg_atomic_init_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition atomics.h:453
#define MAXALIGN(LEN)
Definition c.h:896
#define BUFFERALIGN(LEN)
Definition c.h:898
#define Assert(condition)
Definition c.h:943
int64_t int64
Definition c.h:621
size_t Size
Definition c.h:689
int LWLockNewTrancheId(const char *name)
Definition lwlock.c:562
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition lwlock.c:670
#define NAMEDATALEN
int pgstat_get_slru_index(const char *name)
#define snprintf
Definition port.h:260
static Size SimpleLruShmemSize(int nslots, int nlsns)
Definition slru.c:202
#define SLRU_MAX_ALLOWED_BUFFERS
Definition slru.h:26
int slru_stats_idx
Definition slru.h:105
int64 * page_number
Definition slru.h:60
int num_slots
Definition slru.h:51
LWLockPadded * bank_locks
Definition slru.h:67
int * page_lru_count
Definition slru.h:61
pg_atomic_uint64 latest_page_number
Definition slru.h:102
XLogRecPtr * group_lsn
Definition slru.h:94
int * bank_cur_lru_count
Definition slru.h:84
int lsn_groups_per_page
Definition slru.h:95
SlruPageStatus * page_status
Definition slru.h:58
bool * page_dirty
Definition slru.h:59
LWLockPadded * buffer_locks
Definition slru.h:64
char ** page_buffer
Definition slru.h:57
LWLock lock
Definition lwlock.h:70
uint64 XLogRecPtr
Definition xlogdefs.h:21

References Assert, SlruSharedData::bank_cur_lru_count, SlruSharedData::bank_locks, SlruOpts::bank_tranche_id, SlruSharedData::buffer_locks, SlruOpts::buffer_tranche_id, BUFFERALIGN, fb(), SlruSharedData::group_lsn, SlruSharedData::latest_page_number, LWLockPadded::lock, SlruSharedData::lsn_groups_per_page, LWLockInitialize(), LWLockNewTrancheId(), MAXALIGN, memcpy(), SlruOpts::name, NAMEDATALEN, SlruDesc::nbanks, SlruSharedData::num_slots, SlruDesc::options, SlruSharedData::page_buffer, SlruSharedData::page_dirty, SlruSharedData::page_lru_count, SlruSharedData::page_number, SlruSharedData::page_status, pg_atomic_init_u64(), pgstat_get_slru_index(), SlruDesc::shared, SimpleLruShmemSize(), SLRU_BANK_SIZE, SLRU_MAX_ALLOWED_BUFFERS, SLRU_PAGE_EMPTY, SlruSharedData::slru_stats_idx, and snprintf.

Referenced by InitShmemIndexEntry().

◆ SimpleLruAutotuneBuffers()

int SimpleLruAutotuneBuffers ( int  divisor,
int  max 
)
extern

Definition at line 235 of file slru.c.

236{
237 return Min(max - (max % SLRU_BANK_SIZE),
240}
#define Min(x, y)
Definition c.h:1091
#define Max(x, y)
Definition c.h:1085
int NBuffers
Definition globals.c:144

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

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

◆ SimpleLruDoesPhysicalPageExist()

bool SimpleLruDoesPhysicalPageExist ( SlruDesc ctl,
int64  pageno 
)
extern

Definition at line 795 of file slru.c.

796{
797 int64 segno = pageno / SLRU_PAGES_PER_SEGMENT;
798 int rpageno = pageno % SLRU_PAGES_PER_SEGMENT;
799 int offset = rpageno * BLCKSZ;
800 char path[MAXPGPATH];
801 int fd;
802 bool result;
804
805 /* update the stats counter of checked pages */
806 pgstat_count_slru_blocks_exists(ctl->shared->slru_stats_idx);
807
808 SlruFileName(ctl, path, segno);
809
811 if (fd < 0)
812 {
813 /* expected: file doesn't exist */
814 if (errno == ENOENT)
815 return false;
816
817 /* report error normally */
820 SlruReportIOError(ctl, pageno, NULL);
821 }
822
823 if ((endpos = lseek(fd, 0, SEEK_END)) < 0)
824 {
827 SlruReportIOError(ctl, pageno, NULL);
828 }
829
830 result = endpos >= (off_t) (offset + BLCKSZ);
831
832 if (CloseTransientFile(fd) != 0)
833 {
836 return false;
837 }
838
839 return result;
840}
#define PG_BINARY
Definition c.h:1374
uint32 result
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 void SlruReportIOError(SlruDesc *ctl, int64 pageno, const void *opaque_data)
Definition slru.c:1097
static SlruErrorCause slru_errcause
Definition slru.c:177
static int SlruFileName(SlruDesc *ctl, char *path, int64 segno)
Definition slru.c:94
static int slru_errno
Definition slru.c:178
@ SLRU_SEEK_FAILED
Definition slru.c:170
@ SLRU_OPEN_FAILED
Definition slru.c:169
@ SLRU_CLOSE_FAILED
Definition slru.c:174

References CloseTransientFile(), ctl, endpos, fb(), fd(), MAXPGPATH, OpenTransientFile(), PG_BINARY, pgstat_count_slru_blocks_exists(), result, 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()

◆ SimpleLruReadPage()

int SimpleLruReadPage ( SlruDesc ctl,
int64  pageno,
bool  write_ok,
const void opaque_data 
)
extern

Definition at line 550 of file slru.c.

552{
553 SlruShared shared = ctl->shared;
555
557
558 /* Outer loop handles restart if we must wait for someone else's I/O */
559 for (;;)
560 {
561 int slotno;
562 bool ok;
563
564 /* See if page already is in memory; if not, pick victim slot */
565 slotno = SlruSelectLRUPage(ctl, pageno);
566
567 /* Did we find the page in memory? */
568 if (shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
569 shared->page_number[slotno] == pageno)
570 {
571 /*
572 * If page is still being read in, we must wait for I/O. Likewise
573 * if the page is being written and the caller said that's not OK.
574 */
577 !write_ok))
578 {
580 /* Now we must recheck state from the top */
581 continue;
582 }
583 /* Otherwise, it's ready to use */
584 SlruRecentlyUsed(shared, slotno);
585
586 /* update the stats counter of pages found in the SLRU */
588
589 return slotno;
590 }
591
592 /* We found no match; assert we selected a freeable slot */
594 (shared->page_status[slotno] == SLRU_PAGE_VALID &&
595 !shared->page_dirty[slotno]));
596
597 /* Mark the slot read-busy */
598 shared->page_number[slotno] = pageno;
600 shared->page_dirty[slotno] = false;
601
602 /* Acquire per-buffer lock (cannot deadlock, see notes at top) */
604
605 /* Release bank lock while doing I/O */
607
608 /* Do the read */
609 ok = SlruPhysicalReadPage(ctl, pageno, slotno);
610
611 /* Set the LSNs for this newly read-in page to zero */
613
614 /* Re-acquire bank control lock and update page state */
616
617 Assert(shared->page_number[slotno] == pageno &&
619 !shared->page_dirty[slotno]);
620
622
624
625 /* Now it's okay to ereport if we failed */
626 if (!ok)
628
629 SlruRecentlyUsed(shared, slotno);
630
631 /* update the stats counter of pages not found in SLRU */
633
634 return slotno;
635 }
636}
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1150
bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1929
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1767
@ LW_EXCLUSIVE
Definition lwlock.h:104
void pgstat_count_slru_blocks_hit(int slru_idx)
void pgstat_count_slru_blocks_read(int slru_idx)
static void SimpleLruZeroLSNs(SlruDesc *ctl, int slotno)
Definition slru.c:450
static int SlruSelectLRUPage(SlruDesc *ctl, int64 pageno)
Definition slru.c:1219
static bool SlruPhysicalReadPage(SlruDesc *ctl, int64 pageno, int slotno)
Definition slru.c:853
static void SimpleLruWaitIO(SlruDesc *ctl, int slotno)
Definition slru.c:492
static void SlruRecentlyUsed(SlruShared shared, int slotno)
Definition slru.c:1173
static LWLock * SimpleLruGetBankLock(SlruDesc *ctl, int64 pageno)
Definition slru.h:207

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 ( SlruDesc ctl,
int64  pageno,
const void opaque_data 
)
extern

Definition at line 654 of file slru.c.

655{
656 SlruShared shared = ctl->shared;
658 int bankno = pageno % ctl->nbanks;
661
662 /* Try to find the page while holding only shared lock */
664
665 /* See if page is already in a buffer */
666 for (int slotno = bankstart; slotno < bankend; slotno++)
667 {
668 if (shared->page_status[slotno] != SLRU_PAGE_EMPTY &&
669 shared->page_number[slotno] == pageno &&
671 {
672 /* See comments for SlruRecentlyUsed() */
673 SlruRecentlyUsed(shared, slotno);
674
675 /* update the stats counter of pages found in the SLRU */
677
678 return slotno;
679 }
680 }
681
682 /* No luck, so switch to normal exclusive lock and do regular read */
685
686 return SimpleLruReadPage(ctl, pageno, true, opaque_data);
687}
@ LW_SHARED
Definition lwlock.h:105
int SimpleLruReadPage(SlruDesc *ctl, int64 pageno, bool write_ok, const void *opaque_data)
Definition slru.c:550

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

◆ SimpleLruRequestWithOpts()

void SimpleLruRequestWithOpts ( const SlruOpts options)
extern

Definition at line 246 of file slru.c.

247{
249
250 Assert(options->name != NULL);
251 Assert(options->nslots > 0);
252 Assert(options->PagePrecedes != NULL);
253 Assert(options->errdetail_for_io_error != NULL);
254
256 sizeof(SlruOpts));
258
259 options_copy->base.name = options->name;
260 options_copy->base.size = SimpleLruShmemSize(options_copy->nslots, options_copy->nlsns);
261
263}
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition mcxt.c:1232
MemoryContext TopMemoryContext
Definition mcxt.c:166
void ShmemRequestInternal(ShmemStructOpts *options, ShmemRequestKind kind)
Definition shmem.c:337
@ SHMEM_KIND_SLRU

References Assert, fb(), memcpy(), MemoryContextAlloc(), SHMEM_KIND_SLRU, ShmemRequestInternal(), SimpleLruShmemSize(), and TopMemoryContext.

◆ SimpleLruTruncate()

void SimpleLruTruncate ( SlruDesc ctl,
int64  cutoffPage 
)
extern

Definition at line 1458 of file slru.c.

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

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 ( SlruDesc ctl,
bool  allow_redirtied 
)
extern

Definition at line 1372 of file slru.c.

1373{
1374 SlruShared shared = ctl->shared;
1376 int64 pageno = 0;
1377 int prevbank = SlotGetBankNumber(0);
1378 bool ok;
1379
1380 /* update the stats counter of flushes */
1382
1383 /*
1384 * Find and write dirty pages
1385 */
1386 fdata.num_files = 0;
1387
1389
1390 for (int slotno = 0; slotno < shared->num_slots; slotno++)
1391 {
1393
1394 /*
1395 * If the current bank lock is not same as the previous bank lock then
1396 * release the previous lock and acquire the new lock.
1397 */
1398 if (curbank != prevbank)
1399 {
1402 prevbank = curbank;
1403 }
1404
1405 /* Do nothing if slot is unused */
1406 if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
1407 continue;
1408
1410
1411 /*
1412 * In some places (e.g. checkpoints), we cannot assert that the slot
1413 * is clean now, since another process might have re-dirtied it
1414 * already. That's okay.
1415 */
1417 shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
1418 (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1419 !shared->page_dirty[slotno]));
1420 }
1421
1423
1424 /*
1425 * Now close any files that were open
1426 */
1427 ok = true;
1428 for (int i = 0; i < fdata.num_files; i++)
1429 {
1430 if (CloseTransientFile(fdata.fd[i]) != 0)
1431 {
1433 slru_errno = errno;
1434 pageno = fdata.segno[i] * SLRU_PAGES_PER_SEGMENT;
1435 ok = false;
1436 }
1437 }
1438 if (!ok)
1439 SlruReportIOError(ctl, pageno, NULL);
1440
1441 /* Ensure that directory entries for new files are on disk. */
1442 if (ctl->options.sync_handler != SYNC_HANDLER_NONE)
1443 fsync_fname(ctl->options.Dir, true);
1444}
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 ( SlruDesc ctl,
int  slotno 
)
extern

Definition at line 781 of file slru.c.

782{
783 Assert(ctl->shared->page_status[slotno] != SLRU_PAGE_EMPTY);
784
786}

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

Referenced by SimpleLruZeroAndWritePage(), and test_slru_page_write().

◆ SimpleLruZeroAndWritePage()

void SimpleLruZeroAndWritePage ( SlruDesc ctl,
int64  pageno 
)
extern

Definition at line 466 of file slru.c.

467{
468 int slotno;
469 LWLock *lock;
470
471 lock = SimpleLruGetBankLock(ctl, pageno);
473
474 /* Create and zero the page */
475 slotno = SimpleLruZeroPage(ctl, pageno);
476
477 /* Make sure it's written out */
479 Assert(!ctl->shared->page_dirty[slotno]);
480
481 LWLockRelease(lock);
482}
int SimpleLruZeroPage(SlruDesc *ctl, int64 pageno)
Definition slru.c:397
void SimpleLruWritePage(SlruDesc *ctl, int slotno)
Definition slru.c:781

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 ( SlruDesc ctl,
int64  pageno 
)
extern

Definition at line 397 of file slru.c.

398{
399 SlruShared shared = ctl->shared;
400 int slotno;
401
403
404 /* Find a suitable buffer slot for the page */
405 slotno = SlruSelectLRUPage(ctl, pageno);
407 (shared->page_status[slotno] == SLRU_PAGE_VALID &&
408 !shared->page_dirty[slotno]) ||
409 shared->page_number[slotno] == pageno);
410
411 /* Mark the slot as containing this page */
412 shared->page_number[slotno] = pageno;
414 shared->page_dirty[slotno] = true;
415 SlruRecentlyUsed(shared, slotno);
416
417 /* Set the buffer to zeroes */
418 MemSet(shared->page_buffer[slotno], 0, BLCKSZ);
419
420 /* Set the LSNs for this new page to zero */
422
423 /*
424 * Assume this page is now the latest active page.
425 *
426 * Note that because both this routine and SlruSelectLRUPage run with a
427 * SLRU bank lock held, it is not possible for this to be zeroing a page
428 * that SlruSelectLRUPage is going to evict simultaneously. Therefore,
429 * there's no memory barrier here.
430 */
431 pg_atomic_write_u64(&shared->latest_page_number, pageno);
432
433 /* update the stats counter of zeroed pages */
435
436 return slotno;
437}
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:1107
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 ( SlruDesc ctl,
int64  segno 
)
extern

Definition at line 1576 of file slru.c.

1577{
1578 SlruShared shared = ctl->shared;
1579 int prevbank = SlotGetBankNumber(0);
1580 bool did_write;
1581
1582 /* Clean out any possibly existing references to the segment. */
1584restart:
1585 did_write = false;
1586 for (int slotno = 0; slotno < shared->num_slots; slotno++)
1587 {
1590
1591 /*
1592 * If the current bank lock is not same as the previous bank lock then
1593 * release the previous lock and acquire the new lock.
1594 */
1595 if (curbank != prevbank)
1596 {
1599 prevbank = curbank;
1600 }
1601
1602 if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
1603 continue;
1604
1606 /* not the segment we're looking for */
1607 if (pagesegno != segno)
1608 continue;
1609
1610 /* If page is clean, just change state to EMPTY (expected case). */
1611 if (shared->page_status[slotno] == SLRU_PAGE_VALID &&
1612 !shared->page_dirty[slotno])
1613 {
1615 continue;
1616 }
1617
1618 /* Same logic as SimpleLruTruncate() */
1619 if (shared->page_status[slotno] == SLRU_PAGE_VALID)
1621 else
1623
1624 did_write = true;
1625 }
1626
1627 /*
1628 * Be extra careful and re-check. The IO functions release the control
1629 * lock, so new pages could have been read in.
1630 */
1631 if (did_write)
1632 goto restart;
1633
1635
1637}
static void SlruInternalDeleteSegment(SlruDesc *ctl, int64 segno)
Definition slru.c:1553

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 ( SlruDesc ctl,
char filename,
int64  segpage,
void data 
)
extern

Definition at line 1797 of file slru.c.

1798{
1800
1801 return false; /* keep going */
1802}

References ctl, fb(), SLRU_PAGES_PER_SEGMENT, and SlruInternalDeleteSegment().

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

◆ SlruScanDirCbReportPresence()

bool SlruScanDirCbReportPresence ( SlruDesc ctl,
char filename,
int64  segpage,
void data 
)
extern

Definition at line 1765 of file slru.c.

1767{
1768 int64 cutoffPage = *(int64 *) data;
1769
1771 return true; /* found one; don't iterate any more */
1772
1773 return false; /* keep going */
1774}
const void * data
static bool SlruMayDeleteSegment(SlruDesc *ctl, int64 segpage, int64 cutoffPage)
Definition slru.c:1653

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

Referenced by TruncateCLOG(), and TruncateCommitTs().

◆ SlruScanDirectory()

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

Definition at line 1844 of file slru.c.

1845{
1846 bool retval = false;
1847 DIR *cldir;
1848 struct dirent *clde;
1849 int64 segno;
1850 int64 segpage;
1851
1852 cldir = AllocateDir(ctl->options.Dir);
1853 while ((clde = ReadDir(cldir, ctl->options.Dir)) != NULL)
1854 {
1855 size_t len;
1856
1857 len = strlen(clde->d_name);
1858
1860 strspn(clde->d_name, "0123456789ABCDEF") == len)
1861 {
1862 segno = strtoi64(clde->d_name, NULL, 16);
1864
1865 elog(DEBUG2, "SlruScanDirectory invoking callback on %s/%s",
1866 ctl->options.Dir, clde->d_name);
1867 retval = callback(ctl, clde->d_name, segpage, data);
1868 if (retval)
1869 break;
1870 }
1871 }
1872 FreeDir(cldir);
1873
1874 return retval;
1875}
#define DEBUG2
Definition elog.h:30
#define elog(elevel,...)
Definition elog.h:228
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(SlruDesc *ctl, size_t len)
Definition slru.c:1811
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 ( SlruDesc ctl,
const FileTag ftag,
char path 
)
extern

Definition at line 1884 of file slru.c.

1885{
1886 int fd;
1887 int save_errno;
1888 int result;
1889
1890 SlruFileName(ctl, path, ftag->segno);
1891
1893 if (fd < 0)
1894 return -1;
1895
1897 result = pg_fsync(fd);
1899 save_errno = errno;
1900
1902
1903 errno = save_errno;
1904 return result;
1905}
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:67
static void pgstat_report_wait_end(void)
Definition wait_event.h:83

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

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