コード例 #1
0
 public bool CommitLogEntry(NodeRaftAddress address, uint majorityQuantity, StateLogEntryApplied applied)
 {
     //If we receive acceptance signals of already Committed entries, we just ignore them
     if (this.LastCommittedIndex < applied.StateLogEntryId && stateMachine.NodeTerm == applied.StateLogEntryTerm)    //Setting LastCommittedId
     {
         var key  = GetKey(applied.StateLogEntryTerm, applied.StateLogEntryId);
         var iter = db.NewIterator();
         iter.Seek(key);
         int update = 0;
         while (iter.Valid())
         {
             var entry = StateLogEntry.BiserDecode(iter.Value());
             if (entry.IsCommitted)
             {
                 break;
             }
             entry.IsCommitted = true;
             var value = entry.BiserEncode();
             db.Put(key, value);
             update++;
             iter.Prev();
         }
         this.LastCommittedIndex     = applied.StateLogEntryId;
         this.LastCommittedIndexTerm = applied.StateLogEntryTerm;
         return(update > 0);
     }
     return(false);
 }
コード例 #2
0
        /// <summary>
        /// Leader receives accepted Log
        /// </summary>
        /// <param name="address"></param>
        /// <param name="data"></param>
        public void ParseStateLogEntryAccepted(NodeRaftAddress address, object data)
        {
            if (this.stateMachine.States.NodeState != eNodeState.Leader)
            {
                return;
            }

            StateLogEntryApplied applied = data as StateLogEntryApplied;

            var res = this.EntryIsAccepted(address, this.stateMachine.GetMajorityQuantity(), applied);

            if (res == eEntryAcceptanceResult.Committed)
            {
                distributeQueue.Remove(applied.StateLogEntryId);
                //this.VerbosePrint($"{this.NodeAddress.NodeAddressId}> LogEntry {applied.StateLogEntryId} is COMMITTED (answer from {address.NodeAddressId})"+DateTime.Now.Second+":"+DateTime.Now.Millisecond);
                this.stateMachine.timerLoop.StopLeaderLogResendTimeLoop();
                //Force heartbeat, to make followers to get faster info about commited elements
                LeaderHeartbeat heartBeat = new LeaderHeartbeat()
                {
                    LeaderTerm                     = this.stateMachine.NodeTerm,
                    StateLogLatestIndex            = this.stateMachine.NodeStateLog.StateLogId,
                    StateLogLatestTerm             = this.stateMachine.NodeStateLog.StateLogTerm,
                    LastStateLogCommittedIndex     = this.stateMachine.NodeStateLog.LastCommittedIndex,
                    LastStateLogCommittedIndexTerm = this.stateMachine.NodeStateLog.LastCommittedIndexTerm
                };
                this.stateMachine.network.SendToAll(eRaftSignalType.LeaderHearthbeat, heartBeat, this.stateMachine.NodeAddress, this.stateMachine.entitySettings.EntityName, true);
                //---------------------------------------
                this.stateMachine.States.InLogEntrySend = false;
                EnqueueAndDistrbuteLog();
            }
        }
コード例 #3
0
 public bool CommitLogEntry(NodeRaftAddress address, uint majorityQuantity, StateLogEntryApplied applied)
 {
     //If we receive acceptance signals of already Committed entries, we just ignore them
     if (this.LastCommittedIndex < applied.StateLogEntryId && stateMachine.NodeTerm == applied.StateLogEntryTerm)    //Setting LastCommittedId
     {
         var tocommit = list.FindAll(s => s.Term == applied.StateLogEntryTerm &&
                                     s.Index <= applied.StateLogEntryId &&
                                     s.IsCommitted == false);
         if (tocommit.Count > 0)
         {
             tocommit.ForEach(s => s.IsCommitted = true);
         }
         this.LastCommittedIndex     = applied.StateLogEntryId;
         this.LastCommittedIndexTerm = applied.StateLogEntryTerm;
         return(tocommit.Count > 0);
     }
     return(false);
 }
