Esempio n. 1
0
        public AppendEntryResponse AppendEntryRPCHandler(AppendEntry entry)
        {
            //Check the log check to prevent a intermittent term increase with no back tracking, TODO check whether this causes potentially concurrency issues
            if (entry.Term < _nodeStorage.CurrentTerm && entry.LeaderCommit <= NodeStateService.CommitIndex)
            {
                Logger.LogDebug(NodeStateService.GetNodeLogId() + "Rejected RPC from " + entry.LeaderId + " due to lower term " + entry.Term + "<" + _nodeStorage.CurrentTerm);
                return(new AppendEntryResponse()
                {
                    ConflictName = AppendEntriesExceptionNames.OldTermException,
                    NodeId = _nodeStorage.Id,
                    IsSuccessful = false
                });
            }

            //Reset the timer if the append is from a valid term
            ResetTimer(_electionTimeoutTimer, ClusterOptions.ElectionTimeoutMs, ClusterOptions.ElectionTimeoutMs);

            //If you are a leader or candidate, swap to a follower
            if (NodeStateService.Role == NodeState.Candidate || NodeStateService.Role == NodeState.Leader)
            {
                Logger.LogDebug(NodeStateService.GetNodeLogId() + " detected node " + entry.LeaderId + " is further ahead. Changing to follower");
                SetNodeRole(NodeState.Follower);
            }

            if (NodeStateService.CurrentLeader != entry.LeaderId)
            {
                Logger.LogDebug(NodeStateService.GetNodeLogId() + "Detected uncontacted leader, discovering leader now.");
                //Reset the current leader
                NodeStateService.CurrentLeader = entry.LeaderId;
            }

            if (entry.LeaderCommit > NodeStateService.LatestLeaderCommit)
            {
                Logger.LogDebug(NodeStateService.GetNodeLogId() + "Detected leader commit of " + entry.LeaderCommit + " commiting data on node.");
                NodeStateService.LatestLeaderCommit = entry.LeaderCommit;
            }


            // If your log entry is not within the last snapshot, then check the validity of the previous log index
            if (_nodeStorage.LastSnapshotIncludedIndex < entry.PrevLogIndex)
            {
                var previousEntry = _nodeStorage.GetLogAtIndex(entry.PrevLogIndex);

                if (previousEntry == null && entry.PrevLogIndex != 0)
                {
                    Logger.LogDebug(NodeStateService.GetNodeLogId() + "Missing previous entry at index " + entry.PrevLogIndex + " from term " + entry.PrevLogTerm + " does not exist.");

                    return(new AppendEntryResponse()
                    {
                        IsSuccessful = false,
                        ConflictingTerm = null,
                        ConflictName = AppendEntriesExceptionNames.MissingLogEntryException,
                        FirstTermIndex = null,
                        NodeId = _nodeStorage.Id,
                        LastLogEntryIndex = _nodeStorage.GetTotalLogCount()
                    });
                }
            }
            else
            {
                if (_nodeStorage.LastSnapshotIncludedTerm != entry.PrevLogTerm)
                {
                    Logger.LogDebug(NodeStateService.GetNodeLogId() + "Inconsistency found in the node snapshot and leaders logs, log " + entry.PrevLogIndex + " from term " + entry.PrevLogTerm + " does not exist.");
                    return(new AppendEntryResponse()
                    {
                        ConflictName = AppendEntriesExceptionNames.ConflictingLogEntryException,
                        IsSuccessful = false,
                        ConflictingTerm = entry.PrevLogTerm,
                        NodeId = _nodeStorage.Id,
                        FirstTermIndex = 0 //always set to 0 as snapshots are assumed to be from 0 > n
                    });
                }
            }

            _nodeStorage.SetCurrentTerm(entry.Term);

            foreach (var log in entry.Entries)
            {
                var existingEnty = _nodeStorage.GetLogAtIndex(log.Index);
                if (existingEnty != null && existingEnty.Term != log.Term)
                {
                    Logger.LogDebug(NodeStateService.GetNodeLogId() + "Found inconsistent logs in state, deleting logs from index " + log.Index);
                    _nodeStorage.DeleteLogsFromIndex(log.Index);
                    break;
                }
            }

            NodeStateService.InCluster = true;

            DateTime time = DateTime.Now;

            if (entry.Entries != null && _nodeStorage.GetLogAtIndex(entry.PrevLogIndex) != null && entry.Entries.Count() > 0 && entry.Entries.First().Index > 1 && _nodeStorage.GetLogAtIndex(entry.Entries.First().Index - 1).Term != entry.PrevLogTerm)
            {
                Logger.LogInformation(NodeStateService.GetNodeLogId() + "Last term does not match, log " + entry.PrevLogIndex + " from term " + entry.PrevLogTerm + " does not exist.");
                return(new AppendEntryResponse()
                {
                    ConflictName = AppendEntriesExceptionNames.ConflictingLogEntryException,
                    IsSuccessful = false,
                    ConflictingTerm = entry.PrevLogTerm,
                    NodeId = _nodeStorage.Id,
                    FirstTermIndex = 0//always set to 0 as snapshots are assumed to be from 0 > n
                });
            }

            foreach (var log in entry.Entries)
            {
                try
                {
                    if (!_nodeStorage.LogExists(log.Index))
                    {
                        Logger.LogDebug(NodeStateService.GetNodeLogId() + " adding to node storage " + log);
                        _nodeStorage.AddLog(log);
                    }
                }
                catch (MissingLogEntryException e)
                {
                    Logger.LogError(NodeStateService.GetNodeLogId() + " failed to add log " + log.Index + " with exception " + e.Message + Environment.NewLine + e.StackTrace);
                    return(new AppendEntryResponse()
                    {
                        IsSuccessful = false,
                        ConflictingTerm = null,
                        ConflictName = AppendEntriesExceptionNames.MissingLogEntryException,
                        FirstTermIndex = null,
                        NodeId = _nodeStorage.Id,
                        LastLogEntryIndex = _nodeStorage.GetTotalLogCount()
                    });
                }
                catch (Exception e)
                {
                    Logger.LogError(NodeStateService.GetNodeLogId() + " failed to add log " + log.Index + " with exception " + e.Message + Environment.NewLine + e.StackTrace);
                    return(new AppendEntryResponse()
                    {
                        IsSuccessful = false,
                        ConflictingTerm = null,
                        ConflictName = AppendEntriesExceptionNames.LogAppendingException,
                        FirstTermIndex = null,
                        NodeId = _nodeStorage.Id,
                        LastLogEntryIndex = _nodeStorage.GetTotalLogCount()
                    });
                }
            }

            return(new AppendEntryResponse()
            {
                IsSuccessful = true,
                NodeId = _nodeStorage.Id,
            });
        }