public ChangeFeedNotModifiedPage(
     double requestCharge,
     string activityId,
     IReadOnlyDictionary <string, string> additionalHeaders,
     ChangeFeedState state)
     : base(requestCharge, activityId, additionalHeaders, state)
 {
 }
Beispiel #2
0
        public static CosmosElement ToCosmosElement(ChangeFeedState changeFeedState)
        {
            if (changeFeedState == null)
            {
                throw new ArgumentNullException(nameof(changeFeedState));
            }

            return(changeFeedState.Accept(ChangeFeedToCosmosElementVisitor.Singleton));
        }
Beispiel #3
0
 public ChangeFeedSuccessPage(
     Stream content,
     double requestCharge,
     string activityId,
     ChangeFeedState state)
     : base(requestCharge, activityId, state)
 {
     this.Content = content ?? throw new ArgumentNullException(nameof(content));
 }
 public ChangeFeedSuccessPage(
     Stream content,
     double requestCharge,
     string activityId,
     IReadOnlyDictionary <string, string> additionalHeaders,
     ChangeFeedState state)
     : base(requestCharge, activityId, additionalHeaders, state)
 {
     this.Content = content ?? throw new ArgumentNullException(nameof(content));
 }
Beispiel #5
0
        public async ValueTask <bool> MoveNextAsync()
        {
            this.cancellationToken.ThrowIfCancellationRequested();
            if (this.bufferedException.HasValue)
            {
                this.Current           = this.bufferedException.Value;
                this.bufferedException = null;
                return(true);
            }

            if (!await this.crossPartitionEnumerator.MoveNextAsync())
            {
                throw new InvalidOperationException("ChangeFeed should always have a next page.");
            }

            TryCatch <CrossPartitionPage <ChangeFeedPage, ChangeFeedState> > monadicCrossPartitionPage = this.crossPartitionEnumerator.Current;

            if (monadicCrossPartitionPage.Failed)
            {
                this.Current = TryCatch <ChangeFeedPage> .FromException(monadicCrossPartitionPage.Exception);

                return(true);
            }

            CrossPartitionPage <ChangeFeedPage, ChangeFeedState> crossPartitionPage = monadicCrossPartitionPage.Result;
            ChangeFeedPage backendPage = crossPartitionPage.Page;

            if (backendPage is ChangeFeedNotModifiedPage)
            {
                // Keep draining the cross partition enumerator until
                // We get a non 304 page or we loop back to the same range or run into an exception
                FeedRangeInternal originalRange      = this.crossPartitionEnumerator.CurrentRange;
                double            totalRequestCharge = backendPage.RequestCharge;
                do
                {
                    if (!await this.crossPartitionEnumerator.MoveNextAsync())
                    {
                        throw new InvalidOperationException("ChangeFeed should always have a next page.");
                    }

                    monadicCrossPartitionPage = this.crossPartitionEnumerator.Current;
                    if (monadicCrossPartitionPage.Failed)
                    {
                        // Buffer the exception, since we need to return the request charge so far.
                        this.bufferedException = TryCatch <ChangeFeedPage> .FromException(monadicCrossPartitionPage.Exception);
                    }
                    else
                    {
                        crossPartitionPage  = monadicCrossPartitionPage.Result;
                        backendPage         = crossPartitionPage.Page;
                        totalRequestCharge += backendPage.RequestCharge;
                    }
                }while (!(backendPage is ChangeFeedSuccessPage ||
                          this.crossPartitionEnumerator.CurrentRange.Equals(originalRange) ||
                          this.bufferedException.HasValue));

                // Create a page with the aggregated request charge
                if (backendPage is ChangeFeedSuccessPage changeFeedSuccessPage)
                {
                    backendPage = new ChangeFeedSuccessPage(
                        changeFeedSuccessPage.Content,
                        totalRequestCharge,
                        changeFeedSuccessPage.ActivityId,
                        changeFeedSuccessPage.State);
                }
                else
                {
                    backendPage = new ChangeFeedNotModifiedPage(
                        totalRequestCharge,
                        backendPage.ActivityId,
                        backendPage.State);
                }
            }

            CrossPartitionState <ChangeFeedState> crossPartitionState = crossPartitionPage.State;

            List <CosmosElement> changeFeedContinuationTokens = new List <CosmosElement>();

            foreach ((FeedRangeInternal range, ChangeFeedState state)rangeAndState in crossPartitionState.Value)
            {
                ChangeFeedContinuationToken changeFeedContinuationToken = new ChangeFeedContinuationToken(
                    rangeAndState.range,
                    rangeAndState.state);
                CosmosElement cosmosElementChangeFeedContinuationToken = ChangeFeedContinuationToken.ToCosmosElement(changeFeedContinuationToken);
                changeFeedContinuationTokens.Add(cosmosElementChangeFeedContinuationToken);
            }

            CosmosArray     cosmosElementTokens = CosmosArray.Create(changeFeedContinuationTokens);
            ChangeFeedState state = ChangeFeedState.Continuation(cosmosElementTokens);
            ChangeFeedPage  compositePage;

            if (backendPage is ChangeFeedSuccessPage successPage)
            {
                compositePage = new ChangeFeedSuccessPage(
                    successPage.Content,
                    successPage.RequestCharge,
                    successPage.ActivityId,
                    state);
            }
            else
            {
                compositePage = new ChangeFeedNotModifiedPage(
                    backendPage.RequestCharge,
                    backendPage.ActivityId,
                    state);
            }

            this.Current = TryCatch <ChangeFeedPage> .FromResult(compositePage);

            return(true);
        }
