Example #1
0
        /// <summary>
        /// Only for Follower
        ///  Is called from tryCatch and in lock
        /// </summary>
        /// <param name="address"></param>
        /// <param name="data"></param>
        void ParseStateLogEntrySuggestion(NodeAddress address, byte[] data)
        {
            if (this.NodeState != eNodeState.Follower)
            {
                return;
            }

            StateLogEntrySuggestion suggest = StateLogEntrySuggestion.BiserDecode(data); //data.DeserializeProtobuf<StateLogEntrySuggestion>();

            if (this.NodeTerm > suggest.LeaderTerm)                                      //Sending Leader is not Leader anymore
            {
                this.NodeStateLog.LeaderSynchronizationIsActive = false;
                return;
            }

            if (this.NodeTerm < suggest.LeaderTerm)
            {
                this.NodeTerm = suggest.LeaderTerm;
            }


            if (suggest.StateLogEntry.Index <= NodeStateLog.LastCommittedIndex) //Preventing same entry income, can happen if restoration was sent twice (while switch of leaders)
            {
                return;                                                         //breakpoint don't remove
            }
            //Checking if node can accept current suggestion
            if (suggest.StateLogEntry.PreviousStateLogId > 0)
            {
                var sle = this.NodeStateLog.GetEntryByIndexTerm(suggest.StateLogEntry.PreviousStateLogId, suggest.StateLogEntry.PreviousStateLogTerm);

                if (sle == null)
                {
                    //We don't have previous to this log and need new index request
                    //VerbosePrint($"{NodeAddress.NodeAddressId}>  in sync 1 ");
                    if (entitySettings.InMemoryEntity && entitySettings.InMemoryEntityStartSyncFromLatestEntity && this.NodeStateLog.LastAppliedIndex == 0)
                    {
                        //helps newly starting mode with specific InMemory parameters get only latest command for the entity
                    }
                    else
                    {
                        this.SyncronizeWithLeader();
                        return;
                    }
                }
            }

            //We can apply new Log Entry from the Leader and answer successfully
            this.NodeStateLog.AddToLogFollower(suggest);

            StateLogEntryApplied applied = new StateLogEntryApplied()
            {
                StateLogEntryId   = suggest.StateLogEntry.Index,
                StateLogEntryTerm = suggest.StateLogEntry.Term
                                    // RedirectId = suggest.StateLogEntry.RedirectId
            };

            //this.NodeStateLog.LeaderSynchronizationIsActive = false;

            this.Sender.SendTo(address, eRaftSignalType.StateLogEntryAccepted, applied.SerializeBiser(), this.NodeAddress, entitySettings.EntityName);
        }
        public static StateLogEntrySuggestion BiserDecode(byte[] enc = null, Biser.Decoder extDecoder = null) //!!!!!!!!!!!!!! change return type
        {
            Biser.Decoder decoder = null;
            if (extDecoder == null)
            {
                if (enc == null || enc.Length == 0)
                {
                    return(null);
                }
                decoder = new Biser.Decoder(enc);
                if (decoder.CheckNull())
                {
                    return(null);
                }
            }
            else
            {
                if (extDecoder.CheckNull())
                {
                    return(null);
                }
                else
                {
                    decoder = extDecoder;
                }
            }

            StateLogEntrySuggestion m = new StateLogEntrySuggestion();  //!!!!!!!!!!!!!! change return type

            m.LeaderTerm    = decoder.GetULong();
            m.StateLogEntry = StateLogEntry.BiserDecode(extDecoder: decoder);
            m.IsCommitted   = decoder.GetBool();

            return(m);
        }
