Пример #1
0
        /// <summary>
        /// Verify that ringmaster correctly handles a batch sent to the Transaction Manager execution queue with just book keeping requests.
        /// </summary>
        /// <returns>A <see cref="Task"/> that tracks completion of this test</returns>
        /// <remarks>
        /// RDBug 6351033: When a batch with just book keeping requests was sent to RingMaster,
        /// it did not update an internal variable that tracked last applied batch id and refused
        /// the subsequent batches.  This verifies the fix for that issue.
        /// </remarks>
        public async Task TestTransactionManagerExecutionQueue_EmptyBatch()
        {
            using (var ringMaster = this.ConnectToRingMaster())
            {
                IRingMasterRequestHandler ringMasterRequestHandler = (IRingMasterRequestHandler)ringMaster;
                ulong lastAppliedBatchId = await QueryRingMasterLastAppliedBatchId(ringMaster);

                ulong batchId = lastAppliedBatchId + 1;

                // First send a regular batch to initialize the lastAppliedBatchId tracker in RM
                RequestBatch    initializationBatch = CreateBatch(batchId, CreateTransaction(1));
                RequestResponse batchResponse       = await ringMasterRequestHandler.Request(initializationBatch);

                Assert.AreEqual((int)RingMasterException.Code.Ok, batchResponse.ResultCode);

                lastAppliedBatchId = await QueryRingMasterLastAppliedBatchId(ringMaster);

                batchId = lastAppliedBatchId + 1;

                // Create a batch with only book keeping requests.
                RequestBatch firstBatch = CreateBatch(batchId);

                Trace.TraceInformation("Sending first batch. batchId={0}, executionQueueId={1}", batchId, firstBatch.ExecutionQueueId);
                batchResponse = await ringMasterRequestHandler.Request(firstBatch);

                Assert.AreEqual((int)RingMasterException.Code.Ok, batchResponse.ResultCode);

                // The last applied batch id value must have been updated.
                lastAppliedBatchId = await QueryRingMasterLastAppliedBatchId(ringMaster);

                Trace.TraceInformation("After first batch. lastAppliedBatchId={0}", lastAppliedBatchId);
                Assert.AreEqual(batchId, lastAppliedBatchId);

                // Verify that the internal last applied batch id variable has been updated and subsequent
                // batches will be accepted.
                batchId = lastAppliedBatchId + 1;
                RequestBatch secondBatch = CreateBatch(batchId);
                Trace.TraceInformation("Sending second batch. batchId={0} executionQueueId={1}", batchId, secondBatch.ExecutionQueueId);
                batchResponse = await ringMasterRequestHandler.Request(secondBatch);

                Assert.AreEqual((int)RingMasterException.Code.Ok, batchResponse.ResultCode);

                lastAppliedBatchId = await QueryRingMasterLastAppliedBatchId(ringMaster);

                Trace.TraceInformation("After second batch. lastAppliedBatchId={0}", lastAppliedBatchId);
                Assert.AreEqual(batchId, lastAppliedBatchId);
            }
        }
Пример #2
0
        private async Task IssueRequest(IRingMasterRequestHandler ringMaster, ulong id, string nodePath, CountdownEvent operationsCompletedEvent)
        {
            try
            {
                string bulkWatcherPath = $"bulkwatcher:{nodePath}";
                operationsCompletedEvent.AddCount();
                var timer   = Stopwatch.StartNew();
                var watcher = new Watcher(id, this.instrumentation);

                var installBulkWatcherRequest = new RequestExists(bulkWatcherPath, watcher);

                RequestResponse response = await ringMaster.Request(installBulkWatcherRequest);

                timer.Stop();
                if (response.ResultCode == (int)RingMasterException.Code.Ok)
                {
                    this.instrumentation?.SetWatcherSucceeded(timer.Elapsed);
                }
                else
                {
                    this.instrumentation?.SetWatcherFailed();
                }
            }
            catch (Exception ex)
            {
                Trace.TraceError($"SetBulkWatcher failed id={id}, path={nodePath}, exception={ex.ToString()}");
                this.instrumentation?.SetWatcherFailed();
            }
            finally
            {
                this.semaphore.Release();
                operationsCompletedEvent.Signal();
            }
        }
