Example #1
0
        public void Send(JsonOperationContext context, AppendEntries ae, List <BlittableJsonReaderObject> items = null)
        {
            var msg = new DynamicJsonValue
            {
                ["Type"] = nameof(AppendEntries),
                [nameof(AppendEntries.EntriesCount)]      = ae.EntriesCount,
                [nameof(AppendEntries.LeaderCommit)]      = ae.LeaderCommit,
                [nameof(AppendEntries.PrevLogIndex)]      = ae.PrevLogIndex,
                [nameof(AppendEntries.PrevLogTerm)]       = ae.PrevLogTerm,
                [nameof(AppendEntries.Term)]              = ae.Term,
                [nameof(AppendEntries.TruncateLogBefore)] = ae.TruncateLogBefore,
                [nameof(AppendEntries.TimeAsLeader)]      = ae.TimeAsLeader
            };

            if (ae.ForceElections)
            {
                msg[nameof(AppendEntries.ForceElections)] = true;
            }

            Send(context, msg);

            if (items == null || items.Count == 0)
            {
                return;
            }

            foreach (var item in items)
            {
                Send(context, item);
            }
        }
        public void Send(JsonOperationContext context, Action updateFollowerTicks, AppendEntries ae, List <BlittableJsonReaderObject> items = null)
        {
            if (_log.IsInfoEnabled)
            {
                if (ae.EntriesCount > 0)
                {
                    _log.Info(
                        $"AppendEntries ({ae.EntriesCount:#,#;;0}) in {ae.Term:#,#;;0}, commit: {ae.LeaderCommit:#,#;;0}, leader for: {ae.TimeAsLeader:#,#;;0}, ({ae.PrevLogIndex:#,#;;0} / {ae.PrevLogTerm:#,#;;0}), truncate: {ae.TruncateLogBefore:#,#;;0}, force elections: {ae.ForceElections}.");
                }
            }

            var msg = new DynamicJsonValue
            {
                ["Type"] = nameof(AppendEntries),
                [nameof(AppendEntries.EntriesCount)]      = ae.EntriesCount,
                [nameof(AppendEntries.LeaderCommit)]      = ae.LeaderCommit,
                [nameof(AppendEntries.PrevLogIndex)]      = ae.PrevLogIndex,
                [nameof(AppendEntries.PrevLogTerm)]       = ae.PrevLogTerm,
                [nameof(AppendEntries.Term)]              = ae.Term,
                [nameof(AppendEntries.TruncateLogBefore)] = ae.TruncateLogBefore,
                [nameof(AppendEntries.TimeAsLeader)]      = ae.TimeAsLeader,
                [nameof(AppendEntries.SendingThread)]     = Thread.CurrentThread.ManagedThreadId,
                [nameof(AppendEntries.MinCommandVersion)] = ae.MinCommandVersion
            };

            if (ae.ForceElections)
            {
                msg[nameof(AppendEntries.ForceElections)] = true;
            }

            Send(context, msg);

            if (items == null || items.Count == 0)
            {
                return;
            }

            foreach (var item in items)
            {
                updateFollowerTicks();
                Send(context, item);
            }
        }
Example #3
0
        private (bool HasRemovedFromTopology, long LastAcknowledgedIndex, long LastTruncate, long LastCommit)  ApplyLeaderStateToLocalState(Stopwatch sp, ClusterOperationContext context, List <RachisEntry> entries, AppendEntries appendEntries)
        {
            long lastTruncate;
            long lastCommit;

            bool removedFromTopology = false;

            // we start the tx after we finished reading from the network
            if (_engine.Log.IsInfoEnabled)
            {
                _engine.Log.Info($"{ToString()}: Ready to start tx in {sp.Elapsed}");
            }

            using (var tx = context.OpenWriteTransaction())
            {
                _engine.ValidateTerm(_term);

                if (_engine.Log.IsInfoEnabled)
                {
                    _engine.Log.Info($"{ToString()}: Tx running in {sp.Elapsed}");
                }

                if (entries.Count > 0)
                {
                    var(lastTopology, lastTopologyIndex) = _engine.AppendToLog(context, entries);
                    using (lastTopology)
                    {
                        if (lastTopology != null)
                        {
                            if (_engine.Log.IsInfoEnabled)
                            {
                                _engine.Log.Info($"Topology changed to {lastTopology}");
                            }

                            var topology = JsonDeserializationRachis <ClusterTopology> .Deserialize(lastTopology);

                            if (topology.Members.ContainsKey(_engine.Tag) ||
                                topology.Promotables.ContainsKey(_engine.Tag) ||
                                topology.Watchers.ContainsKey(_engine.Tag))
                            {
                                RachisConsensus.SetTopology(_engine, context, topology);
                            }
                            else
                            {
                                removedFromTopology = true;
                                _engine.ClearAppendedEntriesAfter(context, lastTopologyIndex);
                            }
                        }
                    }
                }

                var lastEntryIndexToCommit = Math.Min(
                    _engine.GetLastEntryIndex(context),
                    appendEntries.LeaderCommit);

                var lastAppliedIndex = _engine.GetLastCommitIndex(context);
                var lastAppliedTerm  = _engine.GetTermFor(context, lastEntryIndexToCommit);

                // we start to commit only after we have any log with a term of the current leader
                if (lastEntryIndexToCommit > lastAppliedIndex && lastAppliedTerm == appendEntries.Term)
                {
                    lastAppliedIndex = _engine.Apply(context, lastEntryIndexToCommit, null, sp);
                }

                lastTruncate = Math.Min(appendEntries.TruncateLogBefore, lastAppliedIndex);
                _engine.TruncateLogBefore(context, lastTruncate);

                lastCommit = lastAppliedIndex;
                if (_engine.Log.IsInfoEnabled)
                {
                    _engine.Log.Info($"{ToString()}: Ready to commit in {sp.Elapsed}");
                }

                tx.Commit();
            }

            if (_engine.Log.IsInfoEnabled)
            {
                _engine.Log.Info($"{ToString()}: Processing entries request with {entries.Count} entries took {sp.Elapsed}");
            }

            var lastAcknowledgedIndex = entries.Count == 0 ? appendEntries.PrevLogIndex : entries[entries.Count - 1].Index;

            return(HasRemovedFromTopology : removedFromTopology, LastAcknowledgedIndex : lastAcknowledgedIndex, LastTruncate : lastTruncate, LastCommit : lastCommit);
        }