Example #3
0
        public void AddLogEntry(StateLogEntrySuggestion suggestion)

        {
            //Restoring current values
            PreviousStateLogId   = suggestion.StateLogEntry.PreviousStateLogId;
            PreviousStateLogTerm = suggestion.StateLogEntry.PreviousStateLogTerm;
            StateLogId           = suggestion.StateLogEntry.Index;
            StateLogTerm         = suggestion.StateLogEntry.Term;
            using (var t = this.db.GetTransaction())
            {
                t.Insert <byte[], byte[]>(stateTableName, new byte[] { 1 }.ToBytes(suggestion.StateLogEntry.Index, suggestion.StateLogEntry.Term), suggestion.StateLogEntry.SerializeBiser());
                t.Commit();
            }
        }
Example #4
0
        /// <summary>
        /// Only for Follower
        ///  Is called from tryCatch and in lock
        /// </summary>
        /// <param name="address"></param>
        /// <param name="data"></param>
        void ParseStateLogEntrySuggestion(NodeRaftAddress address, object data)
        {
            if (this.States.NodeState != eNodeState.Follower)
            {
                return;
            }

            StateLogEntrySuggestion suggest = data as StateLogEntrySuggestion;

            if (this.NodeTerm > suggest.LeaderTerm)  //Sending Leader is not Leader anymore
            {
                this.States.LeaderSynchronizationIsActive = false;
                return;
            }

            if (this.NodeTerm < suggest.LeaderTerm)
            {
                this.NodeTerm = suggest.LeaderTerm;
            }
            if (suggest.StateLogEntry == null || (suggest.StateLogEntry.Index <= NodeStateLog.LastCommittedIndex)) //Preventing same entry income, can happen if restoration was sent twice (while switch of leaders)
            {
                return;                                                                                            //breakpoint don't remove
            }
            //Checking if node can accept current suggestion
            if (suggest.StateLogEntry.PreviousStateLogId > 0)
            {
                var sle = this.NodeStateLog.GetEntryByIndexTerm(suggest.StateLogEntry.PreviousStateLogId, suggest.StateLogEntry.PreviousStateLogTerm);

                if (sle == null)
                {
                    this.SyncronizeWithLeader();
                    return;
                }
            }
            //We can apply new Log Entry from the Leader and answer successfully
            this.logHandler.AddLogEntryByFollower(suggest);

            StateLogEntryApplied applied = new StateLogEntryApplied()
            {
                StateLogEntryId   = suggest.StateLogEntry.Index,
                StateLogEntryTerm = suggest.StateLogEntry.Term
                                    // RedirectId = suggest.StateLogEntry.RedirectId
            };

            this.network.SendTo(address, eRaftSignalType.StateLogEntryAccepted, applied, this.NodeAddress, entitySettings.EntityName);
        }
