/// <summary> /// Calls the provided requests completion handler and waits for it to complete. /// </summary> /// <param name="request">The reqest.</param> /// <returns>A <see cref="Task"/> representing the work performed.</returns> private async Task CompleteOrderedReplication(ReplicationRequest request) { if (this.closing) { this.logger.Log(nameof(OperationReplicator <TOperation>) + nameof(this.CompleteOrderedReplication)); } try { var logSequenceNumber = await request.ReplicationCompleted.Task.ConfigureAwait(false); // Create a record to append. var version = new RecordVersion(this.stateProvider.CurrentEpoch, logSequenceNumber); var record = new OperationCommittedRecord <TOperation>(request.Operation, version); // Write the record. await this.stateProvider.AppendOperation(this.serializer.Serialize <Record>(record), logSequenceNumber).ConfigureAwait(false); } catch (Exception exception) { // If the error was caused by the state provider, propagate that exception. if (request.ReplicationCompleted.Task.Status == TaskStatus.RanToCompletion) { await request.CompletionHandler(Task.FromException <long>(exception)).ConfigureAwait(false); return; } } // Wait for the caller's completion handler to complete before continuing to // process other replication completion handlers. await request.CompletionHandler(request.ReplicationCompleted.Task).Suppressed().ConfigureAwait(false); }
public override Task <Empty> Replicate(ReplicationRequest request, ServerCallContext context) { if (request.Offset >= _storage.LatestOffset) { _storage.Add(request.Offset, request.Message.ToByteArray()); } return(Task.FromResult(new Empty())); }
/// <summary> /// Starts replication of the provided <paramref name="request"/>, ensuring that its completion handler will /// be invoked in the order of replication. /// </summary> /// <param name="request">The request.</param> /// <returns>A <see cref="Task"/> representing the work performed.</returns> private Task InitiateOrderedReplication(ReplicationRequest request) { if (this.closing) { this.logger.Log(nameof(OperationReplicator <TOperation>) + nameof(this.InitiateOrderedReplication)); } try { // If the request has already been cancelled, return without initiating replication. if (request.Cancellation.IsCancellationRequested) { request.Cancel(); return(Task.FromResult(0)); } // To ensure that replication completion handlers are invoked in the order they were // replicated in, post them to the completion worker from this replication worker. this.completionWorker.Post(request); // Start replicating the operation. Do not wait for replication to complete, but instead // propagate the result to the completion task so that the completion worker can handle // it in its due turn. long sequenceNumber; this.replicator.ReplicateAsync(request.OperationData, request.Cancellation, out sequenceNumber) .PropagateToCompletion(request.ReplicationCompleted); if (this.closing) { this.logger.Log("Completed " + nameof(OperationReplicator <TOperation>) + nameof(this.InitiateOrderedReplication)); } return(Task.FromResult(0)); } catch (Exception exception) { // Replication failed, notify the requester. request.ReplicationCompleted.TrySetException(exception); throw; } }