diff --git a/src/client/iomanager4file.cpp b/src/client/iomanager4file.cpp index 63e9c89720..2efd0b1e97 100644 --- a/src/client/iomanager4file.cpp +++ b/src/client/iomanager4file.cpp @@ -227,10 +227,10 @@ void IOManager4File::LeaseTimeoutBlockIO() { } } -void IOManager4File::RefeshSuccAndResumeIO() { +void IOManager4File::ResumeIO() { std::unique_lock lk(exitMtx_); if (exit_ == false) { - scheduler_->RefeshSuccAndResumeIO(); + scheduler_->ResumeIO(); } else { LOG(WARNING) << "io manager already exit, no need resume io!"; } diff --git a/src/client/iomanager4file.h b/src/client/iomanager4file.h index a6d544f333..24e3b07c24 100644 --- a/src/client/iomanager4file.h +++ b/src/client/iomanager4file.h @@ -175,6 +175,14 @@ class IOManager4File : public IOManager { mc_.SetLatestFileSn(newSn); } + /** + * @brief get current file inodeid + * @return file inodeid + */ + uint64_t InodeId() const { + return mc_.InodeId(); + } + private: friend class LeaseExecutor; friend class FlightIOGuard; @@ -187,7 +195,7 @@ class IOManager4File : public IOManager { /** * 当lease又续约成功的时候,LeaseExecutor调用该接口恢复IO */ - void RefeshSuccAndResumeIO(); + void ResumeIO(); /** * 当lesaeexcutor发现版本变更,调用该接口开始等待inflight回来,这段期间IO是hang的 diff --git a/src/client/lease_executor.cpp b/src/client/lease_executor.cpp index 57faa66ef9..8d96ba46f9 100644 --- a/src/client/lease_executor.cpp +++ b/src/client/lease_executor.cpp @@ -104,10 +104,20 @@ bool LeaseExecutor::RefreshLease() { } if (response.status == LeaseRefreshResult::Status::OK) { + if (CURVE_UNLIKELY(iomanager_->InodeId() != response.finfo.id)) { + LOG(ERROR) << fullFileName_ << " inode id changed, current id = " + << iomanager_->InodeId() + << ", but mds response id = " << response.finfo.id + << ", block IO"; + iomanager_->LeaseTimeoutBlockIO(); + isleaseAvaliable_.store(false); + return false; + } + CheckNeedUpdateVersion(response.finfo.seqnum); failedrefreshcount_.store(0); isleaseAvaliable_.store(true); - iomanager_->RefeshSuccAndResumeIO(); + iomanager_->ResumeIO(); return true; } else if (response.status == LeaseRefreshResult::Status::NOT_EXIST) { iomanager_->LeaseTimeoutBlockIO(); @@ -149,10 +159,10 @@ void LeaseExecutor::IncremRefreshFailed() { void LeaseExecutor::CheckNeedUpdateVersion(uint64_t newversion) { const uint64_t currentFileSn = iomanager_->GetLatestFileSn(); - DVLOG(9) << "new file version = " << newversion - << ", current version = " << currentFileSn - << ", filename = " << fullFileName_; if (newversion > currentFileSn) { + LOG(INFO) << fullFileName_ + << " version changed, old version = " << currentFileSn + << ", new version = " << newversion; iomanager_->SetLatestFileSn(newversion); } } diff --git a/src/client/lease_executor.h b/src/client/lease_executor.h index 89a5156086..b3f7e26684 100644 --- a/src/client/lease_executor.h +++ b/src/client/lease_executor.h @@ -68,10 +68,8 @@ class LeaseExecutor { * @param: mdsclient是与mds续约的client * @param: iomanager会在续约失败或者版本变更的时候进行io调度 */ - LeaseExecutor(const LeaseOption& leaseOpt, - UserInfo_t userinfo, - MDSClient* mdscllent, - IOManager4File* iomanager); + LeaseExecutor(const LeaseOption& leaseOpt, UserInfo_t userinfo, + MDSClient* mdscllent, IOManager4File* iomanager); ~LeaseExecutor(); diff --git a/src/client/libcurve_file.cpp b/src/client/libcurve_file.cpp index e28465437a..1869365dd6 100644 --- a/src/client/libcurve_file.cpp +++ b/src/client/libcurve_file.cpp @@ -285,6 +285,8 @@ int FileClient::Read(int fd, char* buf, off_t offset, size_t len) { } if (CheckAligned(offset, len) == false) { + LOG(ERROR) << "Read request not aligned, length = " << len + << ", offset = " << offset << ", fd = " << fd; return -LIBCURVE_ERROR::NOT_ALIGNED; } @@ -304,6 +306,8 @@ int FileClient::Write(int fd, const char* buf, off_t offset, size_t len) { } if (CheckAligned(offset, len) == false) { + LOG(ERROR) << "Write request not aligned, length = " << len + << ", offset = " << offset << ", fd = " << fd; return -LIBCURVE_ERROR::NOT_ALIGNED; } @@ -324,6 +328,8 @@ int FileClient::AioRead(int fd, CurveAioContext* aioctx, } if (CheckAligned(aioctx->offset, aioctx->length) == false) { + LOG(ERROR) << "AioRead request not aligned, length = " << aioctx->length + << ", offset = " << aioctx->offset << ", fd = " << fd; return -LIBCURVE_ERROR::NOT_ALIGNED; } @@ -347,6 +353,9 @@ int FileClient::AioWrite(int fd, CurveAioContext* aioctx, } if (CheckAligned(aioctx->offset, aioctx->length) == false) { + LOG(ERROR) << "AioWrite request not aligned, length = " + << aioctx->length << ", offset = " << aioctx->offset + << ", fd = " << fd; return -LIBCURVE_ERROR::NOT_ALIGNED; } diff --git a/src/client/metacache.h b/src/client/metacache.h index a24f3cee11..787b646e85 100644 --- a/src/client/metacache.h +++ b/src/client/metacache.h @@ -237,6 +237,10 @@ class MetaCache { return unstableHelper_; } + uint64_t InodeId() const { + return fileInfo_.id; + } + private: /** * @brief 从mds更新copyset复制组信息 diff --git a/src/client/request_scheduler.h b/src/client/request_scheduler.h index b68055a6ee..c4ad511480 100644 --- a/src/client/request_scheduler.h +++ b/src/client/request_scheduler.h @@ -118,7 +118,7 @@ class RequestScheduler : public Uncopyable { * 当lease又续约成功的时候,LeaseExecutor调用该接口恢复IO, * IO调度被恢复 */ - void RefeshSuccAndResumeIO() { + void ResumeIO() { std::unique_lock lk(leaseRefreshmtx_); blockIO_.store(false); leaseRefreshcv_.notify_all(); diff --git a/src/mds/nameserver2/curvefs.cpp b/src/mds/nameserver2/curvefs.cpp index ab28113163..4a7779857b 100644 --- a/src/mds/nameserver2/curvefs.cpp +++ b/src/mds/nameserver2/curvefs.cpp @@ -33,8 +33,6 @@ #include "src/mds/common/mds_define.h" using curve::common::TimeUtility; -using ::std::chrono::steady_clock; -using ::std::chrono::microseconds; using curve::mds::topology::LogicalPool; namespace curve { @@ -90,7 +88,7 @@ bool CurveFS::Init(std::shared_ptr storage, std::shared_ptr allocStatistic, const struct CurveFSOption &curveFSOptions, std::shared_ptr topology) { - startTime_ = steady_clock::now(); + startTime_ = std::chrono::steady_clock::now(); storage_ = storage; InodeIDGenerator_ = InodeIDGenerator; chunkSegAllocator_ = chunkSegAllocator; @@ -480,13 +478,8 @@ StatusCode CurveFS::isDirectoryEmpty(const FileInfo &fileInfo, bool *result) { } StatusCode CurveFS::IsSnapshotAllowed(const std::string &fileName) { - // whether the startup time is sufficient for the client to perform - // at least one refresh session - steady_clock::duration timePass = steady_clock::now() - startTime_; - int32_t expiredUs = fileRecordManager_->GetFileRecordExpiredTimeUs(); - if (timePass < 10 * microseconds(expiredUs)) { - LOG(INFO) << "snapshot is not allowed now, fileName = " << fileName - << ", time pass = " << timePass.count(); + if (!IsStartEnoughTime(10)) { + LOG(INFO) << "snapshot is not allowed now, fileName = " << fileName; return StatusCode::kSnapshotFrozen; } @@ -698,6 +691,18 @@ StatusCode CurveFS::CheckFileCanChange(const std::string &fileName, return StatusCode::kDeleteFileBeingCloned; } + if (!IsStartEnoughTime(1)) { + LOG(WARNING) << "MDS doesn't start enough time"; + return StatusCode::kNotSupported; + } + + ClientIpPortType mountPoint; + if (fileRecordManager_->FindFileMountPoint(fileName, &mountPoint)) { + LOG(ERROR) << fileName << "is mounting on " << mountPoint.first << ":" + << mountPoint.second; + return StatusCode::kFileOccupied; + } + return StatusCode::kOK; } @@ -1362,6 +1367,9 @@ StatusCode CurveFS::CloseFile(const std::string &fileName, return ret; } + // remove file record + fileRecordManager_->RemoveFileRecord(fileName); + return StatusCode::kOK; } diff --git a/src/mds/nameserver2/curvefs.h b/src/mds/nameserver2/curvefs.h index 7e33c9b811..3d68bc540e 100644 --- a/src/mds/nameserver2/curvefs.h +++ b/src/mds/nameserver2/curvefs.h @@ -599,6 +599,19 @@ class CurveFS { const FileInfo& fileInfo, uint64_t* fileSize); + /** + * @brief check whether mds has started for enough time, based on the + * file record expiration time(mds.file.expiredTimeUs) + * @param times multiple of file record expiration time + * @return return true if ok, otherwise return false + */ + bool IsStartEnoughTime(int times) const { + std::chrono::steady_clock::duration timePass = + std::chrono::steady_clock::now() - startTime_; + uint32_t expiredUs = fileRecordManager_->GetFileRecordExpiredTimeUs(); + return timePass >= times * std::chrono::microseconds(expiredUs); + } + private: FileInfo rootFileInfo_; std::shared_ptr storage_; diff --git a/src/mds/nameserver2/file_record.cpp b/src/mds/nameserver2/file_record.cpp index 047fceb7ed..cb117b7ddc 100644 --- a/src/mds/nameserver2/file_record.cpp +++ b/src/mds/nameserver2/file_record.cpp @@ -88,6 +88,10 @@ void FileRecordManager::UpdateFileRecord(const std::string& fileName, fileRecords_.emplace(fileName, record); } +void FileRecordManager::RemoveFileRecord(const std::string& filename) { + WriteLockGuard lk(rwlock_); + fileRecords_.erase(filename); +} void FileRecordManager::Scan() { while (sleeper_.wait_for( diff --git a/src/mds/nameserver2/file_record.h b/src/mds/nameserver2/file_record.h index 3eae507989..3c3672c638 100644 --- a/src/mds/nameserver2/file_record.h +++ b/src/mds/nameserver2/file_record.h @@ -141,6 +141,8 @@ class FileRecord { class FileRecordManager { public: + virtual ~FileRecordManager() = default; + /** * @brief initialization * @param[in] sessionOption session configuration @@ -160,7 +162,7 @@ class FileRecordManager { * @brief Get the expired time of the file * @return the expired time */ - uint32_t GetFileRecordExpiredTimeUs() const { + virtual uint32_t GetFileRecordExpiredTimeUs() const { return fileRecordOptions_.fileRecordExpiredTimeUs; } @@ -173,6 +175,12 @@ class FileRecordManager { const std::string& clientIP, uint32_t clientPort); + /** + * @brief remove file record corresponding to filename + * @param filename file record that to be deleted + */ + void RemoveFileRecord(const std::string& filename); + /** * @brief Get the client version corresponding to the input file * @param[in] filename @@ -198,8 +206,8 @@ class FileRecordManager { std::set ListAllClient() const; - bool FindFileMountPoint(const std::string& fileName, - ClientIpPortType* ipPort) const; + virtual bool FindFileMountPoint(const std::string& fileName, + ClientIpPortType* ipPort) const; private: /** diff --git a/src/snapshotcloneserver/common/curvefs_client.cpp b/src/snapshotcloneserver/common/curvefs_client.cpp index 005dea0ce2..c2a0d47496 100644 --- a/src/snapshotcloneserver/common/curvefs_client.cpp +++ b/src/snapshotcloneserver/common/curvefs_client.cpp @@ -338,7 +338,9 @@ int CurveFsClientImpl::RenameCloneFile( }; RetryCondition condition = [] (int ret) { return ret != LIBCURVE_ERROR::OK && - ret != -LIBCURVE_ERROR::NOTEXIST; + ret != -LIBCURVE_ERROR::NOTEXIST && + ret != -LIBCURVE_ERROR::NOT_SUPPORT && + ret != -LIBCURVE_ERROR::FILE_OCCUPIED; // file is in-use }; RetryHelper retryHelper(method, condition); return retryHelper.RetryTimeSecAndReturn(clientMethodRetryTimeSec_, diff --git a/test/client/client_session_unittest.cpp b/test/client/client_session_unittest.cpp index bae5c6f22e..4ec29f2318 100644 --- a/test/client/client_session_unittest.cpp +++ b/test/client/client_session_unittest.cpp @@ -112,6 +112,7 @@ TEST(ClientSession, LeaseTaskTest) { se->set_sessionstatus(::curve::mds::SessionStatus::kSessionOK); finfo->set_filename(filename); + finfo->set_id(1); openresponse.set_statuscode(::curve::mds::StatusCode::kOK); openresponse.set_allocated_protosession(se); openresponse.set_allocated_fileinfo(finfo); @@ -233,8 +234,57 @@ TEST(ClientSession, LeaseTaskTest) { } ASSERT_TRUE(lease->LeaseValid()); - // 9. set refresh success + { + std::unique_lock lk(sessionMtx); + sessionCV.wait(lk, [&]() { return sessionFlag; }); + } + + // 9. set inode id changed + refreshresp.set_allocated_fileinfo(nullptr); // clear existing file info + + curve::mds::FileInfo* newFileInfo = new curve::mds::FileInfo; + newFileInfo->set_filename(filename); + newFileInfo->set_seqnum(2); + newFileInfo->set_id(100); + newFileInfo->set_parentid(0); + newFileInfo->set_filetype(curve::mds::FileType::INODE_PAGEFILE); + newFileInfo->set_chunksize(4 * 1024 * 1024); + newFileInfo->set_length(4 * 1024 * 1024 * 1024ul); + newFileInfo->set_ctime(12345678); + + refreshresp.set_allocated_fileinfo(newFileInfo); + refreshresp.set_statuscode(::curve::mds::StatusCode::kOK); + + FakeReturn* refreshFakeRetWithNewInodeId = new FakeReturn( + nullptr, static_cast(&refreshresp)); + curvefsservice->SetRefreshSession( + refreshFakeRetWithNewInodeId, refresht); + + { + std::unique_lock lk(mtx); + refreshcv.wait(lk); + } + + std::this_thread::sleep_for(std::chrono::seconds(1)); + lease = fileinstance.GetLeaseExecutor(); + ASSERT_FALSE(lease->LeaseValid()); + + // 10. set refresh success + refreshresp.set_allocated_fileinfo(nullptr); // clear existing file info + + newFileInfo = new curve::mds::FileInfo; + newFileInfo->set_filename(filename); + newFileInfo->set_seqnum(2); + newFileInfo->set_id(1); + newFileInfo->set_parentid(0); + newFileInfo->set_filetype(curve::mds::FileType::INODE_PAGEFILE); + newFileInfo->set_chunksize(4 * 1024 * 1024); + newFileInfo->set_length(4 * 1024 * 1024 * 1024ul); + newFileInfo->set_ctime(12345678); + + refreshresp.set_allocated_fileinfo(newFileInfo); refreshresp.set_statuscode(::curve::mds::StatusCode::kOK); + FakeReturn* refreshfakeretOK4 = new FakeReturn(nullptr, static_cast(&refreshresp)); curvefsservice->SetRefreshSession(refreshfakeretOK4, refresht); @@ -251,7 +301,7 @@ TEST(ClientSession, LeaseTaskTest) { std::unique_lock lk(sessionMtx); sessionCV.wait(lk, [&]() { return sessionFlag; }); - // 10. set fake close return + // 11. set fake close return ::curve::mds::CloseFileResponse closeresp; closeresp.set_statuscode(::curve::mds::StatusCode::kOK); FakeReturn* closefileret diff --git a/test/client/fake/fakeMDS.cpp b/test/client/fake/fakeMDS.cpp index 53ab4c0be5..6dcb166a72 100644 --- a/test/client/fake/fakeMDS.cpp +++ b/test/client/fake/fakeMDS.cpp @@ -235,6 +235,11 @@ bool FakeMDS::StartService() { ::curve::mds::ReFreshSessionResponse* refreshresp = new ::curve::mds::ReFreshSessionResponse(); // NOLINT refreshresp->set_statuscode(::curve::mds::StatusCode::kOK); refreshresp->set_sessionid("1234"); + + auto* refreshFileInfo = new ::curve::mds::FileInfo(); + refreshFileInfo->set_id(1); + refreshresp->set_allocated_fileinfo(refreshFileInfo); + FakeReturn* refreshfakeret = new FakeReturn(nullptr, static_cast(refreshresp)); // NOLINT fakecurvefsservice_.SetRefreshSession(refreshfakeret, nullptr); diff --git a/test/client/fake/fakeMDS.h b/test/client/fake/fakeMDS.h index f957138e1f..65bcad198d 100644 --- a/test/client/fake/fakeMDS.h +++ b/test/client/fake/fakeMDS.h @@ -233,7 +233,7 @@ class FakeMDSCurveFSService : public curve::mds::CurveFSService { curve::mds::FileInfo * info = new curve::mds::FileInfo; info->set_seqnum(seq++); info->set_filename("_filename_"); - info->set_id(1); + info->set_id(resp->fileinfo().id()); info->set_parentid(0); info->set_filetype(curve::mds::FileType::INODE_PAGEFILE); info->set_chunksize(4 * 1024 * 1024); diff --git a/test/mds/nameserver2/curvefs_test.cpp b/test/mds/nameserver2/curvefs_test.cpp index 2a0378bb2a..d7091f5a25 100644 --- a/test/mds/nameserver2/curvefs_test.cpp +++ b/test/mds/nameserver2/curvefs_test.cpp @@ -32,10 +32,10 @@ #include "test/mds/nameserver2/mock/mock_inode_id_generator.h" #include "test/mds/nameserver2/mock/mock_chunk_allocate.h" #include "test/mds/nameserver2/mock/mock_clean_manager.h" +#include "test/mds/nameserver2/mock/mock_file_record_manager.h" #include "test/mds/mock/mock_alloc_statistic.h" #include "test/mds/mock/mock_topology.h" - using ::testing::AtLeast; using ::testing::StrEq; using ::testing::_; @@ -60,9 +60,8 @@ class CurveFSTest: public ::testing::Test { mockcleanManager_ = std::make_shared(); topology_ = std::make_shared(); - fileRecordManager_ = std::make_shared(); + fileRecordManager_ = std::make_shared(); - // session repo已经mock,数据库相关参数不需要 fileRecordOptions_.fileRecordExpiredTimeUs = 5 * 1000; fileRecordOptions_.scanIntervalTimeUs = 1 * 1000; @@ -106,7 +105,7 @@ class CurveFSTest: public ::testing::Test { std::shared_ptr mockChunkAllocator_; std::shared_ptr mockcleanManager_; - std::shared_ptr fileRecordManager_; + std::shared_ptr fileRecordManager_; std::shared_ptr allocStatistic_; std::shared_ptr topology_; struct FileRecordOptions fileRecordOptions_; @@ -577,6 +576,56 @@ TEST_F(CurveFSTest, testDeleteFile) { ASSERT_EQ(curvefs_->DeleteFile("/file1", kUnitializedFileID, false), StatusCode::kNotSupported); } + + // test delete failed when mds didn't start for enough time + { + FileInfo fileInfo; + fileInfo.set_filetype(FileType::INODE_PAGEFILE); + EXPECT_CALL(*storage_, GetFile(_, _, _)) + .Times(2) + .WillRepeatedly( + DoAll(SetArgPointee<2>(fileInfo), Return(StoreStatus::OK))); + + std::vector fileInfoList; + EXPECT_CALL(*storage_, ListSnapshotFile(_, _, _)) + .Times(1) + .WillOnce( + DoAll(SetArgPointee<2>(fileInfoList), Return(StoreStatus::OK))); + + EXPECT_CALL(*fileRecordManager_, GetFileRecordExpiredTimeUs()) + .Times(1) + .WillOnce(Return(50 * 1000000ul)); + + ASSERT_EQ(curvefs_->DeleteFile("/file1", kUnitializedFileID, false), + StatusCode::kNotSupported); + } + + // test delete failed when file is in-use + { + FileInfo fileInfo; + fileInfo.set_filetype(FileType::INODE_PAGEFILE); + EXPECT_CALL(*storage_, GetFile(_, _, _)) + .Times(2) + .WillRepeatedly( + DoAll(SetArgPointee<2>(fileInfo), Return(StoreStatus::OK))); + + std::vector fileInfoList; + EXPECT_CALL(*storage_, ListSnapshotFile(_, _, _)) + .Times(1) + .WillOnce( + DoAll(SetArgPointee<2>(fileInfoList), Return(StoreStatus::OK))); + + EXPECT_CALL(*fileRecordManager_, GetFileRecordExpiredTimeUs()) + .Times(1) + .WillOnce(Return(1ul)); + + ClientIpPortType mountPoint("127.0.0.1", 12345); + EXPECT_CALL(*fileRecordManager_, FindFileMountPoint(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(mountPoint), Return(true))); + + ASSERT_EQ(curvefs_->DeleteFile("/file1", kUnitializedFileID, false), + StatusCode::kFileOccupied); + } } TEST_F(CurveFSTest, testGetAllocatedSize) { @@ -1137,7 +1186,7 @@ TEST_F(CurveFSTest, testRenameFile) { } // new file exist, submit delete job fail - { + { FileInfo fileInfo1; FileInfo fileInfo2; fileInfo1.set_filetype(FileType::INODE_PAGEFILE); @@ -1173,6 +1222,50 @@ TEST_F(CurveFSTest, testRenameFile) { ASSERT_EQ(curvefs_->RenameFile("/file1", "/trash/file2", 0, 0), StatusCode::kOK); } + + // new file exist, and new file is in-use(file with session record) + { + FileInfo fileInfo1; + FileInfo fileInfo2; + fileInfo1.set_filetype(FileType::INODE_PAGEFILE); + fileInfo2.set_filetype(FileType::INODE_DIRECTORY); + EXPECT_CALL(*storage_, GetFile(_, _, _)) + .Times(6) + // 查找/file1 + .WillOnce( + DoAll(SetArgPointee<2>(fileInfo1), Return(StoreStatus::OK))) + // check /file1是否有快照 + .WillOnce( + DoAll(SetArgPointee<2>(fileInfo1), Return(StoreStatus::OK))) + // 查找/trash/file2 + .WillOnce( + DoAll(SetArgPointee<2>(fileInfo2), Return(StoreStatus::OK))) + .WillOnce( + DoAll(SetArgPointee<2>(fileInfo1), Return(StoreStatus::OK))) + // check /trash/file2是否有快照 + .WillOnce( + DoAll(SetArgPointee<2>(fileInfo2), Return(StoreStatus::OK))) + .WillOnce( + DoAll(SetArgPointee<2>(fileInfo1), Return(StoreStatus::OK))); + + EXPECT_CALL(*fileRecordManager_, GetFileRecordExpiredTimeUs()) + .Times(2) + .WillRepeatedly(Return(1ul)); + + ClientIpPortType mountPoint("127.0.0.1", 12345); + EXPECT_CALL(*fileRecordManager_, FindFileMountPoint(_, _)) + .Times(2) + .WillOnce(Return(false)) + .WillOnce(DoAll(SetArgPointee<1>(mountPoint), Return(true))); + + EXPECT_CALL(*storage_, ListSnapshotFile(_, _, _)) + .Times(2) + .WillOnce(Return(StoreStatus::KeyNotExist)) + .WillOnce(Return(StoreStatus::KeyNotExist)); + + ASSERT_EQ(StatusCode::kFileOccupied, + curvefs_->RenameFile("/file1", "/trash/file2", 0, 0)); + } } TEST_F(CurveFSTest, testExtendFile) { @@ -1462,6 +1555,28 @@ TEST_F(CurveFSTest, testChangeOwner) { ASSERT_EQ(curvefs_->ChangeOwner("/file1", "owner2"), StatusCode::kNotSupported); } + + // ChangeOwner file is in-use + { + FileInfo fileInfo1; + fileInfo1.set_filetype(FileType::INODE_PAGEFILE); + fileInfo1.set_owner("owner1"); + EXPECT_CALL(*storage_, GetFile(_, _, _)) + .Times(2) + .WillRepeatedly( + DoAll(SetArgPointee<2>(fileInfo1), Return(StoreStatus::OK))); + + EXPECT_CALL(*storage_, ListSnapshotFile(_, _, _)) + .Times(1) + .WillOnce(Return(StoreStatus::KeyNotExist)); + + ClientIpPortType mountPoint("127.0.0.1", 12345); + EXPECT_CALL(*fileRecordManager_, FindFileMountPoint(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(mountPoint), Return(true))); + + ASSERT_EQ(curvefs_->ChangeOwner("/file1", "owner2"), + StatusCode::kFileOccupied); + } } TEST_F(CurveFSTest, testGetOrAllocateSegment) { @@ -1678,9 +1793,13 @@ TEST_F(CurveFSTest, testCreateSnapshotFile) { .WillOnce(DoAll(SetArgPointee<2>(originalFile), Return(StoreStatus::OK))); + EXPECT_CALL(*fileRecordManager_, GetFileRecordExpiredTimeUs()) + .Times(1) + .WillOnce(Return(50 * 1000000ul)); + FileInfo snapShotFileInfoRet; ASSERT_EQ(StatusCode::kSnapshotFrozen, - curvefs_->CreateSnapShotFile(fileName, &snapShotFileInfoRet)); + curvefs_->CreateSnapShotFile(fileName, &snapShotFileInfoRet)); } { // test client version invalid @@ -1697,6 +1816,10 @@ TEST_F(CurveFSTest, testCreateSnapshotFile) { .WillOnce(DoAll(SetArgPointee<2>(originalFile), Return(StoreStatus::OK))); + EXPECT_CALL(*fileRecordManager_, GetFileRecordExpiredTimeUs()) + .Times(1) + .WillOnce(Return(1ul)); + FileInfo info; ASSERT_EQ(StatusCode::kOK, curvefs_->RefreshSession( @@ -1720,6 +1843,10 @@ TEST_F(CurveFSTest, testCreateSnapshotFile) { .WillOnce(DoAll(SetArgPointee<2>(originalFile), Return(StoreStatus::OK))); + EXPECT_CALL(*fileRecordManager_, GetFileRecordExpiredTimeUs()) + .Times(1) + .WillOnce(Return(1ul)); + FileInfo info; ASSERT_EQ(StatusCode::kOK, curvefs_->RefreshSession( @@ -1741,6 +1868,10 @@ TEST_F(CurveFSTest, testCreateSnapshotFile) { .WillOnce(DoAll(SetArgPointee<2>(originalFile), Return(StoreStatus::OK))); + EXPECT_CALL(*fileRecordManager_, GetFileRecordExpiredTimeUs()) + .Times(1) + .WillOnce(Return(1ul)); + std::vector snapShotFiles; FileInfo fileInfo1; snapShotFiles.push_back(fileInfo1); @@ -1792,6 +1923,10 @@ TEST_F(CurveFSTest, testCreateSnapshotFile) { .Times(1) .WillOnce(Return(StoreStatus::OK)); + EXPECT_CALL(*fileRecordManager_, GetFileRecordExpiredTimeUs()) + .Times(1) + .WillOnce(Return(1ul)); + // test client version valid FileInfo snapShotFileInfoRet; ASSERT_EQ(curvefs_->CreateSnapShotFile("/originalFile", @@ -1833,6 +1968,10 @@ TEST_F(CurveFSTest, testCreateSnapshotFile) { .Times(1) .WillOnce(Return(StoreStatus::OK)); + EXPECT_CALL(*fileRecordManager_, GetFileRecordExpiredTimeUs()) + .Times(1) + .WillOnce(Return(1ul)); + // test client version valid FileInfo snapShotFileInfoRet; ASSERT_EQ(curvefs_->CreateSnapShotFile("/originalFile2", diff --git a/test/mds/nameserver2/mock/mock_file_record_manager.h b/test/mds/nameserver2/mock/mock_file_record_manager.h new file mode 100644 index 0000000000..f2efee5f55 --- /dev/null +++ b/test/mds/nameserver2/mock/mock_file_record_manager.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: curve + * Created Date: Tue Nov 3 22:23:04 CST 2020 + * Author: wuhanqing + */ + +#ifndef TEST_MDS_NAMESERVER2_MOCK_MOCK_FILE_RECORD_MANAGER_H_ +#define TEST_MDS_NAMESERVER2_MOCK_MOCK_FILE_RECORD_MANAGER_H_ + +#include + +#include + +#include "src/mds/nameserver2/file_record.h" + +namespace curve { +namespace mds { + +class MockFileRecordManager : public FileRecordManager { + public: + MockFileRecordManager() = default; + ~MockFileRecordManager() = default; + + MOCK_CONST_METHOD0(GetFileRecordExpiredTimeUs, uint32_t()); + MOCK_CONST_METHOD2(FindFileMountPoint, + bool(const std::string&, ClientIpPortType*)); +}; + +} // namespace mds +} // namespace curve + +#endif // TEST_MDS_NAMESERVER2_MOCK_MOCK_FILE_RECORD_MANAGER_H_