/// <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 GetNode 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 GetNodeThread(IRingMasterRequestHandler client, CancellationToken token, int threadId) { int taskCount = 0; var clock = Stopwatch.StartNew(); while (!token.IsCancellationRequested) { while (this.QueuedNodes.TryDequeue(out string path) && !token.IsCancellationRequested) { SpinWait.SpinUntil(() => taskCount < this.AsyncTaskCount || token.IsCancellationRequested); var startTime = clock.Elapsed; var task = client.GetData(path, null) .ContinueWith( t => { Interlocked.Decrement(ref taskCount); if (t.Exception != null) { this.IncrementTotalFailures(); this.Log($"Failed to get {path}: {t.Exception.Message}"); } else { var data = t.Result; this.AddTotalDataSize(data.Length); this.IncrementTotalDataCount(); var duration = clock.Elapsed - startTime; MdmHelper.LogOperationDuration((long)duration.TotalMilliseconds, OperationType.Get); } }); Interlocked.Increment(ref taskCount); this.QueuedNodes.Enqueue(path); } } SpinWait.SpinUntil(() => taskCount == 0); return(Task.FromResult(0)); }
/// <summary> /// Queries the last applied batch id in the given ringmaster. /// </summary> /// <param name="ringMaster">An object that can handle ringmaster requests</param> /// <returns>The last applied transaction id in the given ringmaster or null if the value cannot be retrieved</returns> private static async Task <ulong> QueryRingMasterLastAppliedBatchId(IRingMasterRequestHandler ringMaster) { byte[] result = await ringMaster.GetData(TestExecutionQueue.LastAppliedBatchIdPath, watcher : null); return(BitConverter.ToUInt64(result, 0)); }
/// <summary> /// Gets the full sub tree under the given path. /// </summary> /// <param name="ringMaster">Interface to ringmaster</param> /// <param name="path">Node path</param> /// <param name="withStat">If the stat of the node should be returned</param> /// <returns>Task that will resolve on success to the root of the sub tree under the given path</returns> public static async Task <TreeNode> GetFullSubtree(this IRingMasterRequestHandler ringMaster, string path, bool withStat = false) { return(TreeNode.Deserialize(await ringMaster.GetData(PathDecoration.GetFullContentPath(path, withStat), watcher: null))); }