From 01e9dc43bb58176da7ab626f1f51a9e8043f6c71 Mon Sep 17 00:00:00 2001 From: liuminjian Date: Mon, 6 Nov 2023 21:39:35 -0500 Subject: [PATCH] 1.heartbeat reports disk full error and mds set copyset availflag false. 2.copyset node leader set readonly when receive copyset availflag false from heartbeat. 3.When a disk error occurs, the copyset node leader calls set_error_and_rollback and selects a new leader. 4.Added new rpc method to delete copyset node with wrong status. Signed-off-by: liuminjian --- WORKSPACE | 1 + src/chunkserver/copyset_node.cpp | 15 ++- src/chunkserver/copyset_node.h | 6 +- src/chunkserver/op_request.cpp | 118 +++++++++--------- test/chunkserver/clone/op_request_test.cpp | 37 +++--- test/chunkserver/mock_copyset_node.h | 1 + .../braft/add-iterator-has_error.patch | 28 +++++ 7 files changed, 118 insertions(+), 88 deletions(-) create mode 100644 thirdparties/braft/add-iterator-has_error.patch diff --git a/WORKSPACE b/WORKSPACE index a423f1c46a..ddeffa41a8 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -37,6 +37,7 @@ git_repository( commit = "d12de388c97998f5ccd5cb97ed0da728815ef438", patches = [ "//:thirdparties/braft/0001-fix-change-set_error-to-set_errorv.patch", + "//:thirdparties/braft/add-iterator-has_error.patch", ], patch_args = [ "-p1" diff --git a/src/chunkserver/copyset_node.cpp b/src/chunkserver/copyset_node.cpp index facccac6bc..0a01039714 100755 --- a/src/chunkserver/copyset_node.cpp +++ b/src/chunkserver/copyset_node.cpp @@ -293,8 +293,7 @@ void CopysetNode::on_apply(::braft::Iterator &iter) { */ braft::Closure *closure = iter.done(); - braft::Iterator* iterPtr = &iter; - std::shared_ptr wrapperPtr = std::make_shared(iterPtr); + std::shared_ptr wrapperPtr = std::make_shared(&iter); if (nullptr != closure) { /** * 1.closure不是null,那么说明当前节点正常,直接从内存中拿到Op @@ -327,6 +326,8 @@ void CopysetNode::on_apply(::braft::Iterator &iter) { dataStore_, std::move(request), data, wrapperPtr); } } + // 等待写操作完成,否则on_apply结束后,异步有写错误无法调用set_error_and_rollback() + concurrentapply_->Flush(); } void CopysetNode::on_shutdown() { @@ -988,12 +989,6 @@ void CopysetNode::GetStatus(NodeStatus *status) { raftNode_->get_status(status); } -bool CopysetNode::StatusOK() { - NodeStatus status; - GetStatus(&status); - return status.state != braft::STATE_ERROR; -} - void CopysetNode::GetLeaderLeaseStatus(braft::LeaderLeaseStatus *status) { raftNode_->get_leader_lease_status(status); } @@ -1135,5 +1130,9 @@ void IteratorWrapper::set_error_and_rollback(size_t ntail, const butil::Status* iter_->set_error_and_rollback(ntail, st); } +bool IteratorWrapper::has_error() const{ + return iter_->has_error(); +} + } // namespace chunkserver } // namespace curve diff --git a/src/chunkserver/copyset_node.h b/src/chunkserver/copyset_node.h index 18b4924902..2bca4bb648 100755 --- a/src/chunkserver/copyset_node.h +++ b/src/chunkserver/copyset_node.h @@ -131,6 +131,7 @@ class IteratorWrapper { IteratorWrapper(braft::Iterator *iter): iter_(iter) {} ~IteratorWrapper() {} virtual void set_error_and_rollback(size_t ntail = 1, const butil::Status* st = NULL); + virtual bool has_error() const; private: braft::Iterator *iter_; }; @@ -296,11 +297,6 @@ class CopysetNode : public braft::StateMachine, */ virtual void GetStatus(NodeStatus *status); - /** - * @brief: 判断copyset node的status是否为ERROR - */ - virtual bool StatusOK() ; - /** * @brief: get raft node leader lease status * @param status[out]: raft node leader lease status diff --git a/src/chunkserver/op_request.cpp b/src/chunkserver/op_request.cpp index 12dfcb6144..6c9655f49d 100755 --- a/src/chunkserver/op_request.cpp +++ b/src/chunkserver/op_request.cpp @@ -206,14 +206,14 @@ void DeleteChunkRequest::OnApply(uint64_t index, brpc::ClosureGuard doneGuard(done); // 由于写操作ConcurrentApply异步执行,有可能上一个操作已经失败,如磁盘空间不足,需要检查 - if (!node_->StatusOK()) { + if (iterPtr->has_error()) { LOG(ERROR) << "delete chunk failed: " - << " last log apply fail " + << " last log apply fail " << ", request: " << request_->ShortDebugString(); - iterPtr->set_error_and_rollback(); + iterPtr->set_error_and_rollback(); response_->set_status( CHUNK_OP_STATUS::CHUNK_OP_STATUS_REDIRECTED); - response_->set_appliedindex(node_->GetAppliedIndex()); + response_->set_appliedindex(node_->GetAppliedIndex()); return; } @@ -226,10 +226,10 @@ void DeleteChunkRequest::OnApply(uint64_t index, LOG(ERROR) << "delete chunk failed: " << " data store return: " << ret << ", request: " << request_->ShortDebugString(); - iterPtr->set_error_and_rollback(); + iterPtr->set_error_and_rollback(); response_->set_status( CHUNK_OP_STATUS::CHUNK_OP_STATUS_REDIRECTED); - response_->set_appliedindex(node_->GetAppliedIndex()); + response_->set_appliedindex(node_->GetAppliedIndex()); return; } else { LOG(ERROR) << "delete chunk failed: " @@ -247,9 +247,9 @@ void DeleteChunkRequest::OnApplyFromLog(std::shared_ptr datastore, std::shared_ptr iterPtr) { // 由于写操作ConcurrentApply异步执行,有可能上一个操作已经失败,如磁盘空间不足,需要检查 - if (!node_->StatusOK()) { + if (iterPtr->has_error()) { LOG(ERROR) << "delete chunk failed: " - << " last log apply fail " + << " last log apply fail " << ", request: " << request_->ShortDebugString(); iterPtr->set_error_and_rollback(); return; @@ -266,7 +266,7 @@ void DeleteChunkRequest::OnApplyFromLog(std::shared_ptr datastore, LOG(ERROR) << "delete failed: " << " data store return: " << ret << ", request: " << request.ShortDebugString(); - iterPtr->set_error_and_rollback(); + iterPtr->set_error_and_rollback(); } else { LOG(ERROR) << "delete failed: " << " data store return: " << ret @@ -470,7 +470,7 @@ void WriteChunkRequest::OnApply(uint64_t index, brpc::ClosureGuard doneGuard(done); // 由于写操作ConcurrentApply异步执行,有可能上一个操作已经失败,如磁盘空间不足,需要检查 - if (!node_->StatusOK()) { + if (iterPtr->has_error()) { LOG(ERROR) << "write chunk failed: " << " last log apply fail " << ", request: " << request_->ShortDebugString(); @@ -544,7 +544,7 @@ void WriteChunkRequest::OnApplyFromLog(std::shared_ptr datastore, std::shared_ptr iterPtr) { // 由于写操作ConcurrentApply异步执行,有可能上一个操作已经失败,如磁盘空间不足,需要检查 - if (!node_->StatusOK()) { + if (iterPtr->has_error()) { LOG(ERROR) << "write chunk failed: " << " last log apply fail " << ", request: " << request_->ShortDebugString(); @@ -579,7 +579,7 @@ void WriteChunkRequest::OnApplyFromLog(std::shared_ptr datastore, CSErrorCode::FileFormatError == ret) { /** - * internalerror一般是磁盘错误,为了防止副本不一致, + * internalerror一般是磁盘错误,为了防止副本不一致, * set_error_and_rollback回退日志,copyset node执行step down下线,选举新的leader * 假如空间不足,heartbeat会上传磁盘错误标坏copyset */ @@ -600,11 +600,11 @@ void ReadSnapshotRequest::OnApply(uint64_t index, brpc::ClosureGuard doneGuard(done); // 由于写操作ConcurrentApply异步执行,有可能上一个操作已经失败,如磁盘空间不足,需要检查 - if (!node_->StatusOK()) { + if (iterPtr->has_error()) { LOG(ERROR) << "read snapshot failed: " - << " last log apply fail " + << " last log apply fail " << ", request: " << request_->ShortDebugString(); - iterPtr->set_error_and_rollback(); + iterPtr->set_error_and_rollback(); response_->set_status( CHUNK_OP_STATUS::CHUNK_OP_STATUS_REDIRECTED); response_->set_appliedindex(node_->GetAppliedIndex()); @@ -648,10 +648,10 @@ void ReadSnapshotRequest::OnApply(uint64_t index, LOG(ERROR) << "read snapshot failed: " << " data store return: " << ret << ", request: " << request_->ShortDebugString(); - iterPtr->set_error_and_rollback(); + iterPtr->set_error_and_rollback(); response_->set_status(CHUNK_OP_STATUS::CHUNK_OP_STATUS_REDIRECTED); response_->set_appliedindex(node_->GetAppliedIndex()); - return; + return; } /** * 4.其他错误 @@ -683,11 +683,11 @@ void DeleteSnapshotRequest::OnApply(uint64_t index, brpc::ClosureGuard doneGuard(done); // 由于写操作ConcurrentApply异步执行,有可能上一个操作已经失败,如磁盘空间不足,需要检查 - if (!node_->StatusOK()) { + if (iterPtr->has_error()) { LOG(ERROR) << "delete snapshot failed: " - << " last log apply fail " + << " last log apply fail " << ", request: " << request_->ShortDebugString(); - iterPtr->set_error_and_rollback(); + iterPtr->set_error_and_rollback(); response_->set_status( CHUNK_OP_STATUS::CHUNK_OP_STATUS_REDIRECTED); response_->set_appliedindex(node_->GetAppliedIndex()); @@ -712,8 +712,8 @@ void DeleteSnapshotRequest::OnApply(uint64_t index, iterPtr->set_error_and_rollback(); response_->set_status( CHUNK_OP_STATUS::CHUNK_OP_STATUS_REDIRECTED); - response_->set_appliedindex(node_->GetAppliedIndex()); - return; + response_->set_appliedindex(node_->GetAppliedIndex()); + return; } else { LOG(ERROR) << "delete snapshot or correct sn failed: " << " data store return: " << ret @@ -732,9 +732,9 @@ void DeleteSnapshotRequest::OnApplyFromLog(std::shared_ptr datastor (void)data; // 由于写操作ConcurrentApply异步执行,有可能上一个操作已经失败,如磁盘空间不足,需要检查 - if (!node_->StatusOK()) { + if (iterPtr->has_error()) { LOG(ERROR) << "delete snapshot failed: " - << " last log apply fail " + << " last log apply fail " << ", request: " << request_->ShortDebugString(); iterPtr->set_error_and_rollback(); return; @@ -753,7 +753,7 @@ void DeleteSnapshotRequest::OnApplyFromLog(std::shared_ptr datastor << " data store return: " << ret << ", request: " << request.ShortDebugString(); iterPtr->set_error_and_rollback(); - return; + return; } else { LOG(ERROR) << "delete snapshot or correct sn failed: " << " data store return: " << ret @@ -767,14 +767,14 @@ void CreateCloneChunkRequest::OnApply(uint64_t index, brpc::ClosureGuard doneGuard(done); // 由于写操作ConcurrentApply异步执行,有可能上一个操作已经失败,如磁盘空间不足,需要检查 - if (!node_->StatusOK()) { + if (iterPtr->has_error()) { LOG(ERROR) << "create clone chunk failed: " - << " last log apply fail " + << " last log apply fail " << ", request: " << request_->ShortDebugString(); - iterPtr->set_error_and_rollback(); + iterPtr->set_error_and_rollback(); response_->set_status( CHUNK_OP_STATUS::CHUNK_OP_STATUS_REDIRECTED); - response_->set_appliedindex(node_->GetAppliedIndex()); + response_->set_appliedindex(node_->GetAppliedIndex()); return; } @@ -791,7 +791,7 @@ void CreateCloneChunkRequest::OnApply(uint64_t index, CSErrorCode::CrcCheckError == ret || CSErrorCode::FileFormatError == ret) { /** - * internalerror一般是磁盘错误,为了防止副本不一致, + * internalerror一般是磁盘错误,为了防止副本不一致, * set_error_and_rollback回退日志,copyset node执行step down下线,选举新的leader * 假如空间不足,heartbeat会上传磁盘错误标坏copyset */ @@ -799,9 +799,9 @@ void CreateCloneChunkRequest::OnApply(uint64_t index, << ", request: " << request_->ShortDebugString(); iterPtr->set_error_and_rollback(); response_->set_status( - CHUNK_OP_STATUS::CHUNK_OP_STATUS_REDIRECTED); + CHUNK_OP_STATUS::CHUNK_OP_STATUS_REDIRECTED); response_->set_appliedindex(node_->GetAppliedIndex()); - return; + return; } else if (CSErrorCode::ChunkConflictError == ret) { LOG(WARNING) << "create clone chunk exist: " << ", request: " << request_->ShortDebugString(); @@ -824,13 +824,13 @@ void CreateCloneChunkRequest::OnApplyFromLog(std::shared_ptr datast (void)data; // 由于写操作ConcurrentApply异步执行,有可能上一个操作已经失败,如磁盘空间不足,需要检查 - if (!node_->StatusOK()) { + if (iterPtr->has_error()) { LOG(ERROR) << "create clone chunk failed: " - << " last log apply fail " + << " last log apply fail " << ", request: " << request_->ShortDebugString(); - iterPtr->set_error_and_rollback(); + iterPtr->set_error_and_rollback(); return; - } + } // NOTE: 处理过程中优先使用参数传入的datastore/request auto ret = datastore->CreateCloneChunk(request.chunkid(), @@ -851,7 +851,7 @@ void CreateCloneChunkRequest::OnApplyFromLog(std::shared_ptr datast CSErrorCode::CrcCheckError == ret || CSErrorCode::FileFormatError == ret) { /** - * internalerror一般是磁盘错误,为了防止副本不一致, + * internalerror一般是磁盘错误,为了防止副本不一致, * set_error_and_rollback回退日志,copyset node执行step down下线,选举新的leader * 假如空间不足,heartbeat会上传磁盘错误标坏copyset */ @@ -894,14 +894,14 @@ void PasteChunkInternalRequest::OnApply(uint64_t index, brpc::ClosureGuard doneGuard(done); // 由于写操作ConcurrentApply异步执行,有可能上一个操作已经失败,如磁盘空间不足,需要检查 - if (!node_->StatusOK()) { + if (iterPtr->has_error()) { LOG(ERROR) << "paste chunk failed: " - << " last log apply fail " + << " last log apply fail " << ", request: " << request_->ShortDebugString(); - iterPtr->set_error_and_rollback(); + iterPtr->set_error_and_rollback(); response_->set_status( CHUNK_OP_STATUS::CHUNK_OP_STATUS_REDIRECTED); - response_->set_appliedindex(node_->GetAppliedIndex()); + response_->set_appliedindex(node_->GetAppliedIndex()); return; } @@ -914,9 +914,9 @@ void PasteChunkInternalRequest::OnApply(uint64_t index, response_->set_status(CHUNK_OP_STATUS::CHUNK_OP_STATUS_SUCCESS); node_->UpdateAppliedIndex(index); } else if (CSErrorCode::InternalError == ret) { - + /** - * internalerror一般是磁盘错误,为了防止副本不一致, + * internalerror一般是磁盘错误,为了防止副本不一致, * set_error_and_rollback回退日志,copyset node执行step down下线,选举新的leader * 假如空间不足,heartbeat会上传磁盘错误标坏copyset */ @@ -925,8 +925,8 @@ void PasteChunkInternalRequest::OnApply(uint64_t index, iterPtr->set_error_and_rollback(); response_->set_status( CHUNK_OP_STATUS::CHUNK_OP_STATUS_REDIRECTED); - response_->set_appliedindex(node_->GetAppliedIndex()); - return; + response_->set_appliedindex(node_->GetAppliedIndex()); + return; } else { LOG(ERROR) << "paste chunk failed: " << ", request: " << request_->ShortDebugString(); @@ -942,13 +942,13 @@ void PasteChunkInternalRequest::OnApplyFromLog(std::shared_ptr data std::shared_ptr iterPtr) { // 由于写操作ConcurrentApply异步执行,有可能上一个操作已经失败,如磁盘空间不足,需要检查 - if (!node_->StatusOK()) { + if (iterPtr->has_error()) { LOG(ERROR) << "paste chunk failed: " - << " last log apply fail " + << " last log apply fail " << ", request: " << request_->ShortDebugString(); - iterPtr->set_error_and_rollback(); + iterPtr->set_error_and_rollback(); return; - } + } // NOTE: 处理过程中优先使用参数传入的datastore/request auto ret = datastore->PasteChunk(request.chunkid(), data.to_string().c_str(), @@ -959,7 +959,7 @@ void PasteChunkInternalRequest::OnApplyFromLog(std::shared_ptr data if (CSErrorCode::InternalError == ret) { /** - * internalerror一般是磁盘错误,为了防止副本不一致, + * internalerror一般是磁盘错误,为了防止副本不一致, * set_error_and_rollback回退日志,copyset node执行step down下线,选举新的leader * 假如空间不足,heartbeat会上传磁盘错误标坏copyset */ @@ -978,11 +978,11 @@ void ScanChunkRequest::OnApply(uint64_t index, brpc::ClosureGuard doneGuard(done); // 由于写操作ConcurrentApply异步执行,有可能上一个操作已经失败,如磁盘空间不足,需要检查 - if (!node_->StatusOK()) { + if (iterPtr->has_error()) { LOG(ERROR) << "scan chunk failed: " - << " last log apply fail " + << " last log apply fail " << ", request: " << request_->ShortDebugString(); - iterPtr->set_error_and_rollback(); + iterPtr->set_error_and_rollback(); response_->set_status( CHUNK_OP_STATUS::CHUNK_OP_STATUS_REDIRECTED); return; @@ -1031,9 +1031,9 @@ void ScanChunkRequest::OnApply(uint64_t index, } else if (CSErrorCode::InternalError == ret) { LOG(ERROR) << "scan chunk failed, read chunk internal error" << ", request: " << request_->ShortDebugString(); - iterPtr->set_error_and_rollback(); + iterPtr->set_error_and_rollback(); response_->set_status( - CHUNK_OP_STATUS::CHUNK_OP_STATUS_REDIRECTED); + CHUNK_OP_STATUS::CHUNK_OP_STATUS_REDIRECTED); } else { response_->set_status( CHUNK_OP_STATUS::CHUNK_OP_STATUS_FAILURE_UNKNOWN); @@ -1047,11 +1047,11 @@ void ScanChunkRequest::OnApplyFromLog(std::shared_ptr datastore, / (void)data; // 由于写操作ConcurrentApply异步执行,有可能上一个操作已经失败,如磁盘空间不足,需要检查 - if (!node_->StatusOK()) { + if (iterPtr->has_error()) { LOG(ERROR) << "scan chunk failed: " - << " last log apply fail " + << " last log apply fail " << ", request: " << request_->ShortDebugString(); - iterPtr->set_error_and_rollback(); + iterPtr->set_error_and_rollback(); return; } @@ -1086,7 +1086,7 @@ void ScanChunkRequest::OnApplyFromLog(std::shared_ptr datastore, / LOG(ERROR) << "scan failed: " << " datastore return: " << ret << ", request: " << request.ShortDebugString(); - iterPtr->set_error_and_rollback(); + iterPtr->set_error_and_rollback(); } else { LOG(ERROR) << "scan failed: " << " datastore return: " << ret diff --git a/test/chunkserver/clone/op_request_test.cpp b/test/chunkserver/clone/op_request_test.cpp index 0422e2bf25..e1ece23380 100644 --- a/test/chunkserver/clone/op_request_test.cpp +++ b/test/chunkserver/clone/op_request_test.cpp @@ -84,8 +84,6 @@ class OpRequestTest PeerId peer(PEER_STRING); EXPECT_CALL(*node_, GetLeaderId()) .WillRepeatedly(Return(peer)); - EXPECT_CALL(*node_, StatusOK()) - .WillRepeatedly(Return(true)); } void FakeCloneManager() { @@ -97,7 +95,9 @@ class OpRequestTest void FakeIteratorWrapper() { EXPECT_CALL(*iter_, set_error_and_rollback(_,_)) - .WillRepeatedly(Return(nullptr)); + .WillRepeatedly(Return()); + EXPECT_CALL(*iter_, has_error()) + .WillRepeatedly(Return(false)); } protected: @@ -237,7 +237,7 @@ TEST_P(OpRequestTest, CreateCloneTest) { /** * test OnApply * case:CreateCloneChunk failed - * expect:process exit + * expect:不返回成功 */ { // reset closure @@ -246,8 +246,9 @@ TEST_P(OpRequestTest, CreateCloneTest) { // check result EXPECT_CALL(*datastore_, CreateCloneChunk(_, _, _, _, _)) .WillRepeatedly(Return(CSErrorCode::InternalError)); - - ASSERT_DEATH(opReq->OnApply(3, closure, iter_), ""); + opReq->OnApply(3, closure, iter_); + ASSERT_NE(CHUNK_OP_STATUS::CHUNK_OP_STATUS_SUCCESS, + closure->response_->status()); } /** * test OnApply @@ -292,7 +293,7 @@ TEST_P(OpRequestTest, CreateCloneTest) { /** * 测试 OnApplyFromLog * 用例:CreateCloneChunk失败,返回InternalError - * 预期:进程退出 + * 预期:无返回 */ { // 重置closure @@ -303,12 +304,12 @@ TEST_P(OpRequestTest, CreateCloneTest) { .WillRepeatedly(Return(CSErrorCode::InternalError)); butil::IOBuf data; - ASSERT_DEATH(opReq->OnApplyFromLog(datastore_, *request, data, iter_), ""); + opReq->OnApplyFromLog(datastore_, *request, data, iter_); } /** * 测试 OnApplyFromLog * 用例:CreateCloneChunk失败,返回其他错误 - * 预期:进程退出 + * 预期:无返回 */ { // 重置closure @@ -461,7 +462,7 @@ TEST_P(OpRequestTest, PasteChunkTest) { /** * 测试OnApply * 用例:CreateCloneChunk失败,返回InternalError - * 预期:进程退出 + * 预期:不返回成功 */ { // 重置closure @@ -471,7 +472,9 @@ TEST_P(OpRequestTest, PasteChunkTest) { EXPECT_CALL(*datastore_, PasteChunk(_, _, _, _)) .WillRepeatedly(Return(CSErrorCode::InternalError)); - ASSERT_DEATH(opReq->OnApply(3, closure, iter_), ""); + opReq->OnApply(3, closure, iter_); + ASSERT_NE(CHUNK_OP_STATUS::CHUNK_OP_STATUS_SUCCESS, + closure->response_->status()); } /** * 测试OnApply @@ -514,7 +517,7 @@ TEST_P(OpRequestTest, PasteChunkTest) { /** * 测试 OnApplyFromLog * 用例:CreateCloneChunk失败,返回InternalError - * 预期:进程退出 + * 预期:无返回 */ { // 重置closure @@ -525,12 +528,12 @@ TEST_P(OpRequestTest, PasteChunkTest) { .WillRepeatedly(Return(CSErrorCode::InternalError)); butil::IOBuf data; - ASSERT_DEATH(opReq->OnApplyFromLog(datastore_, *request, data, iter_), ""); + opReq->OnApplyFromLog(datastore_, *request, data, iter_); } /** * 测试 OnApplyFromLog * 用例:CreateCloneChunk失败,返回其他错误 - * 预期:进程退出 + * 预期:无返回 */ { // 重置closure @@ -1014,7 +1017,7 @@ TEST_P(OpRequestTest, ReadChunkTest) { /** * 测试OnApply * 用例:读本地chunk的时候返回错误 - * 预期:请求失败,返回 CHUNK_OP_STATUS_FAILURE_UNKNOWN + * 预期:不返回成功 */ { // 重置closure @@ -1029,7 +1032,9 @@ TEST_P(OpRequestTest, ReadChunkTest) { EXPECT_CALL(*datastore_, ReadChunk(_, _, _, offset, length)) .WillRepeatedly(Return(CSErrorCode::InternalError)); - ASSERT_DEATH(opReq->OnApply(3, closure, iter_), ""); + opReq->OnApply(3, closure, iter_); + ASSERT_NE(CHUNK_OP_STATUS::CHUNK_OP_STATUS_SUCCESS, + closure->response_->status()); } /** * 测试OnApply diff --git a/test/chunkserver/mock_copyset_node.h b/test/chunkserver/mock_copyset_node.h index 1ec38a42e4..0886765387 100644 --- a/test/chunkserver/mock_copyset_node.h +++ b/test/chunkserver/mock_copyset_node.h @@ -81,6 +81,7 @@ class MockIteratorWrapper : public IteratorWrapper { MockIteratorWrapper() = default; ~MockIteratorWrapper() = default; MOCK_METHOD2(set_error_and_rollback, void(size_t, const butil::Status*)); + MOCK_CONST_METHOD0(has_error, bool()); }; } // namespace chunkserver diff --git a/thirdparties/braft/add-iterator-has_error.patch b/thirdparties/braft/add-iterator-has_error.patch new file mode 100644 index 0000000000..2b4cffd0f6 --- /dev/null +++ b/thirdparties/braft/add-iterator-has_error.patch @@ -0,0 +1,28 @@ +diff --git a/src/braft/raft.cpp b/src/braft/raft.cpp +index 6069f70..11adf9a 100644 +--- a/src/braft/raft.cpp ++++ b/src/braft/raft.cpp +@@ -253,6 +253,10 @@ bool Iterator::valid() const { + return _impl->is_good() && _impl->entry()->type == ENTRY_TYPE_DATA; + } + ++bool Iterator::has_error() const { ++ return _impl->has_error(); ++} ++ + int64_t Iterator::index() const { return _impl->index(); } + + int64_t Iterator::term() const { return _impl->entry()->id.term; } +diff --git a/src/braft/raft.h b/src/braft/raft.h +index e4a0f19..83cd353 100644 +--- a/src/braft/raft.h ++++ b/src/braft/raft.h +@@ -178,6 +178,8 @@ public: + // If |st| is not NULL, it should describe the detail of the error. + void set_error_and_rollback(size_t ntail = 1, const butil::Status* st = NULL); + ++ bool has_error() const; ++ + private: + friend class FSMCaller; + Iterator(IteratorImpl* impl) : _impl(impl) {} \ No newline at end of file