예제 #1
0
        public async Task <bool> MoveNext(CancellationToken cancellationToken)
        {
            // Try to walk to the next row for the current response being processed.
            while (_singleResponseRowEnumerator?.MoveNext() != true)
            {
                // If not possible, dispose the old enumerator and create a new one from the
                // next response, if any.
                _singleResponseRowEnumerator?.Dispose();
                if (await _stream.ResponseStream.MoveNext(cancellationToken).ConfigureAwait(false))
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    _singleResponseRowEnumerator = MergeResponseChunks(_stream.ResponseStream.Current);
                }
                else
                {
                    _singleResponseRowEnumerator = null;
                    break;
                }
            }

            // If the current response's enumerator has produced a row, this enumerator should produce
            // that same row.
            if (_singleResponseRowEnumerator != null)
            {
                cancellationToken.ThrowIfCancellationRequested();
                Current = _singleResponseRowEnumerator.Current;
                return(true);
            }

            if (IsRowInProgress &&
                _stream.GrpcCall.GetStatus().StatusCode != StatusCode.Cancelled)
            {
                // TODO: Is there something we could/should do here? Stream prematurely closed
                //       with a row in progress
            }

            return(false);

            IEnumerator <Row> MergeResponseChunks(ReadRowsResponse response)
            {
                foreach (var chunk in response.Chunks)
                {
                    if (chunk.ResetRow)
                    {
                        Reset();
                        continue;
                    }

                    _rowMergeState = _rowMergeState.HandleChunk(this, chunk);

                    if (chunk.CommitRow)
                    {
                        _rowMergeState = _rowMergeState.CommitRow(this);

                        // TODO: Capture response.LastScannedRowKey here for smart retries
                        yield return(_currentCell.Row);
                    }
                }
            }
        }
        public async Task <bool> MoveNext(CancellationToken cancellationToken)
        {
            if (_stream == null)
            {
                await EstablishStream(_requestManager.OriginalRequest).ConfigureAwait(false);
            }

            // Try to walk to the next row for the current response being processed.
            while (_singleResponseRowEnumerator?.MoveNext() != true)
            {
                try
                {
                    // If not possible, dispose the old enumerator and create a new one from the
                    // next response, if any.
                    _singleResponseRowEnumerator?.Dispose();
                    _singleResponseRowEnumerator = null;

                    if (await _stream.ResponseStream.MoveNext(cancellationToken).ConfigureAwait(false))
                    {
                        cancellationToken.ThrowIfCancellationRequested();
                        _singleResponseRowEnumerator = MergeResponseChunks(_stream.ResponseStream.Current);
                    }
                    else
                    {
                        break;
                    }
                }
                catch (RpcException e) when(_retrySettings.RetryFilter(e))
                {
                    var retryRequest = _requestManager.BuildUpdatedRequest();

                    if (retryRequest == null)
                    {
                        break;
                    }

                    // Reset the merging and re-connect to a new stream.
                    Reset();
                    await EstablishStream(retryRequest).ConfigureAwait(false);
                }
            }

            // If the current response's enumerator has produced a row, this enumerator should produce
            // that same row.
            if (_singleResponseRowEnumerator != null)
            {
                cancellationToken.ThrowIfCancellationRequested();
                Current = _singleResponseRowEnumerator.Current;
                return(true);
            }

            if (IsRowInProgress &&
                _stream.GrpcCall?.GetStatus().StatusCode != StatusCode.Cancelled)
            {
                throw new InvalidOperationException("The ReadRows stream has ended with a row in progress.");
            }

            return(false);

            Task EstablishStream(ReadRowsRequest request) =>
            ApiCallRetryExtensions.RetryOperationUntilCompleted(
                () =>
            {
                _stream = _client.ReadRowsInternal(request, _callSettings);
                return(Task.FromResult(true));
            },
                _client.Clock,
                _client.Scheduler,
                _callSettings,
                _retrySettings);

            IEnumerator <Row> MergeResponseChunks(ReadRowsResponse response)
            {
                ByteString previouslyProcessedKey = _lastCompletedRowKey;

                foreach (var chunk in response.Chunks)
                {
                    _rowMergeState = _rowMergeState.HandleChunk(this, chunk);

                    if (chunk.CommitRow)
                    {
                        _rowMergeState       = _rowMergeState.CommitRow(this);
                        _lastCompletedRowKey = _currentCell.Row.Key;
                        _requestManager.IncrementRowsReadSoFar();
                        yield return(_currentCell.Row);
                    }
                }

                if (previouslyProcessedKey != _lastCompletedRowKey)
                {
                    // There was a full row found in the response.
                    TryUpdateLastFoundKey(_lastCompletedRowKey);
                }
                else
                {
                    // Otherwise, the service may have indicated that it processed rows that did not match the filter,
                    // and will not need to be reprocessed.
                    TryUpdateLastFoundKey(response.LastScannedRowKey);
                }

                void TryUpdateLastFoundKey(ByteString lastProcessedKey)
                {
                    if (lastProcessedKey != null && !lastProcessedKey.IsEmpty)
                    {
                        _requestManager.LastFoundKey = lastProcessedKey;
                    }
                }
            }
        }
        public async Task <bool> MoveNext(CancellationToken cancellationToken)
        {
            // Try to walk to the next row for the current response being processed.
            while (_singleResponseRowEnumerator?.MoveNext() != true)
            {
                // If not possible, dispose the old enumerator and create a new one from the
                // next response, if any.
                _singleResponseRowEnumerator?.Dispose();
                if (await _stream.ResponseStream.MoveNext(cancellationToken).ConfigureAwait(false))
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    _singleResponseRowEnumerator = MergeResponseChunks(_stream.ResponseStream.Current);
                }
                else
                {
                    _singleResponseRowEnumerator = null;
                    break;
                }
            }

            // If the current response's enumerator has produced a row, this enumerator should produce
            // that same row.
            if (_singleResponseRowEnumerator != null)
            {
                cancellationToken.ThrowIfCancellationRequested();
                Current = _singleResponseRowEnumerator.Current;
                return(true);
            }

            if (IsRowInProgress &&
                _stream.GrpcCall?.GetStatus().StatusCode != StatusCode.Cancelled)
            {
                throw new InvalidOperationException("The ReadRows stream has ended with a row in progress.");
            }

            return(false);

            IEnumerator <Row> MergeResponseChunks(ReadRowsResponse response)
            {
                foreach (var chunk in response.Chunks)
                {
                    if (chunk.ResetRow)
                    {
                        Assert(
                            (chunk.RowKey == null || chunk.RowKey.IsEmpty) &&
                            chunk.FamilyName == null &&
                            chunk.Qualifier == null &&
                            (chunk.Value == null || chunk.Value.IsEmpty) &&
                            chunk.TimestampMicros == 0,
                            "A reset should have no data");
                        Assert(_rowMergeState != NewRow.Instance, "NewRow must have a rowKey");
                        Reset();
                        continue;
                    }

                    _rowMergeState = _rowMergeState.HandleChunk(this, chunk);

                    if (chunk.CommitRow)
                    {
                        _rowMergeState = _rowMergeState.CommitRow(this);

                        // TODO: Capture response.LastScannedRowKey here for smart retries
                        yield return(_currentCell.Row);
                    }
                }
            }
        }