Example #5
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="suggestion"></param>
        /// <returns></returns>
        public void AddToLogFollower(StateLogEntrySuggestion suggestion)
        {
            try
            {
                if (rn.entitySettings.DelayedPersistenceIsActive)
                {
                    Tuple <ulong, StateLogEntry> tplSle = null;
                    if (
                        sleCache.TryGetValue(suggestion.StateLogEntry.Index, out tplSle)
                        &&
                        tplSle.Item1 == suggestion.StateLogEntry.Term)
                    {
                        return; //we got it already
                    }
                }

                using (var t = this.rn.db.GetTransaction())
                {
                    //Removing from the persisted all keys equal or bigger then supplied Log (also from other terms)
                    foreach (var el in t.SelectForwardFromTo <byte[], byte[]>(tblStateLogEntry,
                                                                              new byte[] { 1 }.ToBytes(suggestion.StateLogEntry.Index, ulong.MinValue), true,
                                                                              new byte[] { 1 }.ToBytes(ulong.MaxValue, ulong.MaxValue), true, true))
                    {
                        if (
                            el.Key.Substring(1, 8).To_UInt64_BigEndian() == suggestion.StateLogEntry.Index &&
                            el.Key.Substring(9, 8).To_UInt64_BigEndian() == suggestion.StateLogEntry.Term
                            )
                        {
                            //we got it already
                            return;
                        }

                        t.RemoveKey <byte[]>(tblStateLogEntry, el.Key);
                    }

                    if (rn.entitySettings.DelayedPersistenceIsActive)
                    {
                        foreach (var iel in sleCache.Where(r => r.Key >= suggestion.StateLogEntry.Index).Select(r => r.Key).ToList())
                        {
                            sleCache.Remove(iel);
                        }

                        sleCache[suggestion.StateLogEntry.Index] = new Tuple <ulong, StateLogEntry>(suggestion.StateLogEntry.Term, suggestion.StateLogEntry);
                    }
                    else
                    {
                        t.Insert <byte[], byte[]>(tblStateLogEntry, new byte[] { 1 }.ToBytes(suggestion.StateLogEntry.Index, suggestion.StateLogEntry.Term), suggestion.StateLogEntry.SerializeBiser());
                    }

                    t.Commit();
                }

                rn.VerbosePrint($"{rn.NodeAddress.NodeAddressId}> AddToLogFollower (I/T): {suggestion.StateLogEntry.Index}/{suggestion.StateLogEntry.Term} -> Result:" +
                                $" { (GetEntryByIndexTerm(suggestion.StateLogEntry.Index, suggestion.StateLogEntry.Term) != null)};");

                //Setting new internal LogId
                PreviousStateLogId   = StateLogId;
                PreviousStateLogTerm = StateLogTerm;
                StateLogId           = suggestion.StateLogEntry.Index;
                StateLogTerm         = suggestion.StateLogEntry.Term;

                tempPrevStateLogId   = PreviousStateLogId;
                tempPrevStateLogTerm = PreviousStateLogTerm;
                tempStateLogId       = StateLogId;
                tempStateLogTerm     = StateLogTerm;

                if (suggestion.IsCommitted)
                {
                    if (
                        this.LastCommittedIndexTerm > suggestion.StateLogEntry.Term
                        ||
                        (
                            this.LastCommittedIndexTerm == suggestion.StateLogEntry.Term
                            &&
                            this.LastCommittedIndex > suggestion.StateLogEntry.Index
                        )
                        )
                    {
                        //Should be not possible
                    }
                    else
                    {
                        this.LastCommittedIndex     = suggestion.StateLogEntry.Index;
                        this.LastCommittedIndexTerm = suggestion.StateLogEntry.Term;

                        //this.rn.Commited(suggestion.StateLogEntry.Index);
                        this.rn.Commited();
                    }
                }
            }
            catch (Exception ex)
            {
            }

            if (this.LastCommittedIndex < rn.LeaderHeartbeat.LastStateLogCommittedIndex)
            {
                rn.SyncronizeWithLeader(true);
            }
            else
            {
                LeaderSynchronizationIsActive = false;
            }
        }
