At Tue, 5 Jul 2022 11:32:42 -0700, Jacob Champion <jchamp...@timescale.com> wrote in > On Thu, Mar 31, 2022 at 11:53 PM Kyotaro Horiguchi > <horikyota....@gmail.com> wrote: > > So this is that. v5 creates a regular snapshot. > > This patch will need a quick rebase over 905c020bef9, which added > `extern` to several missing locations.
Thanks! Just rebased. regards. -- Kyotaro Horiguchi NTT Open Source Software Center
>From abcf0a0e0b3e2de9927d8943a3e3c145ab189508 Mon Sep 17 00:00:00 2001 From: Kyotaro Horiguchi <horikyota....@gmail.com> Date: Tue, 19 Jul 2022 11:50:29 +0900 Subject: [PATCH v6] Create correct snapshot during CREATE_REPLICATION_SLOT Snapshot can hold top XIDs up to the number of server processes but SnapBuildInitialSnapshot tries to store all top-level and sub XIDs to there and easily fails with "initial slot snapshot too large" error. We could instead create a "takenDuringRecovery" snapshot, which later leads to unnecessary visibility checks. Therefore we take trouble to create a regular snapshot by identifying whether each xids is top-level and storing it in the appropriate xid array. Author: Dilip Kumar and Kyotaro Horiguchi --- .../replication/logical/reorderbuffer.c | 20 +++++++++ src/backend/replication/logical/snapbuild.c | 45 +++++++++++++++---- src/include/replication/reorderbuffer.h | 1 + 3 files changed, 58 insertions(+), 8 deletions(-) diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c index 88a37fde72..44ea3f31aa 100644 --- a/src/backend/replication/logical/reorderbuffer.c +++ b/src/backend/replication/logical/reorderbuffer.c @@ -3332,6 +3332,26 @@ ReorderBufferXidHasBaseSnapshot(ReorderBuffer *rb, TransactionId xid) } +/* + * ReorderBufferXidIsKnownSubXact + * Returns true if the xid is a known subtransaction. + */ +bool +ReorderBufferXidIsKnownSubXact(ReorderBuffer *rb, TransactionId xid) +{ + ReorderBufferTXN *txn; + + txn = ReorderBufferTXNByXid(rb, xid, false, + NULL, InvalidXLogRecPtr, false); + + /* a known subtxn? */ + if (txn && rbtxn_is_known_subxact(txn)) + return true; + + return false; +} + + /* * --------------------------------------- * Disk serialization support diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c index 73c0f15214..2b5282788a 100644 --- a/src/backend/replication/logical/snapbuild.c +++ b/src/backend/replication/logical/snapbuild.c @@ -532,7 +532,10 @@ SnapBuildInitialSnapshot(SnapBuild *builder) Snapshot snap; TransactionId xid; TransactionId *newxip; - int newxcnt = 0; + TransactionId *newsubxip; + int newxcnt; + int newsubxcnt; + bool overflowed = false; Assert(!FirstSnapshotSet); Assert(XactIsoLevel == XACT_REPEATABLE_READ); @@ -568,9 +571,17 @@ SnapBuildInitialSnapshot(SnapBuild *builder) MyProc->xmin = snap->xmin; - /* allocate in transaction context */ + /* + * Allocate in transaction context. + * + * We could use only subxip to store all xids (takenduringrecovery + * snapshot) but that causes useless visibility checks later so we hasle to + * create a normal snapshot. + */ newxip = (TransactionId *) palloc(sizeof(TransactionId) * GetMaxSnapshotXidCount()); + newsubxip = (TransactionId *) + palloc(sizeof(TransactionId) * GetMaxSnapshotSubxidCount()); /* * snapbuild.c builds transactions in an "inverted" manner, which means it @@ -578,6 +589,9 @@ SnapBuildInitialSnapshot(SnapBuild *builder) * classical snapshot by marking all non-committed transactions as * in-progress. This can be expensive. */ + newxcnt = 0; + newsubxcnt = 0; + for (xid = snap->xmin; NormalTransactionIdPrecedes(xid, snap->xmax);) { void *test; @@ -591,12 +605,24 @@ SnapBuildInitialSnapshot(SnapBuild *builder) if (test == NULL) { - if (newxcnt >= GetMaxSnapshotXidCount()) - ereport(ERROR, - (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), - errmsg("initial slot snapshot too large"))); - - newxip[newxcnt++] = xid; + /* Store the xid to the appropriate xid array */ + if (ReorderBufferXidIsKnownSubXact(builder->reorder, xid)) + { + if (!overflowed) + { + if (newsubxcnt >= GetMaxSnapshotSubxidCount()) + overflowed = true; + else + newsubxip[newsubxcnt++] = xid; + } + } + else + { + if (newxcnt >= GetMaxSnapshotXidCount()) + elog(ERROR, + "too many transactions while creating snapshot"); + newxip[newxcnt++] = xid; + } } TransactionIdAdvance(xid); @@ -606,6 +632,9 @@ SnapBuildInitialSnapshot(SnapBuild *builder) snap->snapshot_type = SNAPSHOT_MVCC; snap->xcnt = newxcnt; snap->xip = newxip; + snap->subxcnt = newsubxcnt; + snap->subxip = newsubxip; + snap->suboverflowed = overflowed; return snap; } diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h index d109d0baed..736f22a04e 100644 --- a/src/include/replication/reorderbuffer.h +++ b/src/include/replication/reorderbuffer.h @@ -669,6 +669,7 @@ extern void ReorderBufferXidSetCatalogChanges(ReorderBuffer *, TransactionId xid extern bool ReorderBufferXidHasCatalogChanges(ReorderBuffer *, TransactionId xid); extern bool ReorderBufferXidHasBaseSnapshot(ReorderBuffer *, TransactionId xid); +extern bool ReorderBufferXidIsKnownSubXact(ReorderBuffer *rb, TransactionId xid); extern bool ReorderBufferRememberPrepareInfo(ReorderBuffer *rb, TransactionId xid, XLogRecPtr prepare_lsn, XLogRecPtr end_lsn, TimestampTz prepare_time, -- 2.31.1