Пример #3
0
        private void IssueMultiRequest(IRingMasterRequestHandler ringMaster, IReadOnlyList <Op> operations, CountdownEvent operationsCompletedEvent)
        {
            var multiRequest = new RequestMulti(operations, completeSynchronously: true, uid: 0);

            this.semaphore.Wait();
            var timer           = Stopwatch.StartNew();
            int operationsCount = operations.Count;

            operationsCompletedEvent.AddCount(operationsCount);
            ringMaster.Request(multiRequest).ContinueWith(responseTask =>
            {
                this.semaphore.Release();
                timer.Stop();
                try
                {
                    RequestResponse response = responseTask.Result;
                    if (response.ResultCode == (int)RingMasterException.Code.Ok)
                    {
                        this.instrumentation?.DeleteMultiSucceeded(operationsCount, timer.Elapsed);
                    }
                    else
                    {
                        this.instrumentation?.DeleteMultiFailed(operationsCount);
                    }
                }
                catch (Exception)
                {
                    this.instrumentation?.DeleteMultiFailed(operationsCount);
                }
                finally
                {
                    operationsCompletedEvent.Signal(operationsCount);
                }
            });
        }
Пример #4
0
        /// <summary>
        /// Gets the Access Control List associated with a node.
        /// </summary>
        /// <param name="ringMaster">Interface to ringmaster</param>
        /// <param name="path">Node path</param>
        /// <param name="stat"><see cref="Stat"/> associated with the node</param>
        /// <returns>Task that will resolve on success to a List of <see cref="Acl"/>s associated
        /// with the node</returns>
        public static async Task <IReadOnlyList <Acl> > GetACL(this IRingMasterRequestHandler ringMaster, string path, IStat stat)
        {
            RequestResponse response = await ringMaster.Request(
                new RequestGetAcl(path, stat));

            ThrowIfError(response);
            return((IReadOnlyList <Acl>)response.Content);
        }
Пример #5
0
        /// <summary>
        /// Synchronizes with the given path.
        /// </summary>
        /// <param name="ringMaster">Interface to ringmaster</param>
        /// <param name="path">Node path</param>
        /// <returns>Task that tracks the execution of this method</returns>
        public static async Task Sync(this IRingMasterRequestHandler ringMaster, string path)
        {
            RequestResponse response = await ringMaster.Request(
                new RequestSync(
                    path));

            ThrowIfError(response);
        }
Пример #6
0
        /// <summary>
        /// Gets the subtree under a given path.
        /// </summary>
        /// <param name="ringMaster">Interface to RingMaster.</param>
        /// <param name="path">The path to get the subtree of.</param>
        /// <param name="retrievalCondition">Request retrieval condition of the form >:[Top]:[ContinuationPath]</param>
        /// <param name="options">Request options.</param>
        /// <returns>Task that will resolve on success to the root of the subtree under the given path.</returns>
        public static async Task <ResponseGetSubtree> GetSubtree(this IRingMasterRequestHandler ringMaster, string path, string retrievalCondition, RequestGetSubtree.GetSubtreeOptions options = RequestGetSubtree.GetSubtreeOptions.None)
        {
            RequestResponse response = await ringMaster.Request(new RequestGetSubtree(path, retrievalCondition, options));

            ThrowIfError(response);

            var treeNodeData = TreeNode.Deserialize((byte[])response.Content);

            return(new ResponseGetSubtree(treeNodeData, response.ResponsePath));
        }
Пример #7
0
        /// <summary>
        /// Executes multiple operations in a sequence at the server. No atomicity guarantees are provided.
        /// </summary>
        /// <param name="ringMaster">Interface to ringmaster</param>
        /// <param name="operations">List of operations</param>
        /// <param name="mustCompleteSynchronously">If <c>true</c> the server does not complete the operation
        /// until all successful operations are guaranteed to be durable (and are applied locally).</param>
        /// <returns>Task that will resolve on success to a list of
        /// <see cref="OpResult"/>s</returns>
        public static async Task <IReadOnlyList <OpResult> > Batch(this IRingMasterRequestHandler ringMaster, IReadOnlyList <Op> operations, bool mustCompleteSynchronously = false)
        {
            RequestResponse response = await ringMaster.Request(
                new RequestBatch(
                    operations,
                    mustCompleteSynchronously));

            ThrowIfError(response);
            return((IReadOnlyList <OpResult>)response.Content);
        }
