コード例 #1
0
        private Raft.IServer thriftServer; //INTERFACE IMPLEMENTARDA PELO SERVIDOR THRIFT, ATRAVEZ DESSA INTERFACE É POSSIVEL REALMENTE EXECUTAR AS FUNÇÕES THRIFT

        public Node(List <Tuple <string, List <int> > > nodes, int node_index, Raft.IServer thriftServer)
        {
            this.t = 0;

            this.ip            = nodes[node_index].Item1;
            this.port          = nodes[node_index].Item2;
            this.current_state = State.Follower;

            this.nodes      = new Dictionary <Tuple <string, int>, TCP.TCPConnection>();
            this.nodes_acks = new Dictionary <Tuple <string, int>, int>();

            this.cluster_id = "";

            Tuple <int, int>[,] topology = this.PortTopology(nodes);
            for (int i = 0; i < nodes.Count(); i++)
            {
                if (i == node_index)
                {
                    continue;
                }
                var IPLocal  = new Tuple <string, int>(this.ip, topology[node_index, i].Item1);
                var IPRemote = new Tuple <string, int>(nodes[i].Item1, topology[node_index, i].Item2);

                var connection = new TCP.TCPConnection(IPLocal, IPRemote);
                this.nodes.Add(IPRemote, connection);

                this.nodes_acks.Add(IPRemote, 0);  //TODOS NODOS COMEÇAM SEM NENHUM COMMIT REALIZADO
            }

            this.election_time  = new System.Timers.Timer(Random.random.Next(1000, 2000));
            this.heartbeat_time = new System.Timers.Timer((int)(this.election_time.Interval / 3));

            this.election_time.Stop();
            this.heartbeat_time.Stop();

            this.election_time.AutoReset  = true;
            this.heartbeat_time.AutoReset = true;

            this.election_time.Elapsed  += Election;
            this.heartbeat_time.Elapsed += HeartBeat;

            this.log = new Log();

            this.thriftServer = thriftServer;

            Console.WriteLine("RAFT :: Create node with election_time:{0}ms", this.election_time.Interval);
        }
コード例 #2
0
        private void Listen(TCP.TCPConnection connection)
        {
            for (string buffer = null; true; buffer = connection.ReceiveMessage())
            {
                if (buffer == null || buffer == string.Empty)
                {
                    continue;
                }

                foreach (var message in buffer.Split('\0').Where(str => str != string.Empty))
                {
                    if (message.Split('|').Length != 6 || !message.Split('|')[3].Trim().Equals("null"))
                    {
                        Console.WriteLine("RAFT :: RECEIVE FROM <{0}:{1}> AT TERM={2} :: {3}", connection.IPRemote.Address, connection.IPRemote.Port, this.t, message.Trim());
                    }

                    if (message.Contains("request vote for me"))
                    {
                        if (int.Parse(message.Split('|')[0]) > this.t)
                        {
                            this.t = int.Parse(message.Split('|')[0]);
                            if (this.log.last_committed_index <= (int.Parse(message.Split('|')[2])))   //APENAS VOTA SIM SE A ULTIMA ENTRADA DO CANTIDO FOR MAIOR QUE A SUA, OU SEJA ESTA MAIS ATUALIZADO
                            {
                                connection.SendMessage(string.Format("{0}|vote yes", t));
                            }
                            else
                            {
                                connection.SendMessage(string.Format("{0}|vote no", t));
                            }
                        }
                        else
                        {
                            connection.SendMessage(string.Format("{0}|vote no", t));
                        }
                    }
                    else if (message.Contains("vote yes"))
                    {
                        if (int.Parse(message.Split('|')[0]) == this.t)
                        {
                            this.nVotes++;
                        }
                    }
                    else if (message.Contains("win"))
                    {
                        this.election_time.Stop();
                        var t = int.Parse(message.Split('|')[3]);
                        if (this.t <= t)
                        {
                            this.current_state = State.Follower;
                            this.heartbeat_time.Stop();
                            this.election_time.Start();
                            this.t = t;
                        }
                        //this.thriftServer.Commit(string.Format("FollowUpdateLeader({0}, {1});", this.cluster_id, this.cluster_id = message.Split('|')[5]));
                    }
                    else if (message.Contains("AE"))
                    {
                        this.resetTimer();
                        var t = int.Parse(message.Split('|')[0]);
                        if (this.t <= t)
                        {
                            this.current_state = State.Follower;
                            this.heartbeat_time.Stop();
                            this.t = t;

                            this.cluster_id = message.Split('|')[5];
                        }

                        var entryId   = int.Parse(message.Split('|')[2]);
                        var LastEntry = this.log.LastEntry();

                        if (LastEntry == null)
                        {
                            LastEntry = new Entry()
                            {
                                id = -1
                            };
                        }

                        if (LastEntry.id <= entryId)   //CHEGOU UMA ENTRADA ORDENADA, COMITA A ULTIMA E CONCATENA A NOVA
                        {
                            this.log.Commit(this.thriftServer);

                            foreach (var server in this.nodes.Keys)   //TODO SEGUIDOR ASSUME QUE SE ELE RECEBEU TODA A REDE TAMBÉM RECEBEU, CASO NÃO SEJA VERDADE
                                                                      //QUANDO ESSE SEGUIDOR ASSUMIR A LIDERANÇA, UM OUTRO SEGUIDOR IRÁ SOLICITAR O REGISTRO QUE É NECESSARIO
                            {
                                this.nodes_acks[server] = this.log.last_committed_index + 1;
                            }

                            if (LastEntry.id < entryId - 1)                                                      //CHEGOU UMA ENTRADA MUITO A FRENTE
                            {
                                connection.SendMessage(string.Format("NACK|{0}|{1}", this.t, LastEntry.id + 1)); //SOLICITA A ENTRADA DA SEQUENCIA
                                continue;                                                                        //DESCARTA A ENTRADA RECEBIDA (MANTEM O LOG ORDENADO)
                            }

                            if (message.Split('|')[3].Equals("null"))   //APENAS SINAL DE HEARTBEAT NÃO É UM ENVIO DE LOG
                            {
                                continue;
                            }

                            LastEntry = new Entry()
                            {
                                id      = entryId,
                                message = message.Split('|')[3],
                            };

                            this.log.append(LastEntry);
                            connection.SendMessage(string.Format("ACK|{0}|{1}", this.t, LastEntry.id)); //ACEITA A NOVA MENSAGEM
                        }
                    }
                    else if (message.Contains("NACK"))
                    {
                        var requestedId = int.Parse(message.Split('|')[2]);
                        var tuple       = Tuple.Create <string, int>(connection.IPRemote.Address.ToString(), connection.IPRemote.Port);

                        this.nodes_acks[tuple] = requestedId;
                    }
                    else if (message.Contains("ACK"))
                    {
                        var id    = int.Parse(message.Split('|')[2]);
                        var tuple = Tuple.Create <string, int>(connection.IPRemote.Address.ToString(), connection.IPRemote.Port);

                        this.log.SetAck(id, tuple, this.nodes.Count());
                        this.nodes_acks[tuple] = id + 1;

                        //Console.WriteLine("NEXT FOR ME " + tuple.Item1 + ":" + tuple.Item2 + ">>>" + this.nodes_acks[tuple]);
                    }
                }
            }
        }