private async Task RefreshAsync(DocumentServiceRequest request, CancellationToken cancellationToken)
        {
            System.Diagnostics.Debug.Assert(request.IsNameBased);

            string resourceFullName = PathsHelper.GetCollectionPath(request.ResourceAddress);

            if (request.RequestContext.ResolvedCollectionRid != null)
            {
                // Here we will issue backend call only if cache wasn't already refreshed (if whatever is there corresponds to presiously resolved collection rid).
                await this.collectionInfoByNameCache.GetAsync(
                    resourceFullName,
                    CosmosContainerSettings.CreateWithResourceId(request.RequestContext.ResolvedCollectionRid),
                    async() =>
                {
                    CosmosContainerSettings collection = await this.GetByNameAsync(resourceFullName, cancellationToken);
                    if (collection != null)
                    {
                        this.collectionInfoByIdCache.Set(collection.ResourceId, collection);
                    }

                    return(collection);
                },
                    cancellationToken);
            }
            else
            {
                // In case of ForceRefresh directive coming from client, there will be no ResolvedCollectionRid, so we
                // need to refresh unconditionally.
                this.Refresh(request.ResourceAddress);
            }

            request.RequestContext.ResolvedCollectionRid = null;
        }
        private async Task RefreshAsync(DocumentServiceRequest request, CancellationToken cancellationToken)
        {
            System.Diagnostics.Debug.Assert(request.IsNameBased);
            InternalCache cache            = this.GetCache(request.Headers[HttpConstants.HttpHeaders.Version]);
            string        resourceFullName = PathsHelper.GetCollectionPath(request.ResourceAddress);

            if (request.RequestContext.ResolvedCollectionRid != null)
            {
                // Here we will issue backend call only if cache wasn't already refreshed (if whatever is there corresponds to presiously resolved collection rid).
                await cache.collectionInfoByName.GetAsync(
                    resourceFullName,
                    CosmosContainerSettings.CreateWithResourceId(request.RequestContext.ResolvedCollectionRid),
                    async() =>
                {
                    DateTime currentTime = DateTime.UtcNow;
                    CosmosContainerSettings collection = await this.GetByNameAsync(request.Headers[HttpConstants.HttpHeaders.Version], resourceFullName, cancellationToken);
                    cache.collectionInfoById.Set(collection.ResourceId, collection);
                    cache.collectionInfoByNameLastRefreshTime.AddOrUpdate(resourceFullName, currentTime,
                                                                          (string currentKey, DateTime currentValue) => currentTime);
                    cache.collectionInfoByIdLastRefreshTime.AddOrUpdate(collection.ResourceId, currentTime,
                                                                        (string currentKey, DateTime currentValue) => currentTime);
                    return(collection);
                },
                    cancellationToken);
            }
            else
            {
                // In case of ForceRefresh directive coming from client, there will be no ResolvedCollectionRid, so we
                // need to refresh unconditionally.
                this.Refresh(request.ResourceAddress, request.Headers[HttpConstants.HttpHeaders.Version]);
            }

            request.RequestContext.ResolvedCollectionRid = null;
        }
        public void ClearTokenByCollectionFullname(string collectionFullname)
        {
            if (!string.IsNullOrEmpty(collectionFullname))
            {
                string collectionName = PathsHelper.GetCollectionPath(collectionFullname);

                this.rwlock.EnterWriteLock();
                try
                {
                    if (collectionNameByResourceId.ContainsKey(collectionName))
                    {
                        string ignoreString;
                        ulong  ignoreUlong;

                        ulong rid = this.collectionNameByResourceId[collectionName];
                        ConcurrentDictionary <string, ISessionToken> ignored;
                        this.sessionTokensRIDBased.TryRemove(rid, out ignored);
                        this.collectionResourceIdByName.TryRemove(rid, out ignoreString);
                        this.collectionNameByResourceId.TryRemove(collectionName, out ignoreUlong);
                    }
                }
                finally
                {
                    this.rwlock.ExitWriteLock();
                }
            }
        }
