private async Task <FeedResource <Address> > GetMasterAddressesViaGatewayAsync( DocumentServiceRequest request, ResourceType resourceType, string resourceAddress, string entryUrl, bool forceRefresh, bool useMasterCollectionResolver) { INameValueCollection addressQuery = new DictionaryNameValueCollection(StringComparer.Ordinal); addressQuery.Add(HttpConstants.QueryStrings.Url, HttpUtility.UrlEncode(entryUrl)); INameValueCollection headers = new DictionaryNameValueCollection(StringComparer.Ordinal); if (forceRefresh) { headers.Set(HttpConstants.HttpHeaders.ForceRefresh, bool.TrueString); } if (useMasterCollectionResolver) { headers.Set(HttpConstants.HttpHeaders.UseMasterCollectionResolver, bool.TrueString); } if (request.ForceCollectionRoutingMapRefresh) { headers.Set(HttpConstants.HttpHeaders.ForceCollectionRoutingMapRefresh, bool.TrueString); } addressQuery.Add(HttpConstants.QueryStrings.Filter, this.protocolFilter); string resourceTypeToSign = PathsHelper.GetResourcePath(resourceType); headers.Set(HttpConstants.HttpHeaders.XDate, DateTime.UtcNow.ToString("r", CultureInfo.InvariantCulture)); string token = this.tokenProvider.GetUserAuthorizationToken( resourceAddress, resourceTypeToSign, HttpConstants.HttpMethods.Get, headers, AuthorizationTokenType.PrimaryMasterKey, payload: out _); 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> >()); } } }
private async Task <Tuple <PartitionKeyRangeIdentity, PartitionAddressInformation> > ResolveMasterAsync(DocumentServiceRequest request, bool forceRefresh) { Tuple <PartitionKeyRangeIdentity, PartitionAddressInformation> masterAddressAndRange = this.masterPartitionAddressCache; int targetReplicaSetSize = this.serviceConfigReader.SystemReplicationPolicy.MaxReplicaSetSize; forceRefresh = forceRefresh || (masterAddressAndRange != null && masterAddressAndRange.Item2.AllAddresses.Count() < targetReplicaSetSize && DateTime.UtcNow.Subtract(this.suboptimalMasterPartitionTimestamp) > TimeSpan.FromSeconds(this.suboptimalPartitionForceRefreshIntervalInSeconds)); if (forceRefresh || request.ForceCollectionRoutingMapRefresh || this.masterPartitionAddressCache == null) { string entryUrl = PathsHelper.GeneratePath( ResourceType.Database, string.Empty, true); try { using (DocumentServiceResponse response = await this.GetMasterAddressesViaGatewayAsync( request, ResourceType.Database, null, entryUrl, forceRefresh, false)) { FeedResource <Address> masterAddresses = response.GetResource <FeedResource <Address> >(); bool inNetworkRequest = this.IsInNetworkRequest(response); masterAddressAndRange = this.ToPartitionAddressAndRange(string.Empty, masterAddresses.ToList(), inNetworkRequest); this.masterPartitionAddressCache = masterAddressAndRange; this.suboptimalMasterPartitionTimestamp = DateTime.MaxValue; } } catch (Exception) { this.suboptimalMasterPartitionTimestamp = DateTime.MaxValue; throw; } } if (masterAddressAndRange.Item2.AllAddresses.Count() < targetReplicaSetSize && this.suboptimalMasterPartitionTimestamp.Equals(DateTime.MaxValue)) { this.suboptimalMasterPartitionTimestamp = DateTime.UtcNow; } return(masterAddressAndRange); }
private async Task <PartitionAddressInformation> GetAddressesForRangeIdAsync( DocumentServiceRequest request, string collectionRid, string partitionKeyRangeId, bool forceRefresh) { using (DocumentServiceResponse response = await this.GetServerAddressesViaGatewayAsync(request, collectionRid, new[] { partitionKeyRangeId }, forceRefresh)) { FeedResource <Address> addressFeed = response.GetResource <FeedResource <Address> >(); bool inNetworkRequest = this.IsInNetworkRequest(response); IEnumerable <Tuple <PartitionKeyRangeIdentity, PartitionAddressInformation> > addressInfos = addressFeed.Where(addressInfo => ProtocolFromString(addressInfo.Protocol) == this.protocol) .GroupBy(address => address.PartitionKeyRangeId, StringComparer.Ordinal) .Select(group => this.ToPartitionAddressAndRange(collectionRid, @group.ToList(), inNetworkRequest)); Tuple <PartitionKeyRangeIdentity, PartitionAddressInformation> result = addressInfos.SingleOrDefault( addressInfo => StringComparer.Ordinal.Equals(addressInfo.Item1.PartitionKeyRangeId, partitionKeyRangeId)); if (result == null) { string errorMessage = string.Format( CultureInfo.InvariantCulture, RMResources.PartitionKeyRangeNotFound, partitionKeyRangeId, collectionRid); throw new PartitionKeyRangeGoneException(errorMessage) { ResourceAddress = collectionRid }; } return(result.Item2); } }
private async Task <CollectionRoutingMap> GetRoutingMapForCollectionAsync( string collectionRid, CollectionRoutingMap previousRoutingMap, ITrace trace, IClientSideRequestStatistics clientSideRequestStatistics, CancellationToken cancellationToken) { List <PartitionKeyRange> ranges = new List <PartitionKeyRange>(); string changeFeedNextIfNoneMatch = previousRoutingMap == null ? null : previousRoutingMap.ChangeFeedNextIfNoneMatch; HttpStatusCode lastStatusCode = HttpStatusCode.OK; do { INameValueCollection headers = new StoreRequestNameValueCollection(); headers.Set(HttpConstants.HttpHeaders.PageSize, PageSizeString); headers.Set(HttpConstants.HttpHeaders.A_IM, HttpConstants.A_IMHeaderValues.IncrementalFeed); if (changeFeedNextIfNoneMatch != null) { headers.Set(HttpConstants.HttpHeaders.IfNoneMatch, changeFeedNextIfNoneMatch); } RetryOptions retryOptions = new RetryOptions(); using (DocumentServiceResponse response = await BackoffRetryUtility <DocumentServiceResponse> .ExecuteAsync( () => this.ExecutePartitionKeyRangeReadChangeFeedAsync(collectionRid, headers, trace, clientSideRequestStatistics), new ResourceThrottleRetryPolicy(retryOptions.MaxRetryAttemptsOnThrottledRequests, retryOptions.MaxRetryWaitTimeInSeconds), cancellationToken)) { lastStatusCode = response.StatusCode; changeFeedNextIfNoneMatch = response.Headers[HttpConstants.HttpHeaders.ETag]; FeedResource <PartitionKeyRange> feedResource = response.GetResource <FeedResource <PartitionKeyRange> >(); if (feedResource != null) { ranges.AddRange(feedResource); } } }while (lastStatusCode != HttpStatusCode.NotModified); IEnumerable <Tuple <PartitionKeyRange, ServiceIdentity> > tuples = ranges.Select(range => Tuple.Create(range, (ServiceIdentity)null)); CollectionRoutingMap routingMap; if (previousRoutingMap == null) { // Splits could have happened during change feed query and we might have a mix of gone and new ranges. HashSet <string> goneRanges = new HashSet <string>(ranges.SelectMany(range => range.Parents ?? Enumerable.Empty <string>())); routingMap = CollectionRoutingMap.TryCreateCompleteRoutingMap( tuples.Where(tuple => !goneRanges.Contains(tuple.Item1.Id)), string.Empty, changeFeedNextIfNoneMatch); } else { routingMap = previousRoutingMap.TryCombine(tuples, changeFeedNextIfNoneMatch); } if (routingMap == null) { // Range information either doesn't exist or is not complete. throw new NotFoundException($"{DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture)}: GetRoutingMapForCollectionAsync(collectionRid: {collectionRid}), Range information either doesn't exist or is not complete."); } return(routingMap); }
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> >()); } } }