Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit bd619fc

Browse files
committed
Avoid superfluous work for commits during logical slot creation.
Before 955a684 logical decoding snapshot maintenance needed to cope with transactions it might not have seen in their entirety. For such transactions we'd to assume they modified the catalog (could have happened before we were watching), and thus a new snapshot had to be built, and distributed to concurrently running transactions. That's problematic because building a new snapshot isn't that cheap , especially as the the array of committed transactions needs to be sorted. When creating a slot on a server with a lot of transactions, this could make logical slot creation infeasibly expensive. After 955a684 there's no need to deal with transaction that aren't guaranteed to be fully observable. That allows to avoid building snapshots for transactions that haven't modified catalog, even before reaching consistency. While this isn't necessarily a bugfix, slot creation being impossible in some production workloads, is severe enough to warrant backpatching. Author: Andres Freund, based on a quite different patch from Petr Jelinek Analyzed-By: Petr Jelinek Reviewed-By: Petr Jelinek Discussion: https://postgr.es/m/f37e975c-908f-858e-707f-058d3b1eb214@2ndquadrant.com Backpatch: 9.4-, where logical decoding has been introduced
1 parent 7578485 commit bd619fc

File tree

1 file changed

+68
-56
lines changed

1 file changed

+68
-56
lines changed

src/backend/replication/logical/snapbuild.c