Beispiel #4
0
        private static ConcurrentDictionary <string, ISessionToken> GetPartitionKeyRangeIdToTokenMap(SessionContainerState self, DocumentServiceRequest request)
        {
            ulong?maybeRID = null;

            if (request.IsNameBased)
            {
                string collectionName = PathsHelper.GetCollectionPath(request.ResourceAddress);

                if (self.collectionNameByResourceId.TryGetValue(collectionName, out ulong rid))
                {
                    maybeRID = rid;
                }
            }
            else
            {
                if (!string.IsNullOrEmpty(request.ResourceId))
                {
                    ResourceId resourceId = ResourceId.Parse(request.ResourceId);
                    if (resourceId.DocumentCollection != 0)
                    {
                        maybeRID = resourceId.UniqueDocumentCollectionId;
                    }
                }
            }

            ConcurrentDictionary <string, ISessionToken> partitionKeyRangeIdToTokenMap = null;

            if (maybeRID.HasValue)
            {
                self.sessionTokensRIDBased.TryGetValue(maybeRID.Value, out partitionKeyRangeIdToTokenMap);
            }

            return(partitionKeyRangeIdToTokenMap);
        }
        public string GetSessionToken(string collectionLink)
        {
            bool   isNameBased;
            bool   isFeed;
            string resourceTypeString;
            string resourceIdOrFullName;
            ConcurrentDictionary <string, ISessionToken> partitionKeyRangeIdToTokenMap = null;

            if (PathsHelper.TryParsePathSegments(collectionLink, out isFeed, out resourceTypeString, out resourceIdOrFullName, out isNameBased))
            {
                if (isNameBased)
                {
                    string collectionName = PathsHelper.GetCollectionPath(resourceIdOrFullName);
                    this.sessionTokensNameBased.TryGetValue(collectionName, out partitionKeyRangeIdToTokenMap);
                }
                else
                {
                    ResourceId resourceId = ResourceId.Parse(resourceIdOrFullName);
                    if (resourceId.DocumentCollection != 0)
                    {
                        this.sessionTokens.TryGetValue(resourceId.UniqueDocumentCollectionId, out partitionKeyRangeIdToTokenMap);
                    }
                }
            }

            if (partitionKeyRangeIdToTokenMap == null)
            {
                return(string.Empty);
            }

            return(SessionContainer.GetSessionTokenString(partitionKeyRangeIdToTokenMap));
        }
        public void ClearToken(DocumentServiceRequest request, INameValueCollection responseHeaders)
        {
            string ownerFullName  = responseHeaders[HttpConstants.HttpHeaders.OwnerFullName];
            string collectionName = PathsHelper.GetCollectionPath(ownerFullName);
            string resourceIdString;

            if (!request.IsNameBased)
            {
                resourceIdString = request.ResourceId;
            }
            else
            {
                resourceIdString = responseHeaders[HttpConstants.HttpHeaders.OwnerId];
            }

            if (!string.IsNullOrEmpty(resourceIdString))
            {
                ResourceId resourceId = ResourceId.Parse(resourceIdString);
                if (resourceId.DocumentCollection != 0 && collectionName != null)
                {
                    ConcurrentDictionary <string, ISessionToken> ignored;
                    this.sessionTokens.TryRemove(resourceId.UniqueDocumentCollectionId, out ignored);
                    this.sessionTokensNameBased.TryRemove(collectionName, out ignored);
                }
            }
        }
        private async Task <CosmosContainerSettings> ResolveByNameAsync(
            string apiVersion,
            string resourceAddress,
            CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            string        resourceFullName = PathsHelper.GetCollectionPath(resourceAddress);
            InternalCache cache            = this.GetCache(apiVersion);

            return(await cache.collectionInfoByName.GetAsync(
                       resourceFullName,
                       null,
                       async() =>
            {
                DateTime currentTime = DateTime.UtcNow;
                CosmosContainerSettings collection = await this.GetByNameAsync(apiVersion, resourceFullName, cancellationToken);
                cache.collectionInfoById.Set(collection.ResourceId, collection);
                cache.collectionInfoByNameLastRefreshTime.AddOrUpdate(resourceFullName, currentTime,
                                                                      (string currentKey, DateTime currentValue) => currentTime);
                cache.collectionInfoByIdLastRefreshTime.AddOrUpdate(collection.ResourceId, currentTime,
                                                                    (string currentKey, DateTime currentValue) => currentTime);
                return collection;
            },
                       cancellationToken));
        }
        internal virtual async Task <ContainerProperties> ResolveByNameAsync(
            string apiVersion,
            string resourceAddress,
            bool forceRefesh,
            ITrace trace,
            IClientSideRequestStatistics clientSideRequestStatistics,
            CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            string        resourceFullName = PathsHelper.GetCollectionPath(resourceAddress);
            InternalCache cache            = this.GetCache(apiVersion);

            if (forceRefesh)
            {
                cache.collectionInfoByName.TryRemoveIfCompleted(resourceFullName);
            }

            return(await cache.collectionInfoByName.GetAsync(
                       resourceFullName,
                       null,
                       async() =>
            {
                DateTime currentTime = DateTime.UtcNow;
                ContainerProperties collection = await this.GetByNameAsync(apiVersion, resourceFullName, trace, clientSideRequestStatistics, cancellationToken);
                cache.collectionInfoById.Set(collection.ResourceId, collection);
                cache.collectionInfoByNameLastRefreshTime.AddOrUpdate(resourceFullName, currentTime,
                                                                      (string currentKey, DateTime currentValue) => currentTime);
                cache.collectionInfoByIdLastRefreshTime.AddOrUpdate(collection.ResourceId, currentTime,
                                                                    (string currentKey, DateTime currentValue) => currentTime);
                return collection;
            },
                       cancellationToken));
        }
 internal override async Task <IDocumentClientRetryPolicy> GetRetryPolicy(CosmosRequestMessage request)
 {
     return(new PartitionKeyRangeGoneRetryPolicy(
                await client.DocumentClient.GetCollectionCacheAsync(),
                await client.DocumentClient.GetPartitionKeyRangeCacheAsync(),
                PathsHelper.GetCollectionPath(request.RequestUri.ToString()),
                null));
 }
