/// <summary>
            /// Initializes a new instance of the <see cref="SecondaryPreprocessor"/> class.
            /// </summary>
            /// <param name="backend">Backend core</param>
            /// <param name="runOnTxIdMultiplesOf">The action will be run whenever txId % runOnTxIdMultiplesOf == 0.</param>
            /// <param name="runOnTxIdMultiples">The action to run whenever txId % runOnTxIdMultiplesOf == 0.</param>
            public SecondaryPreprocessor(RingMasterBackendCore backend, int runOnTxIdMultiplesOf, RunOnTxIdMultiplesFunction runOnTxIdMultiples)
            {
                if (backend == null)
                {
                    throw new ArgumentNullException(nameof(backend));
                }

                this.backend = backend;

                if (runOnTxIdMultiplesOf < 0)
                {
                    throw new ArgumentException("runOnTxIdMultiplesOf cannot be < 0");
                }

                this.runOnTxIdMultiplesOf = runOnTxIdMultiplesOf;
                this.lastTxRun            = 0;

                this.runOnTxIdMultiples            = runOnTxIdMultiples;
                this.thisCommandPathAllReplicas    = this.backend.ReplicaCommandPathPrefix + "/$$<all>";
                this.thisCommandPathAllSecondaries = this.backend.ReplicaCommandPathPrefix + "/$$<sec>";
                this.thisCommandPathOneSecondary   = this.backend.ReplicaCommandPathPrefix + "/$$<onesec>";
                this.thisCommandPathPrimary        = this.backend.ReplicaCommandPathPrefix + "/$$<prim>";

                Trace.TraceInformation("this.runOnTxIdMultiples={0}", this.runOnTxIdMultiplesOf);
            }
예제 #2
0
 /// <summary>
 /// Initializes a new instance of the <see cref="RingMasterRequestExecutor"/> class.
 /// </summary>
 /// <param name="backend">RingMaster backend</param>
 /// <param name="configuration">Configuration settings</param>
 /// <param name="instrumentation">Instrumentation consumer</param>
 /// <param name="cancellationToken">Token to be observed for cancellation signal</param>
 public RingMasterRequestExecutor(RingMasterBackendCore backend, Configuration configuration, IInstrumentation instrumentation, CancellationToken cancellationToken)
 {
     this.backend                 = backend ?? throw new ArgumentNullException(nameof(backend));
     this.configuration           = configuration ?? throw new ArgumentNullException(nameof(configuration));
     this.instrumentation         = instrumentation;
     this.parentCancellationToken = cancellationToken;
 }
예제 #3
0
 /// <summary>
 /// Initializes a new instance of the <see cref="LoopbackRingMaster"/> class.
 /// </summary>
 /// <param name="backend">Backend core</param>
 /// <param name="readOnlyInterfaceRequiresLocks">Whether readonly interface requires locks</param>
 /// <param name="allowWrites">Whether write operation is allowed</param>
 public LoopbackRingMaster(RingMasterBackendCore backend, bool readOnlyInterfaceRequiresLocks, bool allowWrites)
     : base("loopback:0", 0, null)
 {
     this.backend        = backend ?? throw new ArgumentNullException("backend");
     this.session        = backend.GetLoopbackSession(string.Empty, false, allowWrites, readOnlyInterfaceRequiresLocks);
     this.executionQueue = new ExecutionQueue(this.maxThreads);
     this.session.ROInterfaceRequiresLocks = readOnlyInterfaceRequiresLocks;
 }
예제 #4
0
        /// <inheritdoc />
        public override void Close()
        {
            if (this.executionQueue == null)
            {
                return;
            }

            this.executionQueue.Drain(ExecutionQueue.DrainMode.DisallowAllFurtherEnqueues);
            this.session.Close();
            this.backend = null;
        }
예제 #5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="PseudoNodes"/> class.
        /// </summary>
        /// <param name="backend">the backend to use</param>
        /// <param name="getSettingFunction">Function to get settings</param>
        public PseudoNodes(RingMasterBackendCore backend, Func <string, string> getSettingFunction)
        {
            if (getSettingFunction == null)
            {
                getSettingFunction = (s) => null;
            }

            this.getSetting        = getSettingFunction;
            this.backend           = backend;
            this.serviceHealingMgr = new ServiceHealingManager(this);
        }