Example #6
0
        /// <summary>
        /// +
        /// Can be null.
        /// Must be called inside of operation lock.
        /// </summary>
        /// <param name="logEntryId"></param>
        /// <param name="LeaderTerm"></param>
        /// <returns></returns>
        public StateLogEntrySuggestion GetNextStateLogEntrySuggestionFromRequested(StateLogEntryRequest req)
        {
            StateLogEntrySuggestion le = new StateLogEntrySuggestion()
            {
                LeaderTerm = rn.NodeTerm
            };

            int           cnt      = 0;
            StateLogEntry sle      = null;
            ulong         prevId   = 0;
            ulong         prevTerm = 0;

            using (var t = this.rn.db.GetTransaction())
            {
                if (req.StateLogEntryId == 0)// && req.StateLogEntryTerm == 0)
                {
                    if (rn.entitySettings.DelayedPersistenceIsActive && sleCache.Count > 0)
                    {
                        sle = sleCache.OrderBy(r => r.Key).First().Value.Item2;
                    }
                    else
                    {
                        var trow = t.SelectForwardFromTo <byte[], byte[]>(tblStateLogEntry,
                                                                          new byte[] { 1 }.ToBytes(ulong.MinValue, ulong.MinValue), true,
                                                                          new byte[] { 1 }.ToBytes(ulong.MaxValue, ulong.MaxValue), true).FirstOrDefault();

                        if (trow != null && trow.Exists)
                        {
                            sle = StateLogEntry.BiserDecode(trow.Value);
                        }
                    }


                    //else
                    //{
                    //    //should not normally happen
                    //}

                    if (sle != null)
                    {
                        le.StateLogEntry = sle;

                        if (
                            LastCommittedIndexTerm >= le.StateLogEntry.Term
                            &&
                            LastCommittedIndex >= le.StateLogEntry.Index
                            )
                        {
                            le.IsCommitted = true;
                        }

                        cnt = 2;
                    }
                }
                else
                {
                    Tuple <ulong, StateLogEntry> sleTpl;
                    bool reForward = true;

                    if (rn.entitySettings.DelayedPersistenceIsActive &&
                        sleCache.TryGetValue(req.StateLogEntryId, out sleTpl)
                        )
                    {
                        cnt++;
                        sle      = sleTpl.Item2;
                        prevId   = sle.Index;
                        prevTerm = sle.Term;

                        if (sleCache.TryGetValue(req.StateLogEntryId + 1, out sleTpl))
                        {
                            cnt++;
                            sle = sleTpl.Item2;
                            le.StateLogEntry = sle;
                        }
                    }
                    else
                    {
                        reForward = false;
                        foreach (var el in t.SelectForwardFromTo <byte[], byte[]>(tblStateLogEntry,
                                                                                  //new byte[] { 1 }.ToBytes(req.StateLogEntryId, req.StateLogEntryTerm), true,
                                                                                  new byte[] { 1 }.ToBytes(req.StateLogEntryId, ulong.MinValue), true,
                                                                                  new byte[] { 1 }.ToBytes(ulong.MaxValue, ulong.MaxValue), true).Take(2))
                        {
                            cnt++;
                            sle = StateLogEntry.BiserDecode(el.Value);
                            if (cnt == 1)
                            {
                                prevId   = sle.Index;
                                prevTerm = sle.Term;
                            }
                            else
                            {
                                le.StateLogEntry = sle;
                            }
                        }
                    }


                    if (cnt < 2 && reForward)
                    {
                        ulong toAdd = (ulong)cnt;
                        foreach (var el in t.SelectForwardFromTo <byte[], byte[]>(tblStateLogEntry,
                                                                                  //new byte[] { 1 }.ToBytes(req.StateLogEntryId + toAdd, req.StateLogEntryTerm), true,
                                                                                  new byte[] { 1 }.ToBytes(req.StateLogEntryId + toAdd, ulong.MinValue), true,
                                                                                  new byte[] { 1 }.ToBytes(ulong.MaxValue, ulong.MaxValue), true).Take(2))
                        {
                            cnt++;
                            sle = StateLogEntry.BiserDecode(el.Value);
                            if (cnt == 1)
                            {
                                prevId   = sle.Index;
                                prevTerm = sle.Term;
                            }
                            else
                            {
                                le.StateLogEntry = sle;
                            }
                        }
                    }


                    if (cnt == 2)
                    {
                        le.StateLogEntry.PreviousStateLogId   = prevId;
                        le.StateLogEntry.PreviousStateLogTerm = prevTerm;
                        if (
                            LastCommittedIndexTerm >= le.StateLogEntry.Term
                            &&
                            LastCommittedIndex >= le.StateLogEntry.Index
                            )
                        {
                            le.IsCommitted = true;
                        }
                    }
                }
            }

            //if (first)
            if (cnt != 2)
            {
                return(null);
            }
            return(le);
        }
