Search code examples
azure-service-fabric

Downsides of CommitAsync() w/o any changes to collection


All the samples usually demonstrate some sort of change to reliable collections with CommitAsync() or rollback in case of a failure. My code is using TryRemoveAsync(), so failure is not a concern (will be retried later).

Is there a significant downside to invoking tx.CommitAsync() when no changes to reliable collections where performed?


Solution

  • Whenever you open a Transaction and execute commands against a collection, these commands acquire locks in the TStore(Collection) and are recorded to the transaction temporary dictionary(Change tracking) and also to the transaction logs, the replicator then will forward these changes to the replicas.

    Once you execute the tx.CommitAsync() the temporary records are saved to the disk, the transaction is registered in the logs and then replicated to secondary replicas to also commit and save to the disk, and then the locks are released.

    If the collection is not modified, the transaction won't have anything to save\replicate and will just close the transaction.

    If you don't call tx.CommitAsync() after the operation, the transaction is aborted and any pending operations(if any) are discarded and the abort operation is written to the logs to notify other replicas.

    In both cases, Commit and Abort, will generate logs(and replicate them), The only detail I am not sure is if these logs are also generated when no changes are in place, I assume they are. Regarding performance, the act of reading or attempting to change a collection, will acquire locks and need to be released with a commit or abort, I think these are to biggest impact on your code, because they will prevent other threads of modifying it while you not complete the transaction. In this case I wouldn't be too worried committing an empty transaction.

       // Create a new Transaction object for this partition
       using (ITransaction tx = base.StateManager.CreateTransaction()) {
          //modify the collection
          await m_dic.AddAsync(tx, key, value, cancellationToken);
    
          // CommitAsync sends Commit record to log & secondary replicas
          // After quorum responds, all locks released
          await tx.CommitAsync();
       } // If CommitAsync not called, this line will Dispose the transaction and discard the changes
    

    You can find most of these details on this documentation

    If you really want to go deep on implementation details to answer this question, I suggest you dig the answer in the source code for the replicator here