Beispiel #10
0
        /// <summary>
        /// This method is only used in client SDK in retry policy as it doesn't have request handy.
        /// </summary>
        public void Refresh(string resourceAddress, string apiVersion = null)
        {
            InternalCache cache = this.GetCache(apiVersion);
            if (PathsHelper.IsNameBased(resourceAddress))
            {
                string resourceFullName = PathsHelper.GetCollectionPath(resourceAddress);

                cache.collectionInfoByName.TryRemoveIfCompleted(resourceFullName);
            }
        }
Beispiel #11
0
        private static void SetSessionToken(SessionContainerState self, string collectionRid, string collectionFullname, INameValueCollection responseHeaders)
        {
            ResourceId resourceId     = ResourceId.Parse(collectionRid);
            string     collectionName = PathsHelper.GetCollectionPath(collectionFullname);
            string     token          = responseHeaders[HttpConstants.HttpHeaders.SessionToken];

            if (!string.IsNullOrEmpty(token))
            {
                SessionContainer.SetSessionToken(self, resourceId, collectionName, token);
            }
        }
        public void ClearToken(string collectionRid, string collectionFullname, INameValueCollection responseHeader)
        {
            if (!string.IsNullOrEmpty(collectionFullname))
            {
                string collectionName = PathsHelper.GetCollectionPath(collectionFullname);
                ConcurrentDictionary <string, ISessionToken> ignored;
                this.sessionTokensNameBased.TryRemove(collectionName, out ignored);
            }

            if (!string.IsNullOrEmpty(collectionRid))
            {
                ResourceId resourceId = ResourceId.Parse(collectionRid);
                ConcurrentDictionary <string, ISessionToken> ignored;
                this.sessionTokens.TryRemove(resourceId.UniqueDocumentCollectionId, out ignored);
            }
        }
        internal override Task <ContainerProperties> ResolveByNameAsync(
            string apiVersion,
            string resourceAddress,
            bool forceRefesh,
            ITrace trace,
            IClientSideRequestStatistics clientSideRequestStatistics,
            CancellationToken cancellationToken)
        {
            if (forceRefesh && this.sessionContainer != null)
            {
                return(TaskHelper.InlineIfPossible(
                           async() =>
                {
                    string oldRid = (await base.ResolveByNameAsync(
                                         apiVersion,
                                         resourceAddress,
                                         forceRefesh: false,
                                         trace,
                                         clientSideRequestStatistics,
                                         cancellationToken))?.ResourceId;

                    ContainerProperties propertiesAfterRefresh = await base.ResolveByNameAsync(
                        apiVersion,
                        resourceAddress,
                        forceRefesh,
                        trace,
                        clientSideRequestStatistics,
                        cancellationToken);

                    if (oldRid != null && oldRid != propertiesAfterRefresh?.ResourceId)
                    {
                        string resourceFullName = PathsHelper.GetCollectionPath(resourceAddress);
                        this.sessionContainer.ClearTokenByCollectionFullname(resourceFullName);
                    }

                    return propertiesAfterRefresh;
                },
                           retryPolicy: null,
                           cancellationToken));
            }

            return(TaskHelper.InlineIfPossible(
                       () => base.ResolveByNameAsync(
                           apiVersion, resourceAddress, forceRefesh, trace, clientSideRequestStatistics, cancellationToken),
                       retryPolicy: null,
                       cancellationToken));
        }
