コード例 #1
0
        /// <summary>
        /// Indicates if the resultCode and all internal results are successful.
        /// </summary>
        /// <param name="resultCode">the command result code</param>
        /// <param name="results">the individual results</param>
        /// <returns>true if all is successful</returns>
        private bool AllResultsOk(Code resultCode, IEnumerable <OpResult> results)
        {
            if (resultCode != Code.Ok)
            {
                return(false);
            }

            foreach (OpResult res in results)
            {
                if (res.ErrCode != Code.Ok)
                {
                    return(false);
                }

                if (res.ResultType == OpCode.Multi)
                {
                    OpResult.RunResult asRunResult = (OpResult.RunResult)res;

                    if (!this.AllResultsOk(asRunResult.ErrCode, asRunResult.Results))
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
コード例 #2
0
        /// <summary>
        /// Moves a command into the inflight tree
        /// </summary>
        /// <param name="scheduledCommandPath">the path to move</param>
        /// <param name="stat">the stat of the node to move</param>
        /// <returns>the inflight path where the command was moved</returns>
        private string MoveCommandToInflight(string scheduledCommandPath, IStat stat)
        {
            IRingMasterBackendRequest[] setupOps =
            {
                new RequestCreate(PathInflightToken,  null, new byte[0],  new Acl[0],   CreateMode.Persistent, null),
                new RequestMove(scheduledCommandPath, null, stat.Version, PathInflight, null),
            };

            Code resultCode = Code.Unknown;
            IReadOnlyList <OpResult> results = null;

            ManualResetEvent e = ManualResetEventPool.InstancePool.GetOne();

            try
            {
                this.self.Multi(
                    setupOps,
                    (rc, p, c) =>
                {
                    resultCode = (Code)rc;

                    if (resultCode == Code.Ok)
                    {
                        results = p;
                    }

                    e.Set();
                },
                    null,
                    true);
            }
            finally
            {
                ManualResetEventPool.InstancePool.WaitOneAndReturn(ref e);
            }

            if (!this.AllResultsOk(resultCode, results))
            {
                string details = string.Empty;

                if (results != null)
                {
                    details = string.Join(",", results.Select(c => c.ErrCode));
                }

                throw new InflightExistException($"Could not move command to inflight: {resultCode}, [{details}]");
            }

            return(this.GetInflightPath(scheduledCommandPath));
        }
コード例 #3
0
        /// <summary>
        /// returns the bytes corresponding to the results given
        /// </summary>
        /// <param name="resultCode">result code in the response</param>
        /// <param name="results">Content in the response</param>
        /// <returns>serialization bytes</returns>
        public byte[] GetBytes(Code resultCode, IReadOnlyList <OpResult> results)
        {
            if (results == null)
            {
                throw new ArgumentNullException("results");
            }

            RequestResponse resp = new RequestResponse()
            {
                ResultCode = (int)resultCode,
                Content    = results,
            };

            return(this.marshaller.SerializeResponseAsBytes(resp));
        }
コード例 #4
0
        /// <summary>
        /// Executes the given command and obtains the result bytes on error.
        /// </summary>
        /// <param name="scheduledCommandPath">the path to the command</param>
        /// <param name="stat">the expected stat of the command node</param>
        /// <param name="req">the request to execute</param>
        /// <returns>null on success, or the bytes corresponsing to the execution error</returns>
        private byte[] ExecuteCommandsAndGetResultsOnError(string scheduledCommandPath, IStat stat, IRingMasterBackendRequest req)
        {
            if (req == null)
            {
                return(this.GetBytes(Code.Badarguments, null));
            }

            IStat readStat = this.self.Exists(scheduledCommandPath, false, false);

            if (readStat == null)
            {
                throw new InvalidOperationException($"Scheduled command stat of [{scheduledCommandPath}] is null");
            }

            if (readStat.Version != stat.Version || readStat.Cversion != stat.Cversion)
            {
                throw new InvalidOperationException(
                          $"Scheduled command stat of [{scheduledCommandPath}] is different from expected command stat; " +
                          $"Expected [{stat.Version} {stat.Cversion}], " +
                          $"Actual [{readStat.Version} {readStat.Cversion}]");
            }

            ManualResetEvent e;

            Code resultCode = Code.Unknown;
            IReadOnlyList <OpResult> results = null;

            // setup the command into the inflight tree
            string inflightPath = this.MoveCommandToInflight(scheduledCommandPath, stat);

            // run the command, and atomically remove the inflight marks on success
            IRingMasterBackendRequest[] ops =
            {
                req,
                new RequestDelete(inflightPath,     null,  stat.Version, null, DeleteMode.SuccessEvenIfNodeDoesntExist),
                new RequestDelete(PathInflightToken,null,            -1, null, DeleteMode.SuccessEvenIfNodeDoesntExist),
            };

            e = ManualResetEventPool.InstancePool.GetOne();

            resultCode = Code.Unknown;
            results    = null;

            try
            {
                this.self.Multi(
                    ops,
                    (rc, p, c) =>
                {
                    resultCode = (Code)rc;

                    if (resultCode == Code.Ok)
                    {
                        results = p;
                    }

                    e.Set();
                },
                    null,
                    true);
            }
            finally
            {
                ManualResetEventPool.InstancePool.WaitOneAndReturn(ref e);
            }

            bool allok = this.AllResultsOk(resultCode, results);

            if (allok)
            {
                // if all went well, we are done since the command was deleted from the inflight tree atomically with the operation.
                return(null);
            }

            // otherwise, we need to undo the setup now
            this.MoveInflightPathIntoCommandPath();

            return(this.GetBytes(resultCode, results));
        }
コード例 #5
0
        /// <summary>
        /// moves commands from the inflight path into the command path
        /// </summary>
        /// <param name="expectedName">if present, this is the expected name for the single command in the inflight tree. if not present, this method moves all items (not the inflight token) into the commands tree</param>
        /// <returns>the list of names added to the command tree</returns>
        private string[] MoveInflightPathIntoCommandPath(string expectedName = null)
        {
            string[] children;
            if (expectedName != null)
            {
                children = new string[] { expectedName };
            }
            else
            {
                children = this.self.GetChildren(PathInflight, false).ToArray();
            }

            List <string> movedChildren = new List <string>();

            if (children.Length == 0)
            {
                return(null);
            }

            List <IRingMasterBackendRequest> ops = new List <IRingMasterBackendRequest>();

            foreach (string child in children)
            {
                string childPath = PathInflight + "/" + child;
                if (childPath == PathInflightToken)
                {
                    ops.Add(new RequestDelete(childPath, null, -1, null, DeleteMode.SuccessEvenIfNodeDoesntExist));
                }
                else
                {
                    movedChildren.Add(child);
                    ops.Add(new RequestMove(childPath, null, -1, PathCommands, null));
                }
            }

            IReadOnlyList <OpResult> results = null;
            Code resultCode = Code.Unknown;

            ManualResetEvent e = ManualResetEventPool.InstancePool.GetOne();

            try
            {
                this.self.Multi(
                    ops.ToArray(),
                    (rc, p, c) =>
                {
                    resultCode = (Code)rc;

                    if (rc == (int)Code.Ok)
                    {
                        results = p;
                    }

                    e.Set();
                },
                    null,
                    true);
            }
            finally
            {
                ManualResetEventPool.InstancePool.WaitOneAndReturn(ref e);
            }

            if (!this.AllResultsOk(resultCode, results))
            {
                string details = string.Empty;

                if (results != null)
                {
                    details = string.Join(",", results.Select(c => c.ErrCode));
                }

                throw new InflightExistException($"Could not move command back from inflight: {resultCode}, [{details}]");
            }

            return(movedChildren.ToArray());
        }