Example #1
0
        /// <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));
        }