Пример #8
0
        /// <summary>
        /// Gets the list of children of the node at the given path.
        /// </summary>
        /// <param name="ringMaster">Interface to ringmaster</param>
        /// <param name="path">Node path</param>
        /// <param name="watcher">Watcher interface that receives notifications for changes to this path or null</param>
        /// <param name="retrievalCondition">If not null, the retrieval condition in the form >:[top]:[startingChildName].
        /// <c>
        ///   ">:[Top]:[ChildName]"     ... returns the elements greater than the [ChildName] limited to Top count
        ///                                 so ">:1000:contoso" means give me first 1000 childrens greater than contoso
        ///                                 so ">:1000:"        means give me first 1000 elements
        /// </c>
        /// </param>
        /// <returns>Task that will resolve on success to the list of names of children of the node</returns>
        public static async Task <IReadOnlyList <string> > GetChildren(this IRingMasterRequestHandler ringMaster, string path, IWatcher watcher, string retrievalCondition = null)
        {
            RequestResponse response = await ringMaster.Request(
                new RequestGetChildren(
                    path,
                    watcher,
                    retrievalCondition : retrievalCondition));

            ThrowIfError(response);
            return((IReadOnlyList <string>)response.Content);
        }
Пример #9
0
        /// <summary>
        /// Sets the client authentication digest
        /// </summary>
        /// <param name="ringMaster">Interface to ringmaster</param>
        /// <param name="clientId">The client id</param>
        /// <returns>Task that tracks the execution of this method</returns>
        public static async Task SetAuth(this IRingMasterRequestHandler ringMaster, Id clientId)
        {
            string clientIdentity = string.Format(
                CultureInfo.InvariantCulture,
                "{0}:{1}",
                clientId.Scheme,
                clientId.Identifier);
            RequestResponse response = await ringMaster.Request(new RequestSetAuth(clientIdentity));

            ThrowIfError(response);
        }
Пример #10
0
        /// <summary>
        /// Sets the access control list for the node at the given path if
        /// the given version matches the current version of the node.
        /// </summary>
        /// <param name="ringMaster">Interface to ringmaster</param>
        /// <param name="path">Node path</param>
        /// <param name="acl">Access control list to associate with the node</param>
        /// <param name="version">Version to compare with the current version of the node</param>
        /// <returns>Task that will resolve on success to the <see cref="Stat"/> associated with
        /// the node</returns>
        public static async Task <IStat> SetACL(this IRingMasterRequestHandler ringMaster, string path, IReadOnlyList <Acl> acl, int version)
        {
            RequestResponse response = await ringMaster.Request(
                new RequestSetAcl(
                    path,
                    acl,
                    version));

            ThrowIfError(response);
            return(response.Stat);
        }
Пример #11
0
        /// <summary>
        /// Moves a node with the given path.
        /// </summary>
        /// <param name="ringMaster">The ringmaster handler to operate on</param>
        /// <param name="pathSrc">Node Path to move</param>
        /// <param name="version">Version of the source node</param>
        /// <param name="pathDst">Node Path to be parent of the moved node</param>
        /// <param name="moveMode">Modifiers for the move operation</param>
        /// <returns>Task that will resolve on success to the path to the newly created node</returns>
        public static async Task <string> Move(this IRingMasterRequestHandler ringMaster, string pathSrc, int version, string pathDst, MoveMode moveMode)
        {
            RequestResponse response = await ringMaster.Request(
                new RequestMove(
                    pathSrc,
                    version,
                    pathDst,
                    moveMode));

            ThrowIfError(response);
            return((string)response.Content);
        }
