{
int nxact;
- bool forced_timetravel = false;
+ bool needs_snapshot = false;
+ bool needs_timetravel = false;
bool sub_needs_timetravel = false;
- bool top_needs_timetravel = false;
TransactionId xmax = xid;
/*
- * If we couldn't observe every change of a transaction because it was
- * already running at the point we started to observe we have to assume it
- * made catalog changes.
- *
- * This has the positive benefit that we afterwards have enough
- * information to build an exportable snapshot that's usable by pg_dump et
- * al.
+ * Transactions preceding BUILDING_SNAPSHOT will neither be decoded, nor
+ * will they be part of a snapshot. So we don't need to record anything.
*/
+ if (builder->state == SNAPBUILD_START ||
+ (builder->state == SNAPBUILD_BUILDING_SNAPSHOT &&
+ TransactionIdPrecedes(xid, SnapBuildNextPhaseAt(builder))))
+ {
+ /* ensure that only commits after this are getting replayed */
+ if (builder->start_decoding_at <= lsn)
+ builder->start_decoding_at = lsn + 1;
+ return;
+ }
+
if (builder->state < SNAPBUILD_CONSISTENT)
{
/* ensure that only commits after this are getting replayed */
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.
+ * If building an exportable snapshot, force xid to be tracked, even
+ * if the transaction didn't modify the catalog.
*/
- 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)
+ {
+ needs_timetravel = true;
+ }
}
for (nxact = 0; nxact < nsubxacts; nxact++)
TransactionId subxid = subxacts[nxact];
/*
- * If we're forcing timetravel we also need visibility information
- * about subtransaction, so keep track of subtransaction's state.
+ * Add subtransaction to base snapshot if catalog modifying, we don't
+ * distinguish to toplevel transactions there.
*/
- if (forced_timetravel)
+ if (ReorderBufferXidHasCatalogChanges(builder->reorder, subxid))
{
+ sub_needs_timetravel = true;
+ needs_snapshot = true;
+
+ elog(DEBUG1, "found subtransaction %u:%u with catalog changes",
+ xid, subxid);
+
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.
+ * If we're forcing timetravel we also need visibility information
+ * about subtransaction, so keep track of subtransaction's state, even
+ * if not catalog modifying. Don't need to distribute a snapshot in
+ * that case.
*/
- else if (ReorderBufferXidHasCatalogChanges(builder->reorder, subxid))
+ else if (needs_timetravel)
{
- sub_needs_timetravel = true;
-
- elog(DEBUG1, "found subtransaction %u:%u with catalog changes.",
- xid, subxid);
-
SnapBuildAddCommittedTxn(builder, subxid);
-
if (NormalTransactionIdFollows(subxid, xmax))
xmax = subxid;
}
}
- if (forced_timetravel)
+ /* if top-level modified catalog, it'll need a snapshot */
+ if (ReorderBufferXidHasCatalogChanges(builder->reorder, xid))
{
- elog(DEBUG2, "forced transaction %u to do timetravel.", xid);
-
+ elog(DEBUG2, "found top level transaction %u, with catalog changes",
+ xid);
+ needs_snapshot = true;
+ needs_timetravel = true;
SnapBuildAddCommittedTxn(builder, xid);
}
- /* add toplevel transaction to base snapshot */
- else if (ReorderBufferXidHasCatalogChanges(builder->reorder, xid))
+ else if (sub_needs_timetravel)
{
- elog(DEBUG2, "found top level transaction %u, with catalog changes!",
- xid);
-
- top_needs_timetravel = true;
+ /* track toplevel txn as well, subxact alone isn't meaningful */
SnapBuildAddCommittedTxn(builder, xid);
}
- else if (sub_needs_timetravel)
+ else if (needs_timetravel)
{
- /* mark toplevel txn as timetravel as well */
+ elog(DEBUG2, "forced transaction %u to do timetravel", xid);
+
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 (!needs_timetravel)
{
- /*
- * Adjust xmax of the snapshot builder, we only do that for committed,
- * catalog modifying, transactions, everything else isn't interesting
- * for us since we'll never look at the respective rows.
- */
- if (!TransactionIdIsValid(builder->xmax) ||
- TransactionIdFollowsOrEquals(xmax, builder->xmax))
- {
- builder->xmax = xmax;
- TransactionIdAdvance(builder->xmax);
- }
+ /* record that we cannot export a general snapshot anymore */
+ builder->committed.includes_all_transactions = false;
+ }
+
+ Assert(!needs_snapshot || needs_timetravel);
+ /*
+ * Adjust xmax of the snapshot builder, we only do that for committed,
+ * catalog modifying, transactions, everything else isn't interesting
+ * for us since we'll never look at the respective rows.
+ */
+ if (needs_timetravel &&
+ (!TransactionIdIsValid(builder->xmax) ||
+ TransactionIdFollowsOrEquals(xmax, builder->xmax)))
+ {
+ builder->xmax = xmax;
+ TransactionIdAdvance(builder->xmax);
+ }
+
+ /* if there's any reason to build a historic snapshot, do so now */
+ if (needs_snapshot)
+ {
/*
* If we haven't built a complete snapshot yet there's no need to hand
* it out, it wouldn't (and couldn't) be used anyway.
/* add a new Snapshot to all currently running transactions */
SnapBuildDistributeNewCatalogSnapshot(builder, lsn);
}
- else
- {
- /* record that we cannot export a general snapshot anymore */
- builder->committed.includes_all_transactions = false;
- }
}