src/backend/access/rmgrdesc/Makefile | 1 src/backend/access/rmgrdesc/csnlogdesc.c | 95 +++++++++++++++ src/backend/access/rmgrdesc/xlogdesc.c | 6 + src/backend/access/transam/csn_log.c | 187 ++++++++++++++++++++++------- src/backend/access/transam/csn_snapshot.c | 72 ++++++++++- src/backend/access/transam/rmgr.c | 1 src/backend/access/transam/xlog.c | 12 +- src/backend/commands/vacuum.c | 3 src/backend/storage/ipc/procarray.c | 2 src/backend/utils/time/snapmgr.c | 2 src/bin/pg_controldata/pg_controldata.c | 2 src/bin/pg_upgrade/pg_upgrade.c | 5 + src/bin/pg_upgrade/pg_upgrade.h | 2 src/bin/pg_waldump/rmgrdesc.c | 1 src/include/access/csn_log.h | 29 ++++ src/include/access/rmgrlist.h | 1 src/include/access/xlog_internal.h | 1 src/include/catalog/pg_control.h | 1 18 files changed, 359 insertions(+), 64 deletions(-) diff --git a/src/backend/access/rmgrdesc/Makefile b/src/backend/access/rmgrdesc/Makefile index f88d72fd86..15fc36f7b4 100644 --- a/src/backend/access/rmgrdesc/Makefile +++ b/src/backend/access/rmgrdesc/Makefile @@ -11,6 +11,7 @@ include $(top_builddir)/src/Makefile.global OBJS = \ brindesc.o \ clogdesc.o \ + csnlogdesc.o \ committsdesc.o \ dbasedesc.o \ genericdesc.o \ diff --git a/src/backend/access/rmgrdesc/csnlogdesc.c b/src/backend/access/rmgrdesc/csnlogdesc.c new file mode 100644 index 0000000000..e96b056325 --- /dev/null +++ b/src/backend/access/rmgrdesc/csnlogdesc.c @@ -0,0 +1,95 @@ +/*------------------------------------------------------------------------- + * + * clogdesc.c + * rmgr descriptor routines for access/transam/csn_log.c + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/access/rmgrdesc/csnlogdesc.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/csn_log.h" + + +void +csnlog_desc(StringInfo buf, XLogReaderState *record) +{ + char *rec = XLogRecGetData(record); + uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; + + if (info == XLOG_CSN_ZEROPAGE) + { + int pageno; + + memcpy(&pageno, XLogRecGetData(record), sizeof(int)); + appendStringInfo(buf, "pageno %d", pageno); + } + else if (info == XLOG_CSN_TRUNCATE) + { + int pageno; + + memcpy(&pageno, XLogRecGetData(record), sizeof(int)); + appendStringInfo(buf, "pageno %d", pageno); + } + else if (info == XLOG_CSN_ASSIGNMENT) + { + XidCSN csn; + + memcpy(&csn, XLogRecGetData(record), sizeof(XidCSN)); + appendStringInfo(buf, "assign "INT64_FORMAT"", csn); + } + else if (info == XLOG_CSN_SETXIDCSN) + { + xl_xidcsn_set *xlrec = (xl_xidcsn_set *) rec; + int nsubxids; + + appendStringInfo(buf, "set "INT64_FORMAT" for: %u", + xlrec->xidcsn, + xlrec->xtop); + nsubxids = ((XLogRecGetDataLen(record) - MinSizeOfXidCSNSet) / + sizeof(TransactionId)); + if (nsubxids > 0) + { + int i; + TransactionId *subxids; + + subxids = palloc(sizeof(TransactionId) * nsubxids); + memcpy(subxids, + XLogRecGetData(record) + MinSizeOfXidCSNSet, + sizeof(TransactionId) * nsubxids); + for (i = 0; i < nsubxids; i++) + appendStringInfo(buf, ", %u", subxids[i]); + pfree(subxids); + } + } +} + +const char * +csnlog_identify(uint8 info) +{ + const char *id = NULL; + + switch (info & ~XLR_INFO_MASK) + { + case XLOG_CSN_ASSIGNMENT: + id = "ASSIGNMENT"; + break; + case XLOG_CSN_SETXIDCSN: + id = "SETXIDCSN"; + break; + case XLOG_CSN_ZEROPAGE: + id = "ZEROPAGE"; + break; + case XLOG_CSN_TRUNCATE: + id = "TRUNCATE"; + break; + } + + return id; +} diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c index 1cd97852e8..44e2e8ecec 100644 --- a/src/backend/access/rmgrdesc/xlogdesc.c +++ b/src/backend/access/rmgrdesc/xlogdesc.c @@ -114,7 +114,8 @@ xlog_desc(StringInfo buf, XLogReaderState *record) appendStringInfo(buf, "max_connections=%d max_worker_processes=%d " "max_wal_senders=%d max_prepared_xacts=%d " "max_locks_per_xact=%d wal_level=%s " - "wal_log_hints=%s track_commit_timestamp=%s", + "wal_log_hints=%s track_commit_timestamp=%s " + "enable_csn_snapshot=%s", xlrec.MaxConnections, xlrec.max_worker_processes, xlrec.max_wal_senders, @@ -122,7 +123,8 @@ xlog_desc(StringInfo buf, XLogReaderState *record) xlrec.max_locks_per_xact, wal_level_str, xlrec.wal_log_hints ? "on" : "off", - xlrec.track_commit_timestamp ? "on" : "off"); + xlrec.track_commit_timestamp ? "on" : "off", + xlrec.enable_csn_snapshot ? "on" : "off"); } else if (info == XLOG_FPW_CHANGE) { diff --git a/src/backend/access/transam/csn_log.c b/src/backend/access/transam/csn_log.c index 4e0b8d64e4..4577e61fc3 100644 --- a/src/backend/access/transam/csn_log.c +++ b/src/backend/access/transam/csn_log.c @@ -9,6 +9,11 @@ * transactions. Because of same lifetime and persistancy requirements * this module is quite similar to subtrans.c * + * If we switch database from CSN-base snapshot to xid-base snapshot then, + * nothing wrong. But if we switch xid-base snapshot to CSN-base snapshot + * it should decide a new xid whwich begin csn-base check. It can not be + * oldestActiveXID because of prepared transaction. + * * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * @@ -52,7 +57,8 @@ bool enable_csn_snapshot; static SlruCtlData CSNLogCtlData; #define CsnlogCtl (&CSNLogCtlData) -static int ZeroCSNLogPage(int pageno); +static int ZeroCSNLogPage(int pageno, bool write_xlog); +static void ZeroTruncateCSNLogPage(int pageno, bool write_xlog); static bool CSNLogPagePrecedes(int page1, int page2); static void CSNLogSetPageStatus(TransactionId xid, int nsubxids, TransactionId *subxids, @@ -60,6 +66,11 @@ static void CSNLogSetPageStatus(TransactionId xid, int nsubxids, static void CSNLogSetCSNInSlot(TransactionId xid, XidCSN csn, int slotno); +static void WriteXidCsnXlogRec(TransactionId xid, int nsubxids, + TransactionId *subxids, XidCSN csn); +static void WriteZeroCSNPageXlogRec(int pageno); +static void WriteTruncateCSNXlogRec(int pageno); + /* * CSNLogSetCSN * @@ -77,7 +88,7 @@ static void CSNLogSetCSNInSlot(TransactionId xid, XidCSN csn, */ void CSNLogSetCSN(TransactionId xid, int nsubxids, - TransactionId *subxids, XidCSN csn) + TransactionId *subxids, XidCSN csn, bool write_xlog) { int pageno; int i = 0; @@ -89,6 +100,10 @@ CSNLogSetCSN(TransactionId xid, int nsubxids, Assert(TransactionIdIsValid(xid)); pageno = TransactionIdToPage(xid); /* get page of parent */ + + if(write_xlog) + WriteXidCsnXlogRec(xid, nsubxids, subxids, csn); + for (;;) { int num_on_page = 0; @@ -180,11 +195,7 @@ CSNLogGetCSNByXid(TransactionId xid) /* Callers of CSNLogGetCSNByXid() must check GUC params */ Assert(enable_csn_snapshot); - /* Can't ask about stuff that might not be around anymore */ - Assert(TransactionIdFollowsOrEquals(xid, TransactionXmin)); - /* lock is acquired by SimpleLruReadPage_ReadOnly */ - slotno = SimpleLruReadPage_ReadOnly(CsnlogCtl, pageno, xid); ptr = (XidCSN *) (CsnlogCtl->shared->page_buffer[slotno] + entryno * sizeof(XLogRecPtr)); xid_csn = *ptr; @@ -245,7 +256,7 @@ BootStrapCSNLog(void) LWLockAcquire(CSNLogControlLock, LW_EXCLUSIVE); /* Create and zero the first page of the commit log */ - slotno = ZeroCSNLogPage(0); + slotno = ZeroCSNLogPage(0, false); /* Make sure it's written out */ SimpleLruWritePage(CsnlogCtl, slotno); @@ -263,50 +274,20 @@ BootStrapCSNLog(void) * Control lock must be held at entry, and will be held at exit. */ static int -ZeroCSNLogPage(int pageno) +ZeroCSNLogPage(int pageno, bool write_xlog) { Assert(LWLockHeldByMe(CSNLogControlLock)); + if(write_xlog) + WriteZeroCSNPageXlogRec(pageno); return SimpleLruZeroPage(CsnlogCtl, pageno); } -/* - * This must be called ONCE during postmaster or standalone-backend startup, - * after StartupXLOG has initialized ShmemVariableCache->nextXid. - * - * oldestActiveXID is the oldest XID of any prepared transaction, or nextXid - * if there are none. - */ -void -StartupCSNLog(TransactionId oldestActiveXID) +static void +ZeroTruncateCSNLogPage(int pageno, bool write_xlog) { - int startPage; - int endPage; - - if (!enable_csn_snapshot) - return; - - /* - * Since we don't expect pg_csn to be valid across crashes, we - * initialize the currently-active page(s) to zeroes during startup. - * Whenever we advance into a new page, ExtendCSNLog will likewise - * zero the new page without regard to whatever was previously on disk. - */ - LWLockAcquire(CSNLogControlLock, LW_EXCLUSIVE); - - startPage = TransactionIdToPage(oldestActiveXID); - endPage = TransactionIdToPage(XidFromFullTransactionId(ShmemVariableCache->nextFullXid)); - - while (startPage != endPage) - { - (void) ZeroCSNLogPage(startPage); - startPage++; - /* must account for wraparound */ - if (startPage > TransactionIdToPage(MaxTransactionId)) - startPage = 0; - } - (void) ZeroCSNLogPage(startPage); - - LWLockRelease(CSNLogControlLock); + if(write_xlog) + WriteTruncateCSNXlogRec(pageno); + SimpleLruTruncate(CsnlogCtl, pageno); } /* @@ -379,7 +360,7 @@ ExtendCSNLog(TransactionId newestXact) LWLockAcquire(CSNLogControlLock, LW_EXCLUSIVE); /* Zero the page and make an XLOG entry about it */ - ZeroCSNLogPage(pageno); + ZeroCSNLogPage(pageno, !InRecovery); LWLockRelease(CSNLogControlLock); } @@ -410,7 +391,7 @@ TruncateCSNLog(TransactionId oldestXact) TransactionIdRetreat(oldestXact); cutoffPage = TransactionIdToPage(oldestXact); - SimpleLruTruncate(CsnlogCtl, cutoffPage); + ZeroTruncateCSNLogPage(cutoffPage, true); } /* @@ -436,3 +417,115 @@ CSNLogPagePrecedes(int page1, int page2) return TransactionIdPrecedes(xid1, xid2); } + +void +WriteAssignCSNXlogRec(XidCSN xidcsn) +{ + XidCSN log_csn = 0; + + if(xidcsn > get_last_log_wal_csn()) + { + log_csn = CSNAddByNanosec(xidcsn, 20); + set_last_log_wal_csn(log_csn); + } + else + { + return; + } + + XLogBeginInsert(); + XLogRegisterData((char *) (&log_csn), sizeof(XidCSN)); + XLogInsert(RM_CSNLOG_ID, XLOG_CSN_ASSIGNMENT); +} + +static void +WriteXidCsnXlogRec(TransactionId xid, int nsubxids, + TransactionId *subxids, XidCSN csn) +{ + xl_xidcsn_set xlrec; + XLogRecPtr recptr; + + xlrec.xtop = xid; + xlrec.nsubxacts = nsubxids; + xlrec.xidcsn = csn; + + XLogBeginInsert(); + XLogRegisterData((char *) &xlrec, MinSizeOfXidCSNSet); + XLogRegisterData((char *) subxids, nsubxids * sizeof(TransactionId)); + recptr = XLogInsert(RM_CSNLOG_ID, XLOG_CSN_SETXIDCSN); + XLogFlush(recptr); +} + +/* + * Write a ZEROPAGE xlog record + */ +static void +WriteZeroCSNPageXlogRec(int pageno) +{ + XLogBeginInsert(); + XLogRegisterData((char *) (&pageno), sizeof(int)); + (void) XLogInsert(RM_CSNLOG_ID, XLOG_CSN_ZEROPAGE); +} + +/* + * Write a TRUNCATE xlog record + */ +static void +WriteTruncateCSNXlogRec(int pageno) +{ + XLogRecPtr recptr; + return; + XLogBeginInsert(); + XLogRegisterData((char *) (&pageno), sizeof(int)); + recptr = XLogInsert(RM_CSNLOG_ID, XLOG_CSN_TRUNCATE); + XLogFlush(recptr); +} + + +void +csnlog_redo(XLogReaderState *record) +{ + uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; + + /* Backup blocks are not used in csnlog records */ + Assert(!XLogRecHasAnyBlockRefs(record)); + + if (info == XLOG_CSN_ASSIGNMENT) + { + XidCSN csn; + + memcpy(&csn, XLogRecGetData(record), sizeof(XidCSN)); + LWLockAcquire(CSNLogControlLock, LW_EXCLUSIVE); + set_last_max_csn(csn); + LWLockRelease(CSNLogControlLock); + + } + else if (info == XLOG_CSN_SETXIDCSN) + { + xl_xidcsn_set *xlrec = (xl_xidcsn_set *) XLogRecGetData(record); + CSNLogSetCSN(xlrec->xtop, xlrec->nsubxacts, xlrec->xsub, xlrec->xidcsn, false); + } + else if (info == XLOG_CSN_ZEROPAGE) + { + int pageno; + int slotno; + + memcpy(&pageno, XLogRecGetData(record), sizeof(int)); + LWLockAcquire(CSNLogControlLock, LW_EXCLUSIVE); + slotno = ZeroCSNLogPage(pageno, false); + SimpleLruWritePage(CsnlogCtl, slotno); + LWLockRelease(CSNLogControlLock); + Assert(!CsnlogCtl->shared->page_dirty[slotno]); + + } + else if (info == XLOG_CSN_TRUNCATE) + { + int pageno; + + memcpy(&pageno, XLogRecGetData(record), sizeof(int)); + CsnlogCtl->shared->latest_page_number = pageno; + ZeroTruncateCSNLogPage(pageno, false); + } + else + elog(PANIC, "csnlog_redo: unknown op code %u", info); +} diff --git a/src/backend/access/transam/csn_snapshot.c b/src/backend/access/transam/csn_snapshot.c index e2d4d2649e..a3d164d77e 100644 --- a/src/backend/access/transam/csn_snapshot.c +++ b/src/backend/access/transam/csn_snapshot.c @@ -31,6 +31,8 @@ /* Raise a warning if imported snapshot_csn exceeds ours by this value. */ #define SNAP_DESYNC_COMPLAIN (1*NSECS_PER_SEC) /* 1 second */ +TransactionId xmin_for_csn = InvalidTransactionId; + /* * CSNSnapshotState * @@ -40,7 +42,9 @@ */ typedef struct { - SnapshotCSN last_max_csn; + SnapshotCSN last_max_csn; /* Record the max csn till now */ + XidCSN last_csn_log_wal; /* for interval we log the assign csn to wal */ + TransactionId xmin_for_csn; /*'xmin_for_csn' for when turn xid-snapshot to csn-snapshot*/ volatile slock_t lock; } CSNSnapshotState; @@ -80,6 +84,7 @@ CSNSnapshotShmemInit() if (!found) { csnState->last_max_csn = 0; + csnState->last_csn_log_wal = 0; SpinLockInit(&csnState->lock); } } @@ -116,6 +121,8 @@ GenerateCSN(bool locked) else csnState->last_max_csn = csn; + WriteAssignCSNXlogRec(csn); + if (!locked) SpinLockRelease(&csnState->lock); @@ -131,7 +138,7 @@ GenerateCSN(bool locked) XidCSN TransactionIdGetXidCSN(TransactionId xid) { - XidCSN xid_csn; + XidCSN xid_csn; Assert(enable_csn_snapshot); @@ -145,13 +152,35 @@ TransactionIdGetXidCSN(TransactionId xid) Assert(false); /* Should not happend */ } + /* + * If we just switch a xid-snapsot to a csn_snapshot, we should handle a start + * xid for csn basse check. Just in case we have prepared transaction which + * hold the TransactionXmin but without CSN. + */ + if(InvalidTransactionId == xmin_for_csn) + { + SpinLockAcquire(&csnState->lock); + if(InvalidTransactionId != csnState->xmin_for_csn) + xmin_for_csn = csnState->xmin_for_csn; + else + xmin_for_csn = FrozenTransactionId; + + SpinLockRelease(&csnState->lock); + } + + if ( FrozenTransactionId != xmin_for_csn || + TransactionIdPrecedes(xmin_for_csn, TransactionXmin)) + { + xmin_for_csn = TransactionXmin; + } + /* * For xids which less then TransactionXmin CSNLog can be already * trimmed but we know that such transaction is definetly not concurrently * running according to any snapshot including timetravel ones. Callers * should check TransactionDidCommit after. */ - if (TransactionIdPrecedes(xid, TransactionXmin)) + if (TransactionIdPrecedes(xid, xmin_for_csn)) return FrozenXidCSN; /* Read XidCSN from SLRU */ @@ -251,7 +280,7 @@ CSNSnapshotAbort(PGPROC *proc, TransactionId xid, if (!enable_csn_snapshot) return; - CSNLogSetCSN(xid, nsubxids, subxids, AbortedXidCSN); + CSNLogSetCSN(xid, nsubxids, subxids, AbortedXidCSN, true); /* * Clean assignedXidCsn anyway, as it was possibly set in @@ -292,7 +321,7 @@ CSNSnapshotPrecommit(PGPROC *proc, TransactionId xid, { Assert(XidCSNIsInProgress(oldassignedXidCsn)); CSNLogSetCSN(xid, nsubxids, - subxids, InDoubtXidCSN); + subxids, InDoubtXidCSN, true); } else { @@ -333,8 +362,39 @@ CSNSnapshotCommit(PGPROC *proc, TransactionId xid, assigned_xid_csn = pg_atomic_read_u64(&proc->assignedXidCsn); Assert(XidCSNIsNormal(assigned_xid_csn)); CSNLogSetCSN(xid, nsubxids, - subxids, assigned_xid_csn); + subxids, assigned_xid_csn, true); /* Reset for next transaction */ pg_atomic_write_u64(&proc->assignedXidCsn, InProgressXidCSN); } + +void +set_last_max_csn(XidCSN xidcsn) +{ + csnState->last_max_csn = xidcsn; +} + +void +set_last_log_wal_csn(XidCSN xidcsn) +{ + csnState->last_csn_log_wal = xidcsn; +} + +XidCSN +get_last_log_wal_csn(void) +{ + XidCSN last_csn_log_wal; + + last_csn_log_wal = csnState->last_csn_log_wal; + + return last_csn_log_wal; +} + +/* + * 'xmin_for_csn' for when turn xid-snapshot to csn-snapshot + */ +void +set_xmin_for_csn(void) +{ + csnState->xmin_for_csn = XidFromFullTransactionId(ShmemVariableCache->nextFullXid); +} diff --git a/src/backend/access/transam/rmgr.c b/src/backend/access/transam/rmgr.c index 58091f6b52..b1e5ec350e 100644 --- a/src/backend/access/transam/rmgr.c +++ b/src/backend/access/transam/rmgr.c @@ -28,6 +28,7 @@ #include "replication/origin.h" #include "storage/standby.h" #include "utils/relmapper.h" +#include "access/csn_log.h" /* must be kept in sync with RmgrData definition in xlog_internal.h */ #define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup,mask) \ diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index b7350249da..7187bb0be3 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -4604,6 +4604,7 @@ InitControlFile(uint64 sysidentifier) ControlFile->wal_level = wal_level; ControlFile->wal_log_hints = wal_log_hints; ControlFile->track_commit_timestamp = track_commit_timestamp; + ControlFile->enable_csn_snapshot = enable_csn_snapshot; ControlFile->data_checksum_version = bootstrap_data_checksum_version; } @@ -7056,7 +7057,6 @@ StartupXLOG(void) * maintained during recovery and need not be started yet. */ StartupCLOG(); - StartupCSNLog(oldestActiveXID); StartupSUBTRANS(oldestActiveXID); /* @@ -7874,7 +7874,6 @@ StartupXLOG(void) if (standbyState == STANDBY_DISABLED) { StartupCLOG(); - StartupCSNLog(oldestActiveXID); StartupSUBTRANS(oldestActiveXID); } @@ -9097,7 +9096,6 @@ CreateCheckPoint(int flags) if (!RecoveryInProgress()) { TruncateSUBTRANS(GetOldestXmin(NULL, PROCARRAY_FLAGS_DEFAULT)); - TruncateCSNLog(GetOldestXmin(NULL, PROCARRAY_FLAGS_DEFAULT)); } /* Real work is done, but log and update stats before releasing lock. */ @@ -9720,7 +9718,8 @@ XLogReportParameters(void) max_wal_senders != ControlFile->max_wal_senders || max_prepared_xacts != ControlFile->max_prepared_xacts || max_locks_per_xact != ControlFile->max_locks_per_xact || - track_commit_timestamp != ControlFile->track_commit_timestamp) + track_commit_timestamp != ControlFile->track_commit_timestamp || + enable_csn_snapshot != ControlFile->enable_csn_snapshot) { /* * The change in number of backend slots doesn't need to be WAL-logged @@ -9742,6 +9741,7 @@ XLogReportParameters(void) xlrec.wal_level = wal_level; xlrec.wal_log_hints = wal_log_hints; xlrec.track_commit_timestamp = track_commit_timestamp; + xlrec.enable_csn_snapshot = enable_csn_snapshot; XLogBeginInsert(); XLogRegisterData((char *) &xlrec, sizeof(xlrec)); @@ -9750,6 +9750,8 @@ XLogReportParameters(void) XLogFlush(recptr); } + if (enable_csn_snapshot != ControlFile->enable_csn_snapshot) + set_xmin_for_csn(); ControlFile->MaxConnections = MaxConnections; ControlFile->max_worker_processes = max_worker_processes; ControlFile->max_wal_senders = max_wal_senders; @@ -9758,6 +9760,7 @@ XLogReportParameters(void) ControlFile->wal_level = wal_level; ControlFile->wal_log_hints = wal_log_hints; ControlFile->track_commit_timestamp = track_commit_timestamp; + ControlFile->enable_csn_snapshot = enable_csn_snapshot; UpdateControlFile(); } } @@ -10184,6 +10187,7 @@ xlog_redo(XLogReaderState *record) CommitTsParameterChange(xlrec.track_commit_timestamp, ControlFile->track_commit_timestamp); ControlFile->track_commit_timestamp = xlrec.track_commit_timestamp; + ControlFile->enable_csn_snapshot = xlrec.enable_csn_snapshot; UpdateControlFile(); LWLockRelease(ControlFileLock); diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 5a110edb07..0f301b1db0 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -53,7 +53,7 @@ #include "utils/memutils.h" #include "utils/snapmgr.h" #include "utils/syscache.h" - +#include "access/csn_log.h" /* * GUC parameters @@ -1632,6 +1632,7 @@ vac_truncate_clog(TransactionId frozenXID, */ TruncateCLOG(frozenXID, oldestxid_datoid); TruncateCommitTs(frozenXID); + TruncateCSNLog(frozenXID); TruncateMultiXact(minMulti, minmulti_datoid); /* diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index 158fb9d31f..c671d92ead 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -1736,7 +1736,7 @@ GetSnapshotData(Snapshot snapshot) * Take XidCSN under ProcArrayLock so the snapshot stays * synchronized. */ - if (enable_csn_snapshot) + if (!snapshot->takenDuringRecovery && enable_csn_snapshot) xid_csn = GenerateCSN(false); LWLockRelease(ProcArrayLock); diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c index e2baeb9222..218f32e8ec 100644 --- a/src/backend/utils/time/snapmgr.c +++ b/src/backend/utils/time/snapmgr.c @@ -2265,7 +2265,7 @@ XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot) if (XidInvisibleInCSNSnapshot(xid, snapshot)) { XidCSN gcsn = TransactionIdGetXidCSN(xid); - Assert(XidCSNIsAborted(gcsn)); + Assert(XidCSNIsAborted(gcsn) || XidCSNIsInProgress(gcsn)); } #endif return false; diff --git a/src/bin/pg_controldata/pg_controldata.c b/src/bin/pg_controldata/pg_controldata.c index e73639df74..e7194124c7 100644 --- a/src/bin/pg_controldata/pg_controldata.c +++ b/src/bin/pg_controldata/pg_controldata.c @@ -306,6 +306,8 @@ main(int argc, char *argv[]) ControlFile->max_locks_per_xact); printf(_("track_commit_timestamp setting: %s\n"), ControlFile->track_commit_timestamp ? _("on") : _("off")); + printf(_("enable_csn_snapshot setting: %s\n"), + ControlFile->enable_csn_snapshot ? _("on") : _("off")); printf(_("Maximum data alignment: %u\n"), ControlFile->maxAlign); /* we don't print floatFormat since can't say much useful about it */ diff --git a/src/bin/pg_upgrade/pg_upgrade.c b/src/bin/pg_upgrade/pg_upgrade.c index 70194eb096..863ee73d24 100644 --- a/src/bin/pg_upgrade/pg_upgrade.c +++ b/src/bin/pg_upgrade/pg_upgrade.c @@ -545,6 +545,11 @@ copy_xact_xlog_xid(void) check_ok(); } + if(old_cluster.controldata.cat_ver > CSN_BASE_SNAPSHOT_ADD_VER) + { + copy_subdir_files("pg_csn", "pg_csn"); + } + /* now reset the wal archives in the new cluster */ prep_status("Resetting WAL archives"); exec_prog(UTILITY_LOG_FILE, NULL, true, true, diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h index 8b90cefbe0..f35860dfc5 100644 --- a/src/bin/pg_upgrade/pg_upgrade.h +++ b/src/bin/pg_upgrade/pg_upgrade.h @@ -123,6 +123,8 @@ extern char *output_files[]; */ #define JSONB_FORMAT_CHANGE_CAT_VER 201409291 +#define CSN_BASE_SNAPSHOT_ADD_VER 202002010 + /* * Each relation is represented by a relinfo structure. diff --git a/src/bin/pg_waldump/rmgrdesc.c b/src/bin/pg_waldump/rmgrdesc.c index 852d8ca4b1..282bae882a 100644 --- a/src/bin/pg_waldump/rmgrdesc.c +++ b/src/bin/pg_waldump/rmgrdesc.c @@ -31,6 +31,7 @@ #include "rmgrdesc.h" #include "storage/standbydefs.h" #include "utils/relmapper.h" +#include "access/csn_log.h" #define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup,mask) \ { name, desc, identify}, diff --git a/src/include/access/csn_log.h b/src/include/access/csn_log.h index 9b9611127d..b973e0c2ce 100644 --- a/src/include/access/csn_log.h +++ b/src/include/access/csn_log.h @@ -14,17 +14,42 @@ #include "access/xlog.h" #include "utils/snapshot.h" +/* XLOG stuff */ +#define XLOG_CSN_ASSIGNMENT 0x00 +#define XLOG_CSN_SETXIDCSN 0x10 +#define XLOG_CSN_ZEROPAGE 0x20 +#define XLOG_CSN_TRUNCATE 0x30 + +typedef struct xl_xidcsn_set +{ + XidCSN xidcsn; + TransactionId xtop; /* XID's top-level XID */ + int nsubxacts; /* number of subtransaction XIDs */ + TransactionId xsub[FLEXIBLE_ARRAY_MEMBER]; /* assigned subxids */ +} xl_xidcsn_set; + +#define MinSizeOfXidCSNSet offsetof(xl_xidcsn_set, xsub) +#define CSNAddByNanosec(csn,second) (csn + second * 1000000000L) + extern void CSNLogSetCSN(TransactionId xid, int nsubxids, - TransactionId *subxids, XidCSN csn); + TransactionId *subxids, XidCSN csn, bool write_xlog); extern XidCSN CSNLogGetCSNByXid(TransactionId xid); extern Size CSNLogShmemSize(void); extern void CSNLogShmemInit(void); extern void BootStrapCSNLog(void); -extern void StartupCSNLog(TransactionId oldestActiveXID); extern void ShutdownCSNLog(void); extern void CheckPointCSNLog(void); extern void ExtendCSNLog(TransactionId newestXact); extern void TruncateCSNLog(TransactionId oldestXact); +extern void csnlog_redo(XLogReaderState *record); +extern void csnlog_desc(StringInfo buf, XLogReaderState *record); +extern const char *csnlog_identify(uint8 info); +extern void WriteAssignCSNXlogRec(XidCSN xidcsn); +extern void set_last_max_csn(XidCSN xidcsn); +extern void set_last_log_wal_csn(XidCSN xidcsn); +extern XidCSN get_last_log_wal_csn(void); +extern void set_xmin_for_csn(void); + #endif /* CSNLOG_H */ \ No newline at end of file diff --git a/src/include/access/rmgrlist.h b/src/include/access/rmgrlist.h index 6c15df7e70..b2d12bfb27 100644 --- a/src/include/access/rmgrlist.h +++ b/src/include/access/rmgrlist.h @@ -47,3 +47,4 @@ PG_RMGR(RM_COMMIT_TS_ID, "CommitTs", commit_ts_redo, commit_ts_desc, commit_ts_i PG_RMGR(RM_REPLORIGIN_ID, "ReplicationOrigin", replorigin_redo, replorigin_desc, replorigin_identify, NULL, NULL, NULL) PG_RMGR(RM_GENERIC_ID, "Generic", generic_redo, generic_desc, generic_identify, NULL, NULL, generic_mask) PG_RMGR(RM_LOGICALMSG_ID, "LogicalMessage", logicalmsg_redo, logicalmsg_desc, logicalmsg_identify, NULL, NULL, NULL) +PG_RMGR(RM_CSNLOG_ID, "CSN", csnlog_redo, csnlog_desc, csnlog_identify, NULL, NULL, NULL) diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h index c8869d5226..729cf5bc56 100644 --- a/src/include/access/xlog_internal.h +++ b/src/include/access/xlog_internal.h @@ -236,6 +236,7 @@ typedef struct xl_parameter_change int wal_level; bool wal_log_hints; bool track_commit_timestamp; + bool enable_csn_snapshot; } xl_parameter_change; /* logs restore point */ diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h index de5670e538..9e5d4b0fc0 100644 --- a/src/include/catalog/pg_control.h +++ b/src/include/catalog/pg_control.h @@ -181,6 +181,7 @@ typedef struct ControlFileData int max_prepared_xacts; int max_locks_per_xact; bool track_commit_timestamp; + bool enable_csn_snapshot; /* * This data is used to check for hardware-architecture compatibility of