Beispiel #14
0
        private static string GetSessionToken(SessionContainerState self, string collectionLink)
        {
            bool arePathSegmentsParsed = PathsHelper.TryParsePathSegments(
                collectionLink,
                out _,
                out _,
                out string resourceIdOrFullName,
                out bool isNameBased);

            ConcurrentDictionary <string, ISessionToken> partitionKeyRangeIdToTokenMap = null;

            if (arePathSegmentsParsed)
            {
                ulong?maybeRID = null;

                if (isNameBased)
                {
                    string collectionName = PathsHelper.GetCollectionPath(resourceIdOrFullName);

                    if (self.collectionNameByResourceId.TryGetValue(collectionName, out ulong rid))
                    {
                        maybeRID = rid;
                    }
                }
                else
                {
                    ResourceId resourceId = ResourceId.Parse(resourceIdOrFullName);
                    if (resourceId.DocumentCollection != 0)
                    {
                        maybeRID = resourceId.UniqueDocumentCollectionId;
                    }
                }

                if (maybeRID.HasValue)
                {
                    self.sessionTokensRIDBased.TryGetValue(maybeRID.Value, out partitionKeyRangeIdToTokenMap);
                }
            }

            if (partitionKeyRangeIdToTokenMap == null)
            {
                return(string.Empty);
            }

            return(SessionContainer.GetSessionTokenString(partitionKeyRangeIdToTokenMap));
        }
        /// <summary>
        /// Resolve the ContainerProperties object from the cache. If the collection was read before "refreshAfter" Timespan, force a cache refresh by reading from the backend.
        /// </summary>
        /// <param name="request">Request to resolve.</param>
        /// <param name="refreshAfter"> Time duration to refresh</param>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <param name="trace">The trace.</param>
        /// <returns>Instance of <see cref="ContainerProperties"/>.</returns>
        public virtual Task <ContainerProperties> ResolveCollectionAsync(
            DocumentServiceRequest request,
            TimeSpan refreshAfter,
            CancellationToken cancellationToken,
            ITrace trace)
        {
            cancellationToken.ThrowIfCancellationRequested();
            InternalCache cache = this.GetCache(request.Headers[HttpConstants.HttpHeaders.Version]);

#if !NETSTANDARD16
            Debug.Assert(request.ForceNameCacheRefresh == false);
#endif
            DateTime currentTime     = DateTime.UtcNow;
            DateTime lastRefreshTime = DateTime.MinValue;
            if (request.IsNameBased)
            {
                string resourceFullName = PathsHelper.GetCollectionPath(request.ResourceAddress);

                if (cache.collectionInfoByNameLastRefreshTime.TryGetValue(resourceFullName, out lastRefreshTime))
                {
                    TimeSpan cachedItemStaleness = currentTime - lastRefreshTime;

                    if (cachedItemStaleness > refreshAfter)
                    {
                        cache.collectionInfoByName.TryRemoveIfCompleted(resourceFullName);
                    }
                }
            }
            else
            {
                ResourceId resourceIdParsed     = ResourceId.Parse(request.ResourceId);
                string     collectionResourceId = resourceIdParsed.DocumentCollectionId.ToString();

                if (cache.collectionInfoByIdLastRefreshTime.TryGetValue(collectionResourceId, out lastRefreshTime))
                {
                    TimeSpan cachedItemStaleness = currentTime - lastRefreshTime;

                    if (cachedItemStaleness > refreshAfter)
                    {
                        cache.collectionInfoById.TryRemoveIfCompleted(request.ResourceId);
                    }
                }
            }

            return(this.ResolveCollectionAsync(request, cancellationToken, trace));
        }