Example #7
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="suggestion"></param>
        /// <returns></returns>
        public void AddToLogFollower(StateLogEntrySuggestion suggestion)
        {
            try
            {
                var col = this.db.GetCollection <StateLogEntry>(stateTableName);
                col.DeleteMany(s => (s.Index > suggestion.StateLogEntry.Index && s.Term == suggestion.StateLogEntry.Term) || s.Term > suggestion.StateLogEntry.Term);
                col.Insert(suggestion.StateLogEntry);
                //using (var t = this.db.GetTransaction())
                {
                    //foreach (var el in t.SelectForwardFromTo<byte[], byte[]>(stateTableName,
                    //            new byte[] { 1 }.ToBytes(suggestion.StateLogEntry.Index, ulong.MinValue), true,
                    //            new byte[] { 1 }.ToBytes(ulong.MaxValue, ulong.MaxValue), true, true))
                    //{

                    //    if (
                    //        el.Key.Substring(1, 8).To_UInt64_BigEndian() == suggestion.StateLogEntry.Index &&
                    //        el.Key.Substring(9, 8).To_UInt64_BigEndian() == suggestion.StateLogEntry.Term
                    //        )
                    //    {
                    //        return;
                    //    }

                    //    t.RemoveKey<byte[]>(stateTableName, el.Key);
                    //    //  pups++;
                    //}
                    //t.Insert<byte[], byte[]>(stateTableName, new byte[] { 1 }.ToBytes(suggestion.StateLogEntry.Index, suggestion.StateLogEntry.Term), suggestion.StateLogEntry.SerializeBiser());
                    //t.Commit();
                }

                statemachine.VerbosePrint($"{statemachine.NodeAddress.NodeAddressId}> AddToLogFollower (I/T): {suggestion.StateLogEntry.Index}/{suggestion.StateLogEntry.Term} -> Result:" +
                                          $" { (GetEntryByIndexTerm(suggestion.StateLogEntry.Index, suggestion.StateLogEntry.Term) != null)};");

                //Setting new internal LogId
                PreviousStateLogId   = StateLogId;
                PreviousStateLogTerm = StateLogTerm;
                StateLogId           = suggestion.StateLogEntry.Index;
                StateLogTerm         = suggestion.StateLogEntry.Term;

                tempPrevStateLogId   = PreviousStateLogId;
                tempPrevStateLogTerm = PreviousStateLogTerm;
                tempStateLogId       = StateLogId;
                tempStateLogTerm     = StateLogTerm;

                if (suggestion.IsCommitted)
                {
                    if (
                        this.LastCommittedIndexTerm > suggestion.StateLogEntry.Term
                        ||
                        (
                            this.LastCommittedIndexTerm == suggestion.StateLogEntry.Term
                            &&
                            this.LastCommittedIndex > suggestion.StateLogEntry.Index
                        )
                        )
                    {
                        //Should be not possible
                    }
                    else
                    {
                        this.LastCommittedIndex     = suggestion.StateLogEntry.Index;
                        this.LastCommittedIndexTerm = suggestion.StateLogEntry.Term;
                        this.statemachine.logHandler.Commited();
                    }
                }
            }
            catch (Exception ex)
            {
            }
            if (statemachine.States.LeaderHeartbeat != null && this.LastCommittedIndex < statemachine.States.LeaderHeartbeat.LastStateLogCommittedIndex)
            {
                statemachine.SyncronizeWithLeader(true);
            }
            else
            {
                LeaderSynchronizationIsActive = false;
            }
        }