コード例 #4
0
        public async Task OnRecieve(IChannelHandlerContext context, string msgstr)
        {
            //
            if (!string.IsNullOrEmpty(msgstr))
            {
                //RaftCommand  msgObj = Newtonsoft.Json.JsonConvert.DeserializeObject<RaftCommand>(msgstr, new JsonSerializerSettings()
                //{
                //    NullValueHandling = NullValueHandling.Ignore,
                //    TypeNameHandling = TypeNameHandling.All,
                //    TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Full
                //}
                //);
                int         index  = msgstr.IndexOf(',');
                string      num    = msgstr.Substring(0, index);
                string      base64 = msgstr.Substring(index + 1);
                byte[]      data   = Convert.FromBase64String(base64);
                RaftCommand cmd    = new RaftCommand();
                cmd.Code = Convert.ToInt32(num);
                switch (cmd.Code)
                {
                case RaftCommand.Handshake:
                    cmd.Message = TcpMsgHandshake.BiserDecode(data);
                    break;

                case RaftCommand.HandshakeACK:
                    cmd.Message = TcpMsgHandshake.BiserDecode(data);
                    break;

                case RaftCommand.RaftMessage:
                    cmd.Message = TcpMsgRaft.BiserDecode(data);
                    TcpMsgRaft t = (TcpMsgRaft)cmd.Message;
                    switch (t.RaftSignalType)
                    {
                    case eRaftSignalType.LeaderHearthbeat:
                        t.orginalObject = LeaderHeartbeat.BiserDecode(t.Data);
                        break;

                    case eRaftSignalType.CandidateRequest:
                        t.orginalObject = CandidateRequest.BiserDecode(t.Data);
                        break;

                    case eRaftSignalType.StateLogEntryAccepted:
                        t.orginalObject = StateLogEntryApplied.BiserDecode(t.Data);
                        break;

                    case eRaftSignalType.StateLogEntryRequest:
                        t.orginalObject = StateLogEntryRequest.BiserDecode(t.Data);
                        break;

                    case eRaftSignalType.StateLogEntrySuggestion:
                        t.orginalObject = StateLogEntrySuggestion.BiserDecode(t.Data);
                        break;

                    case eRaftSignalType.StateLogRedirectRequest:
                        t.orginalObject = StateLogEntryRedirectRequest.BiserDecode(t.Data);
                        break;

                    case eRaftSignalType.VoteOfCandidate:
                        t.orginalObject = VoteOfCandidate.BiserDecode(t.Data);
                        break;
                    }
                    break;

                case RaftCommand.FreeMessage:
                    cmd.Message = TcpMsg.BiserDecode(data);
                    break;
                }
                this.packetParser(cmd as RaftCommand);
            }
        }
