diff --git a/src/kvstore/raftex/RaftLogIterator.h b/src/kvstore/raftex/RaftLogIterator.h index 6e850c4b496..a84b4918259 100644 --- a/src/kvstore/raftex/RaftLogIterator.h +++ b/src/kvstore/raftex/RaftLogIterator.h @@ -19,7 +19,7 @@ namespace raftex { class RaftLogIterator final : public LogIterator { public: /** - * @brief Construct a new raf log iterator + * @brief Construct a new raft log iterator * * @param firstLogId First log id in iterator * @param logEntries Log entries from rpc request diff --git a/src/kvstore/raftex/RaftPart.cpp b/src/kvstore/raftex/RaftPart.cpp index 0b0e62b0796..18a329dc3af 100644 --- a/src/kvstore/raftex/RaftPart.cpp +++ b/src/kvstore/raftex/RaftPart.cpp @@ -1566,12 +1566,42 @@ void RaftPart::processAppendLogRequest(const cpp2::AppendLogRequest& req, // previously in fact. There are two choise: ask leader to send logs after committedLogId_ or // just do nothing. if (req.get_last_log_id_sent() < committedLogId_ || - wal_->lastLogId() < req.get_last_log_id_sent() || - wal_->getLogTerm(req.get_last_log_id_sent()) != req.get_last_log_term_sent()) { + wal_->lastLogId() < req.get_last_log_id_sent()) { + // case 1 and case 2 + resp.last_matched_log_id_ref() = committedLogId_; + resp.last_matched_log_term() = committedLogTerm_; + resp.error_code() = nebula::cpp2::ErrorCode::E_RAFT_LOG_GAP; + return; + } + auto prevLogTerm = wal_->getLogTerm(req.get_last_log_id_sent()); + if (UNLIKELY(prevLogTerm == FileBasedWal::INVALID_TERM)) { + /* + At this point, the condition below established: + committedLogId <= req.get_last_log_id_sent() <= wal_->lastLogId() + + When INVALID_TERM is returned, we failed to find the log of req.get_last_log_id_sent() + in wal. This usually happens the node has received a snapshot recently. + */ + if (req.get_last_log_id_sent() == committedLogId_ && + req.get_last_log_term_sent() == committedLogTerm_) { + // Logs are matched of at log index of committedLogId_, and we could check remaing wal if + // there are any. + // The first log of wal must be committedLogId_ + 1, it can't be 0 (no wal) as well + // because it has been checked by case 2 + DCHECK(wal_->firstLogId() == committedLogId_ + 1); + } else { + // case 3: checked by committedLogId_ and committedLogTerm_ + // When log is not matched, we just return committedLogId_ and committedLogTerm_ instead + resp.last_matched_log_id_ref() = committedLogId_; + resp.last_matched_log_term() = committedLogTerm_; + resp.error_code() = nebula::cpp2::ErrorCode::E_RAFT_LOG_GAP; + return; + } + } else if (prevLogTerm != req.get_last_log_term_sent()) { + // case 3 resp.last_matched_log_id_ref() = committedLogId_; resp.last_matched_log_term() = committedLogTerm_; resp.error_code() = nebula::cpp2::ErrorCode::E_RAFT_LOG_GAP; - // lastMatchedLogId is committedLogId_ return; } diff --git a/src/kvstore/wal/FileBasedWal.cpp b/src/kvstore/wal/FileBasedWal.cpp index 85f7f4b6111..5b783b81d85 100644 --- a/src/kvstore/wal/FileBasedWal.cpp +++ b/src/kvstore/wal/FileBasedWal.cpp @@ -718,7 +718,7 @@ size_t FileBasedWal::accessAllWalInfo(std::function f } TermID FileBasedWal::getLogTerm(LogID id) { - TermID term = -1; + TermID term = INVALID_TERM; auto iter = iterator(id, id); if (iter->valid()) { term = iter->logTerm(); diff --git a/src/kvstore/wal/FileBasedWal.h b/src/kvstore/wal/FileBasedWal.h index 54f3fe65af1..296767b314b 100644 --- a/src/kvstore/wal/FileBasedWal.h +++ b/src/kvstore/wal/FileBasedWal.h @@ -49,6 +49,11 @@ class FileBasedWal final : public Wal, public std::enable_shared_from_this