Beispiel #6
0
        public static TryCatch <ChangeFeedState> MonadicFromCosmosElement(CosmosElement cosmosElement)
        {
            if (cosmosElement == null)
            {
                throw new ArgumentNullException(nameof(cosmosElement));
            }

            if (!(cosmosElement is CosmosObject cosmosObject))
            {
                return(TryCatch <ChangeFeedState> .FromException(
                           new FormatException(
                               $"expected change feed state to be an object: {cosmosElement}")));
            }

            if (!cosmosObject.TryGetValue(TypePropertyName, out CosmosString typePropertyValue))
            {
                return(TryCatch <ChangeFeedState> .FromException(
                           new FormatException(
                               $"expected change feed state to have a string type property: {cosmosElement}")));
            }

            ChangeFeedState state;

            switch (typePropertyValue.Value)
            {
            case BeginningTypeValue:
                state = ChangeFeedState.Beginning();
                break;

            case TimeTypeValue:
            {
                if (!cosmosObject.TryGetValue(ValuePropertyName, out CosmosString valuePropertyValue))
                {
                    return(TryCatch <ChangeFeedState> .FromException(
                               new FormatException(
                                   $"expected change feed state to have a string value property: {cosmosElement}")));
                }

                if (!DateTime.TryParse(
                        valuePropertyValue.Value,
                        CultureInfo.InvariantCulture,
                        DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal | DateTimeStyles.AllowWhiteSpaces,
                        out DateTime utcStartTime))
                {
                    return(TryCatch <ChangeFeedState> .FromException(
                               new FormatException(
                                   $"failed to parse start time value: {cosmosElement}")));
                }

                state = ChangeFeedState.Time(utcStartTime);
            }
            break;

            case ContinuationTypeValue:
            {
                if (!cosmosObject.TryGetValue(ValuePropertyName, out CosmosString valuePropertyValue))
                {
                    return(TryCatch <ChangeFeedState> .FromException(
                               new FormatException(
                                   $"expected change feed state to have a string value property: {cosmosElement}")));
                }

                state = ChangeFeedState.Continuation(valuePropertyValue);
            }
            break;

            case NowTypeValue:
                state = ChangeFeedState.Now();
                break;

            default:
                throw new InvalidOperationException();
            }

            return(TryCatch <ChangeFeedState> .FromResult(state));
        }
Beispiel #7
0
 public ChangeFeedContinuationToken(FeedRangeInternal feedRange, ChangeFeedState changeFeedState)
 {
     this.Range = feedRange ?? throw new ArgumentNullException(nameof(feedRange));
     this.State = changeFeedState ?? throw new ArgumentNullException(nameof(changeFeedState));
 }