private static bool TryParseReadWriteQueryPercentages( string configuration, out ReadWriteQueryPercentage readWriteQueryPercentage) { readWriteQueryPercentage = default; string[] readWriteQueryPctList = configuration.Split(","); if (readWriteQueryPctList.Length != 3) { return(false); } if (!int.TryParse(readWriteQueryPctList[0], out int readPercentage) || !int.TryParse(readWriteQueryPctList[1], out int writePercentage) || !int.TryParse(readWriteQueryPctList[2], out int queryPercentage)) { return(false); } if ((readPercentage + writePercentage + queryPercentage) != 100) { return(false); } readWriteQueryPercentage = new ReadWriteQueryPercentage() { ReadPercentage = readPercentage, WritePercentage = writePercentage, QueryPercentage = queryPercentage }; return(true); }
private async Task ExecuteOperationsAsync( CTLConfig config, ILogger logger, IMetrics metrics, InitializationResult initializationResult, ReadWriteQueryPercentage readWriteQueryPercentage, CancellationToken cancellationToken) { logger.LogInformation("Initializing counters and metrics."); CounterOptions readSuccessMeter = new CounterOptions { Name = "#Read Successful Operations", Context = nameof(WorkloadType.ReadWriteQuery) }; CounterOptions readFailureMeter = new CounterOptions { Name = "#Read Unsuccessful Operations", Context = nameof(WorkloadType.ReadWriteQuery) }; CounterOptions writeSuccessMeter = new CounterOptions { Name = "#Write Successful Operations", Context = nameof(WorkloadType.ReadWriteQuery) }; CounterOptions writeFailureMeter = new CounterOptions { Name = "#Write Unsuccessful Operations", Context = nameof(WorkloadType.ReadWriteQuery) }; CounterOptions querySuccessMeter = new CounterOptions { Name = "#Query Successful Operations", Context = nameof(WorkloadType.ReadWriteQuery) }; CounterOptions queryFailureMeter = new CounterOptions { Name = "#Query Unsuccessful Operations", Context = nameof(WorkloadType.ReadWriteQuery) }; TimerOptions readLatencyTimer = new TimerOptions { Name = "Read latency", MeasurementUnit = Unit.Requests, DurationUnit = TimeUnit.Milliseconds, RateUnit = TimeUnit.Seconds, Context = nameof(WorkloadType.ReadWriteQuery), Reservoir = () => new App.Metrics.ReservoirSampling.Uniform.DefaultAlgorithmRReservoir() }; TimerOptions writeLatencyTimer = new TimerOptions { Name = "Write latency", MeasurementUnit = Unit.Requests, DurationUnit = TimeUnit.Milliseconds, RateUnit = TimeUnit.Seconds, Context = nameof(WorkloadType.ReadWriteQuery), Reservoir = () => new App.Metrics.ReservoirSampling.Uniform.DefaultAlgorithmRReservoir() }; TimerOptions queryLatencyTimer = new TimerOptions { Name = "Query latency", MeasurementUnit = Unit.Requests, DurationUnit = TimeUnit.Milliseconds, RateUnit = TimeUnit.Seconds, Context = nameof(WorkloadType.ReadWriteQuery), Reservoir = () => new App.Metrics.ReservoirSampling.Uniform.DefaultAlgorithmRReservoir() }; SemaphoreSlim concurrencyControlSemaphore = new SemaphoreSlim(config.Concurrency); Stopwatch stopwatch = Stopwatch.StartNew(); int writeRange = readWriteQueryPercentage.ReadPercentage + readWriteQueryPercentage.WritePercentage; long diagnosticsThresholdDuration = (long)config.DiagnosticsThresholdDurationAsTimespan.TotalMilliseconds; List <Task> operations = new List <Task>((int)config.Operations); for (long i = 0; ShouldContinue(stopwatch, i, config); i++) { long index = (long)i % 100; if (index < readWriteQueryPercentage.ReadPercentage) { operations.Add(CTLOperationHandler <ItemResponse <Dictionary <string, string> > > .PerformOperationAsync( semaphoreSlim: concurrencyControlSemaphore, diagnosticsLoggingThreshold: diagnosticsThresholdDuration, createTimerContext: () => metrics.Measure.Timer.Time(readLatencyTimer), resultProducer: new SingleExecutionResultProducer <ItemResponse <Dictionary <string, string> > >(() => this.CreateReadOperation( operation: i, containers: initializationResult.Containers, createdDocumentsPerContainer: this.createdDocuments)), onSuccess: () => metrics.Measure.Counter.Increment(readSuccessMeter), onFailure: (Exception ex) => { metrics.Measure.Counter.Increment(readFailureMeter); logger.LogError(ex, "Failure during read operation"); }, logDiagnostics: (ItemResponse <Dictionary <string, string> > response) => logger.LogInformation("Read request took more than latency threshold {0}, diagnostics: {1}", config.DiagnosticsThresholdDuration, response.Diagnostics.ToString()), cancellationToken: cancellationToken)); } else if (index < writeRange) { operations.Add(CTLOperationHandler <ItemResponse <Dictionary <string, string> > > .PerformOperationAsync( semaphoreSlim: concurrencyControlSemaphore, diagnosticsLoggingThreshold: diagnosticsThresholdDuration, createTimerContext: () => metrics.Measure.Timer.Time(writeLatencyTimer), resultProducer: new SingleExecutionResultProducer <ItemResponse <Dictionary <string, string> > >(() => this.CreateWriteOperation( operation: i, containers: initializationResult.Containers, isContentResponseOnWriteEnabled: config.IsContentResponseOnWriteEnabled)), onSuccess: () => metrics.Measure.Counter.Increment(writeSuccessMeter), onFailure: (Exception ex) => { metrics.Measure.Counter.Increment(writeFailureMeter); logger.LogError(ex, "Failure during write operation"); }, logDiagnostics: (ItemResponse <Dictionary <string, string> > response) => logger.LogInformation("Write request took more than latency threshold {0}, diagnostics: {1}", config.DiagnosticsThresholdDuration, response.Diagnostics.ToString()), cancellationToken: cancellationToken)); } else { operations.Add(CTLOperationHandler <FeedResponse <Dictionary <string, string> > > .PerformOperationAsync( semaphoreSlim: concurrencyControlSemaphore, diagnosticsLoggingThreshold: diagnosticsThresholdDuration, createTimerContext: () => metrics.Measure.Timer.Time(queryLatencyTimer), resultProducer: new IteratorResultProducer <Dictionary <string, string> >(this.CreateQueryOperation( operation: i, containers: initializationResult.Containers)), onSuccess: () => metrics.Measure.Counter.Increment(querySuccessMeter), onFailure: (Exception ex) => { metrics.Measure.Counter.Increment(queryFailureMeter); logger.LogError(ex, "Failure during query operation"); }, logDiagnostics: (FeedResponse <Dictionary <string, string> > response) => logger.LogInformation("Query request took more than latency threshold {0}, diagnostics: {1}", config.DiagnosticsThresholdDuration, response.Diagnostics.ToString()), cancellationToken: cancellationToken)); } } await Task.WhenAll(operations); stopwatch.Stop(); logger.LogInformation("[{0}] operations performed in [{1}] seconds.", config.Operations, stopwatch.Elapsed.TotalSeconds); }
private async Task ExecuteOperationsAsync( CTLConfig config, ILogger logger, IMetrics metrics, string loggingContextIdentifier, InitializationResult initializationResult, ReadWriteQueryPercentage readWriteQueryPercentage, CancellationToken cancellationToken) { logger.LogInformation("Initializing counters and metrics."); CounterOptions readSuccessMeter = new CounterOptions { Name = "#Read Successful Operations", Context = loggingContextIdentifier }; CounterOptions readFailureMeter = new CounterOptions { Name = "#Read Unsuccessful Operations", Context = loggingContextIdentifier }; CounterOptions writeSuccessMeter = new CounterOptions { Name = "#Write Successful Operations", Context = loggingContextIdentifier }; CounterOptions writeFailureMeter = new CounterOptions { Name = "#Write Unsuccessful Operations", Context = loggingContextIdentifier }; CounterOptions querySuccessMeter = new CounterOptions { Name = "#Query Successful Operations", Context = loggingContextIdentifier }; CounterOptions queryFailureMeter = new CounterOptions { Name = "#Query Unsuccessful Operations", Context = loggingContextIdentifier }; TimerOptions readLatencyTimer = new TimerOptions { Name = "Read latency", MeasurementUnit = Unit.Requests, DurationUnit = TimeUnit.Milliseconds, RateUnit = TimeUnit.Seconds, Context = loggingContextIdentifier, Reservoir = () => new App.Metrics.ReservoirSampling.Uniform.DefaultAlgorithmRReservoir() }; TimerOptions writeLatencyTimer = new TimerOptions { Name = "Write latency", MeasurementUnit = Unit.Requests, DurationUnit = TimeUnit.Milliseconds, RateUnit = TimeUnit.Seconds, Context = loggingContextIdentifier, Reservoir = () => new App.Metrics.ReservoirSampling.Uniform.DefaultAlgorithmRReservoir() }; TimerOptions queryLatencyTimer = new TimerOptions { Name = "Query latency", MeasurementUnit = Unit.Requests, DurationUnit = TimeUnit.Milliseconds, RateUnit = TimeUnit.Seconds, Context = loggingContextIdentifier, Reservoir = () => new App.Metrics.ReservoirSampling.Uniform.DefaultAlgorithmRReservoir() }; SemaphoreSlim concurrencyControlSemaphore = new SemaphoreSlim(config.Concurrency); Stopwatch stopwatch = Stopwatch.StartNew(); int writeRange = readWriteQueryPercentage.ReadPercentage + readWriteQueryPercentage.WritePercentage; List <Task> operations = new List <Task>(); for (long i = 0; ShouldContinue(stopwatch, i, config); i++) { await concurrencyControlSemaphore.WaitAsync(cancellationToken); long index = i % 100; if (index < readWriteQueryPercentage.ReadPercentage) { operations.Add(CTLOperationHandler <ItemResponse <Dictionary <string, string> > > .PerformOperationAsync( createTimerContext: () => metrics.Measure.Timer.Time(readLatencyTimer), resultProducer: new SingleExecutionResultProducer <ItemResponse <Dictionary <string, string> > >(() => this.CreateReadOperation( operation: i, partitionKeyAttributeName: config.CollectionPartitionKey, containers: initializationResult.Containers, createdDocumentsPerContainer: this.createdDocuments)), onSuccess: () => { concurrencyControlSemaphore.Release(); metrics.Measure.Counter.Increment(readSuccessMeter); }, onFailure: (Exception ex) => { concurrencyControlSemaphore.Release(); metrics.Measure.Counter.Increment(readFailureMeter); Utils.LogError(logger, loggingContextIdentifier, ex, "Failure during read operation"); }, logDiagnostics: (ItemResponse <Dictionary <string, string> > response, TimeSpan latency) => Utils.LogDiagnostics( logger: logger, operationName: "Read", timerContextLatency: latency, config: config, cosmosDiagnostics: response.Diagnostics))); } else if (index < writeRange) { operations.Add(CTLOperationHandler <ItemResponse <Dictionary <string, string> > > .PerformOperationAsync( createTimerContext: () => metrics.Measure.Timer.Time(writeLatencyTimer), resultProducer: new SingleExecutionResultProducer <ItemResponse <Dictionary <string, string> > >(() => this.CreateWriteOperation( operation: i, partitionKeyAttributeName: config.CollectionPartitionKey, containers: initializationResult.Containers, isContentResponseOnWriteEnabled: config.IsContentResponseOnWriteEnabled)), onSuccess: () => { concurrencyControlSemaphore.Release(); metrics.Measure.Counter.Increment(writeSuccessMeter); }, onFailure: (Exception ex) => { concurrencyControlSemaphore.Release(); metrics.Measure.Counter.Increment(writeFailureMeter); Utils.LogError(logger, loggingContextIdentifier, ex, "Failure during write operation"); }, logDiagnostics: (ItemResponse <Dictionary <string, string> > response, TimeSpan latency) => Utils.LogDiagnostics( logger: logger, operationName: "Write", timerContextLatency: latency, config: config, cosmosDiagnostics: response.Diagnostics))); } else { operations.Add(CTLOperationHandler <FeedResponse <Dictionary <string, string> > > .PerformOperationAsync( createTimerContext: () => metrics.Measure.Timer.Time(queryLatencyTimer), resultProducer: new IteratorResultProducer <Dictionary <string, string> >(this.CreateQueryOperation( operation: i, containers: initializationResult.Containers)), onSuccess: () => { concurrencyControlSemaphore.Release(); metrics.Measure.Counter.Increment(querySuccessMeter); }, onFailure: (Exception ex) => { concurrencyControlSemaphore.Release(); metrics.Measure.Counter.Increment(queryFailureMeter); Utils.LogError(logger, loggingContextIdentifier, ex, "Failure during query operation"); }, logDiagnostics: (FeedResponse <Dictionary <string, string> > response, TimeSpan latency) => Utils.LogDiagnostics( logger: logger, operationName: "Query", timerContextLatency: latency, config: config, cosmosDiagnostics: response.Diagnostics))); } } await Task.WhenAll(operations); stopwatch.Stop(); logger.LogInformation("[{0}] operations performed in [{1}] seconds.", operations.Count, stopwatch.Elapsed.TotalSeconds); }