aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/transam/transam.c
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2022-06-27 08:21:08 +0300
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2022-06-27 08:21:08 +0300
commitadf6d5dfb2094cc2bb28b4dea0565dcd0e775ed9 (patch)
tree7a31b3f182f36123e59e22c80aabe3901194fc3c /src/backend/access/transam/transam.c
parent7201cd18627afc64850537806da7f22150d1a83b (diff)
downloadpostgresql-adf6d5dfb2094cc2bb28b4dea0565dcd0e775ed9.tar.gz
postgresql-adf6d5dfb2094cc2bb28b4dea0565dcd0e775ed9.zip
Fix visibility check when XID is committed in CLOG but not in procarray.
TransactionIdIsInProgress had a fast path to return 'false' if the single-item CLOG cache said that the transaction was known to be committed. However, that was wrong, because a transaction is first marked as committed in the CLOG but doesn't become visible to others until it has removed its XID from the proc array. That could lead to an error: ERROR: t_xmin is uncommitted in tuple to be updated or for an UPDATE to go ahead without blocking, before the previous UPDATE on the same row was made visible. The window is usually very short, but synchronous replication makes it much wider, because the wait for synchronous replica happens in that window. Another thing that makes it hard to hit is that it's hard to get such a commit-in-progress transaction into the single item CLOG cache. Normally, if you call TransactionIdIsInProgress on such a transaction, it determines that the XID is in progress without checking the CLOG and without populating the cache. One way to prime the cache is to explicitly call pg_xact_status() on the XID. Another way is to use a lot of subtransactions, so that the subxid cache in the proc array is overflown, making TransactionIdIsInProgress rely on pg_subtrans and CLOG checks. This has been broken ever since it was introduced in 2008, but the race condition is very hard to hit, especially without synchronous replication. There were a couple of reports of the error starting from summer 2021, but no one was able to find the root cause then. TransactionIdIsKnownCompleted() is now unused. In 'master', remove it, but I left it in place in backbranches in case it's used by extensions. Also change pg_xact_status() to check TransactionIdIsInProgress(). Previously, it only checked the CLOG, and returned "committed" before the transaction was actually made visible to other queries. Note that this also means that you cannot use pg_xact_status() to reproduce the bug anymore, even if the code wasn't fixed. Report and analysis by Konstantin Knizhnik. Patch by Simon Riggs, with the pg_xact_status() change added by me. Author: Simon Riggs Reviewed-by: Andres Freund Discussion: https://www.postgresql.org/message-id/flat/4da7913d-398c-e2ad-d777-f752cf7f0bbb%40garret.ru
Diffstat (limited to 'src/backend/access/transam/transam.c')
-rw-r--r--src/backend/access/transam/transam.c27
1 files changed, 0 insertions, 27 deletions
diff --git a/src/backend/access/transam/transam.c b/src/backend/access/transam/transam.c
index dbc5f884e88..5865810135e 100644
--- a/src/backend/access/transam/transam.c
+++ b/src/backend/access/transam/transam.c
@@ -220,33 +220,6 @@ TransactionIdDidAbort(TransactionId transactionId)
}
/*
- * TransactionIdIsKnownCompleted
- * True iff transaction associated with the identifier is currently
- * known to have either committed or aborted.
- *
- * This does NOT look into pg_xact but merely probes our local cache
- * (and so it's not named TransactionIdDidComplete, which would be the
- * appropriate name for a function that worked that way). The intended
- * use is just to short-circuit TransactionIdIsInProgress calls when doing
- * repeated heapam_visibility.c checks for the same XID. If this isn't
- * extremely fast then it will be counterproductive.
- *
- * Note:
- * Assumes transaction identifier is valid.
- */
-bool
-TransactionIdIsKnownCompleted(TransactionId transactionId)
-{
- if (TransactionIdEquals(transactionId, cachedFetchXid))
- {
- /* If it's in the cache at all, it must be completed. */
- return true;
- }
-
- return false;
-}
-
-/*
* TransactionIdCommitTree
* Marks the given transaction and children as committed
*