Пример #12
0
        /// <summary>
        /// Creates a node with the given path.
        /// </summary>
        /// <param name="ringMaster">Interface to ringmaster</param>
        /// <param name="path">Node Path</param>
        /// <param name="data">Data to associate with the node</param>
        /// <param name="acl">Access Control List</param>
        /// <param name="createMode">Specifies the node will be created</param>
        /// <returns>Task that will resolve on success to the path to the newly created node</returns>
        public static async Task <string> Create(this IRingMasterRequestHandler ringMaster, string path, byte[] data, IReadOnlyList <Acl> acl, CreateMode createMode)
        {
            RequestResponse response = await ringMaster.Request(
                new RequestCreate(
                    path,
                    data,
                    acl,
                    createMode));

            ThrowIfError(response);
            return((string)response.Content);
        }
Пример #13
0
        /// <summary>
        /// Gets the data and stat associated with the node at the given path.
        /// </summary>
        /// <param name="ringMaster">Interface to ringmaster</param>
        /// <param name="path">Node path</param>
        /// <param name="watcher">Watcher interface that receives notifications for changes to this path or null</param>
        /// <returns>Task that will resolve on success to the data associated with the node</returns>
        public static async Task <Tuple <IStat, byte[]> > GetDataWithStat(this IRingMasterRequestHandler ringMaster, string path, IWatcher watcher)
        {
            RequestResponse response = await ringMaster.Request(
                new RequestGetData(
                    path,
                    RequestGetData.GetDataOptions.None,
                    watcher,
                    0));

            ThrowIfError(response);
            return(new Tuple <IStat, byte[]>(response.Stat, (byte[])response.Content));
        }
Пример #14
0
        /// <summary>
        /// Sets the data for the node at the given path if the given version matches
        /// the current version of the node (If the given version is -1, it matches any version).
        /// </summary>
        /// <param name="ringMaster">Interface to ringmaster</param>
        /// <param name="path">Node path</param>
        /// <param name="data">Data to associate with the node</param>
        /// <param name="version">Version to compare with the current version of the node</param>
        /// <returns>Task that will resolve on success to the <see cref="Stat"/> associated with the node</returns>
        public static async Task <IStat> SetData(this IRingMasterRequestHandler ringMaster, string path, byte[] data, int version)
        {
            RequestResponse response = await ringMaster.Request(
                new RequestSetData(
                    path,
                    data,
                    version,
                    dataCommand : false));

            ThrowIfError(response);
            return(response.Stat);
        }
Пример #15
0
        public void SetWatchers(IRingMasterRequestHandler ringMaster, int maxWatchers)
        {
            if (ringMaster == null)
            {
                throw new ArgumentNullException(nameof(ringMaster));
            }

            // Semaphore that limits how many simultaneous active watchers are allowed.
            using (var watcherSemaphore = new SemaphoreSlim(maxWatchers, maxWatchers))
            {
                long lastAssignedUniqueId = 0;
                var  random = new RandomGenerator();
                Trace.TraceInformation($"Set watchers");

                while (!this.cancellationToken.IsCancellationRequested)
                {
                    var index    = random.GetRandomInt(0, this.nodeList.Count);
                    var nodePath = this.nodeList[index];

                    ulong id      = (ulong)Interlocked.Increment(ref lastAssignedUniqueId);
                    var   watcher = new Watcher(id, WatcherKind.OneUse, this.instrumentation, watcherSemaphore);

                    watcherSemaphore.Wait(this.cancellationToken);
                    var existsRequest = new RequestExists(nodePath, watcher, id);
                    var timer         = Stopwatch.StartNew();

                    ringMaster.Request(existsRequest).ContinueWith(responseTask =>
                    {
                        try
                        {
                            timer.Stop();
                            RequestResponse response = responseTask.Result;
                            if (response.ResultCode == (int)RingMasterException.Code.Ok)
                            {
                                this.instrumentation?.SetWatcherSucceeded(timer.Elapsed);
                            }
                            else
                            {
                                this.instrumentation?.SetWatcherFailed();
                            }
                        }
                        catch (Exception)
                        {
                            this.instrumentation?.SetWatcherFailed();
                        }
                    });
                }
            }
        }
