public void Follower_as_a_single_node_becomes_leader_automatically() { var hub = new InMemoryTransportHub(); var storageEnvironmentOptions = StorageEnvironmentOptions.CreateMemoryOnly(); storageEnvironmentOptions.OwnsPagers = false; var raftEngineOptions = new RaftEngineOptions( new NodeConnectionInfo { Name = "node1" }, storageEnvironmentOptions, hub.CreateTransportFor("node1"), new DictionaryStateMachine() ) { ElectionTimeout = 1000, HeartbeatTimeout = 1000 / 6 }; PersistentState.ClusterBootstrap(raftEngineOptions); storageEnvironmentOptions.OwnsPagers = true; using (var raftNode = new RaftEngine(raftEngineOptions)) { Assert.Equal(RaftEngineState.Leader, raftNode.State); } }
public RaftNode(int port) { _name = "node-" + port; _url = string.Format("http://{0}:{1}", Environment.MachineName, port); var nodeTransport = new HttpTransport(_name); var node1 = new NodeConnectionInfo { Name = _name, Uri = new Uri(_url) }; var engineOptions = new RaftEngineOptions( node1, StorageEnvironmentOptions.CreateMemoryOnly(), nodeTransport, new DictionaryStateMachine()); engineOptions.ElectionTimeout *= 2; engineOptions.HeartbeatTimeout *= 2; _raftEngine = new RaftEngine(engineOptions); _server = WebApp.Start(new StartOptions { Urls = { string.Format("http://+:{0}/", port) } }, builder => { var httpConfiguration = new HttpConfiguration(); RaftWebApiConfig.Load(); httpConfiguration.MapHttpAttributeRoutes(); httpConfiguration.Properties[typeof(HttpTransportBus)] = nodeTransport.Bus; builder.UseWebApi(httpConfiguration); }); }
public void Follower_as_a_single_node_becomes_leader_automatically() { var hub = new InMemoryTransportHub(); var storageEnvironmentOptions = StorageEnvironmentOptions.CreateMemoryOnly(); storageEnvironmentOptions.OwnsPagers = false; var raftEngineOptions = new RaftEngineOptions( new NodeConnectionInfo { Name = "node1" }, storageEnvironmentOptions, hub.CreateTransportFor("node1"), new DictionaryStateMachine() ) { ElectionTimeout = 1000, HeartbeatTimeout = 1000/6 }; PersistentState.ClusterBootstrap(raftEngineOptions); storageEnvironmentOptions.OwnsPagers = true; using (var raftNode = new RaftEngine(raftEngineOptions)) { Assert.Equal(RaftEngineState.Leader, raftNode.State); } }
public HttpTransportPingTest() { _node1Transport = new HttpTransport("node1", _requestsTimeout, CancellationToken.None); var node1 = new NodeConnectionInfo { Name = "node1", Uri = new Uri("http://localhost:9079") }; var engineOptions = new RaftEngineOptions(node1, StorageEnvironmentOptions.CreateMemoryOnly(), _node1Transport, new DictionaryStateMachine()) { ElectionTimeout = 60 * 1000, HeartbeatTimeout = 10 * 1000 }; _raftEngine = new RaftEngine(engineOptions); NonAdminHttp.EnsureCanListenToWhenInNonAdminContext(9079); _server = WebApp.Start(new StartOptions { Urls = { "http://+:9079/" } }, builder => { var httpConfiguration = new HttpConfiguration(); RaftWebApiConfig.Load(); httpConfiguration.MapHttpAttributeRoutes(); httpConfiguration.Properties[typeof(HttpTransportBus)] = _node1Transport.Bus; builder.UseWebApi(httpConfiguration); }); }
public static void SetTopologyExplicitly(RaftEngineOptions options, Topology topology, bool throwIfTopologyExists) { using (var ps = new PersistentState("ClusterBootstrap", options.StorageOptions, CancellationToken.None)) { if (ps.GetCurrentTopology().HasVoters&& throwIfTopologyExists) { throw new InvalidOperationException("Cannot set topology on a cluster that already have a topology"); } ps.SetCurrentTopology(topology, 0); } }
public static ClusterManager Create(DocumentDatabase systemDatabase, DatabasesLandlord databasesLandlord) { if (systemDatabase == null) { throw new ArgumentNullException("systemDatabase"); } if (databasesLandlord == null) { throw new ArgumentNullException("databasesLandlord"); } DatabaseHelper.AssertSystemDatabase(systemDatabase); var configuration = systemDatabase.Configuration; var nodeConnectionInfo = CreateSelfConnection(systemDatabase); StorageEnvironmentOptions options; if (configuration.Core.RunInMemory == false) { var directoryPath = Path.Combine(configuration.Core.DataDirectory ?? AppDomain.CurrentDomain.BaseDirectory, "Raft"); if (Directory.Exists(directoryPath) == false) { Directory.CreateDirectory(directoryPath); } options = StorageEnvironmentOptions.ForPath(directoryPath); } else { options = StorageEnvironmentOptions.CreateMemoryOnly(configuration.Storage.TempPath); } var transport = new HttpTransport(nodeConnectionInfo.Name, systemDatabase.WorkContext.CancellationToken); var stateMachine = new ClusterStateMachine(systemDatabase, databasesLandlord); var raftEngineOptions = new RaftEngineOptions(nodeConnectionInfo, options, transport, stateMachine) { ElectionTimeout = (int)configuration.Cluster.ElectionTimeout.AsTimeSpan.TotalMilliseconds, HeartbeatTimeout = (int)configuration.Cluster.HeartbeatTimeout.AsTimeSpan.TotalMilliseconds, MaxLogLengthBeforeCompaction = configuration.Cluster.MaxLogLengthBeforeCompaction, MaxEntriesPerRequest = configuration.Cluster.MaxEntriesPerRequest, MaxStepDownDrainTime = configuration.Cluster.MaxStepDownDrainTime.AsTimeSpan }; var raftEngine = new RaftEngine(raftEngineOptions); stateMachine.RaftEngine = raftEngine; return(new ClusterManager(raftEngine)); }
private RaftEngineOptions CreateNodeOptions(string nodeName, int messageTimeout, StorageEnvironmentOptions storageOptions, params string[] peers) { var nodeOptions = new RaftEngineOptions(new NodeConnectionInfo { Name = nodeName }, storageOptions, _inMemoryTransportHub.CreateTransportFor(nodeName), new DictionaryStateMachine()) { ElectionTimeout = messageTimeout, HeartbeatTimeout = messageTimeout / 6, Stopwatch = Stopwatch.StartNew() }; return(nodeOptions); }
public void Follower_on_timeout_should_become_candidate() { var storageEnvironmentOptions = StorageEnvironmentOptions.CreateMemoryOnly(); storageEnvironmentOptions.OwnsPagers = false; var nodeOptions = new RaftEngineOptions(new NodeConnectionInfo { Name = "real" }, storageEnvironmentOptions, _inMemoryTransportHub.CreateTransportFor("real"), new DictionaryStateMachine()); PersistentState.SetTopologyExplicitly(nodeOptions, new Topology( new Guid("355a589b-cadc-463d-a515-5add2ea47205"), new[] { new NodeConnectionInfo { Name = "real" }, new NodeConnectionInfo { Name = "u2" }, new NodeConnectionInfo { Name = "pj" }, }, new NodeConnectionInfo[0], new NodeConnectionInfo[0]), throwIfTopologyExists: true); storageEnvironmentOptions.OwnsPagers = true; using (var node = new RaftEngine(nodeOptions)) { var timeoutEvent = new ManualResetEventSlim(); node.StateTimeout += timeoutEvent.Set; ForceTimeout("real"); timeoutEvent.Wait(); Assert.Equal(RaftEngineState.Candidate, node.State); } }
public HttpTransportPingTest() { _node1Transport = new HttpTransport("node1"); var node1 = new NodeConnectionInfo { Name = "node1", Uri = new Uri("http://localhost:9079") }; var engineOptions = new RaftEngineOptions(node1, StorageEnvironmentOptions.CreateMemoryOnly(), _node1Transport, new DictionaryStateMachine()) { ElectionTimeout = 60 * 1000, HeartbeatTimeout = 10 * 1000 }; _raftEngine = new RaftEngine(engineOptions); _server = WebApp.Start(new StartOptions { Urls = { "http://+:9079/" } }, builder => { var httpConfiguration = new HttpConfiguration(); RaftWebApiConfig.Load(); httpConfiguration.MapHttpAttributeRoutes(); httpConfiguration.Properties[typeof(HttpTransportBus)] = _node1Transport.Bus; builder.UseWebApi(httpConfiguration); }); }
public static void SetTopologyExplicitly(RaftEngineOptions options, Topology topology, bool throwIfTopologyExists) { using (var ps = new PersistentState("ClusterBootstrap", options.StorageOptions, CancellationToken.None)) { if (ps.GetCurrentTopology().HasVoters && throwIfTopologyExists) throw new InvalidOperationException("Cannot set topology on a cluster that already have a topology"); ps.SetCurrentTopology(topology, 0); } }
public static void ClusterBootstrap(RaftEngineOptions options) { SetTopologyExplicitly(options, new Topology(Guid.NewGuid(), new[] { options.SelfConnection }, Enumerable.Empty<NodeConnectionInfo>(), Enumerable.Empty<NodeConnectionInfo>()), throwIfTopologyExists: true); }
public static void ClusterBootstrap(RaftEngineOptions options) { SetTopologyExplicitly(options, new Topology(Guid.NewGuid(), new[] { options.SelfConnection }, Enumerable.Empty <NodeConnectionInfo>(), Enumerable.Empty <NodeConnectionInfo>()), throwIfTopologyExists: true); }
private RaftEngineOptions CreateNodeOptions(string nodeName, int messageTimeout, StorageEnvironmentOptions storageOptions, params string[] peers) { var nodeOptions = new RaftEngineOptions(new NodeConnectionInfo { Name = nodeName }, storageOptions, _inMemoryTransportHub.CreateTransportFor(nodeName), new DictionaryStateMachine()) { ElectionTimeout = messageTimeout, HeartbeatTimeout = messageTimeout / 6, Stopwatch = Stopwatch.StartNew() }; return nodeOptions; }
public void Follower_on_timeout_should_become_candidate() { var storageEnvironmentOptions = StorageEnvironmentOptions.CreateMemoryOnly(); storageEnvironmentOptions.OwnsPagers = false; var nodeOptions = new RaftEngineOptions(new NodeConnectionInfo { Name = "real" }, storageEnvironmentOptions, _inMemoryTransportHub.CreateTransportFor("real"), new DictionaryStateMachine()); PersistentState.SetTopologyExplicitly(nodeOptions, new Topology( new Guid("355a589b-cadc-463d-a515-5add2ea47205"), new[] { new NodeConnectionInfo {Name = "real"}, new NodeConnectionInfo {Name = "u2"}, new NodeConnectionInfo {Name = "pj"}, }, new NodeConnectionInfo[0], new NodeConnectionInfo[0]), throwIfTopologyExists: true); storageEnvironmentOptions.OwnsPagers = true; using (var node = new RaftEngine(nodeOptions)) { var timeoutEvent = new ManualResetEventSlim(); node.StateTimeout += timeoutEvent.Set; ForceTimeout("real"); timeoutEvent.Wait(); Assert.Equal(RaftEngineState.Candidate, node.State); } }
private static void Main(string[] args) { var options = new TailFeatherCommandLineOptions(); if (Parser.Default.ParseArguments(args, options) == false) { var autoBuild = HelpText.AutoBuild(options); HelpText.DefaultParsingErrorsHandler(options, autoBuild); Console.WriteLine(autoBuild.ToString()); return; } var nodeName = options.NodeName ?? (Environment.MachineName + ":" + options.Port); Console.Title = string.Format("Node name: {0}, port: {1}", nodeName, options.Port); var kvso = StorageEnvironmentOptions.ForPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, options.DataPath, "KeyValue")); using (var statemachine = new KeyValueStateMachine(kvso)) { var storageEnvironmentOptions = StorageEnvironmentOptions.ForPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, options.DataPath, "Raft")); var httpTransport = new HttpTransport(nodeName); var raftEngineOptions = new RaftEngineOptions( new NodeConnectionInfo { Name = nodeName, Uri = new Uri("http://" + Environment.MachineName + ":" + options.Port), }, storageEnvironmentOptions, httpTransport, statemachine ) { ElectionTimeout = 5 * 1000, HeartbeatTimeout = 1000, MaxLogLengthBeforeCompaction = 25 }; if (options.Boostrap) { PersistentState.ClusterBootstrap(raftEngineOptions); Console.WriteLine("Setup node as the cluster seed, exiting..."); return; } using (var raftEngine = new RaftEngine(raftEngineOptions)) { using (WebApp.Start(new StartOptions { Urls = { "http://+:" + options.Port + "/" } }, builder => { var httpConfiguration = new HttpConfiguration(); httpConfiguration.Formatters.Remove(httpConfiguration.Formatters.XmlFormatter); httpConfiguration.Formatters.JsonFormatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented; httpConfiguration.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter()); RaftWebApiConfig.Load(); httpConfiguration.MapHttpAttributeRoutes(); httpConfiguration.Properties[typeof(HttpTransportBus)] = httpTransport.Bus; httpConfiguration.Properties[typeof(RaftEngine)] = raftEngine; builder.UseWebApi(httpConfiguration); })) { Console.WriteLine("Ready @ http://" + Environment.MachineName + ":" + options.Port + "/, press ENTER to stop"); Console.ReadLine(); } } } }