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); }
/// <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(); } }
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); }
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); } }
/// <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); }
/// <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); }