#include "pg_trace.h"
#include "pgstat.h"
#include "storage/proc.h"
+#include "storage/sync.h"
/*
* Defines for CLOG page sizes. A page is the same BLCKSZ as is used
{
XactCtl->PagePrecedes = CLOGPagePrecedes;
SimpleLruInit(XactCtl, "Xact", CLOGShmemBuffers(), CLOG_LSNS_PER_PAGE,
- XactSLRULock, "pg_xact", LWTRANCHE_XACT_BUFFER);
+ XactSLRULock, "pg_xact", LWTRANCHE_XACT_BUFFER,
+ SYNC_HANDLER_CLOG);
}
/*
LWLockRelease(XactSLRULock);
}
-/*
- * This must be called ONCE during postmaster or standalone-backend shutdown
- */
-void
-ShutdownCLOG(void)
-{
- /* Flush dirty CLOG pages to disk */
- TRACE_POSTGRESQL_CLOG_CHECKPOINT_START(false);
- SimpleLruFlush(XactCtl, false);
-
- /*
- * fsync pg_xact to ensure that any files flushed previously are durably
- * on disk.
- */
- fsync_fname("pg_xact", true);
-
- TRACE_POSTGRESQL_CLOG_CHECKPOINT_DONE(false);
-}
-
/*
* Perform a checkpoint --- either during shutdown, or on-the-fly
*/
void
CheckPointCLOG(void)
{
- /* Flush dirty CLOG pages to disk */
+ /*
+ * Write dirty CLOG pages to disk. This may result in sync requests
+ * queued for later handling by ProcessSyncRequests(), as part of the
+ * checkpoint.
+ */
TRACE_POSTGRESQL_CLOG_CHECKPOINT_START(true);
- SimpleLruFlush(XactCtl, true);
+ SimpleLruWriteAll(XactCtl, true);
TRACE_POSTGRESQL_CLOG_CHECKPOINT_DONE(true);
}
else
elog(PANIC, "clog_redo: unknown op code %u", info);
}
+
+/*
+ * Entrypoint for sync.c to sync clog files.
+ */
+int
+clogsyncfiletag(const FileTag *ftag, char *path)
+{
+ return SlruSyncFileTag(XactCtl, ftag, path);
+}
CommitTsCtl->PagePrecedes = CommitTsPagePrecedes;
SimpleLruInit(CommitTsCtl, "CommitTs", CommitTsShmemBuffers(), 0,
CommitTsSLRULock, "pg_commit_ts",
- LWTRANCHE_COMMITTS_BUFFER);
+ LWTRANCHE_COMMITTS_BUFFER,
+ SYNC_HANDLER_COMMIT_TS);
commitTsShared = ShmemInitStruct("CommitTs shared",
sizeof(CommitTimestampShared),
LWLockRelease(CommitTsSLRULock);
}
-/*
- * This must be called ONCE during postmaster or standalone-backend shutdown
- */
-void
-ShutdownCommitTs(void)
-{
- /* Flush dirty CommitTs pages to disk */
- SimpleLruFlush(CommitTsCtl, false);
-
- /*
- * fsync pg_commit_ts to ensure that any files flushed previously are
- * durably on disk.
- */
- fsync_fname("pg_commit_ts", true);
-}
-
/*
* Perform a checkpoint --- either during shutdown, or on-the-fly
*/
void
CheckPointCommitTs(void)
{
- /* Flush dirty CommitTs pages to disk */
- SimpleLruFlush(CommitTsCtl, true);
+ /*
+ * Write dirty CommitTs pages to disk. This may result in sync requests
+ * queued for later handling by ProcessSyncRequests(), as part of the
+ * checkpoint.
+ */
+ SimpleLruWriteAll(CommitTsCtl, true);
}
/*
else
elog(PANIC, "commit_ts_redo: unknown op code %u", info);
}
+
+/*
+ * Entrypoint for sync.c to sync commit_ts files.
+ */
+int
+committssyncfiletag(const FileTag *ftag, char *path)
+{
+ return SlruSyncFileTag(CommitTsCtl, ftag, path);
+}
SimpleLruInit(MultiXactOffsetCtl,
"MultiXactOffset", NUM_MULTIXACTOFFSET_BUFFERS, 0,
MultiXactOffsetSLRULock, "pg_multixact/offsets",
- LWTRANCHE_MULTIXACTOFFSET_BUFFER);
+ LWTRANCHE_MULTIXACTOFFSET_BUFFER,
+ SYNC_HANDLER_MULTIXACT_OFFSET);
SimpleLruInit(MultiXactMemberCtl,
"MultiXactMember", NUM_MULTIXACTMEMBER_BUFFERS, 0,
MultiXactMemberSLRULock, "pg_multixact/members",
- LWTRANCHE_MULTIXACTMEMBER_BUFFER);
+ LWTRANCHE_MULTIXACTMEMBER_BUFFER,
+ SYNC_HANDLER_MULTIXACT_MEMBER);
/* Initialize our shared state struct */
MultiXactState = ShmemInitStruct("Shared MultiXact State",
SetMultiXactIdLimit(oldestMXact, oldestMXactDB, true);
}
-/*
- * This must be called ONCE during postmaster or standalone-backend shutdown
- */
-void
-ShutdownMultiXact(void)
-{
- /* Flush dirty MultiXact pages to disk */
- TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(false);
- SimpleLruFlush(MultiXactOffsetCtl, false);
- SimpleLruFlush(MultiXactMemberCtl, false);
- TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(false);
-}
-
/*
* Get the MultiXact data to save in a checkpoint record
*/
{
TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);
- /* Flush dirty MultiXact pages to disk */
- SimpleLruFlush(MultiXactOffsetCtl, true);
- SimpleLruFlush(MultiXactMemberCtl, true);
+ /*
+ * Write dirty MultiXact pages to disk. This may result in sync requests
+ * queued for later handling by ProcessSyncRequests(), as part of the
+ * checkpoint.
+ */
+ SimpleLruWriteAll(MultiXactOffsetCtl, true);
+ SimpleLruWriteAll(MultiXactMemberCtl, true);
TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
}
entryno = MultiXactIdToOffsetEntry(multi);
/*
- * Flush out dirty data, so PhysicalPageExists can work correctly.
- * SimpleLruFlush() is a pretty big hammer for that. Alternatively we
- * could add an in-memory version of page exists, but find_multixact_start
- * is called infrequently, and it doesn't seem bad to flush buffers to
- * disk before truncation.
+ * Write out dirty data, so PhysicalPageExists can work correctly.
*/
- SimpleLruFlush(MultiXactOffsetCtl, true);
- SimpleLruFlush(MultiXactMemberCtl, true);
+ SimpleLruWriteAll(MultiXactOffsetCtl, true);
+ SimpleLruWriteAll(MultiXactMemberCtl, true);
if (!SimpleLruDoesPhysicalPageExist(MultiXactOffsetCtl, pageno))
return false;
SRF_RETURN_DONE(funccxt);
}
+
+/*
+ * Entrypoint for sync.c to sync offsets files.
+ */
+int
+multixactoffsetssyncfiletag(const FileTag *ftag, char *path)
+{
+ return SlruSyncFileTag(MultiXactOffsetCtl, ftag, path);
+}
+
+/*
+ * Entrypoint for sync.c to sync members files.
+ */
+int
+multixactmemberssyncfiletag(const FileTag *ftag, char *path)
+{
+ return SlruSyncFileTag(MultiXactMemberCtl, ftag, path);
+}
snprintf(path, MAXPGPATH, "%s/%04X", (ctl)->Dir, seg)
/*
- * During SimpleLruFlush(), we will usually not need to write/fsync more
- * than one or two physical files, but we may need to write several pages
- * per file. We can consolidate the I/O requests by leaving files open
- * until control returns to SimpleLruFlush(). This data structure remembers
- * which files are open.
+ * During SimpleLruWriteAll(), we will usually not need to write more than one
+ * or two physical files, but we may need to write several pages per file. We
+ * can consolidate the I/O requests by leaving files open until control returns
+ * to SimpleLruWriteAll(). This data structure remembers which files are open.
*/
-#define MAX_FLUSH_BUFFERS 16
+#define MAX_WRITEALL_BUFFERS 16
-typedef struct SlruFlushData
+typedef struct SlruWriteAllData
{
int num_files; /* # files actually open */
- int fd[MAX_FLUSH_BUFFERS]; /* their FD's */
- int segno[MAX_FLUSH_BUFFERS]; /* their log seg#s */
-} SlruFlushData;
+ int fd[MAX_WRITEALL_BUFFERS]; /* their FD's */
+ int segno[MAX_WRITEALL_BUFFERS]; /* their log seg#s */
+} SlruWriteAllData;
-typedef struct SlruFlushData *SlruFlush;
+typedef struct SlruWriteAllData *SlruWriteAll;
+
+/*
+ * Populate a file tag describing a segment file. We only use the segment
+ * number, since we can derive everything else we need by having separate
+ * sync handler functions for clog, multixact etc.
+ */
+#define INIT_SLRUFILETAG(a,xx_handler,xx_segno) \
+( \
+ memset(&(a), 0, sizeof(FileTag)), \
+ (a).handler = (xx_handler), \
+ (a).segno = (xx_segno) \
+)
/*
* Macro to mark a buffer slot "most recently used". Note multiple evaluation
static void SimpleLruZeroLSNs(SlruCtl ctl, int slotno);
static void SimpleLruWaitIO(SlruCtl ctl, int slotno);
-static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruFlush fdata);
+static void SlruInternalWritePage(SlruCtl ctl, int slotno, SlruWriteAll fdata);
static bool SlruPhysicalReadPage(SlruCtl ctl, int pageno, int slotno);
static bool SlruPhysicalWritePage(SlruCtl ctl, int pageno, int slotno,
- SlruFlush fdata);
+ SlruWriteAll fdata);
static void SlruReportIOError(SlruCtl ctl, int pageno, TransactionId xid);
static int SlruSelectLRUPage(SlruCtl ctl, int pageno);
*/
void
SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
- LWLock *ctllock, const char *subdir, int tranche_id)
+ LWLock *ctllock, const char *subdir, int tranche_id,
+ SyncRequestHandler sync_handler)
{
SlruShared shared;
bool found;
* assume caller set PagePrecedes.
*/
ctl->shared = shared;
- ctl->do_fsync = true; /* default behavior */
+ ctl->sync_handler = sync_handler;
strlcpy(ctl->Dir, subdir, sizeof(ctl->Dir));
}
* Control lock must be held at entry, and will be held at exit.
*/
static void
-SlruInternalWritePage(SlruCtl ctl, int slotno, SlruFlush fdata)
+SlruInternalWritePage(SlruCtl ctl, int slotno, SlruWriteAll fdata)
{
SlruShared shared = ctl->shared;
int pageno = shared->page_number[slotno];
/* Now it's okay to ereport if we failed */
if (!ok)
SlruReportIOError(ctl, pageno, InvalidTransactionId);
+
+ /* If part of a checkpoint, count this as a buffer written. */
+ if (fdata)
+ CheckpointStats.ckpt_bufs_written++;
}
/*
*
* For now, assume it's not worth keeping a file pointer open across
* independent read/write operations. We do batch operations during
- * SimpleLruFlush, though.
+ * SimpleLruWriteAll, though.
*
* fdata is NULL for a standalone write, pointer to open-file info during
- * SimpleLruFlush.
+ * SimpleLruWriteAll.
*/
static bool
-SlruPhysicalWritePage(SlruCtl ctl, int pageno, int slotno, SlruFlush fdata)
+SlruPhysicalWritePage(SlruCtl ctl, int pageno, int slotno, SlruWriteAll fdata)
{
SlruShared shared = ctl->shared;
int segno = pageno / SLRU_PAGES_PER_SEGMENT;
}
/*
- * During a Flush, we may already have the desired file open.
+ * During a WriteAll, we may already have the desired file open.
*/
if (fdata)
{
if (fdata)
{
- if (fdata->num_files < MAX_FLUSH_BUFFERS)
+ if (fdata->num_files < MAX_WRITEALL_BUFFERS)
{
fdata->fd[fdata->num_files] = fd;
fdata->segno[fdata->num_files] = segno;
}
pgstat_report_wait_end();
- /*
- * If not part of Flush, need to fsync now. We assume this happens
- * infrequently enough that it's not a performance issue.
- */
- if (!fdata)
+ /* Queue up a sync request for the checkpointer. */
+ if (ctl->sync_handler != SYNC_HANDLER_NONE)
{
- pgstat_report_wait_start(WAIT_EVENT_SLRU_SYNC);
- if (ctl->do_fsync && pg_fsync(fd) != 0)
+ FileTag tag;
+
+ INIT_SLRUFILETAG(tag, ctl->sync_handler, segno);
+ if (!RegisterSyncRequest(&tag, SYNC_REQUEST, false))
{
+ /* No space to enqueue sync request. Do it synchronously. */
+ pgstat_report_wait_start(WAIT_EVENT_SLRU_SYNC);
+ if (pg_fsync(fd) != 0)
+ {
+ pgstat_report_wait_end();
+ slru_errcause = SLRU_FSYNC_FAILED;
+ slru_errno = errno;
+ CloseTransientFile(fd);
+ return false;
+ }
pgstat_report_wait_end();
- slru_errcause = SLRU_FSYNC_FAILED;
- slru_errno = errno;
- CloseTransientFile(fd);
- return false;
}
- pgstat_report_wait_end();
+ }
+ /* Close file, unless part of flush request. */
+ if (!fdata)
+ {
if (CloseTransientFile(fd) != 0)
{
slru_errcause = SLRU_CLOSE_FAILED;
}
/*
- * Flush dirty pages to disk during checkpoint or database shutdown
+ * Write dirty pages to disk during checkpoint or database shutdown. Flushing
+ * is deferred until the next call to ProcessSyncRequests(), though we do fsync
+ * the containing directory here to make sure that newly created directory
+ * entries are on disk.
*/
void
-SimpleLruFlush(SlruCtl ctl, bool allow_redirtied)
+SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
{
SlruShared shared = ctl->shared;
- SlruFlushData fdata;
+ SlruWriteAllData fdata;
int slotno;
int pageno = 0;
int i;
LWLockRelease(shared->ControlLock);
/*
- * Now fsync and close any files that were open
+ * Now close any files that were open
*/
ok = true;
for (i = 0; i < fdata.num_files; i++)
{
- pgstat_report_wait_start(WAIT_EVENT_SLRU_FLUSH_SYNC);
- if (ctl->do_fsync && pg_fsync(fdata.fd[i]) != 0)
- {
- slru_errcause = SLRU_FSYNC_FAILED;
- slru_errno = errno;
- pageno = fdata.segno[i] * SLRU_PAGES_PER_SEGMENT;
- ok = false;
- }
- pgstat_report_wait_end();
-
if (CloseTransientFile(fdata.fd[i]) != 0)
{
slru_errcause = SLRU_CLOSE_FAILED;
SlruReportIOError(ctl, pageno, InvalidTransactionId);
/* Ensure that directory entries for new files are on disk. */
- if (ctl->do_fsync)
+ if (ctl->sync_handler != SYNC_HANDLER_NONE)
fsync_fname(ctl->Dir, true);
}
snprintf(path, MAXPGPATH, "%s/%04X", ctl->Dir, segno);
ereport(DEBUG2,
(errmsg("removing file \"%s\"", path)));
+
+ /*
+ * Tell the checkpointer to forget any sync requests, before we unlink the
+ * file.
+ */
+ if (ctl->sync_handler != SYNC_HANDLER_NONE)
+ {
+ FileTag tag;
+
+ INIT_SLRUFILETAG(tag, ctl->sync_handler, segno);
+ RegisterSyncRequest(&tag, SYNC_FORGET_REQUEST, true);
+ }
+
unlink(path);
LWLockRelease(shared->ControlLock);
return retval;
}
+
+/*
+ * Individual SLRUs (clog, ...) have to provide a sync.c handler function so
+ * that they can provide the correct "SlruCtl" (otherwise we don't know how to
+ * build the path), but they just forward to this common implementation that
+ * performs the fsync.
+ */
+int
+SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
+{
+ int fd;
+ int save_errno;
+ int result;
+
+ SlruFileName(ctl, path, ftag->segno);
+
+ fd = OpenTransientFile(path, O_RDWR | PG_BINARY);
+ if (fd < 0)
+ return -1;
+
+ result = pg_fsync(fd);
+ save_errno = errno;
+
+ CloseTransientFile(fd);
+
+ errno = save_errno;
+ return result;
+}
SubTransCtl->PagePrecedes = SubTransPagePrecedes;
SimpleLruInit(SubTransCtl, "Subtrans", NUM_SUBTRANS_BUFFERS, 0,
SubtransSLRULock, "pg_subtrans",
- LWTRANCHE_SUBTRANS_BUFFER);
- /* Override default assumption that writes should be fsync'd */
- SubTransCtl->do_fsync = false;
+ LWTRANCHE_SUBTRANS_BUFFER, SYNC_HANDLER_NONE);
}
/*
LWLockRelease(SubtransSLRULock);
}
-/*
- * This must be called ONCE during postmaster or standalone-backend shutdown
- */
-void
-ShutdownSUBTRANS(void)
-{
- /*
- * Flush dirty SUBTRANS pages to disk
- *
- * This is not actually necessary from a correctness point of view. We do
- * it merely as a debugging aid.
- */
- TRACE_POSTGRESQL_SUBTRANS_CHECKPOINT_START(false);
- SimpleLruFlush(SubTransCtl, false);
- TRACE_POSTGRESQL_SUBTRANS_CHECKPOINT_DONE(false);
-}
-
/*
* Perform a checkpoint --- either during shutdown, or on-the-fly
*/
CheckPointSUBTRANS(void)
{
/*
- * Flush dirty SUBTRANS pages to disk
+ * Write dirty SUBTRANS pages to disk
*
* This is not actually necessary from a correctness point of view. We do
* it merely to improve the odds that writing of dirty pages is done by
* the checkpoint process and not by backends.
*/
TRACE_POSTGRESQL_SUBTRANS_CHECKPOINT_START(true);
- SimpleLruFlush(SubTransCtl, true);
+ SimpleLruWriteAll(SubTransCtl, true);
TRACE_POSTGRESQL_SUBTRANS_CHECKPOINT_DONE(true);
}
CreateCheckPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_IMMEDIATE);
}
- ShutdownCLOG();
- ShutdownCommitTs();
- ShutdownSUBTRANS();
- ShutdownMultiXact();
}
/*
static void
CheckPointGuts(XLogRecPtr checkPointRedo, int flags)
{
- CheckPointCLOG();
- CheckPointCommitTs();
- CheckPointSUBTRANS();
- CheckPointMultiXact();
- CheckPointPredicate();
CheckPointRelationMap();
CheckPointReplicationSlots();
CheckPointSnapBuild();
CheckPointLogicalRewriteHeap();
- CheckPointBuffers(flags); /* performs all required fsyncs */
CheckPointReplicationOrigin();
+
+ /* Write out all dirty data in SLRUs and the main buffer pool */
+ TRACE_POSTGRESQL_BUFFER_CHECKPOINT_START(flags);
+ CheckpointStats.ckpt_write_t = GetCurrentTimestamp();
+ CheckPointCLOG();
+ CheckPointCommitTs();
+ CheckPointSUBTRANS();
+ CheckPointMultiXact();
+ CheckPointPredicate();
+ CheckPointBuffers(flags);
+
+ /* Perform all queued up fsyncs */
+ TRACE_POSTGRESQL_BUFFER_CHECKPOINT_SYNC_START();
+ CheckpointStats.ckpt_sync_t = GetCurrentTimestamp();
+ ProcessSyncRequests();
+ CheckpointStats.ckpt_sync_end_t = GetCurrentTimestamp();
+ TRACE_POSTGRESQL_BUFFER_CHECKPOINT_DONE();
+
/* We deliberately delay 2PC checkpointing as long as possible */
CheckPointTwoPhase(checkPointRedo);
}
*/
NotifyCtl->PagePrecedes = asyncQueuePagePrecedes;
SimpleLruInit(NotifyCtl, "Notify", NUM_NOTIFY_BUFFERS, 0,
- NotifySLRULock, "pg_notify", LWTRANCHE_NOTIFY_BUFFER);
- /* Override default assumption that writes should be fsync'd */
- NotifyCtl->do_fsync = false;
+ NotifySLRULock, "pg_notify", LWTRANCHE_NOTIFY_BUFFER,
+ SYNC_HANDLER_NONE);
if (!found)
{
void
CheckPointBuffers(int flags)
{
- TRACE_POSTGRESQL_BUFFER_CHECKPOINT_START(flags);
- CheckpointStats.ckpt_write_t = GetCurrentTimestamp();
BufferSync(flags);
- CheckpointStats.ckpt_sync_t = GetCurrentTimestamp();
- TRACE_POSTGRESQL_BUFFER_CHECKPOINT_SYNC_START();
- ProcessSyncRequests();
- CheckpointStats.ckpt_sync_end_t = GetCurrentTimestamp();
- TRACE_POSTGRESQL_BUFFER_CHECKPOINT_DONE();
}
SerialSlruCtl->PagePrecedes = SerialPagePrecedesLogically;
SimpleLruInit(SerialSlruCtl, "Serial",
NUM_SERIAL_BUFFERS, 0, SerialSLRULock, "pg_serial",
- LWTRANCHE_SERIAL_BUFFER);
- /* Override default assumption that writes should be fsync'd */
- SerialSlruCtl->do_fsync = false;
+ LWTRANCHE_SERIAL_BUFFER, SYNC_HANDLER_NONE);
/*
* Create or attach to the SerialControl structure.
SimpleLruTruncate(SerialSlruCtl, tailPage);
/*
- * Flush dirty SLRU pages to disk
+ * Write dirty SLRU pages to disk
*
* This is not actually necessary from a correctness point of view. We do
* it merely as a debugging aid.
* before deleting the file in which they sit, which would be completely
* pointless.
*/
- SimpleLruFlush(SerialSlruCtl, true);
+ SimpleLruWriteAll(SerialSlruCtl, true);
}
/*------------------------------------------------------------------------*/
#include <fcntl.h>
#include <sys/file.h>
+#include "access/commit_ts.h"
+#include "access/clog.h"
+#include "access/multixact.h"
#include "access/xlog.h"
#include "access/xlogutils.h"
#include "commands/tablespace.h"
const FileTag *candidate);
} SyncOps;
+/*
+ * These indexes must correspond to the values of the SyncRequestHandler enum.
+ */
static const SyncOps syncsw[] = {
/* magnetic disk */
- {
+ [SYNC_HANDLER_MD] = {
.sync_syncfiletag = mdsyncfiletag,
.sync_unlinkfiletag = mdunlinkfiletag,
.sync_filetagmatches = mdfiletagmatches
+ },
+ /* pg_xact */
+ [SYNC_HANDLER_CLOG] = {
+ .sync_syncfiletag = clogsyncfiletag
+ },
+ /* pg_commit_ts */
+ [SYNC_HANDLER_COMMIT_TS] = {
+ .sync_syncfiletag = committssyncfiletag
+ },
+ /* pg_multixact/offsets */
+ [SYNC_HANDLER_MULTIXACT_OFFSET] = {
+ .sync_syncfiletag = multixactoffsetssyncfiletag
+ },
+ /* pg_multixact/members */
+ [SYNC_HANDLER_MULTIXACT_MEMBER] = {
+ .sync_syncfiletag = multixactmemberssyncfiletag
}
};
(void *) ftag,
HASH_ENTER,
&found);
- /* if new entry, initialize it */
- if (!found)
+ /* if new entry, or was previously canceled, initialize it */
+ if (!found || entry->canceled)
{
entry->cycle_ctr = sync_cycle_ctr;
entry->canceled = false;
#define CLOG_H
#include "access/xlogreader.h"
+#include "storage/sync.h"
#include "lib/stringinfo.h"
/*
extern void ExtendCLOG(TransactionId newestXact);
extern void TruncateCLOG(TransactionId oldestXact, Oid oldestxid_datoid);
+extern int clogsyncfiletag(const FileTag *ftag, char *path);
+
/* XLOG stuff */
#define CLOG_ZEROPAGE 0x00
#define CLOG_TRUNCATE 0x10
#include "access/xlog.h"
#include "datatype/timestamp.h"
#include "replication/origin.h"
+#include "storage/sync.h"
#include "utils/guc.h"
TransactionId newestXact);
extern void AdvanceOldestCommitTsXid(TransactionId oldestXact);
+extern int committssyncfiletag(const FileTag *ftag, char *path);
+
/* XLOG stuff */
#define COMMIT_TS_ZEROPAGE 0x00
#define COMMIT_TS_TRUNCATE 0x10
#include "access/xlogreader.h"
#include "lib/stringinfo.h"
+#include "storage/sync.h"
/*
extern bool MultiXactIdPrecedesOrEquals(MultiXactId multi1,
MultiXactId multi2);
+extern int multixactoffsetssyncfiletag(const FileTag *ftag, char *path);
+extern int multixactmemberssyncfiletag(const FileTag *ftag, char *path);
+
extern void AtEOXact_MultiXact(void);
extern void AtPrepare_MultiXact(void);
extern void PostPrepare_MultiXact(TransactionId xid);
#include "access/xlogdefs.h"
#include "storage/lwlock.h"
+#include "storage/sync.h"
/*
SlruShared shared;
/*
- * This flag tells whether to fsync writes (true for pg_xact and multixact
- * stuff, false for pg_subtrans and pg_notify).
+ * Which sync handler function to use when handing sync requests over to
+ * the checkpointer. SYNC_HANDLER_NONE to disable fsync (eg pg_notify).
*/
- bool do_fsync;
+ SyncRequestHandler sync_handler;
/*
* Decide which of two page numbers is "older" for truncation purposes. We
extern Size SimpleLruShmemSize(int nslots, int nlsns);
extern void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
- LWLock *ctllock, const char *subdir, int tranche_id);
+ LWLock *ctllock, const char *subdir, int tranche_id,
+ SyncRequestHandler sync_handler);
extern int SimpleLruZeroPage(SlruCtl ctl, int pageno);
extern int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
TransactionId xid);
extern int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno,
TransactionId xid);
extern void SimpleLruWritePage(SlruCtl ctl, int slotno);
-extern void SimpleLruFlush(SlruCtl ctl, bool allow_redirtied);
+extern void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied);
extern void SimpleLruTruncate(SlruCtl ctl, int cutoffPage);
extern bool SimpleLruDoesPhysicalPageExist(SlruCtl ctl, int pageno);
extern bool SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data);
extern void SlruDeleteSegment(SlruCtl ctl, int segno);
+extern int SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path);
+
/* SlruScanDirectory public callbacks */
extern bool SlruScanDirCbReportPresence(SlruCtl ctl, char *filename,
int segpage, void *data);
*/
typedef enum SyncRequestHandler
{
- SYNC_HANDLER_MD = 0 /* md smgr */
+ SYNC_HANDLER_MD = 0,
+ SYNC_HANDLER_CLOG,
+ SYNC_HANDLER_COMMIT_TS,
+ SYNC_HANDLER_MULTIXACT_OFFSET,
+ SYNC_HANDLER_MULTIXACT_MEMBER,
+ SYNC_HANDLER_NONE
} SyncRequestHandler;
/*
SlruCtl
SlruCtlData
SlruErrorCause
-SlruFlush
-SlruFlushData
SlruPageStatus
SlruScanCallback
SlruShared
SlruSharedData
+SlruWriteAll
+SlruWriteAllData
SnapBuild
SnapBuildOnDisk
SnapBuildState
SyncOps
SyncRepConfigData
SyncRepStandbyData
+SyncRequestHandler
SyncRequestType
SysScanDesc
SyscacheCallbackFunction