public async Task CommitUpdateAsync()

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();
            }
        }