コード例 #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
 internal void FillNodeAddress()
 {
     na = new NodeRaftAddress()
     {
         NodeAddressId = Handshake.NodeListeningPort, NodeUId = Handshake.NodeUID, EndPointSID = this.EndPointSID
     };
 }
コード例 #3
0
        public void SendToAll(eRaftSignalType signalType, IEncoder data, NodeRaftAddress senderNodeAddress, string entityName, bool highPriority = false)
        {
            try
            {
                List <TcpPeer> peers = null;
                _sync.EnterReadLock();
                try
                {
                    peers = Peers.Values.ToList();
                }
                catch (Exception ex)
                {
                    //throw;
                }
                finally
                {
                    _sync.ExitReadLock();
                }

                foreach (var peer in peers)
                {
                    peer.Send(RaftCommand.RaftMessage, new TcpMsgRaft()
                    {
                        EntityName = entityName, RaftSignalType = signalType, Data = data.BiserEncode()
                    });
                }
            }
            catch (Exception ex)
            {
            }
        }
コード例 #4
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();
            }
        }
コード例 #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.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);
        }
コード例 #6
0
        /// <summary>
        /// called from lock try..catch
        /// </summary>
        /// <param name="address"></param>
        /// <param name="data"></param>
        public void ParseStateLogRedirectRequest(NodeRaftAddress address, object data)
        {
            StateLogEntryRedirectRequest req = data as StateLogEntryRedirectRequest;

            if (this.stateMachine.States.NodeState != eNodeState.Leader)  //Just return
            {
                return;
            }

            this.AddStateLogEntryForDistribution(req.Data, req.ExternalID);//, redirectId);
            this.EnqueueAndDistrbuteLog();

            //Don't answer, committed value wil be delivered via standard channel
        }
コード例 #7
0
 public void SendTo(NodeRaftAddress nodeAddress, eRaftSignalType signalType, IEncoder data, NodeRaftAddress senderNodeAddress, string entityName)
 {
     try
     {
         TcpPeer peer = null;
         if (Peers.TryGetValue(nodeAddress.EndPointSID, out peer))
         {
             peer.Send(RaftCommand.RaftMessage, new TcpMsgRaft()
             {
                 EntityName = entityName, RaftSignalType = signalType, Data = data.BiserEncode()
             });
         }
     }
     catch (Exception ex)
     {
     }
 }
コード例 #8
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);
 }
コード例 #9
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);
        }