Example #8
0
        /// <summary>
        /// +
        /// Can be null.
        /// Must be called inside of operation lock.
        /// get local commit history for follower
        /// </summary>
        /// <param name="logEntryId"></param>
        /// <param name="LeaderTerm"></param>
        /// <returns></returns>
        public StateLogEntrySuggestion GetNextStateLogEntrySuggestionFromRequested(StateLogEntryRequest req)
        {
            StateLogEntrySuggestion le = new StateLogEntrySuggestion()
            {
                LeaderTerm = statemachine.NodeTerm
            };

            int           cnt      = 0;
            StateLogEntry sle      = null;
            ulong         prevId   = 0;
            ulong         prevTerm = 0;

            var col = this.db.GetCollection <StateLogEntry>(stateTableName);

            //using (var t = this.db.GetTransaction())
            {
                if (req.StateLogEntryId == 0)
                {
                    var trow = col.Query().OrderBy(s => s.Term, 1).OrderBy(s => s.Term, 1).FirstOrDefault();
                    if (trow != null)
                    {
                        le.StateLogEntry = trow;
                        if (LastCommittedIndexTerm >= le.StateLogEntry.Term &&
                            LastCommittedIndex >= le.StateLogEntry.Index
                            )
                        {
                            le.IsCommitted = true;
                        }
                        cnt = 2;
                    }
                }
                else
                {
                    var list = col.Query().Where(s => s.Index >= req.StateLogEntryId).ToList().OrderBy(s => s.Term).OrderBy(s => s.Term).ToList();
                    foreach (var item in list)
                    {
                        cnt++;
                        sle = item;
                        if (cnt == 1)
                        {
                            prevId   = sle.Index;
                            prevTerm = sle.Term;
                        }
                        else
                        {
                            le.StateLogEntry = sle;
                        }
                    }
                    if (cnt < 2)
                    {
                        ulong toAdd = (ulong)cnt;
                        list = col.Query().Where(s => s.Index >= req.StateLogEntryId + toAdd).ToList().OrderBy(s => s.Term).OrderBy(s => s.Index).ToList();
                        foreach (var item in list)
                        {
                            cnt++;
                            sle = item;
                            if (cnt == 1)
                            {
                                prevId   = sle.Index;
                                prevTerm = sle.Term;
                            }
                            else
                            {
                                le.StateLogEntry = sle;
                            }
                        }
                    }
                }
                //if (req.StateLogEntryId == 0)// && req.StateLogEntryTerm == 0)
                //{

                //  var trow = t.SelectForwardFromTo<byte[], byte[]>(stateTableName,
                //               new byte[] { 1 }.ToBytes(ulong.MinValue, ulong.MinValue), true,
                //               new byte[] { 1 }.ToBytes(ulong.MaxValue, ulong.MaxValue), true).FirstOrDefault();

                //  if (trow != null && trow.Exists)
                //      sle = StateLogEntry.BiserDecode(trow.Value);
                //  if (sle != null)
                //    {
                //        le.StateLogEntry = sle;
                //        if (
                //            LastCommittedIndexTerm >= le.StateLogEntry.Term
                //            &&
                //            LastCommittedIndex >= le.StateLogEntry.Index
                //            )
                //        {
                //            le.IsCommitted = true;
                //        }
                //        cnt = 2;
                //    }
                //}
                //else
                //{
                //    Tuple<ulong, StateLogEntry> sleTpl;
                //    bool reForward = true;
                //        reForward = false;
                //        foreach (var el in t.SelectForwardFromTo<byte[], byte[]>(stateTableName,
                //            new byte[] { 1 }.ToBytes(req.StateLogEntryId, ulong.MinValue), true,
                //            new byte[] { 1 }.ToBytes(ulong.MaxValue, ulong.MaxValue), true).Take(2))
                //        {
                //            cnt++;
                //            sle = StateLogEntry.BiserDecode(el.Value);
                //            if (cnt == 1)
                //            {
                //                prevId = sle.Index;
                //                prevTerm = sle.Term;
                //            }
                //            else
                //            {
                //                le.StateLogEntry = sle;
                //            }
                //    }
                //    if (cnt < 2 && reForward)
                //    {
                //        ulong toAdd = (ulong)cnt;
                //        foreach (var el in t.SelectForwardFromTo<byte[], byte[]>(stateTableName,
                //        //new byte[] { 1 }.ToBytes(req.StateLogEntryId + toAdd, req.StateLogEntryTerm), true,
                //        new byte[] { 1 }.ToBytes(req.StateLogEntryId + toAdd, ulong.MinValue), true,
                //        new byte[] { 1 }.ToBytes(ulong.MaxValue, ulong.MaxValue), true).Take(2))
                //        {
                //            cnt++;
                //            sle = StateLogEntry.BiserDecode(el.Value);
                //            if (cnt == 1)
                //            {
                //                prevId = sle.Index;
                //                prevTerm = sle.Term;
                //            }
                //            else
                //            {
                //                le.StateLogEntry = sle;
                //            }
                //        }
            }

            if (cnt == 2)
            {
                le.StateLogEntry.PreviousStateLogId   = prevId;
                le.StateLogEntry.PreviousStateLogTerm = prevTerm;
                if (
                    LastCommittedIndexTerm >= le.StateLogEntry.Term
                    &&
                    LastCommittedIndex >= le.StateLogEntry.Index
                    )
                {
                    le.IsCommitted = true;
                }
            }


            if (cnt != 2)
            {
                return(null);
            }
            return(le);
        }
