Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions src/backend/distributed/transaction/backend_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -1214,7 +1214,7 @@ GetBackendDataForProc(PGPROC *proc, BackendData *result)
* data with this information.
*/
void
CancelTransactionDueToDeadlock(PGPROC *proc)
CancelTransactionDueToDeadlock(PGPROC *proc, DistributedTransactionId *transactionId)
{
BackendData *backendData = &backendManagementShmemData->backends[getProcNo_compat(
proc)];
Expand All @@ -1227,8 +1227,29 @@ CancelTransactionDueToDeadlock(PGPROC *proc)

SpinLockAcquire(&backendData->mutex);

/* send a SIGINT only if the process is still in a distributed transaction */
if (backendData->transactionId.transactionNumber != 0)
DistributedTransactionId *backendXactId = &backendData->transactionId;

/*
* Send a SIGINT only if the backend is still running the very distributed
* transaction that we found to be part of the deadlock. The caller walks the
* whole deadlock cycle to pick a victim after it looks the backend up, so the
* backend may have finished that transaction and started an unrelated one in
* between, and cancelling that one would be wrong.
*
* The initiator node has to be compared as well, because transaction numbers are
* only unique per node. A transaction initiated on another node can therefore
* share a number with a local one, and
* AssociateDistributedTransactionWithBackendProc() matches on the number alone.
*
* The timestamp is not compared, even though DistributedTransactionIdCompare()
* does consider it. That comparison sorts ids gathered from all nodes, whereas
* we only compare against a single live backend: its transaction numbers come
* from a monotonic counter, so a new transaction on it necessarily has a
* different number, and reusing one requires a restart, which invalidates
* this proc.
*/
if (backendXactId->transactionNumber == transactionId->transactionNumber &&
backendXactId->initiatorNodeIdentifier == transactionId->initiatorNodeIdentifier)
{
backendData->cancelledDueToDeadlock = true;
SpinLockRelease(&backendData->mutex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,8 @@ CheckForDistributedDeadlocks(void)
/* we found the deadlock and its associated proc exists */
if (youngestAliveTransaction)
{
CancelTransactionDueToDeadlock(youngestAliveTransaction->initiatorProc);
CancelTransactionDueToDeadlock(youngestAliveTransaction->initiatorProc,
&youngestAliveTransaction->transactionId);
LogCancellingBackend(youngestAliveTransaction);

hash_seq_term(&status);
Expand Down
3 changes: 2 additions & 1 deletion src/include/distributed/backend_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ extern uint64 ExtractGlobalPID(const char *applicationName);
extern int ExtractNodeIdFromGlobalPID(uint64 globalPID, bool missingOk);
extern int ExtractProcessIdFromGlobalPID(uint64 globalPID);
extern void GetBackendDataForProc(PGPROC *proc, BackendData *result);
extern void CancelTransactionDueToDeadlock(PGPROC *proc);
extern void CancelTransactionDueToDeadlock(PGPROC *proc,
DistributedTransactionId *transactionId);
extern bool MyBackendGotCancelledDueToDeadlock(bool clearState);
extern List * ActiveDistributedTransactionNumbers(void);
extern LocalTransactionId GetMyProcLocalTransactionId(void);
Expand Down
Loading