コード例 #5
0
        /// <summary>
        /// +
        /// Only Leader's proc.
        /// Accepts entry return true if Committed
        /// </summary>
        /// <param name="majorityNumber"></param>
        /// <param name="LogId"></param>
        /// <param name="TermId"></param>
        public eEntryAcceptanceResult EntryIsAccepted(NodeRaftAddress address, uint majorityQuantity, StateLogEntryApplied applied)
        {
            //If we receive acceptance signals of already Committed entries, we just ignore them
            if (applied.StateLogEntryId <= this.LastCommittedIndex)
            {
                return(eEntryAcceptanceResult.AlreadyAccepted);    //already accepted
            }
            if (applied.StateLogEntryId <= this.LastAppliedIndex)
            {
                return(eEntryAcceptanceResult.AlreadyAccepted);    //already accepted
            }
            StateLogEntryAcceptance acc = null;

            if (dStateLogEntryAcceptance.TryGetValue(applied.StateLogEntryId, out acc))
            {
                if (acc.Term != applied.StateLogEntryTerm)
                {
                    return(eEntryAcceptanceResult.NotAccepted);   //Came from wrong Leader probably
                }
                acc.acceptedEndPoints.Add(address.EndPointSID);
            }
            else
            {
                acc = new StateLogEntryAcceptance()
                {
                    //Quantity = 2,  //Leader + first incoming
                    Index = applied.StateLogEntryId,
                    Term  = applied.StateLogEntryTerm
                };
                acc.acceptedEndPoints.Add(address.EndPointSID);
                dStateLogEntryAcceptance[applied.StateLogEntryId] = acc;
            }
            if ((acc.acceptedEndPoints.Count + 1) >= majorityQuantity)
            {
                this.LastAppliedIndex = applied.StateLogEntryId;
                //Removing from Dictionary
                dStateLogEntryAcceptance.Remove(applied.StateLogEntryId);

                if (this.LastCommittedIndex < applied.StateLogEntryId && rn.NodeTerm == applied.StateLogEntryTerm)    //Setting LastCommittedId
                {
                    //Saving committed entry (all previous are automatically committed)
                    List <byte[]> lstCommited = new List <byte[]>();
                    lock (inMem.Sync)
                    {
                        foreach (var el in inMem.SelectForwardFromTo(this.LastCommittedIndex + 1, applied.StateLogEntryTerm, true, ulong.MaxValue, applied.StateLogEntryTerm))
                        {
                            lstCommited.Add(el.Item3.Data);
                        }
                    }
                    //Removing entry from command queue
                    //t.RemoveKey<byte[]>(tblAppendLogEntry, new byte[] { 1 }.ToBytes(applied.StateLogEntryTerm, applied.StateLogEntryId));
                    this.leaderState.qDistribution.Remove(applied.StateLogEntryId);
                }
                this.LastCommittedIndex     = applied.StateLogEntryId;
                this.LastCommittedIndexTerm = applied.StateLogEntryTerm;
                this.rn.logHandler.Commited();
                return(eEntryAcceptanceResult.Committed);
            }

            return(eEntryAcceptanceResult.Accepted);
        }
コード例 #6
0
        /// <summary>
        /// +
        /// Only Leader's proc.
        /// Accepts entry return true if Committed
        /// </summary>
        /// <param name="majorityNumber"></param>
        /// <param name="LogId"></param>
        /// <param name="TermId"></param>
        public eEntryAcceptanceResult EntryIsAccepted(NodeRaftAddress address, uint majorityQuantity, StateLogEntryApplied applied)
        {
            //If we receive acceptance signals of already Committed entries, we just ignore them
            if (applied.StateLogEntryId <= this.log.LastCommittedIndex)
            {
                return(eEntryAcceptanceResult.AlreadyAccepted);    //already accepted
            }
            if (applied.StateLogEntryId <= this.log.LastAppliedIndex)
            {
                return(eEntryAcceptanceResult.AlreadyAccepted);    //already accepted
            }
            StateLogEntryAcceptance acc = null;

            if (acceptStateTable.TryGetValue(applied.StateLogEntryId, out acc))
            {
                if (acc.Term != applied.StateLogEntryTerm)
                {
                    return(eEntryAcceptanceResult.NotAccepted);   //Came from wrong Leader probably
                }
                acc.acceptedEndPoints.Add(address.EndPointSID);
            }
            else
            {
                acc = new StateLogEntryAcceptance()
                {
                    Index = applied.StateLogEntryId,
                    Term  = applied.StateLogEntryTerm
                };

                acc.acceptedEndPoints.Add(address.EndPointSID);

                acceptStateTable[applied.StateLogEntryId] = acc;
            }
            if ((acc.acceptedEndPoints.Count + 1) >= majorityQuantity)
            {
                this.log.LastAppliedIndex = applied.StateLogEntryId;

                //Removing from Dictionary
                acceptStateTable.Remove(applied.StateLogEntryId);

                if (this.log.LastCommittedIndex < applied.StateLogEntryId && this.stateMachine.NodeTerm == applied.StateLogEntryTerm)    //Setting LastCommittedId
                {
                    bool commited = this.log.CommitLogEntry(address, majorityQuantity, applied);
                    //todo:: the above operation may commit many log at the same time
                    //should double check this logic
                    // if (this.log.lstCommited.Count > 0)
                    if (commited)
                    {
                        this.Commited();
                    }
                    return(eEntryAcceptanceResult.Committed);
                }
            }

            return(eEntryAcceptanceResult.Accepted);
        }