You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@ignite.apache.org by " Kirill Sizov (Jira)" <ji...@apache.org> on 2023/10/16 07:37:00 UTC

[jira] [Assigned] (IGNITE-20560) It's possible to execute commands on a finished transaction under certain circumstances

     [ https://issues.apache.org/jira/browse/IGNITE-20560?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

 Kirill Sizov reassigned IGNITE-20560:
--------------------------------------

    Assignee:  Kirill Sizov

> It's possible to execute commands on a finished transaction under certain circumstances
> ---------------------------------------------------------------------------------------
>
>                 Key: IGNITE-20560
>                 URL: https://issues.apache.org/jira/browse/IGNITE-20560
>             Project: Ignite
>          Issue Type: Task
>            Reporter:  Kirill Sizov
>            Assignee:  Kirill Sizov
>            Priority: Major
>              Labels: ignite-3
>          Time Spent: 10m
>  Remaining Estimate: 0h
>
> If a cleanup operation crashes, it does not affect the transaction it was for called since the transaction has been finished already.
> However under certain circumstances we may *get the validation that prevents commands from being executed on a finished transaction broken.*
> The issue is that we have {{PartitionReplicaListener.TxCleanupReadyFutureList.state}} that duplicates local txState, and is updated in the cleanup command handler.
> *Details*
> {{PartitionReplicaListener.TxCleanupReadyFutureList.state}} is
>  * +updated+ in {{PartitionReplicaListener.processTxCleanupAction}} and
>  * +read+ in {{{}PartitionReplicaListener.appendTxCommand{}}}.
> If the update has not been called because of a crash, the code in {{{}appendTxCommand{}}}:
> {code:java}
>    txCleanupReadyFutures.compute(txId, (id, txOps) -> {
>                 if (txOps == null) {
>                     txOps = new TxCleanupReadyFutureList();
>                 }
>                 if (isFinalState(txOps.state)) {
>                     fut.completeExceptionally(
>                             new TransactionException(TX_FAILED_READ_WRITE_OPERATION_ERR, "Transaction is already finished."));
>                 } else {
>                     txOps.futures.computeIfAbsent(cmdType, type -> new ArrayList<>()).add(fut);
>                 }
>                 return txOps;
>             });{code}
> will still read {{txOps.state}} as {{PENDING}} and will allow to execute this command instead of throwing a {{{}TransactionException{}}}.
> *Motivation*
>  The identified issue is that we save a transaction state in two places in a primary replica:
> * in txCleanupReadyFutures with cleanup futures,
> * in TxManager#txStateMap where we cached it in the tx state local map.
> *Definition of done*
> # We should remove the transaction state from TxCleanupReadyFutureList and use the state that is stored in TxManager and available through TxManagerImpl#stateMeta(txId)
> # To resolve tests where we are suppressing TxCleanupReplicaReques (ItTxDistributedTestSingleNodeNoCleanupMessage#testTransactionAlreadyRolledback, #testTransactionAlreadyCommitted) we have to check the transaction state map on the transaction coordinator before trying to enlist a new operation in the transaction. Despite the fact that the tests are not completely honest, we will avoid executing an operation after a commit timestamp is already chosen.
> # The tests from point 2 should be rewritten because we do not assume to just drop TxCleanupReplicaRequest (the handling of TxCleanupReplicaRequest is customized so as to skip it) and complete the commit invocation.
> *_Please note there are tests muted with this task._*



--
This message was sent by Atlassian Jira
(v8.20.10#820010)