diff --git a/src/snapshotcloneserver/clone/clone_core.cpp b/src/snapshotcloneserver/clone/clone_core.cpp index 2a28a01b8a..ea35d18366 100644 --- a/src/snapshotcloneserver/clone/clone_core.cpp +++ b/src/snapshotcloneserver/clone/clone_core.cpp @@ -60,6 +60,8 @@ int CloneCoreImpl::CloneOrRecoverPre(const UUID &source, // 查询数据库中是否有任务正在执行 std::vector cloneInfoList; metaStore_->GetCloneInfoByFileName(destination, &cloneInfoList); + bool maybeExist = false; + CloneInfo existCloneInfo; for (auto &info : cloneInfoList) { if ((taskType == CloneTaskType::kClone) && (info.GetTaskType() == CloneTaskType::kClone)) { @@ -74,12 +76,11 @@ int CloneCoreImpl::CloneOrRecoverPre(const UUID &source, << ", destination = " << destination << ", Exist CloneInfo : " << info; if ((info.GetUser() == user) && - (info.GetSrc() == source) && (info.GetIsLazy() == lazyFlag) && (info.GetTaskType() == taskType)) { - // 视为同一个clone,返回任务已存在 - *cloneInfo = info; - return kErrCodeTaskExist; + // 视为同一个clone,可能克隆过,还需判断文件是否存在 + existCloneInfo = info; + maybeExist = true; } else { // 视为不同的克隆,那么文件实际上已被占用,返回文件已存在 return kErrCodeFileExist; @@ -117,11 +118,16 @@ int CloneCoreImpl::CloneOrRecoverPre(const UUID &source, switch (ret) { case LIBCURVE_ERROR::OK: if (CloneTaskType::kClone == taskType) { - LOG(ERROR) << "Clone dest file must not exist" - << ", source = " << source - << ", user = " << user - << ", destination = " << destination; - return kErrCodeFileExist; + if (maybeExist) { + *cloneInfo = existCloneInfo; + return kErrCodeTaskExist; + } else { + LOG(ERROR) << "Clone dest file must not exist" + << ", source = " << source + << ", user = " << user + << ", destination = " << destination; + return kErrCodeFileExist; + } } break; case -LIBCURVE_ERROR::NOTEXIST: diff --git a/test/integration/snapshotcloneserver/snapshotcloneserver_common_test.cpp b/test/integration/snapshotcloneserver/snapshotcloneserver_common_test.cpp index 14240d7876..70ce5e79cd 100644 --- a/test/integration/snapshotcloneserver/snapshotcloneserver_common_test.cpp +++ b/test/integration/snapshotcloneserver/snapshotcloneserver_common_test.cpp @@ -938,5 +938,58 @@ TEST_F(SnapshotCloneServerTest, TestSnapAndCloneWhenSnapHasError) { ASSERT_EQ(kErrCodeFileNotExist, retCode); } +// [线上问题修复]克隆失败,回滚删除克隆卷,再次创建同样的uuid的卷的场景 +TEST_F(SnapshotCloneServerTest, TestCloneHasSameDest) { + std::string uuid1, uuid2, uuid3, uuid4; + // 操作1:testUser1_ clone 镜像testFile1_,fileName=CloneHasSameDestUUID + // 预期1 返回克隆成功 + std::string dstFile = "/ItUser1/CloneHasSameDest"; + int ret = + CloneOrRecover("Clone", testUser1_, testFile1_, dstFile, true, &uuid1); + ASSERT_EQ(0, ret); + + // 删除克隆卷 + UserInfo_t userinfo; + userinfo.owner = testUser1_; + int ret2 = fileClient_->Unlink(dstFile, userinfo, false); + ASSERT_EQ(0, ret2); + + + // 操作2:testUser1_ 再次clone 镜像testFile1_, + // fileName=CloneHasSameDestUUID + // 预期2 返回克隆成功 + ret = + CloneOrRecover("Clone", testUser1_, testFile1_, dstFile, true, &uuid2); + ASSERT_EQ(0, ret); + + // 验证数据正确性 + std::string fakeData(4096, 'x'); + ASSERT_TRUE(CheckFileData(dstFile, testUser1_, fakeData)); + + // 操作3:testUser1_ clone 镜像testFile1_,fileName=CloneHasSameDest2 + // 预期3 返回克隆成功 + dstFile = "/ItUser1/CloneHasSameDest2"; + ret = + CloneOrRecover("Clone", testUser1_, testFile1_, dstFile, true, &uuid3); + ASSERT_EQ(0, ret); + + // 删除克隆卷 + UserInfo_t userinfo2; + userinfo2.owner = testUser1_; + ret2 = fileClient_->Unlink(dstFile, userinfo2, false); + ASSERT_EQ(0, ret2); + + + // 操作4:testUser1_ 再次clone 镜像testFile2_, + // fileName=CloneHasSameDest2 + // 预期4 返回克隆成功 + ret = + CloneOrRecover("Clone", testUser1_, testFile2_, dstFile, true, &uuid4); + ASSERT_EQ(0, ret); + + // 验证数据正确性 + ASSERT_TRUE(CheckFileData(dstFile, testUser1_, fakeData)); +} + } // namespace snapshotcloneserver } // namespace curve