private static async Task LoadData(Benchmark benchmark) { try { List <SampleCustomer> customers = SampleCustomer.GenerateCustomers(benchmark.partitionKeyValue, 100); //Stored Proc for bulk inserting data string scriptId = "BulkImport"; string body = File.ReadAllText(@"spBulkUpload.js"); StoredProcedureResponse sproc = await benchmark.container.Scripts.CreateStoredProcedureAsync(new StoredProcedureProperties(scriptId, body)); int inserted = 0; while (inserted < customers.Count) { dynamic[] args = new dynamic[] { customers.Skip(inserted) }; StoredProcedureExecuteResponse <int> result = await benchmark.container.Scripts.ExecuteStoredProcedureAsync <int>(scriptId, new PartitionKey(benchmark.partitionKeyValue), args); inserted += result.Resource; Console.WriteLine($"Inserted {inserted} items."); } } catch (Exception e) { Console.WriteLine(e.Message + "\nPress any key to continue"); Console.ReadKey(); } }
private async Task VerifyItemReplicated(ConflictGenerator conflict, SampleCustomer customer) { bool notifyOnce = false; foreach (ReplicaRegion region in conflict.replicaRegions) { Container container = region.container; bool isReplicated = false; while (!isReplicated) { try { //Issue a read for an item that doesn't exist to warm the connection await container.ReadItemAsync <SampleCustomer>(customer.Id, new PartitionKey(customer.MyPartitionKey)); isReplicated = true; if (notifyOnce) { Console.WriteLine("Item is replicated"); } } catch { if (!notifyOnce) { Console.WriteLine("Waiting for item to replicate in all regions"); notifyOnce = true; } //swallow any errors and wait 250ms to retry await Task.Delay(250); } } } }
public static async Task WriteBenchmark(Benchmark benchmark) { //Verify the benchmark is setup await InitializeBenchmark(benchmark); //Customers to insert List <SampleCustomer> customers = SampleCustomer.GenerateCustomers(benchmark.partitionKeyValue, 100); //Console.WriteLine($"\nTest {customers.Count} {GetBenchmarkType(benchmark)} against {benchmark.testName} account in {benchmark.writeRegion} from {benchmark.testRegion}\nPress any key to continue\n..."); Console.WriteLine($"\n{benchmark.testDescription}\nPress any key to continue\n..."); Console.ReadKey(true); int test = 0; List <Result> results = new List <Result>(); //Individual Benchmark results Stopwatch stopwatch = new Stopwatch(); foreach (SampleCustomer customer in customers) { stopwatch.Start(); ItemResponse <SampleCustomer> response = await benchmark.container.CreateItemAsync <SampleCustomer>(customer, new PartitionKey(benchmark.partitionKeyValue)); stopwatch.Stop(); Console.WriteLine($"Write {test++} of {customers.Count}, region: {benchmark.writeRegion}, Latency: {stopwatch.ElapsedMilliseconds} ms, Request Charge: {response.RequestCharge} RUs"); results.Add(new Result(stopwatch.ElapsedMilliseconds, response.RequestCharge)); stopwatch.Reset(); } OutputResults(benchmark, results); }
public static async Task CustomSyncBenchmark(Benchmark benchmark) { //Verify the benchmark is setup await Benchmark.InitializeBenchmark(benchmark); //Customers to insert List <SampleCustomer> customers = SampleCustomer.GenerateCustomers(benchmark.partitionKeyValue, 100); //Create Read client for custom sync CosmosClient syncClient = new CosmosClient(benchmark.endpoint, benchmark.key, new CosmosClientOptions { ApplicationRegion = benchmark.readRegion }); Container syncContainer = syncClient.GetContainer(benchmark.databaseId, benchmark.containerId); //Console.WriteLine($"\nTest {customers.Count} {GetBenchmarkType(benchmark)} against {benchmark.testName} account in {benchmark.writeRegion} from {benchmark.testName}\nPress any key to continue\n..."); Console.WriteLine($"\n{benchmark.testDescription}\nPress any key to continue\n..."); Console.ReadKey(true); int test = 0; List <Result> results = new List <Result>(); //Individual Benchmark results Stopwatch stopwatch = new Stopwatch(); foreach (SampleCustomer customer in customers) { stopwatch.Start(); //write item in one region ItemResponse <SampleCustomer> response = await benchmark.container.CreateItemAsync <SampleCustomer>(customer, new PartitionKey(benchmark.partitionKeyValue)); //read back in a second passing the session token with the LSN for the write ItemResponse <SampleCustomer> syncResponse = await syncContainer.ReadItemAsync <SampleCustomer>( customer.Id, new PartitionKey(benchmark.partitionKeyValue), new ItemRequestOptions { SessionToken = response.Headers.Session }); stopwatch.Stop(); Console.WriteLine($"Write {test++} of {customers.Count}, region: {benchmark.writeRegion}, Latency: {stopwatch.ElapsedMilliseconds} ms, Request Charge: {response.RequestCharge} RUs"); results.Add(new Result(stopwatch.ElapsedMilliseconds, response.RequestCharge)); stopwatch.Reset(); } OutputResults(benchmark, results); }
public async Task ProcessConflicts(ConflictGenerator conflictGenerator) { //Use West US 2 region to review conflicts ReplicaRegion replicaRegion = conflictGenerator.replicaRegions.Find(s => s.region == "West US 2"); Container container = replicaRegion.client.GetContainer(conflictGenerator.databaseId, conflictGenerator.containerId); FeedIterator <ConflictProperties> conflictFeed = container.Conflicts.GetConflictQueryIterator <ConflictProperties>(); while (conflictFeed.HasMoreResults) { FeedResponse <ConflictProperties> conflicts = await conflictFeed.ReadNextAsync(); foreach (ConflictProperties c in conflicts) { //Read the conflict and committed item SampleCustomer conflict = container.Conflicts.ReadConflictContent <SampleCustomer>(c); SampleCustomer committed = await container.Conflicts.ReadCurrentAsync <SampleCustomer>(c, new PartitionKey(conflict.MyPartitionKey)); switch (c.OperationKind) { case OperationKind.Create: //For Inserts make the higher UserDefinedId value the winner if (conflict.UserDefinedId >= committed.UserDefinedId) { await container.ReplaceItemAsync <SampleCustomer>(conflict, conflict.Id, new PartitionKey(conflict.MyPartitionKey)); } break; case OperationKind.Replace: //For Updates make the lower UserDefinedId value the winner if (conflict.UserDefinedId <= committed.UserDefinedId) { await container.ReplaceItemAsync <SampleCustomer>(conflict, conflict.Id, new PartitionKey(conflict.MyPartitionKey)); } break; case OperationKind.Delete: //Generally don't resolve deleted items so do nothing break; } // Delete the conflict await container.Conflicts.DeleteAsync(c, new PartitionKey(conflict.MyPartitionKey)); } } }
private async Task <SampleCustomer> UpdateItemAsync(Container container, SampleCustomer customer) { Console.WriteLine($"Update - Name: {customer.Name}, City: {customer.City}, UserDefId: {customer.UserDefinedId}, Region: {customer.Region}"); try { ItemResponse <SampleCustomer> response = await container.ReplaceItemAsync <SampleCustomer>( customer, customer.Id, new PartitionKey(customer.MyPartitionKey)); return(response.Resource); } catch { //Unable to create conflict return(null); } }
public async Task GenerateInsertConflicts(ConflictGenerator conflict) { try { bool isConflicts = false; Console.WriteLine($"{conflict.testName}\nPress any key to continue...\n"); Console.ReadKey(true); //Verify the containers are created and referenced await InitializeConflicts(conflict); while (!isConflicts) { //Generate a sample customer SampleCustomer customer = SampleCustomer.GenerateCustomers(conflict.partitionKeyValue, 1)[0]; //Task list for async inserts List <Task <SampleCustomer> > tasks = new List <Task <SampleCustomer> >(); //Insert same customer into every region foreach (ReplicaRegion replicaRegion in conflict.replicaRegions) { tasks.Add(InsertItemAsync(replicaRegion.container, replicaRegion.region, customer)); } //await tasks SampleCustomer[] insertedItems = await Task.WhenAll(tasks); //Verify conflicts. If two or more items returned then conflicts occurred isConflicts = IsConflict(insertedItems); } } catch (CosmosException e) { Console.WriteLine(e.Message + "\nPress any key to continue"); Console.ReadKey(); } }
private static SampleCustomer Clone(SampleCustomer source) { //Deep copy Document object return(JsonConvert.DeserializeObject <SampleCustomer>(JsonConvert.SerializeObject(source))); }
public async Task GenerateUpdateConflicts(ConflictGenerator conflict) { try { //Verify the containers are created and referenced await InitializeConflicts(conflict); bool isConflicts = false; Console.WriteLine($"\n{conflict.testName}\nPress any key to continue..."); Console.ReadKey(true); Console.WriteLine($"Insert an item to create an update conflict on.\n"); //Get reference to West US 2 region to insert a customer ReplicaRegion insertRegion = conflict.replicaRegions.Find(s => s.region == "West US 2"); //Container to insert customer Container insertContainer = insertRegion.container; //Generate a new customer SampleCustomer seedCustomer = SampleCustomer.GenerateCustomers(conflict.partitionKeyValue, 1)[0]; //Insert Customer seedCustomer = await InsertItemAsync(insertContainer, insertRegion.region, seedCustomer); //Wait for item to replicate globally Console.WriteLine($"\nAllow item to replicate.\n"); //await Task.Delay(5000); await VerifyItemReplicated(conflict, seedCustomer); //Task list for async updates IList <Task <SampleCustomer> > tasks = new List <Task <SampleCustomer> >(); //Read back the replicated customer and get the ETag ItemResponse <SampleCustomer> customerResponse = await insertContainer.ReadItemAsync <SampleCustomer>(seedCustomer.Id, new PartitionKey(seedCustomer.MyPartitionKey)); Console.WriteLine($"Attempting simultaneous update in {replicaRegions.Count} regions\n"); while (!isConflicts) { foreach (ReplicaRegion updateRegion in conflict.replicaRegions) { //DeepCopy the item SampleCustomer updateCustomer = ConflictGenerator.Clone(seedCustomer); //Update region to where update is made and provide new UserDefinedId value updateCustomer.Region = updateRegion.region; updateCustomer.UserDefinedId = ConflictGenerator.RandomNext(0, 1000); //Add update to Task List tasks.Add(UpdateItemAsync(updateRegion.container, updateCustomer)); } SampleCustomer[] updateCustomers = await Task.WhenAll(tasks); isConflicts = IsConflict(updateCustomers); } } catch (Exception e) { Console.WriteLine(e.Message + "\nPress any key to continue"); Console.ReadKey(); } }
private async Task <SampleCustomer> InsertItemAsync(Container container, string region, SampleCustomer item) { //DeepCopy the item item = ConflictGenerator.Clone(item); //Update the region item.Region = region; //Update UserDefinedId to random number for Conflict Resolution item.UserDefinedId = ConflictGenerator.RandomNext(0, 1000); Console.WriteLine($"Attempting insert - Name: {item.Name}, City: {item.City}, UserDefId: {item.UserDefinedId}, Region: {item.Region}"); try { ItemResponse <SampleCustomer> response = await container.CreateItemAsync <SampleCustomer>(item, new PartitionKey(item.MyPartitionKey)); if (response.StatusCode == System.Net.HttpStatusCode.Conflict) { return(null); //item has already replicated so not possible to generate conflict } else { return(response.Resource); } } catch (CosmosException e) { //Conflict error if (e.StatusCode == HttpStatusCode.Conflict) { return(null); } else { throw e; } } }
public async Task ProcessConflicts(ConflictGenerator conflictGenerator) { Console.WriteLine($"\nReading conflicts feed to process any conflicts.\n{Helpers.Line}\nPress any key to continue...\n"); //Use West US 2 region to review conflicts ReplicaRegion replicaRegion = conflictGenerator.replicaRegions.Find(s => s.region == "West US 2"); Container container = replicaRegion.client.GetContainer(conflictGenerator.databaseId, conflictGenerator.containerId); FeedIterator <ConflictProperties> conflictFeed = container.Conflicts.GetConflictQueryIterator <ConflictProperties>(); while (conflictFeed.HasMoreResults) { FeedResponse <ConflictProperties> conflictFeedResponse = await conflictFeed.ReadNextAsync(); Console.WriteLine($"There are {conflictFeedResponse.Count} conflict(s) to process.\nPress any key to continue\n"); Console.ReadKey(true); foreach (ConflictProperties conflictItem in conflictFeedResponse) { //Read the conflict and committed item SampleCustomer conflict = container.Conflicts.ReadConflictContent <SampleCustomer>(conflictItem); SampleCustomer committed = await container.Conflicts.ReadCurrentAsync <SampleCustomer>(conflictItem, new PartitionKey(conflict.MyPartitionKey)); Console.WriteLine($"Processing conflict on customer: {committed.Name}, in {committed.Region} region with conflict in {conflict.Region} region.\n{Helpers.Line}\n"); Console.WriteLine($"Conflict UserDefined Id = {conflict.UserDefinedId}. Committed UserDefined Id = {committed.UserDefinedId}"); switch (conflictItem.OperationKind) { case OperationKind.Create: //For Inserts make the higher UserDefinedId value the winner Console.WriteLine($"Processing insert conflict.\nReplace committed item if conflict has >= UserDefinedId."); if (conflict.UserDefinedId >= committed.UserDefinedId) { Console.WriteLine($"Conflict is the winner. Press any key to replace committed item with conflict.\n"); Console.ReadKey(true); await container.ReplaceItemAsync <SampleCustomer>(conflict, conflict.Id, new PartitionKey(conflict.MyPartitionKey)); } else { Console.WriteLine($"Committed item is the winner. Press any key to continue.\n"); Console.ReadKey(true); } break; case OperationKind.Replace: //For Updates make the lower UserDefinedId value the winner Console.WriteLine($"Processing update conflict.\nUpdate committed item if conflict has a <= UserDefinedId."); if (conflict.UserDefinedId <= committed.UserDefinedId) { Console.WriteLine($"Conflict is the winner. Press any key to replace committed item with conflict.\n"); Console.ReadKey(true); await container.ReplaceItemAsync <SampleCustomer>(conflict, conflict.Id, new PartitionKey(conflict.MyPartitionKey)); } else { Console.WriteLine($"Committed item is the winner. Press any key to continue.\n"); Console.ReadKey(true); } break; case OperationKind.Delete: //Generally don't resolve deleted items so do nothing break; } // Delete the conflict await container.Conflicts.DeleteAsync(conflictItem, new PartitionKey(conflict.MyPartitionKey)); } } }