Beispiel #16
0
        private static bool ShouldUpdateSessionToken(
            DocumentServiceRequest request,
            INameValueCollection responseHeaders,
            out ResourceId resourceId,
            out string collectionName)
        {
            resourceId = null;
            string ownerFullName = responseHeaders[HttpConstants.HttpHeaders.OwnerFullName];

            if (string.IsNullOrEmpty(ownerFullName))
            {
                ownerFullName = request.ResourceAddress;
            }

            collectionName = PathsHelper.GetCollectionPath(ownerFullName);
            string resourceIdString;

            if (request.IsNameBased)
            {
                resourceIdString = responseHeaders[HttpConstants.HttpHeaders.OwnerId];
                if (string.IsNullOrEmpty(resourceIdString))
                {
                    resourceIdString = request.ResourceId;
                }
            }
            else
            {
                resourceIdString = request.ResourceId;
            }

            if (!string.IsNullOrEmpty(resourceIdString))
            {
                resourceId = ResourceId.Parse(resourceIdString);

                if (resourceId.DocumentCollection != 0 &&
                    collectionName != null &&
                    !ReplicatedResourceClient.IsReadingFromMaster(request.ResourceType, request.OperationType))
                {
                    return(true);
                }
            }

            return(false);
        }
        /// <summary>
        /// This method is only used in client SDK in retry policy as it doesn't have request handy.
        /// </summary>
        public void Refresh(string resourceAddress)
        {
            if (PathsHelper.IsNameBased(resourceAddress))
            {
                string resourceFullName = PathsHelper.GetCollectionPath(resourceAddress);

                this.collectionInfoByNameCache.Refresh(
                    resourceFullName,
                    async() =>
                {
                    CosmosContainerSettings collection = await this.GetByNameAsync(resourceFullName, CancellationToken.None);
                    if (collection != null)
                    {
                        this.collectionInfoByIdCache.Set(collection.ResourceId, collection);
                    }

                    return(collection);
                },
                    CancellationToken.None);
            }
        }
Beispiel #18
0
        private static void ClearTokenByCollectionFullname(SessionContainerState self, string collectionFullname)
        {
            if (!string.IsNullOrEmpty(collectionFullname))
            {
                string collectionName = PathsHelper.GetCollectionPath(collectionFullname);

                self.rwlock.EnterWriteLock();
                try
                {
                    if (self.collectionNameByResourceId.ContainsKey(collectionName))
                    {
                        ulong rid = self.collectionNameByResourceId[collectionName];
                        self.sessionTokensRIDBased.TryRemove(rid, out _);
                        self.collectionResourceIdByName.TryRemove(rid, out _);
                        self.collectionNameByResourceId.TryRemove(collectionName, out _);
                    }
                }
                finally
                {
                    self.rwlock.ExitWriteLock();
                }
            }
        }
        internal Task <CosmosContainerSettings> ResolveByNameAsync(
            string resourceAddress,
            CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            string resourceFullName = PathsHelper.GetCollectionPath(resourceAddress);

            return(this.collectionInfoByNameCache.GetAsync(
                       resourceFullName,
                       null,
                       async() =>
            {
                CosmosContainerSettings collection = await this.GetByNameAsync(resourceFullName, cancellationToken);
                if (collection != null)
                {
                    this.collectionInfoByIdCache.Set(collection.ResourceId, collection);
                }

                return collection;
            },
                       cancellationToken));
        }
        private ConcurrentDictionary <string, ISessionToken> GetPartitionKeyRangeIdToTokenMap(DocumentServiceRequest request)
        {
            ConcurrentDictionary <string, ISessionToken> partitionKeyRangeIdToTokenMap = null;

            if (!request.IsNameBased)
            {
                if (!string.IsNullOrEmpty(request.ResourceId))
                {
                    ResourceId resourceId = ResourceId.Parse(request.ResourceId);
                    if (resourceId.DocumentCollection != 0)
                    {
                        this.sessionTokens.TryGetValue(resourceId.UniqueDocumentCollectionId, out partitionKeyRangeIdToTokenMap);
                    }
                }
            }
            else
            {
                string collectionName = PathsHelper.GetCollectionPath(request.ResourceAddress);
                this.sessionTokensNameBased.TryGetValue(collectionName, out partitionKeyRangeIdToTokenMap);
            }

            return(partitionKeyRangeIdToTokenMap);
        }
