/// <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 Create 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 DeleteNodeThread(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.Delete(path, -1, DeleteMode.None) .ContinueWith( t => { Interlocked.Decrement(ref taskCount); if (!t.Result) { this.Log($"Failed to delete {path}."); if (t.Exception != null) { this.Log($"Exception: {t.Exception.Message}"); this.IncrementTotalFailures(); } } else { this.IncrementTotalDataCount(); var duration = clock.Elapsed - startTime; MdmHelper.LogOperationDuration((long)duration.TotalMilliseconds, OperationType.Delete); } }); Interlocked.Increment(ref taskCount); } } SpinWait.SpinUntil(() => taskCount == 0); return(Task.FromResult(0)); }
/// <summary> /// Registers to notifications for any change under the given path. /// </summary> /// <param name="ringMaster">The ringmaster handler to use.</param> /// <param name="timeout">The timeout for retries on setting the watcher.</param> /// <param name="pathToWatch">The path to watch.</param> /// <param name="oneuse">if set to <c>true</c> there will be just one notification triggered, and the watcher will be removed then.</param> /// <param name="sessionlocal">if set to <c>true</c> we will use a local session for this on the server.</param> /// <param name="onChange">The notification callback.</param> /// <returns>an async task indicating a boolean where true means the callback will be invoked</returns> public static async Task <bool> RegisterOnAnySubPathChange( this IRingMasterRequestHandler ringMaster, int timeout, string pathToWatch, bool oneuse, bool sessionlocal, RegisterOnAnySubPathChangeDelegate onChange) { if (ringMaster == null) { throw new ArgumentNullException("rm"); } if (pathToWatch == null) { throw new ArgumentNullException("pathToWatch"); } if (onChange == null) { throw new ArgumentNullException("onChange"); } string path = GetBulkWatcherName(pathToWatch.Replace('/', '_')) + "_" + Guid.NewGuid().ToString(); byte[] data = Encoding.UTF8.GetBytes("$startswith:" + pathToWatch + ",$sessionlocal:" + sessionlocal); DelegateWatcher watcher = new DelegateWatcher( ev => { // if the event was signaled because the bulkwatcher node was deleted, this means the watcher is removed as well. if (ev.EventType == WatchedEvent.WatchedEventType.NodeDeleted && string.Equals(ev.Path, path)) { return; } onChange(RingMasterException.Code.Ok, ev); if (ev.EventType == WatchedEvent.WatchedEventType.WatcherRemoved && ev.KeeperState == WatchedEvent.WatchedEventKeeperState.SyncConnected) { ringMaster.Delete(path, -1, DeleteMode.None).Wait(); } }, oneuse ? WatcherKind.OneUse : default(WatcherKind)); DateTime maxTime = DateTime.UtcNow + TimeSpan.FromMilliseconds(timeout); while (true) { try { await ringMaster.Create(GetBulkWatcherName(null), null, null, CreateMode.Persistent); break; } catch (RingMasterException ex) { if (ex.ErrorCode == RingMasterException.Code.Connectionloss || ex.ErrorCode == RingMasterException.Code.Operationtimeout) { if (DateTime.UtcNow > maxTime) { return(false); } continue; } if (ex.ErrorCode == RingMasterException.Code.Nodeexists) { break; } onChange(ex.ErrorCode, null); return(true); } } while (true) { try { await ringMaster.Create(path, data, null, CreateMode.Ephemeral); break; } catch (RingMasterException ex) { if (ex.ErrorCode == RingMasterException.Code.Connectionloss || ex.ErrorCode == RingMasterException.Code.Operationtimeout) { if (DateTime.UtcNow > maxTime) { return(false); } continue; } if (ex.ErrorCode == RingMasterException.Code.Nodeexists) { break; } onChange(ex.ErrorCode, null); return(true); } } while (true) { try { await ringMaster.Exists(path, watcher, false); break; } catch (RingMasterException ex) { if (ex.ErrorCode == RingMasterException.Code.Connectionloss) { if (DateTime.UtcNow > maxTime) { return(false); } continue; } onChange(ex.ErrorCode, null); return(true); } } return(true); }
public static async Task <bool> Delete(this IRingMasterRequestHandler ringMaster, string path, int version, bool isRecursive) { return(await ringMaster.Delete(path, version, isRecursive?DeleteMode.CascadeDelete : DeleteMode.None)); }