public async Task ParallelizeQueryThroughTokens() { ContainerCore container = null; try { // Create a container large enough to have at least 2 partitions ContainerResponse containerResponse = await this.database.CreateContainerAsync( id : Guid.NewGuid().ToString(), partitionKeyPath : "/id", throughput : 15000); container = (ContainerInlineCore)containerResponse; List <string> generatedIds = Enumerable.Range(0, 1000).Select(n => $"BasicItem{n}").ToList(); foreach (string id in generatedIds) { string item = $@" {{ ""id"": ""{id}"" }}"; using (ResponseMessage createResponse = await container.CreateItemStreamAsync( QueryFeedRangeTests.GenerateStreamFromString(item), new Cosmos.PartitionKey(id))) { Assert.IsTrue(createResponse.IsSuccessStatusCode); } } IReadOnlyList <FeedRange> feedTokens = await container.GetFeedRangesAsync(); Assert.IsTrue(feedTokens.Count > 1, " RUs of the container needs to be increased to ensure at least 2 partitions."); List <Task <List <string> > > tasks = feedTokens.Select(async feedToken => { List <string> results = new List <string>(); FeedIteratorInternal feedIterator = container.GetItemQueryStreamIterator(queryDefinition: new QueryDefinition("select * from T where STARTSWITH(T.id, \"BasicItem\")"), feedRange: feedToken, requestOptions: new QueryRequestOptions() { MaxItemCount = 10 }) as FeedIteratorInternal; string continuation = null; while (feedIterator.HasMoreResults) { using (ResponseMessage responseMessage = await feedIterator.ReadNextAsync(this.cancellationToken)) { if (responseMessage.IsSuccessStatusCode) { using (StreamReader reader = new StreamReader(responseMessage.Content)) { string json = await reader.ReadToEndAsync(); JArray documents = (JArray)JObject.Parse(json).SelectToken("Documents"); foreach (JObject document in documents) { results.Add(document.SelectToken("id").ToString()); } } } continuation = responseMessage.ContinuationToken; break; } } feedIterator = container.GetItemQueryStreamIterator(queryDefinition: new QueryDefinition("select * from T where STARTSWITH(T.id, \"BasicItem\")"), feedRange: feedToken, continuationToken: continuation, requestOptions: new QueryRequestOptions() { MaxItemCount = 10 }) as FeedIteratorInternal; while (feedIterator.HasMoreResults) { using (ResponseMessage responseMessage = await feedIterator.ReadNextAsync(this.cancellationToken)) { if (responseMessage.IsSuccessStatusCode) { using (StreamReader reader = new StreamReader(responseMessage.Content)) { string json = await reader.ReadToEndAsync(); JArray documents = (JArray)JObject.Parse(json).SelectToken("Documents"); foreach (JObject document in documents) { results.Add(document.SelectToken("id").ToString()); } } } } } return(results); }).ToList(); await Task.WhenAll(tasks); CollectionAssert.AreEquivalent(generatedIds, tasks.SelectMany(t => t.Result).ToList()); } finally { await container?.DeleteContainerAsync(); } }
public async Task ReadFeedIteratorCore_CrossPartitionBiDirectional(bool useStatelessIteration) { ContainerCore container = null; try { ContainerResponse containerResponse = await this.database.CreateContainerAsync( new ContainerProperties(id : Guid.NewGuid().ToString(), partitionKeyPath : "/id"), throughput : 50000, cancellationToken : this.cancellationToken); container = (ContainerInlineCore)containerResponse; //create items const int total = 30; QueryRequestOptions requestOptions = new QueryRequestOptions() { MaxItemCount = 10 }; List <string> items = new List <string>(); for (int i = 0; i < total; i++) { string item = $@" {{ ""id"": ""{i}"" }}"; using (ResponseMessage createResponse = await container.CreateItemStreamAsync( ReadFeedRangeTests.GenerateStreamFromString(item), new Cosmos.PartitionKey(i.ToString()))) { Assert.IsTrue(createResponse.IsSuccessStatusCode); } } string continuation = null; FeedIterator iter = container.GetItemQueryStreamIterator( continuationToken: continuation, requestOptions: requestOptions); int count = 0; List <string> forwardOrder = new List <string>(); while (iter.HasMoreResults) { if (useStatelessIteration) { iter = container.GetItemQueryStreamIterator( continuationToken: continuation, requestOptions: requestOptions); } using (ResponseMessage response = await iter.ReadNextAsync()) { Assert.IsNotNull(response); continuation = response.ContinuationToken; using (StreamReader reader = new StreamReader(response.Content)) { string json = await reader.ReadToEndAsync(); JArray documents = (JArray)JObject.Parse(json).SelectToken("Documents"); count += documents.Count; if (documents.Any()) { forwardOrder.Add(documents.First().SelectToken("id").ToString()); } } } } Assert.IsNotNull(forwardOrder); Assert.AreEqual(total, count); Assert.IsFalse(forwardOrder.Where(x => string.IsNullOrEmpty(x)).Any()); requestOptions.Properties = requestOptions.Properties = new Dictionary <string, object>(); requestOptions.Properties.Add(Documents.HttpConstants.HttpHeaders.EnumerationDirection, (byte)BinaryScanDirection.Reverse); count = 0; List <string> reverseOrder = new List <string>(); continuation = null; iter = container .GetItemQueryStreamIterator(queryDefinition: null, continuationToken: continuation, requestOptions: requestOptions); while (iter.HasMoreResults) { if (useStatelessIteration) { iter = container .GetItemQueryStreamIterator(queryDefinition: null, continuationToken: continuation, requestOptions: requestOptions); } using (ResponseMessage response = await iter.ReadNextAsync()) { continuation = response.ContinuationToken; Assert.IsNotNull(response); using (StreamReader reader = new StreamReader(response.Content)) { string json = await reader.ReadToEndAsync(); JArray documents = (JArray)JObject.Parse(json).SelectToken("Documents"); count += documents.Count; if (documents.Any()) { reverseOrder.Add(documents.First().SelectToken("id").ToString()); } } } } Assert.IsNotNull(reverseOrder); Assert.AreEqual(total, count); forwardOrder.Reverse(); CollectionAssert.AreEqual(forwardOrder, reverseOrder); Assert.IsFalse(reverseOrder.Where(x => string.IsNullOrEmpty(x)).Any()); } finally { await container?.DeleteContainerAsync(); } }