Lines changed: 68 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -911,105 +911,122 @@ SnapBuildCommitTxn(SnapBuild *builder, XLogRecPtr lsn, TransactionId xid,
911911
{
912912
int nxact;
913913

914-
bool forced_timetravel = false;
914+
bool needs_snapshot = false;
915+
bool needs_timetravel = false;
915916
bool sub_needs_timetravel = false;
916-
bool top_needs_timetravel = false;
917917

918918
TransactionId xmax = xid;
919919

920920
/*
921-
* If we couldn't observe every change of a transaction because it was
922-
* already running at the point we started to observe we have to assume it
923-
* made catalog changes.
924-
*
925-
* This has the positive benefit that we afterwards have enough
926-
* information to build an exportable snapshot that's usable by pg_dump et
927-
* al.
921+
* Transactions preceding BUILDING_SNAPSHOT will neither be decoded, nor
922+
* will they be part of a snapshot. So we don't need to record anything.
928923
*/
924+
if (builder->state == SNAPBUILD_START ||
925+
(builder->state == SNAPBUILD_BUILDING_SNAPSHOT &&
926+
TransactionIdPrecedes(xid, SnapBuildNextPhaseAt(builder))))
927+
{
928+
/* ensure that only commits after this are getting replayed */
929+
if (builder->start_decoding_at <= lsn)
930+
builder->start_decoding_at = lsn + 1;
931+
return;
932+
}
933+
929934
if (builder->state < SNAPBUILD_CONSISTENT)
930935
{
931936
/* ensure that only commits after this are getting replayed */
932937
if (builder->start_decoding_at <= lsn)
933938
builder->start_decoding_at = lsn + 1;
934939

935940
/*
936-
* We could avoid treating !SnapBuildTxnIsRunning transactions as
937-
* timetravel ones, but we want to be able to export a snapshot when
938-
* we reached consistency.
941+
* If building an exportable snapshot, force xid to be tracked, even
942+
* if the transaction didn't modify the catalog.
939943
*/
940-
forced_timetravel = true;
941-
elog(DEBUG1, "forced to assume catalog changes for xid %u because it was running too early", xid);
944+
if (builder->building_full_snapshot)
945+
{
946+
needs_timetravel = true;
947+
}
942948
}
943949

944950
for (nxact = 0; nxact < nsubxacts; nxact++)
945951
{
946952
TransactionId subxid = subxacts[nxact];
947953

948954
/*
949-
* If we're forcing timetravel we also need visibility information
950-
* about subtransaction, so keep track of subtransaction's state.
955+
* Add subtransaction to base snapshot if catalog modifying, we don't
956+
* distinguish to toplevel transactions there.
951957
*/
952-
if (forced_timetravel)
958+
if (ReorderBufferXidHasCatalogChanges(builder->reorder, subxid))
953959
{
960+
sub_needs_timetravel = true;
961+
needs_snapshot = true;
962+
963+
elog(DEBUG1, "found subtransaction %u:%u with catalog changes",
964+
xid, subxid);
965+
954966
SnapBuildAddCommittedTxn(builder, subxid);
967+
955968
if (NormalTransactionIdFollows(subxid, xmax))
956969
xmax = subxid;
957970
}
958-
959971
/*
960-
* Add subtransaction to base snapshot if it DDL, we don't distinguish
961-
* to toplevel transactions there.
972+
* If we're forcing timetravel we also need visibility information
973+
* about subtransaction, so keep track of subtransaction's state, even
974+
* if not catalog modifying. Don't need to distribute a snapshot in
975+
* that case.
962976
*/
963-
else if (ReorderBufferXidHasCatalogChanges(builder->reorder, subxid))
977+
else if (needs_timetravel)
964978
{
965-
sub_needs_timetravel = true;
966-
967-
elog(DEBUG1, "found subtransaction %u:%u with catalog changes.",
968-
xid, subxid);
969-
970979
SnapBuildAddCommittedTxn(builder, subxid);
971-
972980
if (NormalTransactionIdFollows(subxid, xmax))
973981
xmax = subxid;
974982
}
975983
}
976984

977-
if (forced_timetravel)
985+
/* if top-level modified catalog, it'll need a snapshot */
986+
if (ReorderBufferXidHasCatalogChanges(builder->reorder, xid))
978987
{
979-
elog(DEBUG2, "forced transaction %u to do timetravel.", xid);
980-
988+
elog(DEBUG2, "found top level transaction %u, with catalog changes",
989+
xid);
990+
needs_snapshot = true;
991+
needs_timetravel = true;
981992
SnapBuildAddCommittedTxn(builder, xid);
982993
}
983-
/* add toplevel transaction to base snapshot */
984-
else if (ReorderBufferXidHasCatalogChanges(builder->reorder, xid))
994+
else if (sub_needs_timetravel)
985995
{
986-
elog(DEBUG2, "found top level transaction %u, with catalog changes!",
987-
xid);
988-
989-
top_needs_timetravel = true;
996+
/* track toplevel txn as well, subxact alone isn't meaningful */
990997
SnapBuildAddCommittedTxn(builder, xid);
991998
}
992-
else if (sub_needs_timetravel)
999+
else if (needs_timetravel)
9931000
{
994-
/* mark toplevel txn as timetravel as well */
1001+
elog(DEBUG2, "forced transaction %u to do timetravel", xid);
1002+
9951003
SnapBuildAddCommittedTxn(builder, xid);
9961004
}
9971005

998-
/* if there's any reason to build a historic snapshot, do so now */
999-
if (forced_timetravel || top_needs_timetravel || sub_needs_timetravel)
1006+
if (!needs_timetravel)
10001007
{
1001-
/*
1002-
* Adjust xmax of the snapshot builder, we only do that for committed,
1003-
* catalog modifying, transactions, everything else isn't interesting
1004-
* for us since we'll never look at the respective rows.
1005-
*/
1006-
if (!TransactionIdIsValid(builder->xmax) ||
1007-
TransactionIdFollowsOrEquals(xmax, builder->xmax))
1008-
{
1009-
builder->xmax = xmax;
1010-
TransactionIdAdvance(builder->xmax);
1011-
}
1008+
/* record that we cannot export a general snapshot anymore */
1009+
builder->committed.includes_all_transactions = false;
1010+
}
1011+
1012+
Assert(!needs_snapshot || needs_timetravel);
10121013

1014+
/*
1015+
* Adjust xmax of the snapshot builder, we only do that for committed,
1016+
* catalog modifying, transactions, everything else isn't interesting
1017+
* for us since we'll never look at the respective rows.
1018+
*/
1019+
if (needs_timetravel &&
1020+
(!TransactionIdIsValid(builder->xmax) ||
1021+
TransactionIdFollowsOrEquals(xmax, builder->xmax)))
1022+
{
1023+
builder->xmax = xmax;
1024+
TransactionIdAdvance(builder->xmax);
1025+
}
1026+
1027+
/* if there's any reason to build a historic snapshot, do so now */
1028+
if (needs_snapshot)
1029+
{
10131030
/*
10141031
* If we haven't built a complete snapshot yet there's no need to hand
10151032
* it out, it wouldn't (and couldn't) be used anyway.
@@ -1041,11 +1058,6 @@ SnapBuildCommitTxn(SnapBuild *builder, XLogRecPtr lsn, TransactionId xid,
10411058
/* add a new Snapshot to all currently running transactions */
10421059
SnapBuildDistributeNewCatalogSnapshot(builder, lsn);
10431060
}
1044-
else
1045-
{
1046-
/* record that we cannot export a general snapshot anymore */
1047-
builder->committed.includes_all_transactions = false;
1048-
}
10491061
}
10501062

10511063

0 commit comments

Comments
 (0)