예제 #6
0
        /// <summary>
        /// Gets a client to the primary.
        /// </summary>
        /// <param name="backend">The backend.</param>
        /// <param name="port">The port.</param>
        /// <param name="ssl">The SSL.</param>
        /// <returns>the new client to the primary</returns>
        internal static RingMaster GetClientToPrimary(RingMasterBackendCore backend, int port, SslWrapping ssl)
        {
            if (backend == null)
            {
                throw new ArgumentNullException("backend");
            }

            // addr will contain the list of peers, or '127.0.0.1' if none is there
            string addr = string.Empty;

            ClusterMember[] cm = backend.Factory.GetAgreedMembers();

            if (cm != null)
            {
                foreach (ClusterMember m in cm)
                {
                    if (addr == string.Empty)
                    {
                        addr = string.Format("{0}:{1}", m.Address, port);
                    }
                    else
                    {
                        addr = string.Format("{0};{1}:{2}", addr, m.Address, port);
                    }
                }
            }
            else
            {
                // nothing on cm, just us.
                addr = "127.0.0.1:" + port;
            }

            Trace.TraceInformation("SetupPseudoNodes {0} ", addr);

            RingMaster rm = new RingMaster(addr, 1000, null);

            rm.AddAuthInfo(AuthSchemes.Digest, "root");
            rm.SetSsl(ssl);
            return(rm);
        }
예제 #7
0
 /// <summary>
 /// Initializes a new instance of the <see cref="RMCommands"/> class.
 /// </summary>
 /// <param name="be">Backend core</param>
 public RMCommands(RingMasterBackendCore be)
 {
     this.backend = be;
 }