Пример #16
0
        /// <summary>
        /// Queries the <see cref="Stat"/> of the node with the given path.
        /// </summary>
        /// <param name="ringMaster">Interface to ringmaster</param>
        /// <param name="path">Node path</param>
        /// <param name="watcher">Watcher interface that receives notifications for changes to this path or null</param>
        /// <param name="ignoreNonodeError">If set to <c>true</c> an exception is not thrown if no node is found at the given path</param>
        /// <returns>Task that will resolve on success to the <see cref="Stat"/> associated with the node</returns>
        public static async Task <IStat> Exists(this IRingMasterRequestHandler ringMaster, string path, IWatcher watcher, bool ignoreNonodeError)
        {
            RequestResponse response = await ringMaster.Request(
                new RequestExists(
                    path,
                    watcher));

            if (ignoreNonodeError &&
                (RingMasterException.GetCode(response.ResultCode) == RingMasterException.Code.Nonode))
            {
                return(response.Stat);
            }

            ThrowIfError(response);
            return((IStat)response.Content);
        }
Пример #17
0
        /// <summary>
        /// Apply a set of delete operations as a multi.
        /// </summary>
        /// <param name="ringMaster">Interface to RingMaster</param>
        /// <param name="deleteOperations">Delete operations to apply as a batch</param>
        /// <returns>Async task to indicate the completion of the request</returns>
        private async Task DeleteMulti(IRingMasterRequestHandler ringMaster, IReadOnlyList <Op> deleteOperations)
        {
            var timer        = Stopwatch.StartNew();
            var multiRequest = new RequestMulti(deleteOperations, completeSynchronously: true);
            var response     = await ringMaster.Request(multiRequest);

            if (response.ResultCode == (int)RingMasterException.Code.Ok)
            {
                this.deletedCount += deleteOperations.Count;
                this.instrumentation?.DeleteMultiSucceeded(this.deletedCount, deleteOperations.Count, timer.Elapsed);
            }
            else
            {
                this.instrumentation?.DeleteMultiFailed(this.deletedCount, deleteOperations.Count, timer.Elapsed);
                throw RingMasterException.GetException(response);
            }
        }
Пример #18
0
        /// <summary>
        /// Gets the data associated with the node at the given path.
        /// </summary>
        /// <param name="ringMaster">Interface to ringmaster</param>
        /// <param name="path">Node path</param>
        /// <param name="options">Options for this request</param>
        /// <param name="optionArgument">Argument for options</param>
        /// <param name="watcher">Watcher interface that receives notifications for changes to this path or null</param>
        /// <returns>Task that will resolve on success to the data associated with the node</returns>
        public static async Task <byte[]> GetData(
            this IRingMasterRequestHandler ringMaster,
            string path,
            RequestGetData.GetDataOptions options,
            RequestGetData.IGetDataOptionArgument optionArgument,
            IWatcher watcher)
        {
            RequestResponse response = await ringMaster.Request(
                new RequestGetData(
                    path,
                    options,
                    optionArgument,
                    watcher : watcher));

            ThrowIfError(response);
            return((byte[])response.Content);
        }
Пример #19
0
        /// <summary>
        /// Queue GetChildren requests.
        /// </summary>
        /// <param name="ringMaster">RingMaster client</param>
        /// <param name="rootPath">Path to enumerate</param>
        /// <param name="maxChildren">Maximum number of children to retrieve</param>
        public void QueueRequests(IRingMasterRequestHandler ringMaster, string rootPath, int maxChildren)
        {
            if (ringMaster == null)
            {
                throw new ArgumentNullException(nameof(ringMaster));
            }

            var   random    = new RandomGenerator();
            ulong requestId = 0;

            Trace.TraceInformation($"Queue GetChildren: path={rootPath}");

            while (!this.cancellationToken.IsCancellationRequested)
            {
                string startingChildName  = random.GetRandomName(this.MinNodeNameLength, this.MaxNodeNameLength);
                var    getChildrenRequest = new RequestGetChildren(rootPath, watcher: null, retrievalCondition: $">:{maxChildren}:{startingChildName}", uid: requestId++);

                this.semaphore.Wait();
                var timer = Stopwatch.StartNew();

                ringMaster.Request(getChildrenRequest).ContinueWith(responseTask =>
                {
                    this.semaphore.Release();
                    timer.Stop();

                    try
                    {
                        RequestResponse response = responseTask.Result;
                        if (response.ResultCode == (int)RingMasterException.Code.Ok)
                        {
                            var children = (IReadOnlyList <string>)response.Content;
                            this.instrumentation?.GetChildrenSucceeded(rootPath, children.Count, timer.Elapsed);
                        }
                        else
                        {
                            this.instrumentation?.GetChildrenFailed(rootPath);
                        }
                    }
                    catch (Exception)
                    {
                        this.instrumentation?.GetChildrenFailed(rootPath);
                    }
                });
            }
        }
