private void ProcessClientReq()
        {
            Console.WriteLine("[Server-{0} :: {1}] is processing a client request ...\n",
                              this.Id, this.CurrentTerm);

            this.Client = ((Tuple <Machine, Command>) this.Payload).Item1;

            var newEntry = new Entry();

            newEntry.Command = ((Tuple <Machine, Command>) this.Payload).Item2;
            newEntry.Index   = this.Log.Count;
            newEntry.Term    = this.CurrentTerm;

            this.Log.Clear();
            this.Log.Add(newEntry);

            var appendEntries = new AppendEntriesMessage();

            appendEntries.Term         = this.CurrentTerm;
            appendEntries.LeaderId     = this.Id;
            appendEntries.LeaderCommit = this.CommitIndex;


            if (this.Servers != null)
            {
                for (int idx = 0; idx < this.Servers.Count; idx++)
                {
                    if (idx == this.Id)
                    {
                        continue;
                    }

                    appendEntries.Entries = new List <Entry>();

                    var nextIndex = this.NextIndex[idx];

                    if (this.Log.Count - 1 >= nextIndex && nextIndex >= 0)
                    {
                        for (int i = nextIndex; i < this.Log.Count; i++)
                        {
                            appendEntries.Entries.Add(this.Log[i]);
                        }
                    }
                    else
                    {
                        appendEntries.Entries.Add(newEntry);
                    }

                    this.Send(this.Servers[idx], new eAppendEntries(appendEntries));
                }
            }

            this.Acks.Add(true);
        }
        private void ProcessHeartBeat()
        {
            Console.WriteLine("[Server-{0} :: {1}] is sending heartbeats ...\n",
                              this.Id, this.CurrentTerm);

            if (this.Servers != null)
            {
                for (int idx = 0; idx < this.Servers.Count; idx++)
                {
                    if (idx != this.Id)
                    {
                        var appendEntries = new AppendEntriesMessage();
                        appendEntries.Term     = this.CurrentTerm;
                        appendEntries.LeaderId = this.Id;
                        appendEntries.Entries  = new List <Entry>();

                        this.Send(this.Servers[idx], new eAppendEntries(appendEntries));
                    }
                }
            }
        }
        private void ProcessAppendEntriesAck()
        {
            var appendEntriesAck = (AppendEntriesAckMessage)this.Payload;

            if (appendEntriesAck.Success)
            {
                Console.WriteLine("[Server-{0} :: {1}] received a successful append entries ack from " +
                                  "server {2} with term {3} ...\n", this.Id, this.CurrentTerm,
                                  appendEntriesAck.SenderId, appendEntriesAck.Term);
                this.NextIndex[appendEntriesAck.SenderId]  = this.Log.Count - 1;
                this.MatchIndex[appendEntriesAck.SenderId] = this.Log.Count - 1;
            }
            else
            {
                Console.WriteLine("[Server-{0} :: {1}] received an un-successful append entries ack from " +
                                  "server {2} with term {3} ...\n", this.Id, this.CurrentTerm,
                                  appendEntriesAck.SenderId, appendEntriesAck.Term);
                this.NextIndex[appendEntriesAck.SenderId] = this.NextIndex[appendEntriesAck.SenderId] - 1;
                if (this.NextIndex[appendEntriesAck.SenderId] < 0)
                {
                    this.NextIndex[appendEntriesAck.SenderId] = 0;
                }

                if (this.Servers != null && this.Log.Count > 0)
                {
                    var appendEntries = new AppendEntriesMessage();
                    appendEntries.Term         = this.CurrentTerm;
                    appendEntries.LeaderId     = this.Id;
                    appendEntries.LeaderCommit = this.CommitIndex;
                    appendEntries.Entries      = new List <Entry>();

                    var nextIndex = this.NextIndex[appendEntriesAck.SenderId];
                    if (this.Log.Count - 1 >= nextIndex)
                    {
                        for (int i = nextIndex; i < this.Log.Count; i++)
                        {
                            appendEntries.Entries.Add(this.Log[i]);
                        }
                    }
                    else
                    {
                        appendEntries.Entries.Add(this.Log[this.Log.Count - 1]);
                    }

                    if (nextIndex > 0)
                    {
                        appendEntries.PrevLogIndex = nextIndex - 1;
                        appendEntries.PrevLogTerm  = this.Log[nextIndex - 1].Term;
                    }

                    this.Send(this.Servers[appendEntriesAck.SenderId], new eAppendEntries(appendEntries));
                }
            }

            if (appendEntriesAck.Term > this.CurrentTerm)
            {
                this.CurrentTerm = appendEntriesAck.Term;
            }

            this.Acks.Add(appendEntriesAck.Success);

            int ackCounter = 0;

            foreach (var ack in this.Acks)
            {
                if (ack)
                {
                    ackCounter = ackCounter + 1;
                }
            }

            var majority = (this.Votes.Length / 2) + 1;

            if (this.Acks.Count == this.Votes.Length &&
                this.Log.Count > 0 && this.Client != null)
            {
                if (ackCounter >= majority)
                {
                    var latestCommand = this.Log[this.Log.Count - 1].Command;
                    if (latestCommand.CommandType == CommandTypes.Add)
                    {
                        this.State = this.State + latestCommand.Value;
                    }
                    else
                    {
                        this.State = this.State - latestCommand.Value;
                    }

                    this.CommitIndex = this.Log.Count - 1;
                    this.Send(this.Client, new eClientReqAck(this.State));
                }
                else
                {
                    this.Send(this.Client, new eClientReqAck(null));
                }
            }
        }