예제 #8
0
            /// <summary>
            /// runs the command encoded in the given path
            /// </summary>
            /// <param name="path">the command encoded in the path</param>
            /// <param name="data">optionally, the data associated with the request</param>
            /// <param name="session">Client session</param>
            /// <param name="lockList">the lock list of the invocation</param>
            /// <param name="requestedCommand">Requested command on return</param>
            /// <param name="content">More info on the command on return</param>
            /// <returns>code for possible error</returns>
            public Code RunCommandPath(string path, byte[] data, ClientSession session, ILockListTransaction lockList, out string requestedCommand, out object content)
            {
                if (path == null)
                {
                    throw new ArgumentNullException(nameof(path));
                }

                Code result = Code.Apierror;

                requestedCommand = "unknown";
                content          = "unknown command";

                if (!this.IsCommand(path))
                {
                    return(result);
                }

                string[] pieces = path.Split('/');

                if (pieces.Length >= 2)
                {
                    requestedCommand = pieces[1].ToLower();

                    if (!this.IsCommandAllowed(session, requestedCommand))
                    {
                        content = "command not allowed now";
                        return(Code.Apierror);
                    }

                    RingMasterEventSource.Log.RunCommand(requestedCommand);
                    this.backend.auditConsumer?.OnRunCommand(requestedCommand);

                    switch (requestedCommand)
                    {
                    case "getsetting":
                    {
                        content = RingMasterBackendCore.GetSetting(pieces[2]);
                        result  = Code.Ok;
                        break;
                    }

                    case "gc":
                    {
                        GC.Collect();
                        content = "GC scheduled";
                        result  = Code.Ok;
                        break;
                    }

                    case "takecheckpoint":
                    {
                        bool ok = this.backend.Factory.TakeCheckpoint();
                        content = string.Format("Checkpoint {0}scheduled", ok ? string.Empty : "not ");
                        result  = Code.Ok;
                        break;
                    }

                    case "buildtreefile":
                    {
                        string   commandResult;
                        string[] args = Encoding.UTF8.GetString(data).Split('|');
                        try
                        {
                            int             ver  = int.Parse(args[2]);
                            RequestResponse resp = this.backend.BuildTreeFile(nodepath: args[0], filename: args[1], version: ver);
                            commandResult = resp.ResultCode == (int)Code.Ok ? "success" : "failed";
                            result        = (Code)resp.ResultCode;
                        }
                        catch (Exception e)
                        {
                            commandResult = "failed:" + e.Message;
                            result        = Code.Systemerror;
                        }

                        content = string.Format("buildtreefile: nodepath={0} filename={1} result={2}", args[0], args[1], commandResult);

                        break;
                    }

                    case "mount":
                    {
                        string   commandResult;
                        string[] args = Encoding.UTF8.GetString(data).Split('|');
                        try
                        {
                            RequestResponse resp = this.backend.Mount(nodepath: args[0], filename: args[1], allowremount: false);
                            commandResult = resp.ResultCode == (int)Code.Ok ? "success" : "failed";
                            result        = (Code)resp.ResultCode;
                        }
                        catch (Exception e)
                        {
                            commandResult = "failed:" + e.Message;
                            result        = Code.Unknown;
                        }

                        content = string.Format("mount: nodepath={0} filename={1} result={2}", args[0], args[1], commandResult);

                        break;
                    }

                    case "remountroot":
                    {
                        string commandResult;
                        string filepath = Encoding.UTF8.GetString(data);
                        try
                        {
                            RequestResponse resp = this.backend.Mount(nodepath: "/", filename: filepath, allowremount: true, mountRoot: true);
                            commandResult = resp.ResultCode == (int)Code.Ok ? "success" : "failed";
                            result        = (Code)resp.ResultCode;
                        }
                        catch (Exception e)
                        {
                            commandResult = "failed:" + e.Message;
                            result        = Code.Unknown;
                        }

                        content = string.Format("mountroot: nodepath=/ filename={0} result={1}", filepath, commandResult);

                        break;
                    }

                    case "unmount":
                    {
                        string   commandResult;
                        string[] args = Encoding.UTF8.GetString(data).Split('|');

                        try
                        {
                            RequestResponse resp = this.backend.Unmount(args[0]);
                            commandResult = resp.ResultCode == (int)Code.Ok ? "success" : "failed";
                            result        = (Code)resp.ResultCode;
                        }
                        catch (Exception e)
                        {
                            commandResult = "failed:" + e.Message;
                            result        = Code.Unknown;
                        }

                        content = string.Format("mount: nodepath={0} result={1}", args[0], commandResult);

                        break;
                    }

                    case "remount":
                    {
                        string   commandResult;
                        string[] args = Encoding.UTF8.GetString(data).Split('|');
                        try
                        {
                            RequestResponse resp = this.backend.Mount(nodepath: args[0], filename: args[1], allowremount: true);
                            commandResult = resp.ResultCode == (int)Code.Ok ? "success" : "failed";
                            result        = (Code)resp.ResultCode;
                        }
                        catch (Exception e)
                        {
                            commandResult = "failed:" + e.Message;
                            result        = Code.Unknown;
                        }

                        content = string.Format("remount: nodepath={0} result={1}", args[0], commandResult);

                        break;
                    }

                    case "measure":
                    {
                        StringBuilder sb = new StringBuilder();

                        Dictionary <string, object> results;
                        try
                        {
                            this.backend.CanMeasure = true;
                            ((IUnsafeTreeAccess)this.backend).LockRootNoSync();

                            results = this.backend.MeasureFullTree(PlatformHelper.ProcessorCount, maxTimeForMeasurementInMillis);
                        }
                        finally
                        {
                            this.backend.CanMeasure = false;
                            ((IUnsafeTreeAccess)this.backend).ReleaseRoot();
                        }

                        if (results != null)
                        {
                            foreach (KeyValuePair <string, object> line in results)
                            {
                                string text;
                                string child_i = line.Key;

                                Exception e = line.Value as Exception;

                                if (e != null)
                                {
                                    text = string.Format("Metrics for {0}: {1}", child_i, e);
                                }
                                else
                                {
                                    ulong metrics = (ulong)line.Value;
                                    text = string.Format("Metrics for {0} is {1:X}", child_i, metrics);
                                }

                                sb.AppendLine(text);
                            }
                        }

                        content = sb.ToString();
                        result  = Code.Ok;
                        break;
                    }

                    case "getlocaltime":
                    {
                        content = string.Format("local time: " + DateTime.UtcNow.ToString("o"));
                        result  = Code.Ok;
                        break;
                    }

                    case "getcommands":
                    {
                        content = this.GetCommands();
                        result  = Code.Ok;
                        break;
                    }

                    case "trace":
                    {
                        string message = "<null>";
                        if (data != null)
                        {
                            message = Encoding.UTF8.GetString(data);
                        }

                        content = "traced: " + message;
                        result  = Code.Ok;
                        Trace.TraceInformation(message);
                        break;
                    }

                    case "failoverinto":
                    {
                        string replica = "<any>";
                        if (data != null)
                        {
                            replica = Encoding.UTF8.GetString(data);
                        }

                        content = "Failing over into: " + replica + " in 10 seconds";
                        this.backend.FailoverInto(replica, 10000);
                        result = Code.Ok;
                        break;
                    }

                    case "downloadurlintolocation":
                    {
                        string arguments = null;

                        if (data != null)
                        {
                            arguments = Encoding.UTF8.GetString(data);
                        }

                        // we run this one command asynchronously with any potential replication
                        bool hasStarted = this.backend.DownloadUrlIntoLocation(arguments);
                        if (hasStarted)
                        {
                            content = string.Format("DownloadUrlIntoLocation started arguments={0}", arguments);
                            result  = Code.Ok;
                        }
                        else
                        {
                            content = string.Format("DownloadUrlIntoLocation functionality is not implemented");
                            result  = Code.Unimplemented;
                        }

                        break;
                    }

                    case "poisonpill":
                    {
                        string spec = null;

                        if (data != null)
                        {
                            spec = Encoding.UTF8.GetString(data);
                        }

                        RequestResponse res = this.GeneratePoisonPill(spec, session, lockList);
                        if (res != null)
                        {
                            content = string.Format("poison pill executed. Result = {0}", res.Content);
                            result  = (Code)res.ResultCode;
                        }
                        else
                        {
                            content = "Poison pills not allowed from config";
                            result  = Code.Authfailed;
                        }

                        break;
                    }

                    case "importcheckpoint":
                    {
                        string location = null;

                        if (data != null)
                        {
                            location = Encoding.UTF8.GetString(data);
                        }

                        RingMasterThreadPool.Instance.QueueUserWorkItem(_ =>
                            {
                                Thread.Sleep(5000);
                                bool ok = this.backend.ImportCheckpoint(location);
                                Trace.TraceWarning("Import checkpoint {0}: {1}", location, ok ? "Succeeded" : "Failed");
                                if (ok)
                                {
                                    Trace.TraceWarning("This instance will die now");
                                    Environment.Exit(1);
                                }
                            });

                        content = "Importing checkpoint " + location + "file and restarting";
                        result  = Code.Ok;

                        break;
                    }

                    case "getstats":
                    {
                        lock (this.SyncObject)
                        {
                            content = string.Format("PersistentData.TotalNodes={0} PersistentData.TotalData={1} EphemeralData.TotalNodes={2} EphemeralData.TotalData={3}", this.backend.Factory.TotalNodes, this.backend.Factory.TotalData, this.backend.EphemeralFactory.TotalNodes, this.backend.EphemeralFactory.TotalData);
                        }

                        result = Code.Ok;

                        break;
                    }

                    case "dumpnodes":
                    {
                        bool scanEphemerals = pieces.Length > 2 && string.Equals(pieces[2], "scanephemerals", StringComparison.InvariantCultureIgnoreCase);
                        content = this.backend.Factory.DumpAllNodesForDebug();

                        if (scanEphemerals)
                        {
                            lock (this.SyncObject)
                            {
                                content = content + Environment.NewLine + "---Eph:" + Environment.NewLine + this.backend.ScanForEphemeral() + Environment.NewLine + "---";
                            }
                        }

                        result = Code.Ok;

                        break;
                    }

                    case "getverbositylevel":
                    {
                        content = "verbosity level is " + this.backend.GetVerbosityLevel();
                        result  = Code.Ok;
                        break;
                    }

                    case "setverbositylevel":
                    {
                        int vlev = int.Parse(pieces[2]);
                        content = string.Format("verbosity level was {0} now is set to {1}", this.backend.GetVerbosityLevel(), vlev);
                        this.backend.SetupVerbosityLevel(vlev);
                        result = Code.Ok;
                        break;
                    }

                    case "cleanuprsl":
                    {
                        RingMasterThreadPool.Instance.QueueUserWorkItem(_ =>
                            {
                                Thread.Sleep(10000);
                                Trace.TraceWarning("This instance will wipe its state {0} now", this.backend.GetType().Name);
                                this.backend.Factory.WipeAllDataAndShutdown();
                                Trace.TraceWarning("This instance will die now");
                                Environment.Exit(1);
                            });
                        content = "cleaning up RSL folder and restarting";
                        result  = Code.Ok;
                        break;
                    }

                    case "restart":
                    {
                        uint waitMS = 10000;

                        if (pieces.Length > 2)
                        {
                            if (!uint.TryParse(pieces[2], out waitMS))
                            {
                                waitMS = 10000;
                            }
                        }

                        // 2 minutes max wait
                        waitMS = Math.Min(waitMS, 120000);

                        RingMasterThreadPool.Instance.QueueUserWorkItem(_ =>
                            {
                                Thread.Sleep((int)waitMS);
                                Trace.TraceInformation("This instance will stop {0} now", this.backend.GetType().Name);
                                this.backend.Stop();

                                Thread.Sleep(2000);
                                Trace.TraceInformation("This instance will restart {0} now", this.backend.GetType().Name);
                                this.backend.Start(CancellationToken.None);
                            });

                        content = "restarted in " + waitMS + " miliseconds";
                        result  = Code.Ok;
                        break;
                    }

                    case "die":
                    {
                        RingMasterThreadPool.Instance.QueueUserWorkItem(_ =>
                            {
                                Thread.Sleep(10000);
                                Trace.TraceWarning("This instance will die now");
                                Environment.Exit(1);
                            });

                        if (pieces.Length > 2)
                        {
                            this.backend.FailoverInto(pieces[2]);
                        }

                        content = "die in 10 seconds";
                        result  = Code.Ok;
                        break;
                    }
                    }
                }

                return(result);
            }
예제 #9
0
 /// <summary>
 /// Initializes a new instance of the <see cref="LoopbackRingMaster"/> class.
 /// </summary>
 /// <param name="backend">Backend core</param>
 /// <param name="readOnlyInterfaceRequiresLocks">Whether readonly interface requires locks</param>
 public LoopbackRingMaster(RingMasterBackendCore backend, bool readOnlyInterfaceRequiresLocks = true)
     : this(backend, readOnlyInterfaceRequiresLocks, true)
 {
 }