Пример #20
0
        public static async Task <bool> Delete(this IRingMasterRequestHandler ringMaster, string path, int version, DeleteMode deletemode = DeleteMode.None)
        {
            RequestResponse response = await ringMaster.Request(
                new RequestDelete(
                    path,
                    version,
                    deletemode));

            switch (RingMasterException.GetCode(response.ResultCode))
            {
            case RingMasterException.Code.Ok: return(true);

            case RingMasterException.Code.Nonode: return(false);

            default:
                break;
            }

            ThrowIfError(response);
            return(false);
        }
Пример #21
0
        private void IssueRequest(IRingMasterRequestHandler ringMaster, string nodePath, byte[] nodeData, CountdownEvent operationsCompletedEvent)
        {
            var setDataRequest = new RequestSetData(nodePath, nodeData, -1);

            this.semaphore.Wait();

            operationsCompletedEvent.AddCount();
            var timer = Stopwatch.StartNew();

            ringMaster.Request(setDataRequest).ContinueWith(responseTask =>
            {
                try
                {
                    this.semaphore.Release();
                    timer.Stop();

                    RequestResponse response = responseTask.Result;
                    if (response.ResultCode == (int)RingMasterException.Code.Ok)
                    {
                        this.instrumentation?.SetDataMultiSucceeded(1, timer.Elapsed);
                    }
                    else
                    {
                        this.instrumentation?.SetDataMultiFailed(1);
                    }
                }
                catch (Exception)
                {
                    this.instrumentation?.SetDataMultiFailed(1);
                }
                finally
                {
                    operationsCompletedEvent.Signal();
                }
            });
        }
Пример #22
0
        public void QueueBatches(IRingMasterRequestHandler ringMaster, int batchLength)
        {
            if (ringMaster == null)
            {
                throw new ArgumentNullException(nameof(ringMaster));
            }

            ulong batchId = 0;
            var   random  = new RandomGenerator();

            Trace.TraceInformation($"Queue Exists Batches");

            while (!this.cancellationToken.IsCancellationRequested)
            {
                var operations = new Op[batchLength];
                for (int i = 0; i < batchLength; i++)
                {
                    var index    = random.GetRandomInt(0, this.nodeList.Count);
                    var nodePath = this.nodeList[index];

                    operations[i] = Op.Check(nodePath, -1);
                }

                var batchRequest = new RequestBatch(operations, completeSynchronously: false, uid: batchId++);
                this.semaphore.Wait();
                var timer = Stopwatch.StartNew();

                ringMaster.Request(batchRequest).ContinueWith(responseTask =>
                {
                    try
                    {
                        this.semaphore.Release();
                        timer.Stop();
                        int successCount         = 0;
                        int failureCount         = 0;
                        RequestResponse response = responseTask.Result;
                        if (response.ResultCode == (int)RingMasterException.Code.Ok)
                        {
                            var results = (IReadOnlyList <OpResult>)response.Content;
                            if (results != null)
                            {
                                foreach (var result in results)
                                {
                                    if (result.ErrCode == RingMasterException.Code.Ok)
                                    {
                                        successCount++;
                                    }
                                    else
                                    {
                                        failureCount++;
                                    }
                                }
                            }

                            this.instrumentation?.BatchProcessed(timer.Elapsed, batchRequest.Requests.Count, successCount, failureCount);
                        }
                        else
                        {
                            this.instrumentation?.BatchFailed(batchRequest.Requests.Count);
                        }
                    }
                    catch (Exception)
                    {
                        this.instrumentation?.BatchFailed(batchRequest.Requests.Count);
                    }
                });
            }
        }