youngyangyang04 / KVstorageBaseRaft-cpp

【代码随想录知识星球】项目分享-基于Raft的k-v存储数据库🔥
574 stars 113 forks source link

未生成快照 #55

Closed Pyolar closed 6 months ago

Pyolar commented 6 months ago

Persister类里面的 long long m_raftStateSize; 其他函数里面没有及时更新,导致kvserver类里面的IfNeedToSendSnapShotCommand一直没被触发,是不是会导致不能生成快照,我本地跑起来,快照的txt文件也确实是空的,这个有什么考虑吗?

578223592 commented 6 months ago

Persister类里面的 long long m_raftStateSize; 其他函数里面没有及时更新,导致kvserver类里面的IfNeedToSendSnapShotCommand一直没被触发,是不是会导致不能生成快照,我本地跑起来,快照的txt文件也确实是空的,这个有什么考虑吗?

@Pyolar

  1. 在原来的设计中m_raftStateSize这块确实存在问题,目前已经修改了相关的逻辑,应该是可以正常更新m_raftStateSize的值了,更新pr:#56

  2. 关于“是不是会导致不能生成快照,我本地跑起来,快照的txt文件也确实是空的,这个有什么考虑吗?”,这块其实没有太多的考虑,出于两点: a. 快照是对于算法保存内容的压缩优化,在学习中重要些不是特别高。 b. 在mit课程中也没有对这块有强制性的设计要求,本仓库代码为了正确性还是“翻译”mit为主,因此这块也没有太多设计考量。

Pyolar commented 6 months ago

56 @578223592

感谢您抽出时间来回答我的问题,不胜感激。但还有个问题需要向您请教: 1.考虑到raft.cpp中,persist高频持久化raftstate,是否会导致raftstate文件中的m_raftStateSize值一直清空,增加,但是增加的很小,导致不能触发快照(快照文件为空),而且raftstatePersist文件也一直为空。快照以及状态文件 2.clearRaftState(); 是否应该是由生成快照后来操作,也就是Save中

578223592 commented 6 months ago

56 @578223592 感谢您抽出时间来回答我的问题,不胜感激。但还有个问题需要向您请教: 1.考虑到raft.cpp中,persist高频持久化raftstate,是否会导致raftstate文件中的m_raftStateSize值一直清空,增加,但是增加的很小,导致不能触发快照(快照文件为空),而且raftstatePersist文件也一直为空。快照以及状态文件 2.clearRaftState(); 是否应该是由生成快照后来操作,也就是Save中

不必客气,本仓库的主要目的是学习raft算法,所以细节设计确实很可能会有很不合理的地方,欢迎指正。

  1. 关于快照,实际上生成快照的关键代码在于:
    void KvServer::IfNeedToSendSnapShotCommand(int raftIndex, int proportion) {
    if (m_raftNode->GetRaftStateSize() > m_maxRaftState / 10.0) {
    // Send SnapShot Command
    auto snapshot = MakeSnapShot();
    m_raftNode->Snapshot(raftIndex, snapshot);
    }
    }

    即快照的生成是由raftServer层来负责检测,如果满足生成快照的条件(数据库的数据量达到一定阈值),那么就往下生成快照并保存。 如果文件一直为空,那么应该是数据量还没满足到m_maxRaftState 这个阈值。

  2. 没太明白你的意思
Pyolar commented 6 months ago

@578223592 我之前表述可能不太清楚,我换一种表述: 1.是否存在下述问题: void Persister::SaveRaftState(const std::string &data) { std::lock_guard<std::mutex> lg(m_mtx); // 将raftstate和snapshot写入本地文件 clearRaftState(); m_raftStateOutStream << data; m_raftStateSize += data.size(); } Persister类中SaveRaftState的这段代码在raft.cpp中会被persist函数频繁的调用,而persist函数的调用就会清空文件,导致持久化层m_raftStateSize值一直达不到阈值,便不会触发生成快照 2.是否可以这么改: 每次持久化的时候并不一定要重置m_raftStateSize值,而是等生成快照的时候再重置m_raftStateSize值,因为生成快照是和m_raftStateSize值息息相关的。 以上表述如有不对请指出,我理解的也不一定完全正确。

578223592 commented 6 months ago

@Pyolar 调用SaveRaftState函数的是:

void Raft::persist() {
  // Your code here (2C).
  auto data = persistData();
  m_persister->SaveRaftState(data);
  // fmt.Printf("RaftNode[%d] persist starts, currentTerm[%d] voteFor[%d] log[%v]\n", rf.me, rf.currentTerm,
  // rf.votedFor, rf.logs) fmt.Printf("%v\n", string(data))
}

由于该函数Raft::persist()每次都是全量生成数据,因此持久化的m_raftStateSize 会在持久化的时候赋值为初始值0。

  1. 我的回答依然是:https://github.com/youngyangyang04/KVstorageBaseRaft-cpp/issues/55#issuecomment-2041359215的第一点
  2. m_raftStateSize的作用是: image ,与快照snapshot关系不大。
Pyolar commented 6 months ago

@578223592 ’全量数据‘ ,瞬间就明白了,谢谢。

578223592 commented 6 months ago

@Pyolar 非常高兴哈哈哈,也欢迎对仓库改进pr或者提出更多的问题issue