Example #9
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="suggestion"></param>
        /// <returns></returns>
        public void AddLogEntryByFollower(StateLogEntrySuggestion suggestion)
        {
            try
            {
                using (var t = this.db.GetTransaction())
                {
                    foreach (var el in t.SelectForwardFromTo <byte[], byte[]>(stateTableName,
                                                                              new byte[] { 1 }.ToBytes(suggestion.StateLogEntry.Index, ulong.MinValue), true,
                                                                              new byte[] { 1 }.ToBytes(ulong.MaxValue, ulong.MaxValue), true, true))
                    {
                        if (
                            el.Key.Substring(1, 8).To_UInt64_BigEndian() == suggestion.StateLogEntry.Index &&
                            el.Key.Substring(9, 8).To_UInt64_BigEndian() == suggestion.StateLogEntry.Term
                            )
                        {
                            return;
                        }

                        t.RemoveKey <byte[]>(stateTableName, el.Key);
                        //  pups++;
                    }
                    t.Insert <byte[], byte[]>(stateTableName, new byte[] { 1 }.ToBytes(suggestion.StateLogEntry.Index, suggestion.StateLogEntry.Term), suggestion.StateLogEntry.SerializeBiser());
                    t.Commit();
                }

                // statemachine.VerbosePrint($"{statemachine.NodeAddress.NodeAddressId}> AddToLogFollower (I/T): {suggestion.StateLogEntry.Index}/{suggestion.StateLogEntry.Term} -> Result:" +
                //    $" { (GetEntryByIndexTerm(suggestion.StateLogEntry.Index, suggestion.StateLogEntry.Term) != null)};");

                //Setting new internal LogId
                PreviousStateLogId   = StateLogId;
                PreviousStateLogTerm = StateLogTerm;
                StateLogId           = suggestion.StateLogEntry.Index;
                StateLogTerm         = suggestion.StateLogEntry.Term;

                //tempPrevStateLogId = PreviousStateLogId;
                //tempPrevStateLogTerm = PreviousStateLogTerm;
                //tempStateLogId = StateLogId;
                //tempStateLogTerm = StateLogTerm;

                if (suggestion.IsCommitted)
                {
                    if (
                        this.LastCommittedIndexTerm > suggestion.StateLogEntry.Term
                        ||
                        (
                            this.LastCommittedIndexTerm == suggestion.StateLogEntry.Term
                            &&
                            this.LastCommittedIndex > suggestion.StateLogEntry.Index
                        )
                        )
                    {
                        //Should be not possible
                    }
                    else
                    {
                        this.LastCommittedIndex     = suggestion.StateLogEntry.Index;
                        this.LastCommittedIndexTerm = suggestion.StateLogEntry.Term;
                    }
                }
            }
            catch (Exception ex)
            {
            }
        }
