/// <inheritdoc /> public MaybeResponse <ReadJournalResponse> ReadJournal(ReadJournalRequest request, Action <UsnRecord> onUsnRecordReceived) { Contract.Assert(request.VolumeGuidPath.IsValid); SafeFileHandle volumeHandle; OpenFileResult volumeOpenResult = OpenVolumeHandle(request.VolumeGuidPath, out volumeHandle); using (volumeHandle) { if (!volumeOpenResult.Succeeded) { string message = I($"Failed to open a volume handle for the volume '{request.VolumeGuidPath.Path}'"); return(new MaybeResponse <ReadJournalResponse>( new ErrorResponse(ErrorStatus.FailedToOpenVolumeHandle, message))); } Usn startUsn = request.StartUsn; Usn endUsn = request.EndUsn ?? Usn.Zero; int extraReadCount = request.ExtraReadCount ?? -1; long timeLimitInTicks = request.TimeLimit?.Ticks ?? -1; var sw = new StopwatchVar(); using (var swRun = sw.Start()) { byte[] buffer = new byte[JournalReadBufferSize]; while (true) { if (timeLimitInTicks >= 0 && timeLimitInTicks < swRun.ElapsedTicks) { return(new MaybeResponse <ReadJournalResponse>( new ReadJournalResponse(status: ReadUsnJournalStatus.Success, nextUsn: startUsn, timeout: true))); } ReadUsnJournalResult result = FileUtilities.TryReadUsnJournal( volumeHandle, buffer, request.JournalId, startUsn, isJournalUnprivileged: IsJournalUnprivileged); if (!result.Succeeded) { // Bug #1164760 shows that the next USN can be non-zero. return(new MaybeResponse <ReadJournalResponse>(new ReadJournalResponse(status: result.Status, nextUsn: result.NextUsn))); } if (result.Records.Count == 0) { return (new MaybeResponse <ReadJournalResponse>( new ReadJournalResponse(status: ReadUsnJournalStatus.Success, nextUsn: result.NextUsn))); } foreach (var record in result.Records) { onUsnRecordReceived(record); } Contract.Assume(startUsn < result.NextUsn); startUsn = result.NextUsn; if (!endUsn.IsZero) { if (startUsn >= endUsn && (--extraReadCount) < 0) { return(new MaybeResponse <ReadJournalResponse>( new ReadJournalResponse(status: ReadUsnJournalStatus.Success, nextUsn: result.NextUsn))); } } } } } }
public async Task <RpcCallResult <Unit> > CallAsync( Func <CallOptions, AsyncUnaryCall <RpcResponse> > func, string operationName, CancellationToken cancellationToken = default(CancellationToken), bool waitForConnection = false) { TimeSpan waitForConnectionDuration = TimeSpan.Zero; if (waitForConnection) { var waitForConnectionSw = new StopwatchVar(); using (waitForConnectionSw.Start()) { try { Logger.Log.DistributionTrace(m_loggingContext, $"Attempt to connect to '{Channel.Target}' for operation {operationName}. ChannelState '{Channel.State}'"); await Channel.ConnectAsync(DateTime.UtcNow.Add(InactiveTimeout)); Logger.Log.DistributionTrace(m_loggingContext, $"Connected to '{Channel.Target}' for operation {operationName}. Duration {waitForConnectionSw.TotalElapsed.TotalMilliseconds}ms."); } catch (OperationCanceledException e) { var duration = waitForConnectionSw.TotalElapsed; Logger.Log.DistributionTrace(m_loggingContext, $"Failed to connect to '{Channel.Target}' for operation {operationName}. Duration {duration.TotalMilliseconds}ms. Failure {e.Message}"); return(new RpcCallResult <Unit>(RpcCallResultState.Cancelled, attempts: 1, duration: TimeSpan.Zero, waitForConnectionDuration: duration)); } } waitForConnectionDuration = waitForConnectionSw.TotalElapsed; } var callDurationSw = new StopwatchVar(); using (callDurationSw.Start()) { try { var callOptions = new CallOptions( deadline: DateTime.UtcNow.Add(CallTimeout), cancellationToken: cancellationToken); Logger.Log.DistributionTrace(m_loggingContext, $"Attempt to call '{Channel.Target}' for operation {operationName}. ChannelState '{Channel.State}'"); await func(callOptions); Logger.Log.DistributionTrace(m_loggingContext, $"Called '{Channel.Target}' for operation {operationName}. Duration {callDurationSw.TotalElapsed.TotalMilliseconds}ms."); } catch (RpcException e) { RpcCallResultState state = e.Status.StatusCode == StatusCode.Cancelled ? RpcCallResultState.Cancelled : RpcCallResultState.Failed; Logger.Log.DistributionTrace(m_loggingContext, $"Failed to call '{Channel.Target}' for operation {operationName}. Duration {callDurationSw.TotalElapsed.TotalMilliseconds}ms. Failure {e.Message}"); return(new RpcCallResult <Unit>( state, attempts: 1, duration: callDurationSw.TotalElapsed, waitForConnectionDuration: waitForConnectionDuration, lastFailure: state == RpcCallResultState.Failed ? new RecoverableExceptionFailure(new BuildXLException(e.Message, e)) : null)); } } return(new RpcCallResult <Unit>(Unit.Void, attempts: 1, duration: callDurationSw.TotalElapsed, waitForConnectionDuration: waitForConnectionDuration)); }