private void ResumeReplicas(string documentId) { ResourceId documentRId = ResourceId.Parse(documentId); string collectionId = documentRId.DocumentCollectionId.ToString(); IEnumerable <string> indexFiles = Directory.EnumerateFiles("c:\\wfroot\\", "*.bwdata", SearchOption.AllDirectories); List <string> collectionIndexFiles = new List <string>(); foreach (string indexFile in indexFiles) { if (indexFile.Contains(collectionId)) { collectionIndexFiles.Add(indexFile); } } foreach (string fileName in collectionIndexFiles) { string directoryName = Path.GetDirectoryName(fileName); string manualRecoveryFileFullName = Path.Combine(directoryName, MultiRegionStrongTests.repairInProgressFileName); try { File.Delete(manualRecoveryFileFullName); } catch (FileNotFoundException) { } } }
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); }
private Task <ContainerProperties> ResolveByRidAsync( string apiVersion, string resourceId, ITrace trace, IClientSideRequestStatistics clientSideRequestStatistics, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ResourceId resourceIdParsed = ResourceId.Parse(resourceId); string collectionResourceId = resourceIdParsed.DocumentCollectionId.ToString(); InternalCache cache = this.GetCache(apiVersion); return(cache.collectionInfoById.GetAsync( collectionResourceId, null, async() => { DateTime currentTime = DateTime.UtcNow; ContainerProperties collection = await this.GetByRidAsync(apiVersion, collectionResourceId, trace, clientSideRequestStatistics, cancellationToken); cache.collectionInfoByIdLastRefreshTime.AddOrUpdate(collectionResourceId, currentTime, (string currentKey, DateTime currentValue) => currentTime); return collection; }, cancellationToken)); }
public static IReadOnlyList <Record> GetRecords(this ReadFeedPage page) { using (MemoryStream memoryStream = new MemoryStream()) { page.Content.CopyTo(memoryStream); CosmosObject responseEnvolope = CosmosObject.CreateFromBuffer(memoryStream.ToArray()); if (!responseEnvolope.TryGetValue("Documents", out CosmosArray documents)) { throw new InvalidOperationException(); } List <Record> records = new List <Record>(); foreach (CosmosElement document in documents) { CosmosObject documentObject = (CosmosObject)document; ResourceId rid = ResourceId.Parse(((CosmosString)documentObject["_rid"]).Value); long ticks = Number64.ToLong(((CosmosNumber)documentObject["_ts"]).Value); string id = ((CosmosString)documentObject["id"]).Value; CosmosObject payload = documentObject; Record record = new Record(rid, new DateTime(ticks: ticks, DateTimeKind.Utc), id, payload); records.Add(record); } return(records); } }
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 static void ClearTokenByResourceId(SessionContainerState self, string resourceId) { if (!string.IsNullOrEmpty(resourceId)) { ResourceId resource = ResourceId.Parse(resourceId); if (resource.DocumentCollection != 0) { ulong rid = resource.UniqueDocumentCollectionId; self.rwlock.EnterWriteLock(); try { if (self.collectionResourceIdByName.ContainsKey(rid)) { string collectionName = self.collectionResourceIdByName[rid]; _ = self.sessionTokensRIDBased.TryRemove(rid, out _); _ = self.collectionResourceIdByName.TryRemove(rid, out _); _ = self.collectionNameByResourceId.TryRemove(collectionName, out _); } } finally { self.rwlock.ExitWriteLock(); } } } }
public void ClearTokenByResourceId(string resourceId) { if (!string.IsNullOrEmpty(resourceId)) { ResourceId resource = ResourceId.Parse(resourceId); if (resource.DocumentCollection != 0) { ulong rid = resource.UniqueDocumentCollectionId; this.rwlock.EnterWriteLock(); try { if (this.collectionResourceIdByName.ContainsKey(rid)) { string ignoreString; ulong ignoreUlong; string collectionName = this.collectionResourceIdByName[rid]; 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(); } } } }
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); } }
internal static string GetAuthorizationResourceIdOrFullName(string resourceType, string resourceIdOrFullName) { if (string.IsNullOrEmpty(resourceType) || string.IsNullOrEmpty(resourceIdOrFullName)) { return(resourceIdOrFullName); } if (PathsHelper.IsNameBased(resourceIdOrFullName)) { // resource fullname is always end with name (not type segment like docs/colls). return(resourceIdOrFullName); } if (resourceType.Equals(Paths.OffersPathSegment, StringComparison.OrdinalIgnoreCase) || resourceType.Equals(Paths.PartitionsPathSegment, StringComparison.OrdinalIgnoreCase) || resourceType.Equals(Paths.TopologyPathSegment, StringComparison.OrdinalIgnoreCase) || resourceType.Equals(Paths.RidRangePathSegment, StringComparison.OrdinalIgnoreCase) || resourceType.Equals(Paths.SnapshotsPathSegment, StringComparison.OrdinalIgnoreCase)) { return(resourceIdOrFullName); } ResourceId parsedRId = ResourceId.Parse(resourceIdOrFullName); if (resourceType.Equals(Paths.DatabasesPathSegment, StringComparison.OrdinalIgnoreCase)) { return(parsedRId.DatabaseId.ToString()); } else if (resourceType.Equals(Paths.UsersPathSegment, StringComparison.OrdinalIgnoreCase)) { return(parsedRId.UserId.ToString()); } else if (resourceType.Equals(Paths.UserDefinedTypesPathSegment, StringComparison.OrdinalIgnoreCase)) { return(parsedRId.UserDefinedTypeId.ToString()); } else if (resourceType.Equals(Paths.CollectionsPathSegment, StringComparison.OrdinalIgnoreCase)) { return(parsedRId.DocumentCollectionId.ToString()); } else if (resourceType.Equals(Paths.ClientEncryptionKeysPathSegment, StringComparison.OrdinalIgnoreCase)) { return(parsedRId.ClientEncryptionKeyId.ToString()); } else if (resourceType.Equals(Paths.DocumentsPathSegment, StringComparison.OrdinalIgnoreCase)) { return(parsedRId.DocumentId.ToString()); } else { // leaf node return(resourceIdOrFullName); } }
/// <summary> Load the data in the table </summary> public override void LoadData() { DataTable table = GetAllData(); foreach (DataRow row in table.Rows) { long resourceId = ResourceId.Parse(row); Resource resource = TableManager.Resource.GetResource(resourceId); DateTime date = Date.Parse(row); int price = Price.Parse(row); resource.AddPriceHistory(date, price); } }
//Workaround //This method was removed from Direct private static ResourceId NewDocumentId(string collectionId, uint documentId) { ResourceId collectionResourceId = ResourceId.Parse(collectionId); ResourceId documentResourceId = ResourceId.Empty; //Properties have private setters documentResourceId.GetType().GetProperty(nameof(documentResourceId.Database)).SetValue(documentResourceId, collectionResourceId.Database); documentResourceId.GetType().GetProperty(nameof(documentResourceId.DocumentCollection)).SetValue(documentResourceId, collectionResourceId.DocumentCollection); documentResourceId.GetType().GetProperty(nameof(documentResourceId.Document)).SetValue(documentResourceId, documentId); return(documentResourceId); }
/// <summary> Loads the data in this table </summary> public override void LoadData() { DataTable table = GetAllData(); foreach (DataRow row in table.Rows) { Profession profession = TableManager.Profession.GetProfession(ProfessionId.Parse(row)); int grade = Grade.Parse(row); Resource resource = TableManager.Resource.GetResource(ResourceId.Parse(row)); int amount = Amount.Parse(row); profession.AddUpgradeCost(grade, resource, amount); } }
/// <summary> Load all recipe costs from the database </summary> public override void LoadData() { DataTable table = GetAllData(); foreach (DataRow row in table.Rows) { long recipeId = RecipeId.Parse(row); long resourceId = ResourceId.Parse(row); int amount = Amount.Parse(row); Recipe recipe = TableManager.Recipe.GetRecipe(recipeId); Resource resource = TableManager.Resource.GetResource(resourceId); recipe.AddConsumed(resource, amount); } }
private static bool IsSameCollection(PartitionKeyRange initiallyResolved, PartitionKeyRange newlyResolved) { if (initiallyResolved == null) { throw new ArgumentException("parent"); } if (newlyResolved == null) { return(false); } if (initiallyResolved.Id == PartitionKeyRange.MasterPartitionKeyRangeId && newlyResolved.Id == PartitionKeyRange.MasterPartitionKeyRangeId) { return(true); } if (initiallyResolved.Id == PartitionKeyRange.MasterPartitionKeyRangeId || newlyResolved.Id == PartitionKeyRange.MasterPartitionKeyRangeId) { string message = "Request was resolved to master partition and then to server partition."; Debug.Assert(false, message); DefaultTrace.TraceCritical(message); return(false); } if (ResourceId.Parse(initiallyResolved.ResourceId).DocumentCollection != ResourceId.Parse(newlyResolved.ResourceId).DocumentCollection) { return(false); } if (initiallyResolved.Id != newlyResolved.Id && !(newlyResolved.Parents != null && newlyResolved.Parents.Contains(initiallyResolved.Id))) { // the above condition should be always false in current codebase. // We don't need to refresh any caches if we resolved to a range which is child of previously resolved range. // Quorum reads should be handled transparently as child partitions share LSNs with parent partitions which are gone. string message = "Request is targeted at a partition key range which is not child of previously targeted range."; Debug.Assert(false, message); DefaultTrace.TraceCritical(message); return(false); } return(true); }
private Task <CosmosContainerSettings> ResolveByRidAsync( string resourceId, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ResourceId resourceIdParsed = ResourceId.Parse(resourceId); string collectionResourceId = resourceIdParsed.DocumentCollectionId.ToString(); return(this.collectionInfoByIdCache.GetAsync( collectionResourceId, null, () => this.GetByRidAsync(collectionResourceId, cancellationToken), cancellationToken)); }
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); } }
/// <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)); }
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)); }
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); }
public Record Add(int pkrangeid, CosmosObject payload) { // using pkrangeid for database since resource id doesnt serialize both document and pkrangeid. ResourceId currentResourceId; if (this.Count == 0) { currentResourceId = ResourceId.Parse("AYIMAMmFOw8YAAAAAAAAAA=="); PropertyInfo documentProp = currentResourceId .GetType() .GetProperty("Document", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); documentProp.SetValue(currentResourceId, (ulong)1); PropertyInfo databaseProp = currentResourceId .GetType() .GetProperty("Database", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); databaseProp.SetValue(currentResourceId, (uint)pkrangeid + 1); } else { currentResourceId = this.storage[this.storage.Count - 1].ResourceIdentifier; } ResourceId nextResourceId = ResourceId.Parse("AYIMAMmFOw8YAAAAAAAAAA=="); { PropertyInfo documentProp = nextResourceId .GetType() .GetProperty("Document", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); documentProp.SetValue(nextResourceId, (ulong)(currentResourceId.Document + 1)); PropertyInfo databaseProp = nextResourceId .GetType() .GetProperty("Database", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); databaseProp.SetValue(nextResourceId, (uint)pkrangeid + 1); } Record record = new Record(nextResourceId, DateTime.UtcNow.Ticks, Guid.NewGuid().ToString(), payload); this.storage.Add(record); return(record); }
private static IEnumerable <CosmosElement> ExecuteCrossPartitionOrdering( IEnumerable <CosmosElement> dataSource, IReadOnlyDictionary <string, PartitionKeyRange> ridToPartitionKeyRange) { // Grab from the left most partition first IOrderedEnumerable <CosmosElement> orderedDataSource = dataSource .OrderBy((element) => { string rid = ((CosmosString)((CosmosObject)element)["_rid"]).Value; PartitionKeyRange partitionKeyRange = ridToPartitionKeyRange[rid]; return(partitionKeyRange.MinInclusive); }, StringComparer.Ordinal); // Break all final ties within partition by document id orderedDataSource = orderedDataSource .ThenBy(element => ResourceId.Parse(((CosmosString)((CosmosObject)element)["_rid"]).Value).Document); return(orderedDataSource); }
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); }
private static void SetupAccountAndCacheOperations( out string secondaryRegionNameForUri, out string globalEndpoint, out string secondaryRegionEndpiont, out string databaseName, out string containerName, out ResourceId containerResourceId, out Mock <IHttpHandler> mockHttpHandler, out IReadOnlyList <string> primaryRegionPartitionKeyRangeIds, out TransportAddressUri primaryRegionprimaryReplicaUri) { string accountName = "testAccount"; string primaryRegionNameForUri = "eastus"; secondaryRegionNameForUri = "westus"; globalEndpoint = $"https://{accountName}.documents.azure.com:443/"; Uri globalEndpointUri = new Uri(globalEndpoint); string primaryRegionEndpoint = $"https://{accountName}-{primaryRegionNameForUri}.documents.azure.com"; secondaryRegionEndpiont = $"https://{accountName}-{secondaryRegionNameForUri}.documents.azure.com"; databaseName = "testDb"; containerName = "testContainer"; string containerRid = "ccZ1ANCszwk="; containerResourceId = ResourceId.Parse(containerRid); List <AccountRegion> writeRegion = new List <AccountRegion>() { new AccountRegion() { Name = "East US", Endpoint = $"{primaryRegionEndpoint}:443/" } }; List <AccountRegion> readRegions = new List <AccountRegion>() { new AccountRegion() { Name = "East US", Endpoint = $"{primaryRegionEndpoint}:443/" }, new AccountRegion() { Name = "West US", Endpoint = $"{secondaryRegionEndpiont}:443/" } }; // Create a mock http handler to inject gateway responses. // MockBehavior.Strict ensures that only the mocked APIs get called mockHttpHandler = new Mock <IHttpHandler>(MockBehavior.Strict); MockSetupsHelper.SetupStrongAccountProperties( mockHttpClientHandler: mockHttpHandler, endpoint: globalEndpointUri.ToString(), accountName: accountName, writeRegions: writeRegion, readRegions: readRegions); MockSetupsHelper.SetupContainerProperties( mockHttpHandler: mockHttpHandler, regionEndpoint: primaryRegionEndpoint, databaseName: databaseName, containerName: containerName, containerRid: containerRid); MockSetupsHelper.SetupPartitionKeyRanges( mockHttpHandler: mockHttpHandler, regionEndpoint: primaryRegionEndpoint, containerResourceId: containerResourceId, partitionKeyRangeIds: out primaryRegionPartitionKeyRangeIds); MockSetupsHelper.SetupAddresses( mockHttpHandler: mockHttpHandler, partitionKeyRangeId: primaryRegionPartitionKeyRangeIds.First(), regionEndpoint: primaryRegionEndpoint, regionName: primaryRegionNameForUri, containerResourceId: containerResourceId, primaryReplicaUri: out primaryRegionprimaryReplicaUri); }
public async Task TestHttpRequestExceptionScenarioAsync() { // testhost.dll.config sets it to 2 seconds which causes it to always expire before retrying. Remove the override. System.Configuration.ConfigurationManager.AppSettings["UnavailableLocationsExpirationTimeInSeconds"] = "500"; string accountName = nameof(TestHttpRequestExceptionScenarioAsync); string primaryRegionNameForUri = "eastus"; string secondaryRegionNameForUri = "westus"; string globalEndpoint = $"https://{accountName}.documents.azure.com:443/"; Uri globalEndpointUri = new Uri(globalEndpoint); string primaryRegionEndpoint = $"https://{accountName}-{primaryRegionNameForUri}.documents.azure.com"; string secondaryRegionEndpiont = $"https://{accountName}-{secondaryRegionNameForUri}.documents.azure.com"; string databaseName = "testDb"; string containerName = "testContainer"; string containerRid = "ccZ1ANCszwk="; ResourceId containerResourceId = ResourceId.Parse(containerRid); List <AccountRegion> writeRegion = new List <AccountRegion>() { new AccountRegion() { Name = "East US", Endpoint = $"{primaryRegionEndpoint}:443/" } }; List <AccountRegion> readRegions = new List <AccountRegion>() { new AccountRegion() { Name = "East US", Endpoint = $"{primaryRegionEndpoint}:443/" }, new AccountRegion() { Name = "West US", Endpoint = $"{secondaryRegionEndpiont}:443/" } }; List <AccountRegion> writeRegionFailedOver = new List <AccountRegion>() { new AccountRegion() { Name = "West US", Endpoint = $"{secondaryRegionEndpiont}:443/" } }; List <AccountRegion> readRegionsFailedOver = new List <AccountRegion>() { new AccountRegion() { Name = "West US", Endpoint = $"{secondaryRegionEndpiont}:443/" }, new AccountRegion() { Name = "East US", Endpoint = $"{primaryRegionEndpoint}:443/" }, }; // Create a mock http handler to inject gateway responses. // MockBehavior.Strict ensures that only the mocked APIs get called Mock <IHttpHandler> mockHttpHandler = new Mock <IHttpHandler>(MockBehavior.Strict); mockHttpHandler.Setup(x => x.SendAsync( It.Is <HttpRequestMessage>(m => m.RequestUri == globalEndpointUri || m.RequestUri.ToString().Contains(primaryRegionNameForUri)), It.IsAny <CancellationToken>())).Throws(new HttpRequestException("Mock HttpRequestException to simulate region being down")); int count = 0; mockHttpHandler.Setup(x => x.SendAsync( It.Is <HttpRequestMessage>(x => x.RequestUri == new Uri(secondaryRegionEndpiont)), It.IsAny <CancellationToken>())) .Returns <HttpRequestMessage, CancellationToken>((request, cancellationToken) => { // Simulate the legacy gateway being down. After 40 requests simulate the write region pointing to new location. count++; if (count < 2) { return(Task.FromResult(MockSetupsHelper.CreateStrongAccount(accountName, writeRegion, readRegions))); } else { return(Task.FromResult(MockSetupsHelper.CreateStrongAccount(accountName, writeRegionFailedOver, readRegionsFailedOver))); } }); MockSetupsHelper.SetupContainerProperties( mockHttpHandler: mockHttpHandler, regionEndpoint: secondaryRegionEndpiont, databaseName: databaseName, containerName: containerName, containerRid: containerRid); MockSetupsHelper.SetupPartitionKeyRanges( mockHttpHandler: mockHttpHandler, regionEndpoint: secondaryRegionEndpiont, containerResourceId: containerResourceId, partitionKeyRangeIds: out IReadOnlyList <string> secondaryRegionPartitionKeyRangeIds); MockSetupsHelper.SetupAddresses( mockHttpHandler: mockHttpHandler, partitionKeyRangeId: secondaryRegionPartitionKeyRangeIds.First(), regionEndpoint: secondaryRegionEndpiont, regionName: secondaryRegionNameForUri, containerResourceId: containerResourceId, primaryReplicaUri: out TransportAddressUri secondaryRegionprimaryReplicaUri); Mock <TransportClient> mockTransport = new Mock <TransportClient>(MockBehavior.Strict); MockSetupsHelper.SetupRequestTimeoutException( mockTransport, secondaryRegionprimaryReplicaUri); // Partition key ranges are the same in both regions so the SDK // does not need to go the secondary to get the partition key ranges. // Only the addresses need to be mocked on the secondary MockSetupsHelper.SetupAddresses( mockHttpHandler: mockHttpHandler, partitionKeyRangeId: secondaryRegionPartitionKeyRangeIds.First(), regionEndpoint: secondaryRegionEndpiont, regionName: secondaryRegionNameForUri, containerResourceId: containerResourceId, primaryReplicaUri: out TransportAddressUri secondaryRegionPrimaryReplicaUri); MockSetupsHelper.SetupCreateItemResponse( mockTransport, secondaryRegionPrimaryReplicaUri); CosmosClientOptions cosmosClientOptions = new CosmosClientOptions() { EnablePartitionLevelFailover = true, ConsistencyLevel = Cosmos.ConsistencyLevel.Strong, ApplicationPreferredRegions = new List <string>() { Regions.EastUS, Regions.WestUS }, HttpClientFactory = () => new HttpClient(new HttpHandlerHelper(mockHttpHandler.Object)), TransportClientHandlerFactory = (original) => mockTransport.Object, }; using (CosmosClient customClient = new CosmosClient( globalEndpoint, Convert.ToBase64String(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())), cosmosClientOptions)) { Container container = customClient.GetContainer(databaseName, containerName); ToDoActivity toDoActivity = new ToDoActivity() { Id = "TestItem", Pk = "TestPk" }; ItemResponse <ToDoActivity> response = await container.CreateItemAsync(toDoActivity, new Cosmos.PartitionKey(toDoActivity.Pk)); Assert.AreEqual(HttpStatusCode.Created, response.StatusCode); mockTransport.VerifyAll(); mockHttpHandler.VerifyAll(); // Clears all the setups. No network calls should be done on the next operation. mockHttpHandler.Reset(); mockTransport.Reset(); MockSetupsHelper.SetupCreateItemResponse( mockTransport, secondaryRegionPrimaryReplicaUri); ToDoActivity toDoActivity2 = new ToDoActivity() { Id = "TestItem2", Pk = "TestPk" }; response = await container.CreateItemAsync(toDoActivity2, new Cosmos.PartitionKey(toDoActivity2.Pk)); Assert.AreEqual(HttpStatusCode.Created, response.StatusCode); mockTransport.Setup(x => x.Dispose()); // Reset it back to the override to avoid impacting other tests. System.Configuration.ConfigurationManager.AppSettings["UnavailableLocationsExpirationTimeInSeconds"] = "2"; } await Task.Delay(TimeSpan.FromMinutes(2)); }
private static IEnumerable <CosmosElement> ExecuteOrderByClause( IEnumerable <CosmosElement> dataSource, SqlOrderByClause sqlOrderByClause, IReadOnlyDictionary <string, PartitionKeyRange> ridToPartitionKeyRange) { // Sort by the columns left to right SqlOrderByItem firstItem = sqlOrderByClause.OrderByItems[0]; // Since we don't supply an explicit index on the policy undefined items don't show up in the sort order if (sqlOrderByClause.OrderByItems.Length == 1) { dataSource = dataSource.Where(element => firstItem.Expression.Accept( ScalarExpressionEvaluator.Singleton, element) != Undefined); } IOrderedEnumerable <CosmosElement> orderedDataSource; if (firstItem.IsDescending) { orderedDataSource = dataSource.OrderByDescending( element => firstItem.Expression.Accept( ScalarExpressionEvaluator.Singleton, element)); } else { orderedDataSource = dataSource.OrderBy( element => firstItem.Expression.Accept( ScalarExpressionEvaluator.Singleton, element)); } foreach (SqlOrderByItem sqlOrderByItem in sqlOrderByClause.OrderByItems.Skip(1)) { if (sqlOrderByItem.IsDescending) { orderedDataSource = orderedDataSource.ThenByDescending( element => sqlOrderByItem.Expression.Accept( ScalarExpressionEvaluator.Singleton, element)); } else { orderedDataSource = orderedDataSource.ThenBy( element => sqlOrderByItem.Expression.Accept( ScalarExpressionEvaluator.Singleton, element)); } } // Grab from the left most partition first orderedDataSource = orderedDataSource .ThenBy((element) => { string rid = ((CosmosString)((CosmosObject)element)["_rid"]).Value; PartitionKeyRange partitionKeyRange = ridToPartitionKeyRange[rid]; return(partitionKeyRange.MinInclusive); }, StringComparer.Ordinal); // Break all final ties within partition by document id if (firstItem.IsDescending) { orderedDataSource = orderedDataSource .ThenByDescending(element => ResourceId.Parse(((CosmosString)((CosmosObject)element)["_rid"]).Value).Document); } else { orderedDataSource = orderedDataSource .ThenBy(element => ResourceId.Parse(((CosmosString)((CosmosObject)element)["_rid"]).Value).Document); } return(orderedDataSource); }