0

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?

Sean Feldman
  • 23,443
  • 7
  • 55
  • 80

1 Answers1

2

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

Diego Mendes
  • 10,631
  • 2
  • 32
  • 36
  • Thank you Diego. My question is about performance implications when collections are not modified, yet transaction is committed. – Sean Feldman May 12 '18 at 03:59
  • I've updated the answer with a bit extra info, beyond that is out of my knowledge, I've added a link to the replicator source code, I think you will find the rest of the answer there, or maybe wait for someone from SF team with a better answer. – Diego Mendes May 13 '18 at 12:26
  • 1
    _"I wouldn't be too worried committing an empty transaction."_. I've up-voted for now, as I think you've provided good info and tend to agree that there shoulnd't be any major performance impact. Will see if anything from the SF team will answer and mark appropreately. Thank you again. – Sean Feldman May 13 '18 at 19:21
  • 4
    Confirm the general sentiment: there's no overhead or problem with calling Commit when there's no changes. SF guidance would be to always explicitly call Commit or Abort, even if there's no changes. – masnider May 14 '18 at 20:43