From ff27b1fc7099fa668a9e28daa28bfee1ad9410bd Mon Sep 17 00:00:00 2001 From: Petr Jelinek Date: Tue, 21 Feb 2017 19:58:18 +0100 Subject: [PATCH 5/5] Skip unnecessary snapshot builds When doing initial snapshot build during logical decoding initialization, don't build snapshots for transactions where we know the transaction didn't do any catalog changes. Otherwise we might end up with thousands of useless snapshots on busy server which can be quite expensive. --- src/backend/replication/logical/snapbuild.c | 100 ++++++++++++++++------------ 1 file changed, 58 insertions(+), 42 deletions(-) diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c index d989576..916b297 100644 --- a/src/backend/replication/logical/snapbuild.c +++ b/src/backend/replication/logical/snapbuild.c @@ -975,9 +975,8 @@ SnapBuildCommitTxn(SnapBuild *builder, XLogRecPtr lsn, TransactionId xid, { int nxact; - bool forced_timetravel = false; - bool sub_needs_timetravel = false; - bool top_needs_timetravel = false; + bool need_timetravel = false; + bool need_snapshot = false; TransactionId xmax = xid; @@ -997,12 +996,22 @@ SnapBuildCommitTxn(SnapBuild *builder, XLogRecPtr lsn, TransactionId xid, builder->start_decoding_at = lsn + 1; /* - * We could avoid treating !SnapBuildTxnIsRunning transactions as - * timetravel ones, but we want to be able to export a snapshot when - * we reached consistency. + * When building full snapshot we need to keep track of all + * transactions. */ - forced_timetravel = true; - elog(DEBUG1, "forced to assume catalog changes for xid %u because it was running too early", xid); + if (builder->building_full_snapshot) + { + need_timetravel = true; + elog(DEBUG1, "forced to assume catalog changes for xid %u because it was running too early", xid); + } + + /* + * If we could not observe the just finished transaction since it + * started (because it started before we started tracking), we'll + * always need a snapshot. + */ + if (SnapBuildTxnIsRunning(builder, xid)) + need_snapshot = true; } for (nxact = 0; nxact < nsubxacts; nxact++) @@ -1015,23 +1024,13 @@ SnapBuildCommitTxn(SnapBuild *builder, XLogRecPtr lsn, TransactionId xid, SnapBuildEndTxn(builder, lsn, subxid); /* - * If we're forcing timetravel we also need visibility information - * about subtransaction, so keep track of subtransaction's state. - */ - if (forced_timetravel) - { - SnapBuildAddCommittedTxn(builder, subxid); - if (NormalTransactionIdFollows(subxid, xmax)) - xmax = subxid; - } - - /* * Add subtransaction to base snapshot if it DDL, we don't distinguish * to toplevel transactions there. */ - else if (ReorderBufferXidHasCatalogChanges(builder->reorder, subxid)) + if (ReorderBufferXidHasCatalogChanges(builder->reorder, subxid)) { - sub_needs_timetravel = true; + need_timetravel = true; + need_snapshot = true; elog(DEBUG1, "found subtransaction %u:%u with catalog changes.", xid, subxid); @@ -1041,6 +1040,17 @@ SnapBuildCommitTxn(SnapBuild *builder, XLogRecPtr lsn, TransactionId xid, if (NormalTransactionIdFollows(subxid, xmax)) xmax = subxid; } + /* + * If we have already decided that timetravel is needed for this + * transaction, we also need visibility information about + * subtransaction, so keep track of subtransaction's state. + */ + else if (need_timetravel) + { + SnapBuildAddCommittedTxn(builder, subxid); + if (NormalTransactionIdFollows(subxid, xmax)) + xmax = subxid; + } } /* @@ -1049,29 +1059,27 @@ SnapBuildCommitTxn(SnapBuild *builder, XLogRecPtr lsn, TransactionId xid, */ SnapBuildEndTxn(builder, lsn, xid); - if (forced_timetravel) - { - elog(DEBUG2, "forced transaction %u to do timetravel.", xid); - - SnapBuildAddCommittedTxn(builder, xid); - } - /* add toplevel transaction to base snapshot */ - else if (ReorderBufferXidHasCatalogChanges(builder->reorder, xid)) + /* + * Add toplevel transaction to base snapshot if it made any cataog + * changes... + */ + if (ReorderBufferXidHasCatalogChanges(builder->reorder, xid)) { elog(DEBUG2, "found top level transaction %u, with catalog changes!", xid); - top_needs_timetravel = true; + need_timetravel = true; + need_snapshot = true; SnapBuildAddCommittedTxn(builder, xid); } - else if (sub_needs_timetravel) + /* ... or if previous checks decided we need timetravel anyway. */ + else if (need_timetravel) { - /* mark toplevel txn as timetravel as well */ SnapBuildAddCommittedTxn(builder, xid); } /* if there's any reason to build a historic snapshot, do so now */ - if (forced_timetravel || top_needs_timetravel || sub_needs_timetravel) + if (need_timetravel) { /* * Adjust xmax of the snapshot builder, we only do that for committed, @@ -1092,15 +1100,25 @@ SnapBuildCommitTxn(SnapBuild *builder, XLogRecPtr lsn, TransactionId xid, if (builder->state < SNAPBUILD_FULL_SNAPSHOT) return; + /* We always need to build snapshot if there isn't one yet. */ + need_snapshot = need_snapshot || !builder->snapshot; + /* - * Decrease the snapshot builder's refcount of the old snapshot, note - * that it still will be used if it has been handed out to the - * reorderbuffer earlier. + * Decrease the snapshot builder's refcount of the old snapshot if we + * plan to build new one, note that it still will be used if it has + * been handed out to the reorderbuffer earlier. */ - if (builder->snapshot) + if (builder->snapshot && need_snapshot) SnapBuildSnapDecRefcount(builder->snapshot); - builder->snapshot = SnapBuildBuildSnapshot(builder, xid); + /* Build new snapshot unless asked not to. */ + if (need_snapshot) + { + builder->snapshot = SnapBuildBuildSnapshot(builder, xid); + + /* refcount of the snapshot builder for the new snapshot */ + SnapBuildSnapIncRefcount(builder->snapshot); + } /* we might need to execute invalidations, add snapshot */ if (!ReorderBufferXidHasBaseSnapshot(builder->reorder, xid)) @@ -1110,11 +1128,9 @@ SnapBuildCommitTxn(SnapBuild *builder, XLogRecPtr lsn, TransactionId xid, builder->snapshot); } - /* refcount of the snapshot builder for the new snapshot */ - SnapBuildSnapIncRefcount(builder->snapshot); - /* add a new Snapshot to all currently running transactions */ - SnapBuildDistributeNewCatalogSnapshot(builder, lsn); + if (need_snapshot) + SnapBuildDistributeNewCatalogSnapshot(builder, lsn); } else { -- 2.7.4