/// <summary> /// Tests basic ringmaster functionality /// </summary> /// <param name="ringMaster">RingMaster client</param> /// <param name="instanceRootPath">Root path that must be used by this instance for creating nodes</param> /// <param name="iteration">Current iteration</param> /// <returns><c>true</c> if the functionality test passed, <c>false</c> otherwise</returns> private async Task <bool> TestRingMasterFunctionality(IRingMasterRequestHandler ringMaster, string instanceRootPath, long iteration) { var timer = Stopwatch.StartNew(); try { var random = new Random(); string nodePath = string.Format($"{instanceRootPath}/Node"); RingMasterWatchdogEventSource.Log.Create(iteration, nodePath); await ringMaster.Create(nodePath, null, null, CreateMode.PersistentAllowPathCreation, throwIfNodeExists : false); RingMasterWatchdogEventSource.Log.Exists(iteration, nodePath); var nodeStat = await ringMaster.Exists(nodePath, watcher : null); int nodeDataLength = random.Next(RingMasterWatchdog.DefaultMaxNodeDataLength); byte[] nodeData = new byte[nodeDataLength]; random.NextBytes(nodeData); RingMasterWatchdogEventSource.Log.SetData(iteration, nodePath, nodeData.Length); await ringMaster.SetData(nodePath, nodeData, nodeStat.Version); RingMasterWatchdogEventSource.Log.GetData(iteration, nodePath); var retrievedData = await ringMaster.GetData(nodePath, watcher : null); if (retrievedData == null) { RingMasterWatchdogEventSource.Log.GetDataFailed_RetrievedDataIsNull(iteration, nodePath, nodeData.Length); throw new InvalidOperationException($"Node {nodePath}: Retrieved data is null. expectedDataLength={nodeData.Length}"); } if (retrievedData.Length != nodeData.Length) { RingMasterWatchdogEventSource.Log.GetDataFailed_RetrievedDataLengthMismatch(iteration, nodePath, nodeData.Length, retrievedData.Length); throw new InvalidOperationException($"Node {nodePath}: Retrieved data length mismatch retrievedDataLength={retrievedData.Length} expectedDataLength={nodeData.Length}"); } if (!retrievedData.SequenceEqual(nodeData)) { RingMasterWatchdogEventSource.Log.GetDataFailed_RetrievedDataIsDifferent(iteration, nodePath, nodeData.Length); throw new InvalidOperationException($"Node {nodePath}: Retrieved data is different"); } RingMasterWatchdogEventSource.Log.Delete(iteration, nodePath, nodeStat.Version); await ringMaster.Delete(nodePath, -1); RingMasterWatchdogEventSource.Log.TestRingMasterFunctionalitySucceeded(iteration, timer.ElapsedMilliseconds); return(true); } catch (System.Exception ex) { RingMasterWatchdogEventSource.Log.TestRingMasterFunctionalityFailed(iteration, timer.ElapsedMilliseconds, ex.ToString()); } return(false); }
/// <summary> /// Work load for testing SetNode method /// </summary> /// <param name="client">RingMasterClient object</param> /// <param name="token">Cancellation token</param> /// <param name="threadId">Thread sequence number</param> /// <returns>Async task</returns> private Task SetNodeThread(IRingMasterRequestHandler client, CancellationToken token, int threadId) { int taskCount = 0; var rnd = new Random(); var clock = Stopwatch.StartNew(); while (!token.IsCancellationRequested) { while (this.QueuedNodes.TryDequeue(out string path) && !token.IsCancellationRequested) { var data = Helpers.MakeRandomData(rnd, rnd.Next(this.MinDataSize, this.MaxDataSize)); SpinWait.SpinUntil(() => taskCount < this.AsyncTaskCount || token.IsCancellationRequested); var startTime = clock.Elapsed; var task = client.SetData(path, data, -1) .ContinueWith( t => { Interlocked.Decrement(ref taskCount); if (t.Exception != null) { this.IncrementTotalFailures(); this.Log($"Failed to set {path}: {t.Exception.Message}"); } else { this.AddTotalDataSize(data.Length); this.IncrementTotalDataCount(); var duration = clock.Elapsed - startTime; MdmHelper.LogOperationDuration((long)duration.TotalMilliseconds, OperationType.Set); } }); Interlocked.Increment(ref taskCount); this.QueuedNodes.Enqueue(path); } } SpinWait.SpinUntil(() => taskCount == 0); return(Task.FromResult(0)); }