Beispiel #21
0
        protected override async Task <FeedResponse <dynamic> > ExecuteInternalAsync(CancellationToken cancellationToken)
        {
            CollectionCache collectionCache = await this.Client.GetCollectionCacheAsync();

            PartitionKeyRangeCache partitionKeyRangeCache = await this.Client.GetPartitionKeyRangeCache();

            IDocumentClientRetryPolicy retryPolicyInstance = this.Client.RetryPolicy.GetRequestPolicy();

            retryPolicyInstance = new InvalidPartitionExceptionRetryPolicy(collectionCache, retryPolicyInstance);
            if (base.ResourceTypeEnum.IsPartitioned())
            {
                retryPolicyInstance = new PartitionKeyRangeGoneRetryPolicy(
                    collectionCache,
                    partitionKeyRangeCache,
                    PathsHelper.GetCollectionPath(base.ResourceLink),
                    retryPolicyInstance);
            }

            return(await BackoffRetryUtility <FeedResponse <dynamic> > .ExecuteAsync(
                       async() =>
            {
                this.fetchExecutionRangeAccumulator.BeginFetchRange();
                ++this.retries;
                this.fetchSchedulingMetrics.Start();
                this.fetchExecutionRangeAccumulator.BeginFetchRange();
                FeedResponse <dynamic> response = await this.ExecuteOnceAsync(retryPolicyInstance, cancellationToken);
                this.fetchSchedulingMetrics.Stop();
                this.fetchExecutionRangeAccumulator.EndFetchRange(response.Count, this.retries);

                if (!string.IsNullOrEmpty(response.Headers[HttpConstants.HttpHeaders.QueryMetrics]))
                {
                    this.fetchExecutionRangeAccumulator.EndFetchRange(response.Count, this.retries);
                    response = new FeedResponse <dynamic>(
                        response,
                        response.Count,
                        response.Headers,
                        response.UseETagAsContinuation,
                        new Dictionary <string, QueryMetrics>
                    {
                        {
                            singlePartitionKeyId,
                            QueryMetrics.CreateFromDelimitedStringAndClientSideMetrics(
                                response.Headers[HttpConstants.HttpHeaders.QueryMetrics],
                                new ClientSideMetrics(
                                    this.retries,
                                    response.RequestCharge,
                                    this.fetchExecutionRangeAccumulator.GetExecutionRanges(),
                                    string.IsNullOrEmpty(response.ResponseContinuation) ? new List <Tuple <string, SchedulingTimeSpan> >()
                            {
                                new Tuple <string, SchedulingTimeSpan>(singlePartitionKeyId, this.fetchSchedulingMetrics.Elapsed)
                            } : new List <Tuple <string, SchedulingTimeSpan> >()),
                                Guid.Parse(response.ActivityId))
                        }
                    },
                        response.RequestStatistics,
                        response.DisallowContinuationTokenMessage,
                        response.ResponseLengthBytes);
                }

                this.retries = -1;
                return response;
            },
                       retryPolicyInstance,
                       cancellationToken));
        }
        protected override async Task <DocumentFeedResponse <CosmosElement> > ExecuteInternalAsync(CancellationToken token)
        {
            CollectionCache collectionCache = await this.Client.GetCollectionCacheAsync();

            PartitionKeyRangeCache partitionKeyRangeCache = await this.Client.GetPartitionKeyRangeCacheAsync();

            IDocumentClientRetryPolicy retryPolicyInstance = this.Client.ResetSessionTokenRetryPolicy.GetRequestPolicy();

            retryPolicyInstance = new InvalidPartitionExceptionRetryPolicy(retryPolicyInstance);
            if (base.ResourceTypeEnum.IsPartitioned())
            {
                retryPolicyInstance = new PartitionKeyRangeGoneRetryPolicy(
                    collectionCache,
                    partitionKeyRangeCache,
                    PathsHelper.GetCollectionPath(base.ResourceLink),
                    retryPolicyInstance);
            }

            return(await BackoffRetryUtility <DocumentFeedResponse <CosmosElement> > .ExecuteAsync(
                       async() =>
            {
                this.fetchExecutionRangeAccumulator.BeginFetchRange();
                ++this.retries;
                Tuple <DocumentFeedResponse <CosmosElement>, string> responseAndPartitionIdentifier = await this.ExecuteOnceAsync(retryPolicyInstance, token);
                DocumentFeedResponse <CosmosElement> response = responseAndPartitionIdentifier.Item1;
                string partitionIdentifier = responseAndPartitionIdentifier.Item2;
                if (!string.IsNullOrEmpty(response.ResponseHeaders[HttpConstants.HttpHeaders.QueryMetrics]))
                {
                    this.fetchExecutionRangeAccumulator.EndFetchRange(
                        partitionIdentifier,
                        response.ActivityId,
                        response.Count,
                        this.retries);
                    response = new DocumentFeedResponse <CosmosElement>(
                        response,
                        response.Count,
                        response.Headers,
                        response.UseETagAsContinuation,
                        new Dictionary <string, QueryMetrics>
                    {
                        {
                            partitionIdentifier,
                            QueryMetrics.CreateFromDelimitedStringAndClientSideMetrics(
                                response.ResponseHeaders[HttpConstants.HttpHeaders.QueryMetrics],
                                response.ResponseHeaders[HttpConstants.HttpHeaders.IndexUtilization],
                                new ClientSideMetrics(
                                    this.retries,
                                    response.RequestCharge,
                                    this.fetchExecutionRangeAccumulator.GetExecutionRanges()))
                        }
                    },
                        response.RequestStatistics,
                        response.DisallowContinuationTokenMessage,
                        response.ResponseLengthBytes);
                }

                this.retries = -1;
                return response;
            },
                       retryPolicyInstance,
                       token));
        }
