Пример #1
0
		public void CanSendTimeoutNow()
		{
			using (var node2Transport = new HttpTransport("node2"))
			{
				var node1 = new NodeConnectionInfo { Name = "node1", Uri = new Uri("http://localhost:9079") };
				node2Transport.Send(node1, new AppendEntriesRequest
				{
					From = "node2",
					ClusterTopologyId = new Guid("355a589b-cadc-463d-a515-5add2ea47205"),
					Term = 2,
					PrevLogIndex = 0,
					PrevLogTerm = 0,
					LeaderCommit = 1,
					Entries = new[]
					{
						new LogEntry
						{
							Term = 2,
							Index = 1,
							Data = new JsonCommandSerializer().Serialize(new DictionaryCommand.Set
							{
								Key = "a",
								Value = 2
							})
						},
					}
				});
				MessageContext context;
				var gotIt = node2Transport.TryReceiveMessage(_timeout, CancellationToken.None, out context);

				Assert.True(gotIt);
				Assert.True(((AppendEntriesResponse)context.Message).Success);

				var mres = new ManualResetEventSlim();
				_raftEngine.StateChanged += state =>
				{
					if (state == RaftEngineState.CandidateByRequest)
						mres.Set();
				};

				node2Transport.Send(node1, new TimeoutNowRequest
				{
					Term = 4,
					From = "node2",
					ClusterTopologyId = new Guid("355a589b-cadc-463d-a515-5add2ea47205"),
				});

				gotIt = node2Transport.TryReceiveMessage(_timeout, CancellationToken.None, out context);

				Assert.True(gotIt);

				Assert.True(context.Message is NothingToDo);

				Assert.True(mres.Wait(_timeout));
			}
		}
Пример #2
0
        public void CanAskIfCanInstallSnapshot()
        {
            using (var node2Transport = new HttpTransport("node2"))
            {
                var node1 = new NodeConnectionInfo { Name = "node1", Uri = new Uri("http://localhost:9079") };

                node2Transport.Send(node1, new CanInstallSnapshotRequest
                {
                    From = "node2",
                    ClusterTopologyId = new Guid("355a589b-cadc-463d-a515-5add2ea47205"),
                    Term = 2,
                    Index = 3,
                });

                MessageContext context;
                var gotIt = node2Transport.TryReceiveMessage(_timeout, CancellationToken.None, out context);

                Assert.True(gotIt);
                var msg = (CanInstallSnapshotResponse)context.Message;
                Assert.True(msg.Success);
            }
        }
Пример #3
0
		public void CanSendRequestVotesAndGetReply()
		{
			using (var node2Transport = new HttpTransport("node2"))
			{
				var node1 = new NodeConnectionInfo { Name = "node1", Uri = new Uri("http://localhost:9079") };
				node2Transport.Send(node1, new RequestVoteRequest
				{
					TrialOnly = true,
					From = "node2",
					ClusterTopologyId = new Guid("355a589b-cadc-463d-a515-5add2ea47205"),
					Term = 3,
					LastLogIndex = 2,
					LastLogTerm = 2,
				});

				MessageContext context;
				var gotIt = node2Transport.TryReceiveMessage(_timeout, CancellationToken.None, out context);

				Assert.True(gotIt);

				Assert.True(context.Message is RequestVoteResponse);
			}
		}
Пример #4
0
        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);
            });
        }
Пример #5
0
		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();
					}
				}
			}
		}
Пример #6
0
        public void CanSendEntries()
        {
            using (var node2Transport = new HttpTransport("node2"))
            {
                var node1 = new NodeConnectionInfo { Name = "node1", Uri = new Uri("http://localhost:9079") };

                node2Transport.Send(node1, new AppendEntriesRequest
                {
                    From = "node2",
                    ClusterTopologyId = new Guid("355a589b-cadc-463d-a515-5add2ea47205"),
                    Term = 2,
                    PrevLogIndex = 0,
                    PrevLogTerm = 0,
                    LeaderCommit = 1,
                    Entries = new LogEntry[]
                    {
                        new LogEntry
                        {
                            Term = 2,
                            Index = 1,
                            Data = new JsonCommandSerializer().Serialize(new DictionaryCommand.Set
                            {
                                Key = "a",
                                Value = 2
                            })
                        },
                    }
                });

                MessageContext context;
                var gotIt = node2Transport.TryReceiveMessage(_timeout, CancellationToken.None, out context);

                Assert.True(gotIt);

                var appendEntriesResponse = (AppendEntriesResponse)context.Message;
                Assert.True(appendEntriesResponse.Success);

                Assert.Equal(2, ((DictionaryStateMachine)_raftEngine.StateMachine).Data["a"]);
            }
        }
Пример #7
0
        public void CanInstallSnapshot()
        {
            using (var node2Transport = new HttpTransport("node2"))
            {
                var node1 = new NodeConnectionInfo { Name = "node1", Uri = new Uri("http://localhost:9079") };

                node2Transport.Send(node1, new CanInstallSnapshotRequest
                {
                    From = "node2",
                    ClusterTopologyId = new Guid("355a589b-cadc-463d-a515-5add2ea47205"),
                    Term = 2,
                    Index = 3,
                });

                MessageContext context;
                var gotIt = node2Transport.TryReceiveMessage(_timeout, CancellationToken.None, out context);
                Assert.True(gotIt);
                Assert.True(context.Message is CanInstallSnapshotResponse);

                node2Transport.Stream(node1, new InstallSnapshotRequest
                {
                    From = "node2",
                    ClusterTopologyId = new Guid("355a589b-cadc-463d-a515-5add2ea47205"),
                    Term = 2,
                    Topology = new Topology(new Guid("355a589b-cadc-463d-a515-5add2ea47205")),
                    LastIncludedIndex = 2,
                    LastIncludedTerm = 2,
                }, stream =>
                {
                    var streamWriter = new StreamWriter(stream);
                    var data = new Dictionary<string, int> { { "a", 2 } };
                    new JsonSerializer().Serialize(streamWriter, data);
                    streamWriter.Flush();
                });

                gotIt = node2Transport.TryReceiveMessage(_timeout, CancellationToken.None, out context);

                Assert.True(gotIt);

                var appendEntriesResponse = (InstallSnapshotResponse)context.Message;
                Assert.True(appendEntriesResponse.Success);

                Assert.Equal(2, ((DictionaryStateMachine)_raftEngine.StateMachine).Data["a"]);
            }
        }