in src/Microsoft.ServiceFabric.Actors/Runtime/VolatileActorStateTable.cs [116:189]
public async Task CommitUpdateAsync(long sequenceNumber, Exception ex = null)
{
// Invalid LSN
if (sequenceNumber == 0)
{
if (ex != null)
{
throw ex;
}
throw new FabricException(FabricErrorCode.SequenceNumberCheckFailed);
}
// This list is used to store the replication contexts that have been commited
// and are then marked as complete outside the read/write lock. Marking as complete
// outside the lock is important because when the replication context is marked as
// complete by calling TaskCompletionSource.SetResult(), the task associated with
// TaskCompletionSource, immediately starts executing synchronously in the same thread
// (while the lock still being held) which then tries to again acquire read/write lock
// causing System.Threading.LockRecursionException.
//
// In .Net 4.6, TaskCompletionSource.SetResult() accepts an additional argument which
// makes the task associated with TaskCompletionSource execute asynchronously on a different
// thread. Till we move to .Net 4.6, we will adopt the above approach.
var committedReplicationContexts = new List<ReplicationContext>();
ReplicationContext replicationContext = null;
using (this.rwLock.AcquireWriteLock())
{
replicationContext = this.pendingReplicationContexts[sequenceNumber];
replicationContext.SetReplicationComplete(ex);
if (sequenceNumber == this.uncommittedEntriesList.First.Value.ActorStateDataWrapper.SequenceNumber)
{
while (
this.uncommittedEntriesList.Count > 0 &&
this.uncommittedEntriesList.First.Value.IsReplicationComplete)
{
var listNode = this.uncommittedEntriesList.First;
this.uncommittedEntriesList.RemoveFirst();
if (!listNode.Value.IsFailed)
{
this.ApplyUpdate_UnderWriteLock(listNode);
}
listNode.Value.CompleteReplication();
var seqNum = listNode.Value.ActorStateDataWrapper.SequenceNumber;
if (this.pendingReplicationContexts[seqNum].IsAllEntriesComplete)
{
committedReplicationContexts.Add(this.pendingReplicationContexts[seqNum]);
this.pendingReplicationContexts.Remove(seqNum);
}
}
replicationContext = null;
}
}
// Mark the committed replication contexts as complete in order of increasing LSN
foreach (var repCtx in committedReplicationContexts)
{
repCtx.MarkAsCompleted();
}
if (replicationContext != null)
{
await replicationContext.WaitForCompletionAsync();
}
}