Example #10
0
        /// <summary>
        /// +
        /// Can be null.
        /// Must be called inside of operation lock.
        /// get local commit history for follower
        /// </summary>
        /// <param name="logEntryId"></param>
        /// <param name="LeaderTerm"></param>
        /// <returns></returns>
        public StateLogEntrySuggestion GetNextStateLogEntrySuggestion(StateLogEntryRequest req)
        {
            StateLogEntrySuggestion le = new StateLogEntrySuggestion()
            {
                LeaderTerm = statemachine.NodeTerm
            };

            int           cnt      = 0;
            StateLogEntry sle      = null;
            ulong         prevId   = 0;
            ulong         prevTerm = 0;

            using (var t = this.db.GetTransaction())
            {
                if (req.StateLogEntryId == 0)// && req.StateLogEntryTerm == 0)
                {
                    var trow = t.SelectForwardFromTo <byte[], byte[]>(stateTableName,
                                                                      new byte[] { 1 }.ToBytes(ulong.MinValue, ulong.MinValue), true,
                                                                      new byte[] { 1 }.ToBytes(ulong.MaxValue, ulong.MaxValue), true).FirstOrDefault();

                    if (trow != null && trow.Exists)
                    {
                        sle = StateLogEntry.BiserDecode(trow.Value);
                    }
                    if (sle != null)
                    {
                        le.StateLogEntry = sle;
                        if (
                            LastCommittedIndexTerm >= le.StateLogEntry.Term
                            &&
                            LastCommittedIndex >= le.StateLogEntry.Index
                            )
                        {
                            le.IsCommitted = true;
                        }
                        cnt = 2;
                    }
                }
                else
                {
                    Tuple <ulong, StateLogEntry> sleTpl;
                    bool reForward = true;
                    reForward = false;
                    foreach (var el in t.SelectForwardFromTo <byte[], byte[]>(stateTableName,
                                                                              new byte[] { 1 }.ToBytes(req.StateLogEntryId, ulong.MinValue), true,
                                                                              new byte[] { 1 }.ToBytes(ulong.MaxValue, ulong.MaxValue), true).Take(2))
                    {
                        cnt++;
                        sle = StateLogEntry.BiserDecode(el.Value);
                        if (cnt == 1)
                        {
                            prevId   = sle.Index;
                            prevTerm = sle.Term;
                        }
                        else
                        {
                            le.StateLogEntry = sle;
                        }
                    }
                    if (cnt < 2 && reForward)
                    {
                        ulong toAdd = (ulong)cnt;
                        foreach (var el in t.SelectForwardFromTo <byte[], byte[]>(stateTableName,
                                                                                  //new byte[] { 1 }.ToBytes(req.StateLogEntryId + toAdd, req.StateLogEntryTerm), true,
                                                                                  new byte[] { 1 }.ToBytes(req.StateLogEntryId + toAdd, ulong.MinValue), true,
                                                                                  new byte[] { 1 }.ToBytes(ulong.MaxValue, ulong.MaxValue), true).Take(2))
                        {
                            cnt++;
                            sle = StateLogEntry.BiserDecode(el.Value);
                            if (cnt == 1)
                            {
                                prevId   = sle.Index;
                                prevTerm = sle.Term;
                            }
                            else
                            {
                                le.StateLogEntry = sle;
                            }
                        }
                    }
                    if (cnt == 2)
                    {
                        le.StateLogEntry.PreviousStateLogId   = prevId;
                        le.StateLogEntry.PreviousStateLogTerm = prevTerm;
                        if (
                            LastCommittedIndexTerm >= le.StateLogEntry.Term
                            &&
                            LastCommittedIndex >= le.StateLogEntry.Index
                            )
                        {
                            le.IsCommitted = true;
                        }
                    }
                }
            }
            if (cnt != 2)
            {
                return(null);
            }
            return(le);
        }