Beispiel #23
0
        private async Task <FeedResource <Address> > GetServerAddressesViaGatewayAsync(
            DocumentServiceRequest request,
            string collectionRid,
            IEnumerable <string> partitionKeyRangeIds,
            bool forceRefresh)
        {
            string entryUrl = PathsHelper.GeneratePath(ResourceType.Document, collectionRid, true);

            INameValueCollection addressQuery = new DictionaryNameValueCollection();

            addressQuery.Add(HttpConstants.QueryStrings.Url, HttpUtility.UrlEncode(entryUrl));

            INameValueCollection headers = new DictionaryNameValueCollection();

            if (forceRefresh)
            {
                headers.Set(HttpConstants.HttpHeaders.ForceRefresh, bool.TrueString);
            }

            if (request.ForceCollectionRoutingMapRefresh)
            {
                headers.Set(HttpConstants.HttpHeaders.ForceCollectionRoutingMapRefresh, bool.TrueString);
            }

            addressQuery.Add(HttpConstants.QueryStrings.Filter, this.protocolFilter);
            addressQuery.Add(HttpConstants.QueryStrings.PartitionKeyRangeIds, string.Join(",", partitionKeyRangeIds));

            string resourceTypeToSign = PathsHelper.GetResourcePath(ResourceType.Document);

            headers.Set(HttpConstants.HttpHeaders.XDate, DateTime.UtcNow.ToString("r", CultureInfo.InvariantCulture));
            string token = null;

            try
            {
                token = this.tokenProvider.GetUserAuthorizationToken(
                    collectionRid,
                    resourceTypeToSign,
                    HttpConstants.HttpMethods.Get,
                    headers,
                    AuthorizationTokenType.PrimaryMasterKey);
            }
            catch (UnauthorizedException)
            {
            }

            if (token == null && request.IsNameBased)
            {
                // User doesn't have rid based resource token. Maybe he has name based.
                string collectionAltLink = PathsHelper.GetCollectionPath(request.ResourceAddress);
                token = this.tokenProvider.GetUserAuthorizationToken(
                    collectionAltLink,
                    resourceTypeToSign,
                    HttpConstants.HttpMethods.Get,
                    headers,
                    AuthorizationTokenType.PrimaryMasterKey);
            }

            headers.Set(HttpConstants.HttpHeaders.Authorization, token);

            Uri targetEndpoint = UrlUtility.SetQuery(this.addressEndpoint, UrlUtility.CreateQuery(addressQuery));

            string identifier = GatewayAddressCache.LogAddressResolutionStart(request, targetEndpoint);

            using (HttpResponseMessage httpResponseMessage = await this.httpClient.GetAsync(targetEndpoint, headers))
            {
                using (DocumentServiceResponse documentServiceResponse =
                           await ClientExtensions.ParseResponseAsync(httpResponseMessage))
                {
                    GatewayAddressCache.LogAddressResolutionEnd(request, identifier);

                    return(documentServiceResponse.GetResource <FeedResource <Address> >());
                }
            }
        }