diff --git a/curvefs/src/client/fuse_s3_client.cpp b/curvefs/src/client/fuse_s3_client.cpp index 54e08a007b..17f2e178da 100644 --- a/curvefs/src/client/fuse_s3_client.cpp +++ b/curvefs/src/client/fuse_s3_client.cpp @@ -50,10 +50,30 @@ CURVEFS_ERROR FuseS3Client::Init(const FuseClientOption &option) { ::curvefs::client::common::S3Info2FsS3Option(s3Info, &fsS3Option); SetFuseClientS3Option(&opt, fsS3Option); - s3Client_ = std::make_shared(); - s3Client_->Init(opt.s3Opt.s3AdaptrOpt); - ret = s3Adaptor_->Init(opt.s3Opt.s3ClientAdaptorOpt, s3Client_.get(), - inodeManager_, mdsClient_); + auto s3Client = std::make_shared(); + s3Client->Init(opt.s3Opt.s3AdaptrOpt); + auto fsCacheManager = std::make_shared( + dynamic_cast(s3Adaptor_.get()), + opt.s3Opt.s3ClientAdaptorOpt.readCacheMaxByte, + opt.s3Opt.s3ClientAdaptorOpt.writeCacheMaxByte); + if (opt.s3Opt.s3ClientAdaptorOpt.diskCacheOpt.diskCacheType != + DiskCacheType::Disable) { + auto wrapper = std::make_shared(); + auto diskCacheRead = std::make_shared(); + auto diskCacheWrite = std::make_shared(); + auto diskCacheManager = std::make_shared( + wrapper, diskCacheWrite, diskCacheRead); + auto diskCacheManagerImpl = std::make_shared( + diskCacheManager, s3Client.get()); + ret = s3Adaptor_->Init(opt.s3Opt.s3ClientAdaptorOpt, s3Client, + inodeManager_, mdsClient_, fsCacheManager, + diskCacheManagerImpl, true); + } else { + ret = s3Adaptor_->Init(opt.s3Opt.s3ClientAdaptorOpt, s3Client, + inodeManager_, mdsClient_, fsCacheManager, + nullptr); + } + return ret; } diff --git a/curvefs/src/client/fuse_s3_client.h b/curvefs/src/client/fuse_s3_client.h index 6762bf8bb9..93943457f2 100644 --- a/curvefs/src/client/fuse_s3_client.h +++ b/curvefs/src/client/fuse_s3_client.h @@ -27,7 +27,7 @@ #include #include "curvefs/src/client/fuse_client.h" - +#include "curvefs/src/client/s3/client_s3_cache_manager.h" namespace curvefs { namespace client { @@ -35,8 +35,7 @@ class FuseS3Client : public FuseClient { public: FuseS3Client() : FuseClient(), - s3Adaptor_(std::make_shared()), - s3Client_(nullptr) {} + s3Adaptor_(std::make_shared()) {} FuseS3Client(const std::shared_ptr &mdsClient, const std::shared_ptr &metaClient, @@ -45,8 +44,7 @@ class FuseS3Client : public FuseClient { const std::shared_ptr &s3Adaptor) : FuseClient(mdsClient, metaClient, inodeManager, dentryManager), - s3Adaptor_(s3Adaptor), - s3Client_(nullptr) {} + s3Adaptor_(s3Adaptor) {} CURVEFS_ERROR Init(const FuseClientOption &option) override; @@ -85,9 +83,6 @@ class FuseS3Client : public FuseClient { private: // s3 adaptor std::shared_ptr s3Adaptor_; - - // s3 client - std::shared_ptr s3Client_; }; diff --git a/curvefs/src/client/s3/client_s3_adaptor.cpp b/curvefs/src/client/s3/client_s3_adaptor.cpp index 17c4de99f8..aa454c59ad 100644 --- a/curvefs/src/client/s3/client_s3_adaptor.cpp +++ b/curvefs/src/client/s3/client_s3_adaptor.cpp @@ -32,11 +32,44 @@ namespace curvefs { namespace client { +/* +CURVEFS_ERROR +S3ClientAdaptorImpl::Init( + const S3ClientAdaptorOption &option, std::shared_ptr client, + std::shared_ptr inodeManager, + std::shared_ptr mdsClient, + std::shared_ptr diskCacheManagerImpl) { + auto ret = Init(option, client, inodeManager, mdsClient); + if (ret != CURVEFS_ERROR::OK) { + LOG(ERROR) << "Init s3 client adaptor failed, ret: " << ret; + return ret; + } + if (HasDiskCache()) { + diskCacheManagerImpl_ = diskCacheManagerImpl; + if (diskCacheManagerImpl_->Init(option) < 0) { + LOG(ERROR) << "Init disk cache failed"; + return CURVEFS_ERROR::INTERNAL; + } + // init rpc send exec-queue + downloadTaskQueues_.resize(prefetchExecQueueNum_); + for (auto &q : downloadTaskQueues_) { + int rc = bthread::execution_queue_start( + &q, nullptr, &S3ClientAdaptorImpl::ExecAsyncDownloadTask, this); + if (rc != 0) { + LOG(ERROR) << "Init AsyncRpcQueues failed"; + return CURVEFS_ERROR::INTERNAL; + } + } + } + + return CURVEFS_ERROR::OK; +} CURVEFS_ERROR -S3ClientAdaptorImpl::Init(const S3ClientAdaptorOption &option, S3Client *client, - std::shared_ptr inodeManager, - std::shared_ptr mdsClient) { +S3ClientAdaptorImpl::Init( + const S3ClientAdaptorOption &option, std::shared_ptr client, + std::shared_ptr inodeManager, + std::shared_ptr mdsClient) { pendingReq_ = 0; blockSize_ = option.blockSize; chunkSize_ = option.chunkSize; @@ -73,18 +106,41 @@ S3ClientAdaptorImpl::Init(const S3ClientAdaptorOption &option, S3Client *client, toStop_.store(false, std::memory_order_release); bgFlushThread_ = Thread(&S3ClientAdaptorImpl::BackGroundFlush, this); + return CURVEFS_ERROR::OK; +} +*/ +CURVEFS_ERROR +S3ClientAdaptorImpl::Init( + const S3ClientAdaptorOption &option, std::shared_ptr client, + std::shared_ptr inodeManager, + std::shared_ptr mdsClient, + std::shared_ptr fsCacheManager, + std::shared_ptr diskCacheManagerImpl, + bool startBackGround) { + pendingReq_ = 0; + blockSize_ = option.blockSize; + chunkSize_ = option.chunkSize; + pageSize_ = option.pageSize; + if (chunkSize_ % blockSize_ != 0) { + LOG(ERROR) << "chunkSize:" << chunkSize_ + << " is not integral multiple for the blockSize:" + << blockSize_; + return CURVEFS_ERROR::INVALIDPARAM; + } + fuseMaxSize_ = option.fuseMaxSize; + prefetchBlocks_ = option.prefetchBlocks; + prefetchExecQueueNum_ = option.prefetchExecQueueNum; + diskCacheType_ = option.diskCacheOpt.diskCacheType; + memCacheNearfullRatio_ = option.nearfullRatio; + throttleBaseSleepUs_ = option.baseSleepUs; + flushIntervalSec_ = option.flushIntervalSec; + client_ = client; + inodeManager_ = inodeManager; + mdsClient_ = mdsClient; + fsCacheManager_ = fsCacheManager; + diskCacheManagerImpl_ = diskCacheManagerImpl; if (HasDiskCache()) { - std::shared_ptr wrapper = - std::make_shared(); - std::shared_ptr diskCacheRead = - std::make_shared(); - std::shared_ptr diskCacheWrite = - std::make_shared(); - std::shared_ptr diskCacheManager = - std::make_shared(wrapper, diskCacheWrite, - diskCacheRead); - diskCacheManagerImpl_ = - std::make_shared(diskCacheManager, client); + diskCacheManagerImpl_ = diskCacheManagerImpl; if (diskCacheManagerImpl_->Init(option) < 0) { LOG(ERROR) << "Init disk cache failed"; return CURVEFS_ERROR::INTERNAL; @@ -100,7 +156,21 @@ S3ClientAdaptorImpl::Init(const S3ClientAdaptorOption &option, S3Client *client, } } } + if (startBackGround) { + toStop_.store(false, std::memory_order_release); + bgFlushThread_ = Thread(&S3ClientAdaptorImpl::BackGroundFlush, this); + } + LOG(INFO) << "S3ClientAdaptorImpl Init. block size:" << blockSize_ + << ", chunk size: " << chunkSize_ + << ", prefetchBlocks: " << prefetchBlocks_ + << ", prefetchExecQueueNum: " << prefetchExecQueueNum_ + << ", intervalSec: " << option.intervalSec + << ", flushIntervalSec: " << option.flushIntervalSec + << ", writeCacheMaxByte: " << option.writeCacheMaxByte + << ", readCacheMaxByte: " << option.readCacheMaxByte + << ", nearfullRatio: " << option.nearfullRatio + << ", baseSleepUs: " << option.baseSleepUs; return CURVEFS_ERROR::OK; } @@ -117,9 +187,11 @@ int S3ClientAdaptorImpl::Write(uint64_t inodeId, uint64_t offset, VLOG(6) << "pendingReq_ is: " << pendingReq_; uint64_t pendingReq = pendingReq_.load(std::memory_order_seq_cst); fsCacheManager_->DataCacheByteInc(length); - if ((fsCacheManager_->GetDataCacheSize() + pendingReq * fuseMaxSize_) >= - fsCacheManager_->GetDataCacheMaxSize()) { - LOG(INFO) << "write cache is full, wait flush"; + uint64_t size = fsCacheManager_->GetDataCacheSize(); + uint64_t maxSize = fsCacheManager_->GetDataCacheMaxSize(); + if ((size + pendingReq * fuseMaxSize_) >= maxSize) { + LOG(INFO) << "write cache is full, wait flush. size:" << size + << ", maxSize:" << maxSize; fsCacheManager_->WaitFlush(); } } diff --git a/curvefs/src/client/s3/client_s3_adaptor.h b/curvefs/src/client/s3/client_s3_adaptor.h index 17a236e1e0..e558a52706 100644 --- a/curvefs/src/client/s3/client_s3_adaptor.h +++ b/curvefs/src/client/s3/client_s3_adaptor.h @@ -65,10 +65,23 @@ class S3ClientAdaptor { * @brief Initailize s3 client * @param[in] options the options for s3 client */ - virtual CURVEFS_ERROR Init(const S3ClientAdaptorOption& option, - S3Client* client, - std::shared_ptr inodeManager, - std::shared_ptr mdsClient) = 0; + /* + virtual CURVEFS_ERROR + Init(const S3ClientAdaptorOption &option, std::shared_ptr client, + std::shared_ptr inodeManager, + std::shared_ptr mdsClient, + std::shared_ptr diskcacheManagerImpl) = 0; + virtual CURVEFS_ERROR + Init(const S3ClientAdaptorOption &option, std::shared_ptr client, + std::shared_ptr inodeManager, + std::shared_ptr mdsClient) = 0;*/ + virtual CURVEFS_ERROR + Init(const S3ClientAdaptorOption &option, std::shared_ptr client, + std::shared_ptr inodeManager, + std::shared_ptr mdsClient, + std::shared_ptr fsCacheManager, + std::shared_ptr diskCacheManagerImpl, + bool startBackGround = false) = 0; /** * @brief write data to s3 * @param[in] options the options for s3 client @@ -94,14 +107,30 @@ class S3ClientAdaptor { class S3ClientAdaptorImpl : public S3ClientAdaptor { public: S3ClientAdaptorImpl() {} - virtual ~S3ClientAdaptorImpl() {} + virtual ~S3ClientAdaptorImpl() { + LOG(INFO) << "delete S3ClientAdaptorImpl"; + } /** * @brief Initailize s3 client * @param[in] options the options for s3 client */ - CURVEFS_ERROR Init(const S3ClientAdaptorOption& option, S3Client* client, - std::shared_ptr inodeManager, - std::shared_ptr mdsClient); + /* + CURVEFS_ERROR + Init(const S3ClientAdaptorOption &option, std::shared_ptr client, + std::shared_ptr inodeManager, + std::shared_ptr mdsClient, + std::shared_ptr diskCacheManagerImpl); + CURVEFS_ERROR + Init(const S3ClientAdaptorOption &option, std::shared_ptr client, + std::shared_ptr inodeManager, + std::shared_ptr mdsClient);*/ + CURVEFS_ERROR + Init(const S3ClientAdaptorOption &option, std::shared_ptr client, + std::shared_ptr inodeManager, + std::shared_ptr mdsClient, + std::shared_ptr fsCacheManager, + std::shared_ptr diskCacheManagerImpl, + bool startBackGround = false); /** * @brief write data to s3 * @param[in] options the options for s3 client @@ -125,7 +154,7 @@ class S3ClientAdaptorImpl : public S3ClientAdaptor { return fsCacheManager_; } uint32_t GetFlushInterval() { return flushIntervalSec_; } - S3Client *GetS3Client() { return client_; } + std::shared_ptr GetS3Client() { return client_; } uint32_t GetPrefetchBlocks() { return prefetchBlocks_; } @@ -173,18 +202,6 @@ class S3ClientAdaptorImpl : public S3ClientAdaptor { } void InitMetrics(const std::string &fsName); void CollectMetrics(InterfaceMetric *interface, int count, uint64_t start); - - // for test - void InitForTest( - std::shared_ptr diskcacheManagerImpl, - std::shared_ptr fsCacheManager, - std::shared_ptr inodeManager) { - diskCacheManagerImpl_ = diskcacheManagerImpl; - fsCacheManager_ = fsCacheManager; - inodeManager_ = inodeManager; - chunkSize_ = 4 * 1024 * 1024; - } - void SetDiskCache(DiskCacheType type) { diskCacheType_ = type; } @@ -213,7 +230,7 @@ class S3ClientAdaptorImpl : public S3ClientAdaptor { std::shared_ptr s3Metric_; private: - S3Client* client_; + std::shared_ptr client_; uint64_t blockSize_; uint64_t chunkSize_; uint32_t fuseMaxSize_; diff --git a/curvefs/src/client/s3/client_s3_cache_manager.cpp b/curvefs/src/client/s3/client_s3_cache_manager.cpp index 6433bf2385..80b2c71c48 100644 --- a/curvefs/src/client/s3/client_s3_cache_manager.cpp +++ b/curvefs/src/client/s3/client_s3_cache_manager.cpp @@ -1451,6 +1451,15 @@ void ChunkCacheManager::UpdateWriteCacheMap(uint64_t oldChunkPos, (void)ret; } +void ChunkCacheManager::AddWriteDataCacheForTest(DataCachePtr dataCache) { + WriteLockGuard writeLockGuard(rwLockWrite_); + + dataWCacheMap_.emplace(dataCache->GetChunkPos(), dataCache); + s3ClientAdaptor_->GetFsCacheManager()->DataCacheNumInc(); + s3ClientAdaptor_->GetFsCacheManager()->DataCacheByteInc( + dataCache->GetActualLen()); +} + DataCache::DataCache(S3ClientAdaptorImpl *s3ClientAdaptor, ChunkCacheManagerPtr chunkCacheManager, uint64_t chunkPos, uint64_t len, const char *data) @@ -1832,6 +1841,7 @@ void DataCache::Write(uint64_t chunkPos, uint64_t len, const char *data, void DataCache::Truncate(uint64_t size) { uint64_t blockSize = s3ClientAdaptor_->GetBlockSize(); uint32_t pageSize = s3ClientAdaptor_->GetPageSize(); + assert(size <= len_); curve::common::LockGuard lg(mtx_); uint64_t truncatePos = chunkPos_ + size; diff --git a/curvefs/src/client/s3/client_s3_cache_manager.h b/curvefs/src/client/s3/client_s3_cache_manager.h index 668dadcddc..b831d7f30b 100644 --- a/curvefs/src/client/s3/client_s3_cache_manager.h +++ b/curvefs/src/client/s3/client_s3_cache_manager.h @@ -111,9 +111,9 @@ class DataCache : public std::enable_shared_from_this { } } - void Write(uint64_t chunkPos, uint64_t len, const char *data, + virtual void Write(uint64_t chunkPos, uint64_t len, const char *data, const std::vector &mergeDataCacheVer); - void Truncate(uint64_t size); + virtual void Truncate(uint64_t size); uint64_t GetChunkPos() { return chunkPos_; } uint64_t GetLen() { return len_; } PageData *GetPageData(uint64_t blockIndex, uint64_t pageIndex) { @@ -138,7 +138,8 @@ class DataCache : public std::enable_shared_from_this { uint64_t GetActualLen() { return actualLen_; } - CURVEFS_ERROR Flush(uint64_t inodeId, bool force, bool toS3 = false); + virtual CURVEFS_ERROR Flush(uint64_t inodeId, bool force, + bool toS3 = false); void Release(); bool IsDirty() { return dirty_.load(std::memory_order_acquire); } void SetDelete() { return delete_.store(true, std::memory_order_release); } @@ -210,21 +211,22 @@ class ChunkCacheManager : index_(index), s3ClientAdaptor_(s3ClientAdaptor) {} virtual ~ChunkCacheManager() = default; - void WriteNewDataCache(S3ClientAdaptorImpl *s3ClientAdaptor, + virtual void WriteNewDataCache(S3ClientAdaptorImpl *s3ClientAdaptor, uint32_t chunkPos, uint32_t len, const char *data); - void AddReadDataCache(DataCachePtr dataCache); - DataCachePtr + virtual void AddReadDataCache(DataCachePtr dataCache); + virtual DataCachePtr FindWriteableDataCache(uint64_t pos, uint64_t len, std::vector *mergeDataCacheVer, uint64_t inodeId); - void ReadByWriteCache(uint64_t chunkPos, uint64_t readLen, char *dataBuf, - uint64_t dataBufOffset, - std::vector *requests); - void ReadByReadCache(uint64_t chunkPos, uint64_t readLen, char *dataBuf, - uint64_t dataBufOffset, - std::vector *requests); - CURVEFS_ERROR Flush(uint64_t inodeId, bool force, bool toS3 = false); + virtual void ReadByWriteCache(uint64_t chunkPos, uint64_t readLen, + char *dataBuf, uint64_t dataBufOffset, + std::vector *requests); + virtual void ReadByReadCache(uint64_t chunkPos, uint64_t readLen, + char *dataBuf, uint64_t dataBufOffset, + std::vector *requests); + virtual CURVEFS_ERROR Flush(uint64_t inodeId, bool force, + bool toS3 = false); uint64_t GetIndex() { return index_; } bool IsEmpty() { ReadLockGuard writeCacheLock(rwLockChunk_); @@ -232,10 +234,19 @@ class ChunkCacheManager } virtual void ReleaseReadDataCache(uint64_t key); - void ReleaseCache(); + virtual void ReleaseCache(); void TruncateCache(uint64_t chunkPos); void UpdateWriteCacheMap(uint64_t oldChunkPos, DataCache *dataCache); - + // for unit test + void AddWriteDataCacheForTest(DataCachePtr dataCache); + void ReleaseCacheForTest() { + { + WriteLockGuard writeLockGuard(rwLockWrite_); + dataWCacheMap_.clear(); + } + WriteLockGuard writeLockGuard(rwLockRead_); + dataRCacheMap_.clear(); + } public: RWLock rwLockChunk_; // for read write chunk RWLock rwLockWrite_; // for dataWCacheMap_ @@ -264,13 +275,21 @@ class FileCacheManager { FileCacheManager() {} ChunkCacheManagerPtr FindOrCreateChunkCacheManager(uint64_t index); void ReleaseCache(); - void TruncateCache(uint64_t offset, uint64_t fileSize); + virtual void TruncateCache(uint64_t offset, uint64_t fileSize); virtual CURVEFS_ERROR Flush(bool force, bool toS3 = false); - int Write(uint64_t offset, uint64_t length, const char *dataBuf); - int Read(uint64_t inodeId, uint64_t offset, uint64_t length, char *dataBuf); + virtual int Write(uint64_t offset, uint64_t length, const char *dataBuf); + virtual int Read(uint64_t inodeId, uint64_t offset, uint64_t length, + char *dataBuf); bool IsEmpty() { return chunkCacheMap_.empty(); } - uint64_t GetInodeId() const { return inode_; } + void SetChunkCacheManagerForTest(uint64_t index, + ChunkCacheManagerPtr chunkCacheManager) { + WriteLockGuard writeLockGuard(rwLock_); + + auto ret = chunkCacheMap_.emplace(index, chunkCacheManager); + assert(ret.second); + (void)ret; + } private: void WriteChunk(uint64_t index, uint64_t chunkPos, uint64_t writeLen, @@ -319,7 +338,7 @@ class FsCacheManager { s3ClientAdaptor_(s3ClientAdaptor), isWaiting_(false) {} FsCacheManager() {} virtual FileCacheManagerPtr FindFileCacheManager(uint64_t inodeId); - FileCacheManagerPtr FindOrCreateFileCacheManager(uint64_t fsId, + virtual FileCacheManagerPtr FindOrCreateFileCacheManager(uint64_t fsId, uint64_t inodeId); void ReleaseFileCacheManager(uint64_t inodeId); @@ -333,11 +352,11 @@ class FsCacheManager { return wDataCacheNum_.load(std::memory_order_relaxed); } - uint64_t GetDataCacheSize() { + virtual uint64_t GetDataCacheSize() { return wDataCacheByte_.load(std::memory_order_relaxed); } - uint64_t GetDataCacheMaxSize() { + virtual uint64_t GetDataCacheMaxSize() { return writeCacheMaxByte_; } @@ -388,7 +407,7 @@ class FsCacheManager { writeCacheMaxByte_; } - uint64_t MemCacheRatio() { + virtual uint64_t MemCacheRatio() { return 100 * wDataCacheByte_.load(std::memory_order_relaxed) / writeCacheMaxByte_; } @@ -398,6 +417,15 @@ class FsCacheManager { return lruByte_; } + void SetFileCacheManagerForTest(uint64_t inodeId, + FileCacheManagerPtr fileCacheManager) { + WriteLockGuard writeLockGuard(rwLock_); + + auto ret = fileCacheManagerMap_.emplace(inodeId, fileCacheManager); + assert(ret.second); + (void)ret; + } + private: class ReadCacheReleaseExecutor { public: diff --git a/curvefs/test/client/BUILD b/curvefs/test/client/BUILD index 813b7ea931..ca4b39448e 100644 --- a/curvefs/test/client/BUILD +++ b/curvefs/test/client/BUILD @@ -57,8 +57,12 @@ cc_binary( srcs = glob([ "main.cpp", "client_s3_adaptor_test.cpp", - "client_s3_adaptor_test2.cpp", + "fs_cache_manager_test.cpp", + "file_cache_manager_test.cpp", + "chunk_cache_manager_test.cpp", + "data_cache_test.cpp", "client_s3_test.cpp", + "client_s3_adaptor_Integration.cpp", "*.h", ]), copts = CURVE_TEST_COPTS, @@ -83,9 +87,13 @@ cc_test( "*.c", "*.h"], exclude = [ "block_device_client_test.cpp", + "client_s3_test.cpp", "client_s3_adaptor_test.cpp", - "client_s3_adaptor_test2.cpp", - "client_s3_test.cpp" ] + "fs_cache_manager_test.cpp", + "file_cache_manager_test.cpp", + "chunk_cache_manager_test.cpp", + "data_cache_test.cpp", + "client_s3_adaptor_Integration.cpp"] ), copts = CURVE_TEST_COPTS + ["-I/usr/local/include/fuse3"], deps = [ @@ -103,17 +111,3 @@ cc_test( visibility = ["//visibility:public"], ) -cc_test( - name = "curvefs_fs_cache_manager_test", - srcs = [ - "fs_cache_manager_test.cpp", - ] + glob([ - "*.h", - ]), - deps = [ - "//curvefs/src/client:fuse_client_lib", - "//external:gtest", - "@com_google_googletest//:gtest_main", - ], - copts = CURVE_TEST_COPTS, -) diff --git a/curvefs/test/client/chunk_cache_manager_test.cpp b/curvefs/test/client/chunk_cache_manager_test.cpp new file mode 100644 index 0000000000..c8fcf1aadc --- /dev/null +++ b/curvefs/test/client/chunk_cache_manager_test.cpp @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2021 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: Wed Mar 23 2022 + * Author: huyao + */ + +#include +#include + +#include "curvefs/src/client/s3/client_s3_adaptor.h" +#include "curvefs/src/client/s3/client_s3_cache_manager.h" +#include "curvefs/test/client/mock_client_s3_cache_manager.h" + +namespace curvefs { +namespace client { +using ::testing::_; +using ::testing::DoAll; +using ::testing::Invoke; +using ::testing::Return; +using ::testing::SetArgPointee; +using ::testing::SetArgReferee; +using ::testing::WithArg; + +class ChunkCacheManagerTest : public testing::Test { + protected: + ChunkCacheManagerTest() {} + ~ChunkCacheManagerTest() {} + void SetUp() override { + uint64_t index = 0; + + S3ClientAdaptorOption option; + option.blockSize = 1 * 1024 * 1024; + option.chunkSize = 4 * 1024 * 1024; + option.pageSize = 64 * 1024; + option.intervalSec = 5000; + option.flushIntervalSec = 5000; + option.readCacheMaxByte = 104857600; + option.writeCacheMaxByte = 10485760000; + option.diskCacheOpt.diskCacheType = (DiskCacheType)0; + s3ClientAdaptor_ = new S3ClientAdaptorImpl(); + auto fsCacheManager_ = std::make_shared( + s3ClientAdaptor_, option.readCacheMaxByte, + option.writeCacheMaxByte); + s3ClientAdaptor_->Init(option, nullptr, nullptr, nullptr, + fsCacheManager_, nullptr); + chunkCacheManager_ = + std::make_shared(index, s3ClientAdaptor_); + } + void TearDown() override { + delete s3ClientAdaptor_; + s3ClientAdaptor_ = nullptr; + } + + protected: + S3ClientAdaptorImpl *s3ClientAdaptor_; + std::shared_ptr chunkCacheManager_; +}; + +TEST_F(ChunkCacheManagerTest, test_write_new_data) { + uint64_t offset = 0; + uint64_t len = 1024; + int length = len; + char *buf = new char[len]; + + chunkCacheManager_->WriteNewDataCache(s3ClientAdaptor_, offset, len, buf); + ASSERT_EQ(65536, s3ClientAdaptor_->GetFsCacheManager()->GetDataCacheSize()); + + delete buf; +} + +TEST_F(ChunkCacheManagerTest, test_add_read_data_cache) { + uint64_t offset = 0; + uint64_t len = 1024 * 1024; + char *buf = new char[len]; + auto dataCache = std::make_shared( + s3ClientAdaptor_, chunkCacheManager_, offset, len, buf); + chunkCacheManager_->AddReadDataCache(dataCache); + ASSERT_EQ(len, s3ClientAdaptor_->GetFsCacheManager()->GetLruByte()); + offset = 2 * 1024 * 1024; + auto dataCache1 = std::make_shared( + s3ClientAdaptor_, chunkCacheManager_, offset, len, buf); + chunkCacheManager_->AddReadDataCache(dataCache1); + ASSERT_EQ(2 * len, s3ClientAdaptor_->GetFsCacheManager()->GetLruByte()); + offset = 0; + len = 512 * 1024; + auto dataCache2 = std::make_shared( + s3ClientAdaptor_, chunkCacheManager_, offset, len, buf); + chunkCacheManager_->AddReadDataCache(dataCache2); + ASSERT_EQ(1.5 * 1024 * 1024, + s3ClientAdaptor_->GetFsCacheManager()->GetLruByte()); + delete buf; +} + +TEST_F(ChunkCacheManagerTest, test_find_writeable_datacache) { + uint64_t inodeId = 1; + uint64_t offset = 0; + uint64_t len = 1024 * 1024; + char *buf = new char[len]; + + std::vector mergeDataCacheVer; + ASSERT_EQ(nullptr, chunkCacheManager_->FindWriteableDataCache( + offset, len, &mergeDataCacheVer, inodeId)); + chunkCacheManager_->WriteNewDataCache(s3ClientAdaptor_, offset, len, buf); + len = 512 * 1024; + ASSERT_NE(nullptr, chunkCacheManager_->FindWriteableDataCache( + offset, len, &mergeDataCacheVer, inodeId)); + ASSERT_EQ(0, mergeDataCacheVer.size()); + offset = 2 * 1024 * 1024; + chunkCacheManager_->WriteNewDataCache(s3ClientAdaptor_, offset, len, buf); + offset = 1024 * 1024; + len = 1024 * 1024; + ASSERT_NE(nullptr, chunkCacheManager_->FindWriteableDataCache( + offset, len, &mergeDataCacheVer, inodeId)); + ASSERT_EQ(1, mergeDataCacheVer.size()); + + delete buf; +} + +TEST_F(ChunkCacheManagerTest, test_read_by_write_cache) { + uint64_t offset = 0; + uint64_t len = 1024; + char *buf = new char[len + 1]; + char *dataCacheBuf = new char[len]; + char *expectBuf = new char[len + 1]; + std::vector requests; + memset(buf, 'a', len); + memset(buf + len, 0, 1); + memset(dataCacheBuf, 'b', len); + + chunkCacheManager_->ReadByWriteCache(offset, len, buf, 0, &requests); + ASSERT_EQ(1, requests.size()); + requests.clear(); + + chunkCacheManager_->WriteNewDataCache(s3ClientAdaptor_, 1024, len, + dataCacheBuf); + chunkCacheManager_->ReadByWriteCache(offset, len, buf, 0, &requests); + ASSERT_EQ(1, requests.size()); + requests.clear(); + /* + ----- ReadData + ------ DataCache + */ + offset = 512; + chunkCacheManager_->ReadByWriteCache(offset, len, buf, 0, &requests); + memset(expectBuf, 'a', 512); + memset(expectBuf + 512, 'b', 512); + memset(expectBuf + len, 0, 1); + EXPECT_STREQ(buf, expectBuf); + ASSERT_EQ(1, requests.size()); + requests.clear(); + + len = 2048; + delete buf; + delete expectBuf; + buf = new char[len + 1]; + expectBuf = new char[len + 1]; + memset(buf, 'a', len); + memset(buf + len, 0, 1); + chunkCacheManager_->ReadByWriteCache(offset, len, buf, 0, &requests); + memset(expectBuf, 'a', len); + memset(expectBuf + 512, 'b', 1024); + memset(expectBuf + len, 0, 1); + EXPECT_STREQ(buf, expectBuf); + ASSERT_EQ(2, requests.size()); + requests.clear(); + + len = 512; + delete buf; + delete expectBuf; + buf = new char[len + 1]; + expectBuf = new char[len + 1]; + memset(buf, 'a', len - 1); + memset(buf + len, 0, 1); + offset = 1024; + chunkCacheManager_->ReadByWriteCache(offset, len, buf, 0, &requests); + memset(expectBuf, 'b', len); + memset(expectBuf + len, 0, 1); + EXPECT_STREQ(buf, expectBuf); + ASSERT_EQ(0, requests.size()); + requests.clear(); + + len = 1024; + delete buf; + delete expectBuf; + buf = new char[len + 1]; + expectBuf = new char[len + 1]; + memset(buf, 'a', len); + memset(buf + len, 0, 1); + offset = 1536; + chunkCacheManager_->ReadByWriteCache(offset, len, buf, 0, &requests); + memset(expectBuf, 'a', len); + memset(expectBuf, 'b', 512); + memset(expectBuf + len, 0, 1); + EXPECT_STREQ(buf, expectBuf); + ASSERT_EQ(1, requests.size()); + requests.clear(); + + delete buf; + delete expectBuf; + delete dataCacheBuf; +} + +TEST_F(ChunkCacheManagerTest, test_read_by_read_cache) { + uint64_t offset = 0; + uint64_t len = 1024; + char *buf = new char[len + 1]; + char *dataCacheBuf = new char[len]; + char *expectBuf = new char[len + 1]; + std::vector requests; + memset(buf, 'a', len); + memset(buf + len, 0, 1); + memset(dataCacheBuf, 'b', len); + + chunkCacheManager_->ReadByReadCache(offset, len, buf, 0, &requests); + ASSERT_EQ(1, requests.size()); + requests.clear(); + + auto dataCache = std::make_shared( + s3ClientAdaptor_, chunkCacheManager_, 1024, len, dataCacheBuf); + chunkCacheManager_->AddReadDataCache(dataCache); + chunkCacheManager_->ReadByReadCache(offset, len, buf, 0, &requests); + ASSERT_EQ(1, requests.size()); + requests.clear(); + /* + ----- ReadData + ------ DataCache + */ + offset = 512; + chunkCacheManager_->ReadByReadCache(offset, len, buf, 0, &requests); + memset(expectBuf, 'a', 512); + memset(expectBuf + 512, 'b', 512); + memset(expectBuf + len, 0, 1); + EXPECT_STREQ(buf, expectBuf); + ASSERT_EQ(1, requests.size()); + requests.clear(); + + len = 2048; + delete buf; + delete expectBuf; + buf = new char[len + 1]; + expectBuf = new char[len + 1]; + memset(buf, 'a', len); + memset(buf + len, 0, 1); + chunkCacheManager_->ReadByReadCache(offset, len, buf, 0, &requests); + memset(expectBuf, 'a', len); + memset(expectBuf + 512, 'b', 1024); + memset(expectBuf + len, 0, 1); + EXPECT_STREQ(buf, expectBuf); + ASSERT_EQ(2, requests.size()); + requests.clear(); + + len = 512; + delete buf; + delete expectBuf; + buf = new char[len + 1]; + expectBuf = new char[len + 1]; + memset(buf, 'a', len - 1); + memset(buf + len, 0, 1); + offset = 1024; + chunkCacheManager_->ReadByReadCache(offset, len, buf, 0, &requests); + memset(expectBuf, 'b', len); + memset(expectBuf + len, 0, 1); + EXPECT_STREQ(buf, expectBuf); + ASSERT_EQ(0, requests.size()); + requests.clear(); + + len = 1024; + delete buf; + delete expectBuf; + buf = new char[len + 1]; + expectBuf = new char[len + 1]; + memset(buf, 'a', len); + memset(buf + len, 0, 1); + offset = 1536; + chunkCacheManager_->ReadByReadCache(offset, len, buf, 0, &requests); + memset(expectBuf, 'a', len); + memset(expectBuf, 'b', 512); + memset(expectBuf + len, 0, 1); + EXPECT_STREQ(buf, expectBuf); + ASSERT_EQ(1, requests.size()); + requests.clear(); + + delete buf; + delete expectBuf; + delete dataCacheBuf; +} + +TEST_F(ChunkCacheManagerTest, test_flush) { + uint64_t inodeId = 1; + uint64_t offset = 0; + uint64_t len = 1024 * 1024; + char *buf = new char[len]; + auto dataCache = std::make_shared( + s3ClientAdaptor_, chunkCacheManager_, offset, len, buf); + EXPECT_CALL(*dataCache, Flush(_, _, _)) + .WillOnce(Return(CURVEFS_ERROR::OK)) + .WillOnce(Return(CURVEFS_ERROR::INTERNAL)); + chunkCacheManager_->AddWriteDataCacheForTest(dataCache); + + ASSERT_EQ(CURVEFS_ERROR::OK, + chunkCacheManager_->Flush(inodeId, true, true)); + chunkCacheManager_->AddWriteDataCacheForTest(dataCache); + ASSERT_EQ(CURVEFS_ERROR::INTERNAL, + chunkCacheManager_->Flush(inodeId, true, true)); + chunkCacheManager_->ReleaseCacheForTest(); + + delete buf; +} + +TEST_F(ChunkCacheManagerTest, test_release_read_dataCache) { + uint64_t offset = 0; + uint64_t len = 1024 * 1024; + char *buf = new char[len]; + auto dataCache = std::make_shared( + s3ClientAdaptor_, chunkCacheManager_, offset, len, buf); + chunkCacheManager_->AddReadDataCache(dataCache); + chunkCacheManager_->ReleaseReadDataCache(offset); + ASSERT_EQ(true, chunkCacheManager_->IsEmpty()); + + delete buf; +} + + +TEST_F(ChunkCacheManagerTest, test_truncate_cache) { + uint64_t offset = 0; + uint64_t len = 1024 * 1024; + char *buf = new char[len]; + auto dataCache = std::make_shared( + s3ClientAdaptor_, chunkCacheManager_, offset, len, buf); + /*EXPECT_CALL(*dataCache, Truncate(_)) + .WillOnce(Return());*/ + chunkCacheManager_->AddWriteDataCacheForTest(dataCache); + ASSERT_EQ(len, s3ClientAdaptor_->GetFsCacheManager()->GetDataCacheSize()); + chunkCacheManager_->TruncateCache(0); + ASSERT_EQ(0, s3ClientAdaptor_->GetFsCacheManager()->GetDataCacheSize()); + + chunkCacheManager_->AddWriteDataCacheForTest(dataCache); + ASSERT_EQ(len, s3ClientAdaptor_->GetFsCacheManager()->GetDataCacheSize()); + chunkCacheManager_->TruncateCache(512 * 1024); + ASSERT_EQ(len - 512 * 1024, + s3ClientAdaptor_->GetFsCacheManager()->GetDataCacheSize()); + chunkCacheManager_->ReleaseCacheForTest(); + + chunkCacheManager_->AddReadDataCache(dataCache); + chunkCacheManager_->TruncateCache(512); + ASSERT_EQ(true, chunkCacheManager_->IsEmpty()); + + chunkCacheManager_->ReleaseCacheForTest(); + delete buf; +} + +} // namespace client +} // namespace curvefs diff --git a/curvefs/test/client/client_s3_adaptor_Integration.cpp b/curvefs/test/client/client_s3_adaptor_Integration.cpp new file mode 100644 index 0000000000..456765c238 --- /dev/null +++ b/curvefs/test/client/client_s3_adaptor_Integration.cpp @@ -0,0 +1,2991 @@ +/* + * Copyright (c) 2021 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: Thur Jun 22 2021 + * Author: huyao + */ + +#include "curvefs/src/client/s3/client_s3_adaptor.h" + +#include +#include +#include + +#include "curvefs/test/client/mock_client_s3.h" +#include "curvefs/test/client/mock_inode_cache_manager.h" +#include "curvefs/test/client/mock_mds_client.h" +#include "curvefs/test/client/mock_metaserver_service.h" +#include "curvefs/test/client/mock_spacealloc_service.h" +#include "src/common/curve_define.h" + +namespace curvefs { +namespace client { +namespace common { +DECLARE_bool(enableCto); +} // namespace common +} // namespace client +} // namespace curvefs + +namespace curvefs { +namespace client { +using ::curve::common::kMB; +using ::testing::_; +using ::testing::DoAll; +using ::testing::Invoke; +using ::testing::Return; +using ::testing::SetArgPointee; +using ::testing::SetArgReferee; +using ::testing::WithArg; + +using rpcclient::MockMdsClient; + +template +void S3RpcService(google::protobuf::RpcController *cntl_base, + const RpcRequestType *request, RpcResponseType *response, + google::protobuf::Closure *done) { + if (RpcFailed) { + brpc::Controller *cntl = static_cast(cntl_base); + cntl->SetFailed(112, "Not connected to"); + } + LOG(INFO) << "run s3 prc service"; + done->Run(); +} + +struct S3Data { + char *buf; + uint64_t len; +}; + +static std::map gObjectDataMaps; + +int S3Upload(std::string name, const char *buf, uint64_t len) { + S3Data &tmp = gObjectDataMaps[name]; + + tmp.len = len; + tmp.buf = new char[len]; + strncpy(tmp.buf, buf, len); + LOG(INFO) << "S3Upload len:" << len << ",name" << name << "buf:" << buf[0]; + return len; +} + +int S3Download(std::string name, char *buf, uint64_t offset, uint64_t len) { + S3Data &tmp = gObjectDataMaps[name]; + + assert((offset + len) <= tmp.len); + strncpy(buf, tmp.buf + offset, len); + LOG(INFO) << "S3Download offset:" << offset << ",len:" << len + << ",name:" << name << "buf:" << buf[0]; + return len; +} + +class ClientS3IntegrationTest : public testing::Test { + protected: + ClientS3IntegrationTest() {} + ~ClientS3IntegrationTest() {} + void SetUp() override { + Aws::InitAPI(awsOptions_); + ASSERT_EQ(0, server_.AddService(&mockMetaServerService_, + brpc::SERVER_DOESNT_OWN_SERVICE)); + ASSERT_EQ(0, server_.Start(addr_.c_str(), nullptr)); + S3ClientAdaptorOption option; + option.blockSize = 1 * 1024 * 1024; + option.chunkSize = 4 * 1024 * 1024; + option.pageSize = 64 * 1024; + option.intervalSec = 5000; + option.flushIntervalSec = 5000; + option.readCacheMaxByte = 104857600; + option.writeCacheMaxByte = 10485760000; + option.diskCacheOpt.diskCacheType = (DiskCacheType)0; + + std::shared_ptr mockInodeManager( + &mockInodeManager_); + std::shared_ptr mockMdsClient(&mockMdsClient_); + std::shared_ptr mockS3Client(&mockS3Client_); + s3ClientAdaptor_ = new S3ClientAdaptorImpl(); + auto fsCacheManager = std::make_shared( + s3ClientAdaptor_, option.readCacheMaxByte, + option.writeCacheMaxByte); + s3ClientAdaptor_->Init(option, mockS3Client, mockInodeManager, + mockMdsClient, fsCacheManager, nullptr); + s3ClientAdaptor_->SetFsId(2); + curvefs::client::common::FLAGS_enableCto = false; + } + + void TearDown() override { + Aws::ShutdownAPI(awsOptions_); + server_.Stop(0); + server_.Join(); + } + + protected: + S3ClientAdaptorImpl *s3ClientAdaptor_; + MockMetaServerService mockMetaServerService_; + MockS3Client mockS3Client_; + MockInodeCacheManager mockInodeManager_; + MockMdsClient mockMdsClient_; + std::string addr_ = "127.0.0.1:5630"; + brpc::Server server_; + Aws::SDKOptions awsOptions_; +}; +uint64_t gInodeId1 = 1; +void InitInodeForIntegration(Inode *inode) { + inode->set_inodeid(gInodeId1); + inode->set_fsid(2); + inode->set_length(0); + inode->set_ctime(1623835517); + inode->set_mtime(1623835517); + inode->set_atime(1623835517); + inode->set_uid(1); + inode->set_gid(1); + inode->set_mode(1); + inode->set_nlink(1); + inode->set_type(curvefs::metaserver::FsFileType::TYPE_S3); + gInodeId1++; +} + +TEST_F(ClientS3IntegrationTest, test_first_write) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 2 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + + int ret = s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(len, ret); + + delete buf; + buf = NULL; +} + +TEST_F(ClientS3IntegrationTest, test_overlap_write) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 1 * 1024 * 1024; + uint64_t len = 2 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + + offset = 0; + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + + offset = 2 * 1024 * 1024; + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + + delete buf; + buf = NULL; +} + +TEST_F(ClientS3IntegrationTest, test_hole_write) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 1 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + offset = 2 * 1024 * 1024; + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(2, fsCacheManager->GetDataCacheNum()); + + delete buf; + buf = NULL; +} + +TEST_F(ClientS3IntegrationTest, test_append_write) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 1 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + offset = offset + len; + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + + delete buf; + buf = NULL; +} + +TEST_F(ClientS3IntegrationTest, test_write_more_chunk) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 5 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(2, fsCacheManager->GetDataCacheNum()); + + delete buf; + buf = NULL; +} + +/* + ------ write1 + ------ write2 + ------------ write3 +*/ +TEST_F(ClientS3IntegrationTest, test_write_merge_data1) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 1 * 1024 * 1024; + uint64_t len = 1 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + offset = 3 * 1024 * 1024; + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(2, fsCacheManager->GetDataCacheNum()); + + offset = 1.5 * 1024 * 1024; + len = 2 * 1024 * 1024; + char *buf1 = new char[len]; + memset(buf1, 'b', len); + + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf1); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + + delete buf; + delete buf1; +} + +/* + ------ write1 + ------ write2 + ------------------- write3 +*/ +TEST_F(ClientS3IntegrationTest, test_write_merge_data2) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 1 * 1024 * 1024; + uint64_t len = 1 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + offset = 3 * 1024 * 1024; + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(2, fsCacheManager->GetDataCacheNum()); + + offset = 0; + len = 3.5 * 1024 * 1024; + char *buf1 = new char[len]; + memset(buf1, 'b', len); + + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf1); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + + delete buf; + delete buf1; +} + +TEST_F(ClientS3IntegrationTest, test_read_one_chunk) { + uint64_t readFileLen = 2 * 1024 * 1024; + curvefs::metaserver::Inode inode; + uint64_t offset = 0; + uint64_t len = 1 * 1024 * 1024; + uint64_t chunkSize = s3ClientAdaptor_->GetChunkSize(); + uint64_t chunkIndex = offset / chunkSize; + InitInodeForIntegration(&inode); + inode.set_length(readFileLen); + + auto s3ChunkInfoMap = inode.mutable_s3chunkinfomap(); + S3ChunkInfoList *s3ChunkInfoList = new S3ChunkInfoList(); + S3ChunkInfo *s3ChunkInfo = s3ChunkInfoList->add_s3chunks(); + s3ChunkInfo->set_chunkid(25); + s3ChunkInfo->set_compaction(0); + s3ChunkInfo->set_offset(0); + s3ChunkInfo->set_len(readFileLen); + s3ChunkInfo->set_size(readFileLen); + s3ChunkInfo->set_zero(false); + s3ChunkInfoMap->insert({chunkIndex, *s3ChunkInfoList}); + + char *buf = new char[len]; + char *tmpbuf = new char[len]; + memset(tmpbuf, 'a', len); + + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<1>(*tmpbuf), Return(1 * 1024 * 1024))) + .WillOnce(Return(-1)); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillOnce( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))) + .WillOnce( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + + int ret = s3ClientAdaptor_->Read(inode.inodeid(), offset, len, buf); + ASSERT_EQ(len, ret); + ASSERT_EQ('a', buf[0]); + offset = offset + len; + ret = s3ClientAdaptor_->Read(inode.inodeid(), offset, len, buf); + ASSERT_EQ(-1, ret); + + delete buf; + buf = NULL; +} +/* + ------------ a write1 + ------ b write2 + ------ b read1 + ------ a read2 +*/ +TEST_F(ClientS3IntegrationTest, test_read_overlap_block1) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 2 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + len = 1 * 1024 * 1024; + memset(buf, 'b', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + char *readBuf = new char[len + 1]; + char *expectBuf = new char[len + 1]; + memset(readBuf, 0, len + 1); + memset(expectBuf, 'b', len); + memset(expectBuf + len, 0, 1); + + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + offset = offset + len; + memset(expectBuf, 'a', len); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + delete readBuf; + delete buf; + delete expectBuf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* + ------------ a write1 + ------------ b write2 + ------ a read1 + ------ b read2 +*/ +TEST_F(ClientS3IntegrationTest, test_read_overlap_block2) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 2 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + offset = 1 * 1024 * 1024; + len = 2 * 1024 * 1024; + memset(buf, 'b', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + offset = 0; + len = 1 * 1024 * 1024; + char *readBuf = new char[len + 1]; + memset(readBuf, 0, len + 1); + char *expectBuf = new char[len + 1]; + memset(expectBuf, 'a', len); + memset(expectBuf + len, 0, 1); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + + offset = offset + len; + memset(expectBuf, 'b', len); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + delete readBuf; + delete buf; + delete expectBuf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* + ------------------ a write1 + ------ b write2 + ------ a read1 + ------ b read2 + ------ a read3 +*/ +TEST_F(ClientS3IntegrationTest, test_read_overlap_block3) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 3 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + offset = 1 * 1024 * 1024; + len = 1 * 1024 * 1024; + memset(buf, 'b', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + offset = 0; + len = 1 * 1024 * 1024; + char *readBuf = new char[len + 1]; + memset(readBuf, 0, len + 1); + char *expectBuf = new char[len + 1]; + memset(expectBuf, 'a', len); + memset(expectBuf + len, 0, 1); + + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + offset = offset + len; + memset(expectBuf, 'b', len); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + offset = offset + len; + memset(expectBuf, 'a', len); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + delete readBuf; + delete buf; + delete expectBuf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* + ------ a write1 + ------------------ b write2 + ------ b read1 + ------ b read2 + ------ b read3 +*/ +TEST_F(ClientS3IntegrationTest, test_read_overlap_block4) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t max_len = 3 * 1024 * 1024; + uint64_t offset = 1 * 1024 * 1024; + uint64_t len = 1 * 1024 * 1024; + char *buf = new char[max_len]; + memset(buf, 'a', len); + + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Invoke(S3Upload)); + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + offset = 0; + len = 3 * 1024 * 1024; + memset(buf, 'b', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(len); + offset = 0; + len = 1 * 1024 * 1024; + char *readBuf = new char[len + 1]; + memset(readBuf, 0, len + 1); + char *expectBuf = new char[len + 1]; + memset(expectBuf, 'b', len); + memset(expectBuf + len, 0, 1); + + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + offset = offset + len; + memset(expectBuf, 'b', len); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + offset = offset + len; + memset(expectBuf, 'b', len); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + delete readBuf; + delete buf; + delete expectBuf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* + ------------ a write1 + ------------ b write2 + ------ b read1 + ------ b read2 + ------ a read3 +*/ +TEST_F(ClientS3IntegrationTest, test_read_overlap_block5) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t max_len = 2 * 1024 * 1024; + uint64_t offset = 1 * 1024 * 1024; + uint64_t len = 2 * 1024 * 1024; + char *buf = new char[max_len]; + memset(buf, 'a', len); + + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Invoke(S3Upload)); + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + offset = 0; + len = 2 * 1024 * 1024; + memset(buf, 'b', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + offset = 0; + len = 1 * 1024 * 1024; + char *readBuf = new char[len + 1]; + char *expectBuf = new char[len + 1]; + memset(readBuf, 0, len + 1); + memset(expectBuf, 0, len + 1); + + memset(expectBuf, 'b', len); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + offset = offset + len; + memset(expectBuf, 'b', len); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + offset = offset + len; + memset(expectBuf, 'a', len); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + // delete readBuf; + delete buf; + delete expectBuf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* + ------ ------ read + ------ writed +*/ +TEST_F(ClientS3IntegrationTest, test_read_hole1) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 1 * 1024 * 1024; + uint64_t len = 1 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Invoke(S3Upload)); + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillOnce( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))) + .WillOnce( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + offset = 0; + len = 1 * 1024 * 1024; + char *readBuf = new char[len + 1]; + memset(readBuf, 'a', len); + memset(readBuf + len, 0, 1); + char *expectBuf = new char[len + 1]; + memset(expectBuf, 0, len + 1); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + offset = 2 * 1024 * 1024; + inode.set_length(offset + len); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + // cleanup + delete buf; + delete readBuf; + delete expectBuf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} +/* + ------------ read + ------------ writed +*/ +TEST_F(ClientS3IntegrationTest, test_read_hole2) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 1 * 1024 * 1024; + uint64_t len = 2 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Invoke(S3Upload)); + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillOnce( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + offset = 0; + len = 2 * 1024 * 1024; + char *readBuf = new char[len + 1]; + memset(readBuf, 0, len + 1); + char *expectBuf = new char[len + 1]; + memset(expectBuf, 0, len + 1); + memset(expectBuf + 1024 * 1024, 'a', 1024 * 1024); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + + EXPECT_STREQ(expectBuf, readBuf); + + // cleanup + delete buf; + delete readBuf; + delete expectBuf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} +/* + ------------ read + ------ writed +*/ +TEST_F(ClientS3IntegrationTest, test_read_hole3) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 1 * 1024 * 1024; + uint64_t len = 1 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Invoke(S3Upload)); + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillOnce( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + offset = 0; + len = 2 * 1024 * 1024; + char *readBuf = new char[len + 1]; + memset(readBuf, 0, len + 1); + char *expectBuf = new char[len + 1]; + memset(expectBuf, 0, len + 1); + memset(expectBuf + 1024 * 1024, 'a', 1024 * 1024); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + // cleanup + delete buf; + delete readBuf; + delete expectBuf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* + ------------------ read + ------ ------ writed +*/ +TEST_F(ClientS3IntegrationTest, test_read_hole4) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 1 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Invoke(S3Upload)); + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillOnce( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + offset = 2 * 1024 * 1024; + memset(buf, 'b', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + offset = 0; + len = 3 * 1024 * 1024; + char *readBuf = new char[len + 1]; + memset(readBuf, 0, len + 1); + char *expectBuf = new char[len + 1]; + memset(expectBuf, 0, len + 1); + memset(expectBuf, 'a', 1024 * 1024); + memset(expectBuf + 2 * 1024 * 1024, 'b', 1024 * 1024); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + + EXPECT_STREQ(expectBuf, readBuf); + + // cleanup + delete buf; + delete readBuf; + delete expectBuf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* + ------ a write1 + ------ b write2 + ------------------ read1 +*/ +TEST_F(ClientS3IntegrationTest, test_read_more_write) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 100; + char *buf = new char[len]; + memset(buf, 'a', len); + + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Invoke(S3Upload)); + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillOnce( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + offset = 120; + memset(buf, 'b', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + offset = 0; + len = 1024; + inode.set_length(1024); + char *readBuf = new char[len + 1]; + memset(readBuf, 0, len + 1); + char *expectBuf = new char[len + 1]; + memset(expectBuf, 0, len + 1); + memset(expectBuf, 'a', 100); + memset(expectBuf + 120, 'b', 100); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + + EXPECT_STREQ(expectBuf, readBuf); + + // cleanup + delete buf; + delete readBuf; + delete expectBuf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* + ------ a write1 + ------ b write2 + ------ c write3 + ------ b read1 +*/ +TEST_F(ClientS3IntegrationTest, test_read_more_write2) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 34339840; + uint64_t len = 512; + char *buf = new char[len]; + memset(buf, 'a', len); + + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Invoke(S3Upload)); + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + offset = 34340864; + memset(buf, 'b', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + offset = 34340352; + memset(buf, 'c', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + offset = 34340864; + char *readBuf = new char[len + 1]; + memset(readBuf, 0, len + 1); + char *expectBuf = new char[len + 1]; + memset(expectBuf, 0, len + 1); + memset(expectBuf, 'b', len); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + + EXPECT_STREQ(expectBuf, readBuf); + + // cleanup + delete buf; + delete readBuf; + delete expectBuf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +TEST_F(ClientS3IntegrationTest, test_read_more_chunks) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 4 * 1024 * 1024 - 1024; + uint64_t len = 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Invoke(S3Upload)); + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + offset = 4 * 1024 * 1024; + memset(buf, 'b', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + offset = 4 * 1024 * 1024 - 1024; + len = 2048; + inode.set_length(4 * 1024 * 1024 + 1024); + char *readBuf = new char[len + 1]; + memset(readBuf, 0, len + 1); + char *expectBuf = new char[len + 1]; + memset(expectBuf, 0, len + 1); + memset(expectBuf, 'a', 1024); + memset(expectBuf + 1024, 'b', 1024); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + + EXPECT_STREQ(expectBuf, readBuf); + + // cleanup + delete buf; + delete readBuf; + delete expectBuf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* + ----------------- write1 + ------ truncate + +*/ +TEST_F(ClientS3IntegrationTest, test_truncate_small1) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 5 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + ASSERT_EQ(len, s3ClientAdaptor_->GetFsCacheManager()->GetDataCacheSize()); + len = 1 * 1024 * 1024; + CURVEFS_ERROR ret = s3ClientAdaptor_->Truncate(&inode, len); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(len, s3ClientAdaptor_->GetFsCacheManager()->GetDataCacheSize()); + + // cleanup + delete buf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* + --- --- --- --- --- --- write + ------------------- truncate1 + ------- truncate2 + +*/ +TEST_F(ClientS3IntegrationTest, test_truncate_small2) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 512 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + inode.set_length(8 * 1024 * 1024); + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + for (int i = 0; i < 6; i++) { + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + offset = offset + len * 2; + } + ASSERT_EQ(6, fsCacheManager->GetDataCacheNum()); + + uint64_t truncateLen = 3 * 1024 * 1024; + CURVEFS_ERROR ret = s3ClientAdaptor_->Truncate(&inode, truncateLen); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(3 * len, + s3ClientAdaptor_->GetFsCacheManager()->GetDataCacheSize()); + + truncateLen = 1200 * 1024; + ret = s3ClientAdaptor_->Truncate(&inode, truncateLen); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(704 * 1024, + s3ClientAdaptor_->GetFsCacheManager()->GetDataCacheSize()); + + // cleanup + delete buf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* + --- --- --- --- --- --- write + ------------------- truncate1 + ------- truncate2 + +*/ +TEST_F(ClientS3IntegrationTest, test_truncate_small3) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 512 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + inode.set_length(8 * 1024 * 1024); + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + uint64_t chunkId = 25; + EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) + .WillRepeatedly( + DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))); + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Invoke(S3Upload)); + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillRepeatedly( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + EXPECT_CALL(mockS3Client_, UploadAsync(_)) + .WillRepeatedly( + Invoke([&](const std::shared_ptr &context) { + S3Data &tmp = gObjectDataMaps[context->key]; + tmp.len = context->bufferSize; + tmp.buf = new char[context->bufferSize]; + strncpy(tmp.buf, context->buffer, context->bufferSize); + context->retCode = 0; + context->cb(context); + })); + + + for (int i = 0; i < 6; i++) { + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + offset = offset + len * 2; + } + ASSERT_EQ(6, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(6 * len, fsCacheManager->GetDataCacheSize()); + ASSERT_EQ(0, fsCacheManager->GetLruByte()); + + CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); + inode = inodeWrapper->GetInodeUnlocked(); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(0, fsCacheManager->GetDataCacheSize()); + ASSERT_EQ(6 * len, fsCacheManager->GetLruByte()); + + uint64_t truncateLen = 3 * 1024 * 1024; + ret = s3ClientAdaptor_->Truncate(&inode, truncateLen); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(3 * len, s3ClientAdaptor_->GetFsCacheManager()->GetLruByte()); + + truncateLen = 1200 * 1024; + ret = s3ClientAdaptor_->Truncate(&inode, truncateLen); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(len, s3ClientAdaptor_->GetFsCacheManager()->GetLruByte()); + + // cleanup + delete buf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} +/* + file size 0 + ------------------- truncate + +*/ +TEST_F(ClientS3IntegrationTest, test_truncate_big1) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 1 * 1024 * 1024; + CURVEFS_ERROR ret; + uint64_t chunkIndex = offset / s3ClientAdaptor_->GetChunkSize(); + ::curvefs::space::AllocateS3ChunkResponse response; + response.set_status(::curvefs::space::SpaceStatusCode::SPACE_OK); + response.set_chunkid(25); + // mock + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillOnce( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + ret = s3ClientAdaptor_->Truncate(&inode, len); + inode.set_length(len); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + auto s3InfoListIter = inode.s3chunkinfomap().find(chunkIndex); + S3ChunkInfo tmp; + ASSERT_NE(s3InfoListIter, inode.s3chunkinfomap().end()); + ASSERT_EQ(1, s3InfoListIter->second.s3chunks_size()); + tmp = s3InfoListIter->second.s3chunks(0); + ASSERT_EQ(len, tmp.len()); + ASSERT_EQ(offset, tmp.offset()); + ASSERT_EQ(true, tmp.zero()); + + char *readBuf = new char[len + 1]; + memset(readBuf, 0, len + 1); + char *expectBuf = new char[len + 1]; + memset(expectBuf, 0, len + 1); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + // cleanup + delete readBuf; + delete expectBuf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* + --- write + ------------------- truncate + +*/ +TEST_F(ClientS3IntegrationTest, test_truncate_big2) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 1 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + uint64_t chunkIndex = offset / s3ClientAdaptor_->GetChunkSize(); + + ::curvefs::space::AllocateS3ChunkResponse response; + response.set_status(::curvefs::space::SpaceStatusCode::SPACE_OK); + response.set_chunkid(25); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillOnce( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + len = 5 * 1024 * 1024; + s3ClientAdaptor_->Truncate(&inode, len); + inode.set_length(len); + auto s3InfoListIter = inode.s3chunkinfomap().find(chunkIndex); + ASSERT_NE(s3InfoListIter, inode.s3chunkinfomap().end()); + ASSERT_EQ(1, s3InfoListIter->second.s3chunks_size()); + + char *readBuf = new char[len + 1]; + memset(readBuf, 0, len + 1); + char *expectBuf = new char[len + 1]; + memset(expectBuf, 0, len + 1); + memset(expectBuf, 'a', 1 * 1024 * 1024); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + + EXPECT_STREQ(expectBuf, readBuf); + + // cleanup + delete buf; + delete readBuf; + delete expectBuf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* + ------- truncate1 + ------------- truncate2 + ------------ read1 + --- read2 + ------------ read3 + +*/ +TEST_F(ClientS3IntegrationTest, test_truncate_big3) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 1 * 1024 * 1024; + CURVEFS_ERROR ret; + uint64_t chunkIndex = offset / s3ClientAdaptor_->GetChunkSize(); + ::curvefs::space::AllocateS3ChunkResponse response; + response.set_status(::curvefs::space::SpaceStatusCode::SPACE_OK); + response.set_chunkid(25); + // mock + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillRepeatedly( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + + ret = s3ClientAdaptor_->Truncate(&inode, len); + inode.set_length(len); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + auto s3InfoListIter = inode.s3chunkinfomap().find(chunkIndex); + S3ChunkInfo tmp; + ASSERT_NE(s3InfoListIter, inode.s3chunkinfomap().end()); + ASSERT_EQ(1, s3InfoListIter->second.s3chunks_size()); + tmp = s3InfoListIter->second.s3chunks(0); + ASSERT_EQ(len, tmp.len()); + ASSERT_EQ(offset, tmp.offset()); + ASSERT_EQ(true, tmp.zero()); + + len = 2 * 1024 * 1024; + ret = s3ClientAdaptor_->Truncate(&inode, len); + inode.set_length(len); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + s3InfoListIter = inode.s3chunkinfomap().find(chunkIndex); + ASSERT_NE(s3InfoListIter, inode.s3chunkinfomap().end()); + ASSERT_EQ(2, s3InfoListIter->second.s3chunks_size()); + tmp = s3InfoListIter->second.s3chunks(1); + ASSERT_EQ(1 * 1024 * 1024, tmp.len()); + ASSERT_EQ(1 * 1024 * 1024, tmp.offset()); + ASSERT_EQ(true, tmp.zero()); + + char *readBuf = new char[len + 1]; + memset(readBuf, 0, len + 1); + char *expectBuf = new char[len + 1]; + memset(expectBuf, 0, len + 1); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + offset = 512; + len = 512; + char *readBuf1 = new char[len + 1]; + memset(readBuf1, 0, len + 1); + char *expectBuf1 = new char[len + 1]; + memset(expectBuf1, 0, len + 1); + + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf1); + EXPECT_STREQ(expectBuf1, readBuf1); + + len = 1 * 1024 * 1024; + inode.set_length(3 * 1024 * 1024); + offset = 1.5 * 1024 * 1024; + char *readBuf2 = new char[len + 1]; + memset(readBuf2, 0, len + 1); + char *expectBuf2 = new char[len + 1]; + memset(expectBuf2, 0, len + 1); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf2); + EXPECT_STREQ(expectBuf2, readBuf2); + + // cleanup + delete readBuf; + delete expectBuf; + delete readBuf1; + delete expectBuf1; + delete readBuf2; + delete expectBuf2; + + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +TEST_F(ClientS3IntegrationTest, test_releaseCache) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 1 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + + s3ClientAdaptor_->ReleaseCache(inode.inodeid()); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + + offset = 2 * 1024 * 1024; + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + ASSERT_EQ(2, fsCacheManager->GetDataCacheNum()); + + s3ClientAdaptor_->ReleaseCache(inode.inodeid()); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + + // cleanup + delete buf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +TEST_F(ClientS3IntegrationTest, test_flush_first_write) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 2 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + uint64_t chunkIndex = offset / s3ClientAdaptor_->GetChunkSize(); + // mock + uint64_t chunkId = 25; + + EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) + .WillRepeatedly( + DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))); + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Return(1 * 1024 * 1024)); + + EXPECT_CALL(mockS3Client_, UploadAsync(_)) + .WillRepeatedly( + Invoke([&](const std::shared_ptr &context) { + context->retCode = 0; + context->cb(context); + })); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillRepeatedly( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); + + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + ret = s3ClientAdaptor_->Flush(inode.inodeid()); + inode = inodeWrapper->GetInodeUnlocked(); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + auto s3InfoListIter = inode.s3chunkinfomap().find(chunkIndex); + S3ChunkInfo tmp; + ASSERT_NE(s3InfoListIter, inode.s3chunkinfomap().end()); + ASSERT_EQ(1, s3InfoListIter->second.s3chunks_size()); + tmp = s3InfoListIter->second.s3chunks(0); + ASSERT_EQ(len, tmp.len()); + ASSERT_EQ(offset, tmp.offset()); + + // cleanup + delete buf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* + ------- write1 + ------- write2 + flush +*/ +TEST_F(ClientS3IntegrationTest, test_flush_overlap_write) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 2 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + uint64_t chunkIndex = offset / s3ClientAdaptor_->GetChunkSize(); + // mock + uint64_t chunkId = 25; + + EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) + .WillRepeatedly( + DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))); + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Return(1 * 1024 * 1024)); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillRepeatedly( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + EXPECT_CALL(mockS3Client_, UploadAsync(_)) + .WillRepeatedly( + Invoke([&](const std::shared_ptr &context) { + context->retCode = 0; + context->cb(context); + })); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + offset = 1 * 1024 * 1024; + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + + CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); + inode = inodeWrapper->GetInodeUnlocked(); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + auto s3InfoListIter = inode.s3chunkinfomap().find(chunkIndex); + S3ChunkInfo tmp; + ASSERT_NE(s3InfoListIter, inode.s3chunkinfomap().end()); + ASSERT_EQ(1, s3InfoListIter->second.s3chunks_size()); + tmp = s3InfoListIter->second.s3chunks(0); + ASSERT_EQ(3 * 1024 * 1024, tmp.len()); + ASSERT_EQ(0, tmp.offset()); + + // cleanup + delete buf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* This is a use case for an inconsistency problem */ +TEST_F(ClientS3IntegrationTest, test_flush_overlap_write2) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 16748032; + uint64_t len = 512; + char *buf = new char[len]; + memset(buf, 'a', len); + uint64_t chunkIndex = offset / s3ClientAdaptor_->GetChunkSize(); + // mock + uint64_t chunkId = 25; + + EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) + .WillRepeatedly( + DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillRepeatedly( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + EXPECT_CALL(mockS3Client_, UploadAsync(_)) + .WillRepeatedly( + Invoke([&](const std::shared_ptr &context) { + context->retCode = 0; + context->cb(context); + })); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + offset = 16749056; + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(2, fsCacheManager->GetDataCacheNum()); + + offset = 16748544; + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + + CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); + inode = inodeWrapper->GetInodeUnlocked(); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + auto s3InfoListIter = inode.s3chunkinfomap().find(chunkIndex); + S3ChunkInfo tmp; + ASSERT_NE(s3InfoListIter, inode.s3chunkinfomap().end()); + ASSERT_EQ(1, s3InfoListIter->second.s3chunks_size()); + tmp = s3InfoListIter->second.s3chunks(0); + ASSERT_EQ(1536, tmp.len()); + ASSERT_EQ(16748032, tmp.offset()); + + // cleanup + delete buf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +TEST_F(ClientS3IntegrationTest, test_flush_hole_write) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 1 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + uint64_t chunkIndex = offset / s3ClientAdaptor_->GetChunkSize(); + // mock + uint64_t chunkId = 25; + + EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) + .WillRepeatedly( + DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))); + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Return(1 * 1024 * 1024)); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillRepeatedly( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + EXPECT_CALL(mockS3Client_, UploadAsync(_)) + .WillRepeatedly( + Invoke([&](const std::shared_ptr &context) { + context->retCode = 0; + context->cb(context); + })); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + offset = 2 * 1024 * 1024; + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(2, fsCacheManager->GetDataCacheNum()); + + CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); + inode = inodeWrapper->GetInodeUnlocked(); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + auto s3InfoListIter = inode.s3chunkinfomap().find(chunkIndex); + S3ChunkInfo tmp; + S3ChunkInfoList tmpList; + ASSERT_NE(s3InfoListIter, inode.s3chunkinfomap().end()); + tmpList = s3InfoListIter->second; + ASSERT_EQ(2, tmpList.s3chunks_size()); + tmp = tmpList.s3chunks(0); + ASSERT_EQ(1 * 1024 * 1024, tmp.len()); + ASSERT_EQ(0, tmp.offset()); + tmp = tmpList.s3chunks(1); + ASSERT_EQ(1 * 1024 * 1024, tmp.len()); + ASSERT_EQ(2 * 1024 * 1024, tmp.offset()); + + // cleanup + delete buf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +TEST_F(ClientS3IntegrationTest, test_flush_write_more_chunk) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 5 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + // mock + uint64_t chunkId = 25; + + EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) + .WillRepeatedly( + DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))); + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Return(1 * 1024 * 1024)); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillRepeatedly( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + EXPECT_CALL(mockS3Client_, UploadAsync(_)) + .WillRepeatedly( + Invoke([&](const std::shared_ptr &context) { + context->retCode = 0; + context->cb(context); + })); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(2, fsCacheManager->GetDataCacheNum()); + + CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); + inode = inodeWrapper->GetInodeUnlocked(); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(2, inode.s3chunkinfomap_size()); + auto s3InfoListIter = inode.s3chunkinfomap().find(0); + S3ChunkInfo tmp; + S3ChunkInfoList tmpList; + ASSERT_NE(s3InfoListIter, inode.s3chunkinfomap().end()); + VLOG(9) << "index: " << s3InfoListIter->first; + tmpList = s3InfoListIter->second; + ASSERT_EQ(1, tmpList.s3chunks_size()); + tmp = tmpList.s3chunks(0); + ASSERT_EQ(4 * 1024 * 1024, tmp.len()); + ASSERT_EQ(0, tmp.offset()); + s3InfoListIter = inode.s3chunkinfomap().find(1); + tmpList = s3InfoListIter->second; + tmp = tmpList.s3chunks(0); + ASSERT_EQ(1 * 1024 * 1024, tmp.len()); + ASSERT_EQ(4 * 1024 * 1024, tmp.offset()); + + // cleanup + delete buf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* + ------ write1 + --- write2 + flush + --- read1 +*/ +TEST_F(ClientS3IntegrationTest, test_flush_write_and_read1) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 2 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + // mock + uint64_t chunkId = 25; + + EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) + .WillRepeatedly( + DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))); + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Invoke(S3Upload)); + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillRepeatedly( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + EXPECT_CALL(mockS3Client_, UploadAsync(_)) + .WillRepeatedly( + Invoke([&](const std::shared_ptr &context) { + S3Data &tmp = gObjectDataMaps[context->key]; + tmp.len = context->bufferSize; + tmp.buf = new char[context->bufferSize]; + strncpy(tmp.buf, context->buffer, context->bufferSize); + context->retCode = 0; + context->cb(context); + })); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + len = 1 * 1024 * 1024; + memset(buf, 'b', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + + CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); + uint64_t len1 = inode.length(); + inode = inodeWrapper->GetInodeUnlocked(); + inode.set_length(len1); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(1, inode.s3chunkinfomap_size()); + auto s3InfoListIter = inode.s3chunkinfomap().begin(); + S3ChunkInfo tmp; + S3ChunkInfoList tmpList; + ASSERT_NE(s3InfoListIter, inode.s3chunkinfomap().end()); + tmpList = s3InfoListIter->second; + ASSERT_EQ(1, tmpList.s3chunks_size()); + tmp = tmpList.s3chunks(0); + ASSERT_EQ(2 * 1024 * 1024, tmp.len()); + ASSERT_EQ(0, tmp.offset()); + + char *readBuf = new char[len + 1]; + char *expectBuf = new char[len + 1]; + memset(readBuf, 0, len + 1); + memset(expectBuf, 'b', len); + memset(expectBuf + len, 0, 1); + + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + // cleanup + delete buf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* + ------ write + flush + --- read cache + --- read +*/ +TEST_F(ClientS3IntegrationTest, test_flush_write_and_read2) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 2 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + // mock + uint64_t chunkId = 25; + + EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) + .WillRepeatedly( + DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))); + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Invoke(S3Upload)); + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillRepeatedly( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + EXPECT_CALL(mockS3Client_, UploadAsync(_)) + .WillRepeatedly( + Invoke([&](const std::shared_ptr &context) { + S3Data &tmp = gObjectDataMaps[context->key]; + tmp.len = context->bufferSize; + tmp.buf = new char[context->bufferSize]; + strncpy(tmp.buf, context->buffer, context->bufferSize); + context->retCode = 0; + context->cb(context); + })); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + + CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); + uint64_t len1 = inode.length(); + inode = inodeWrapper->GetInodeUnlocked(); + inode.set_length(len1); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(1, inode.s3chunkinfomap_size()); + auto s3InfoListIter = inode.s3chunkinfomap().begin(); + S3ChunkInfo tmp; + S3ChunkInfoList tmpList; + ASSERT_NE(s3InfoListIter, inode.s3chunkinfomap().end()); + tmpList = s3InfoListIter->second; + ASSERT_EQ(1, tmpList.s3chunks_size()); + tmp = tmpList.s3chunks(0); + ASSERT_EQ(2 * 1024 * 1024, tmp.len()); + ASSERT_EQ(0, tmp.offset()); + + offset = 512; + len = 1 * 1024 * 1024; + char *readBuf = new char[len + 1]; + char *expectBuf = new char[len + 1]; + memset(readBuf, 0, len + 1); + memset(expectBuf, 'a', len); + memset(expectBuf + len, 0, 1); + + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + s3ClientAdaptor_->ReleaseCache(inode.inodeid()); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + // cleanup + delete buf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* + --- a write + flush + --- 0 read1 + --- 0 read2 + --------- read3 +*/ +TEST_F(ClientS3IntegrationTest, test_flush_write_and_read3) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 1 * 1024 * 1024; + uint64_t len = 1 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + + uint64_t chunkId = 25; + + EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) + .WillRepeatedly( + DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))); + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Invoke(S3Upload)); + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillRepeatedly( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + EXPECT_CALL(mockS3Client_, UploadAsync(_)) + .WillRepeatedly( + Invoke([&](const std::shared_ptr &context) { + S3Data &tmp = gObjectDataMaps[context->key]; + tmp.len = context->bufferSize; + tmp.buf = new char[context->bufferSize]; + strncpy(tmp.buf, context->buffer, context->bufferSize); + context->retCode = 0; + context->cb(context); + })); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); + uint64_t len1 = inode.length(); + inode = inodeWrapper->GetInodeUnlocked(); + inode.set_length(len1); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(1, inode.s3chunkinfomap_size()); + + offset = 0; + len = 1 * 1024 * 1024; + char *readBuf = new char[len + 1]; + memset(readBuf, 'a', len); + memset(readBuf + len, 0, 1); + char *expectBuf = new char[len + 1]; + memset(expectBuf, 0, len + 1); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + offset = 2 * 1024 * 1024; + inode.set_length(offset + len); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + s3ClientAdaptor_->ReleaseCache(inode.inodeid()); + + offset = 0; + len = 3 * 1024 * 1024; + char *readBuf1 = new char[len + 1]; + char *expectBuf1 = new char[len + 1]; + memset(readBuf1, 'b', len); + memset(readBuf1 + len, 0, 1); + memset(expectBuf1, 0, len + 1); + memset(expectBuf1 + 1024 * 1024, 'a', 1024 * 1024); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf1); + EXPECT_STREQ(expectBuf1, readBuf1); + + s3ClientAdaptor_->ReleaseCache(inode.inodeid()); + offset = 1.5 * 1024 * 1024; + len = 1 * 1024 * 1024; + char *readBuf2 = new char[len + 1]; + char *expectBuf2 = new char[len + 1]; + memset(readBuf2, 'b', len); + memset(readBuf2 + len, 0, 1); + memset(expectBuf2, 0, len + 1); + memset(expectBuf2, 'a', 0.5 * 1024 * 1024); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf2); + EXPECT_STREQ(expectBuf2, readBuf2); + + // cleanup + delete buf; + delete readBuf; + delete expectBuf; + delete readBuf1; + delete expectBuf1; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* + ------ a write1 + ------ b write2 + flush + releaseReadCache + --- b read + +*/ +TEST_F(ClientS3IntegrationTest, test_flush_write_and_read4) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0 * 1024 * 1024; + uint64_t len = 2 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + + uint64_t chunkId = 25; + uint64_t chunkId1 = 26; + EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))) + .WillOnce(DoAll(SetArgPointee<1>(chunkId1), Return(FSStatusCode::OK))); + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Invoke(S3Upload)); + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillRepeatedly( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + EXPECT_CALL(mockS3Client_, UploadAsync(_)) + .WillRepeatedly( + Invoke([&](const std::shared_ptr &context) { + S3Data &tmp = gObjectDataMaps[context->key]; + tmp.len = context->bufferSize; + tmp.buf = new char[context->bufferSize]; + strncpy(tmp.buf, context->buffer, context->bufferSize); + context->retCode = 0; + context->cb(context); + })); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); + uint64_t len1 = inode.length(); + inode = inodeWrapper->GetInodeUnlocked(); + inode.set_length(len1); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(1, inode.s3chunkinfomap_size()); + + offset = 1 * 1024 * 1024; + memset(buf, 'b', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + fsCacheManager = s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + ret = s3ClientAdaptor_->Flush(inode.inodeid()); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(1, inode.s3chunkinfomap_size()); + + s3ClientAdaptor_->ReleaseCache(inode.inodeid()); + len = 1 * 1024 * 1024; + char *readBuf = new char[len + 1]; + memset(readBuf, 'c', len); + memset(readBuf + len, 0, 1); + char *expectBuf = new char[len + 1]; + memset(expectBuf, 'b', len); + memset(expectBuf + len, 0, 1); + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + // cleanup + delete buf; + delete readBuf; + delete expectBuf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* This is a use case for an inconsistency problem */ +TEST_F(ClientS3IntegrationTest, test_flush_write_and_read5) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 1 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', 512 * 1024); + memset(buf + 512 * 1024, 'b', 512 * 1024); + + uint64_t chunkId = 25; + uint64_t chunkId1 = 26; + EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))) + .WillOnce(DoAll(SetArgPointee<1>(chunkId1), Return(FSStatusCode::OK))); + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Invoke(S3Upload)); + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillRepeatedly( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + EXPECT_CALL(mockS3Client_, UploadAsync(_)) + .WillRepeatedly( + Invoke([&](const std::shared_ptr &context) { + S3Data &tmp = gObjectDataMaps[context->key]; + tmp.len = context->bufferSize; + tmp.buf = new char[context->bufferSize]; + strncpy(tmp.buf, context->buffer, context->bufferSize); + context->retCode = 0; + context->cb(context); + })); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); + uint64_t len1 = inode.length(); + inode = inodeWrapper->GetInodeUnlocked(); + inode.set_length(len1); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(1, inode.s3chunkinfomap_size()); + + offset = 0; + len = 512 * 1024; + memset(buf, 'c', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(1024 * 1024); + + fsCacheManager = s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + ret = s3ClientAdaptor_->Flush(inode.inodeid()); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(1, inode.s3chunkinfomap_size()); + + s3ClientAdaptor_->ReleaseCache(inode.inodeid()); + inode = inodeWrapper->GetInodeUnlocked(); + inode.set_length(1024 * 1024); + auto s3ChunkInfoMap = inode.mutable_s3chunkinfomap(); + auto s3chunkInfoListIter = s3ChunkInfoMap->find(0); + ASSERT_EQ(2, s3chunkInfoListIter->second.s3chunks_size()); + + offset = 512 * 1024; + len = 1; + char *readBuf = new char[len + 1]; + memset(readBuf, 'c', len); + memset(readBuf + len, 0, 1); + char *expectBuf = new char[len + 1]; + memset(expectBuf, 'b', len); + memset(expectBuf + len, 0, 1); + + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + // cleanup + delete buf; + delete readBuf; + delete expectBuf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* + ------ write1 + flush + --- write2 + flush + ------ read1 +*/ +TEST_F(ClientS3IntegrationTest, test_flush_write_and_read6) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 1024; + uint64_t len = 1 * 1024 * 1024 - 2048; + char *buf = new char[len]; + memset(buf, 'a', len); + + uint64_t chunkId = 25; + uint64_t chunkId1 = 26; + EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))) + .WillOnce(DoAll(SetArgPointee<1>(chunkId1), Return(FSStatusCode::OK))); + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Invoke(S3Upload)); + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillRepeatedly( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + EXPECT_CALL(mockS3Client_, UploadAsync(_)) + .WillRepeatedly( + Invoke([&](const std::shared_ptr &context) { + S3Data &tmp = gObjectDataMaps[context->key]; + tmp.len = context->bufferSize; + tmp.buf = new char[context->bufferSize]; + strncpy(tmp.buf, context->buffer, context->bufferSize); + context->retCode = 0; + context->cb(context); + })); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); + inode = inodeWrapper->GetInodeUnlocked(); + inode.set_length(offset + len); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(1, inode.s3chunkinfomap_size()); + + offset = 2048; + len = 512 * 1024; + memset(buf, 'b', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + fsCacheManager = s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + ret = s3ClientAdaptor_->Flush(inode.inodeid()); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(1, inode.s3chunkinfomap_size()); + + s3ClientAdaptor_->ReleaseCache(inode.inodeid()); + inode = inodeWrapper->GetInodeUnlocked(); + inode.set_length(1024 * 1024); + auto s3ChunkInfoMap = inode.mutable_s3chunkinfomap(); + auto s3chunkInfoListIter = s3ChunkInfoMap->find(0); + ASSERT_EQ(2, s3chunkInfoListIter->second.s3chunks_size()); + + offset = 1024; + len = 1024 * 1024 - 2048; + char *readBuf = new char[len + 1]; + memset(readBuf, 'c', len); + memset(readBuf + len, 0, 1); + char *expectBuf = new char[len + 1]; + memset(expectBuf, 'a', len); + memset(expectBuf + 1024, 'b', 512 * 1024); + memset(expectBuf + len, 0, 1); + + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + // cleanup + delete buf; + delete readBuf; + delete expectBuf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* + ------ a write1 + - b write2 + - c write3 + ------ read +*/ +TEST_F(ClientS3IntegrationTest, test_flush_write_and_read7) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 1 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + + uint64_t chunkId = 25; + uint64_t chunkId1 = 26; + uint64_t chunkId2 = 27; + EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))) + .WillOnce(DoAll(SetArgPointee<1>(chunkId1), Return(FSStatusCode::OK))) + .WillOnce(DoAll(SetArgPointee<1>(chunkId2), Return(FSStatusCode::OK))); + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Invoke(S3Upload)); + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillRepeatedly( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + EXPECT_CALL(mockS3Client_, UploadAsync(_)) + .WillRepeatedly( + Invoke([&](const std::shared_ptr &context) { + S3Data &tmp = gObjectDataMaps[context->key]; + tmp.len = context->bufferSize; + tmp.buf = new char[context->bufferSize]; + strncpy(tmp.buf, context->buffer, context->bufferSize); + context->retCode = 0; + context->cb(context); + })); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); + inode = inodeWrapper->GetInodeUnlocked(); + inode.set_length(offset + len); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(1, inode.s3chunkinfomap_size()); + + offset = 1024; + len = 512; + memset(buf, 'b', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + fsCacheManager = s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + ret = s3ClientAdaptor_->Flush(inode.inodeid()); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(1, inode.s3chunkinfomap_size()); + + offset = 2048; + len = 512; + memset(buf, 'c', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + ret = s3ClientAdaptor_->Flush(inode.inodeid()); + + s3ClientAdaptor_->ReleaseCache(inode.inodeid()); + inode = inodeWrapper->GetInodeUnlocked(); + inode.set_length(1024 * 1024); + auto s3ChunkInfoMap = inode.mutable_s3chunkinfomap(); + auto s3chunkInfoListIter = s3ChunkInfoMap->find(0); + ASSERT_EQ(3, s3chunkInfoListIter->second.s3chunks_size()); + + offset = 0; + len = 1024 * 1024; + char *readBuf = new char[len + 1]; + memset(readBuf, 'd', len); + memset(readBuf + len, 0, 1); + char *expectBuf = new char[len + 1]; + memset(expectBuf, 'a', len); + memset(expectBuf + 1024, 'b', 512); + memset(expectBuf + 2048, 'c', 512); + memset(expectBuf + len, 0, 1); + + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + // cleanup + delete buf; + delete readBuf; + delete expectBuf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* This is a use case for an inconsistency problem */ +TEST_F(ClientS3IntegrationTest, test_flush_write_and_read8) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 20971520; + uint64_t len = 4194304; + char *buf = new char[len]; + memset(buf, 'a', len); + + uint64_t chunkId = 25; + uint64_t chunkId1 = 26; + uint64_t chunkId2 = 27; + inode.set_length(offset + len); + EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))) + .WillOnce(DoAll(SetArgPointee<1>(chunkId1), Return(FSStatusCode::OK))) + .WillOnce(DoAll(SetArgPointee<1>(chunkId2), Return(FSStatusCode::OK))); + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Invoke(S3Upload)); + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillRepeatedly( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + EXPECT_CALL(mockS3Client_, UploadAsync(_)) + .WillRepeatedly( + Invoke([&](const std::shared_ptr &context) { + S3Data &tmp = gObjectDataMaps[context->key]; + tmp.len = context->bufferSize; + tmp.buf = new char[context->bufferSize]; + strncpy(tmp.buf, context->buffer, context->bufferSize); + context->retCode = 0; + context->cb(context); + })); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); + inode = inodeWrapper->GetInodeUnlocked(); + + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(1, inode.s3chunkinfomap_size()); + + len = 524288; + memset(buf, 'b', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + fsCacheManager = s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + ret = s3ClientAdaptor_->Flush(inode.inodeid()); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(1, inode.s3chunkinfomap_size()); + + len = 1048576; + memset(buf, 'c', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + ret = s3ClientAdaptor_->Flush(inode.inodeid()); + + s3ClientAdaptor_->ReleaseCache(inode.inodeid()); + inode = inodeWrapper->GetInodeUnlocked(); + + auto s3ChunkInfoMap = inode.mutable_s3chunkinfomap(); + auto s3chunkInfoListIter = s3ChunkInfoMap->find(5); + ASSERT_EQ(3, s3chunkInfoListIter->second.s3chunks_size()); + + offset = 20971520; + len = 4194304; + char *readBuf = new char[len + 1]; + memset(readBuf, 'd', len); + memset(readBuf + len, 0, 1); + char *expectBuf = new char[len + 1]; + memset(expectBuf, 'a', len); + memset(expectBuf, 'c', 1048576); + memset(expectBuf + len, 0, 1); + + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + // cleanup + delete buf; + delete readBuf; + delete expectBuf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* This is a use case for an inconsistency problem */ +TEST_F(ClientS3IntegrationTest, test_flush_write_and_read9) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 92274688; + uint64_t len = 4194304; + char *buf = new char[len]; + memset(buf, 'a', len); + memset(buf + (93210624 - 92274688), 'b', 1024); + + uint64_t chunkId = 25; + uint64_t chunkId1 = 26; + uint64_t chunkId2 = 27; + inode.set_length(offset + len); + EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))) + .WillOnce(DoAll(SetArgPointee<1>(chunkId1), Return(FSStatusCode::OK))) + .WillOnce(DoAll(SetArgPointee<1>(chunkId2), Return(FSStatusCode::OK))); + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Invoke(S3Upload)); + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillRepeatedly( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + EXPECT_CALL(mockS3Client_, UploadAsync(_)) + .WillRepeatedly( + Invoke([&](const std::shared_ptr &context) { + S3Data &tmp = gObjectDataMaps[context->key]; + tmp.len = context->bufferSize; + tmp.buf = new char[context->bufferSize]; + strncpy(tmp.buf, context->buffer, context->bufferSize); + context->retCode = 0; + context->cb(context); + })); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); + inode = inodeWrapper->GetInodeUnlocked(); + + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(1, inode.s3chunkinfomap_size()); + + offset = 92405760; + len = 1024; + memset(buf, 'c', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + fsCacheManager = s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + ret = s3ClientAdaptor_->Flush(inode.inodeid()); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(1, inode.s3chunkinfomap_size()); + + offset = 93547520; + len = 1024; + memset(buf, 'd', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + ret = s3ClientAdaptor_->Flush(inode.inodeid()); + + s3ClientAdaptor_->ReleaseCache(inode.inodeid()); + inode = inodeWrapper->GetInodeUnlocked(); + + auto s3ChunkInfoMap = inode.mutable_s3chunkinfomap(); + auto s3chunkInfoListIter = s3ChunkInfoMap->find(22); + ASSERT_EQ(3, s3chunkInfoListIter->second.s3chunks_size()); + + offset = 93210624; + len = 1024; + char *readBuf = new char[len + 1]; + memset(readBuf, 'e', len); + memset(readBuf + len, 0, 1); + char *expectBuf = new char[len + 1]; + memset(expectBuf, 'b', len); + memset(expectBuf + len, 0, 1); + + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + // cleanup + delete buf; + delete readBuf; + delete expectBuf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* This is a use case for an inconsistency problem */ +TEST_F(ClientS3IntegrationTest, test_flush_write_and_read10) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 8388608; + uint64_t len = 4194304; + char *buf = new char[len]; + memset(buf, 'a', len); + + uint64_t chunkId = 1; + uint64_t chunkId1 = 2; + uint64_t chunkId2 = 3; + uint64_t chunkId3 = 4; + uint64_t chunkId4 = 5; + uint64_t chunkId5 = 6; + uint64_t chunkId6 = 7; + inode.set_length(offset + len); + EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))) + .WillOnce(DoAll(SetArgPointee<1>(chunkId1), Return(FSStatusCode::OK))) + .WillOnce(DoAll(SetArgPointee<1>(chunkId2), Return(FSStatusCode::OK))) + .WillOnce(DoAll(SetArgPointee<1>(chunkId3), Return(FSStatusCode::OK))) + .WillOnce(DoAll(SetArgPointee<1>(chunkId4), Return(FSStatusCode::OK))) + .WillOnce(DoAll(SetArgPointee<1>(chunkId5), Return(FSStatusCode::OK))) + .WillOnce(DoAll(SetArgPointee<1>(chunkId6), Return(FSStatusCode::OK))); + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Invoke(S3Upload)); + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillRepeatedly( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + EXPECT_CALL(mockS3Client_, UploadAsync(_)) + .WillRepeatedly( + Invoke([&](const std::shared_ptr &context) { + S3Data &tmp = gObjectDataMaps[context->key]; + tmp.len = context->bufferSize; + tmp.buf = new char[context->bufferSize]; + strncpy(tmp.buf, context->buffer, context->bufferSize); + context->retCode = 0; + context->cb(context); + })); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); + inode = inodeWrapper->GetInodeUnlocked(); + + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(1, inode.s3chunkinfomap_size()); + + offset = 8818688; + len = 4096; + memset(buf, 'b', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + fsCacheManager = s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + ret = s3ClientAdaptor_->Flush(inode.inodeid()); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(1, inode.s3chunkinfomap_size()); + + offset = 9961472; + len = 1048576; + memset(buf, 'c', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + ret = s3ClientAdaptor_->Flush(inode.inodeid()); + + offset = 8523776; + len = 4096; + memset(buf, 'd', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + ret = s3ClientAdaptor_->Flush(inode.inodeid()); + + offset = 8732672; + len = 512; + memset(buf, 'e', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + ret = s3ClientAdaptor_->Flush(inode.inodeid()); + + offset = 9184768; + len = 512; + memset(buf, 'f', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + ret = s3ClientAdaptor_->Flush(inode.inodeid()); + + offset = 9437184; + len = 1048576; + memset(buf, 'g', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + ret = s3ClientAdaptor_->Flush(inode.inodeid()); + + + s3ClientAdaptor_->ReleaseCache(inode.inodeid()); + inode = inodeWrapper->GetInodeUnlocked(); + + offset = 9437184; + len = 131072; + char *readBuf = new char[len + 1]; + memset(readBuf, 'h', len); + memset(readBuf + len, 0, 1); + char *expectBuf = new char[len + 1]; + memset(expectBuf, 'g', len); + memset(expectBuf + len, 0, 1); + + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + // cleanup + delete buf; + delete readBuf; + delete expectBuf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* This is a use case for an inconsistency problem */ +TEST_F(ClientS3IntegrationTest, test_flush_write_and_read11) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 196608; + uint64_t len = 131072; + char *buf = new char[len]; + memset(buf, 'a', len); + + uint64_t chunkId = 1; + uint64_t chunkId1 = 2; + + inode.set_length(offset + len); + EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))) + .WillOnce(DoAll(SetArgPointee<1>(chunkId1), Return(FSStatusCode::OK))); + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Invoke(S3Upload)); + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillRepeatedly( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + EXPECT_CALL(mockS3Client_, UploadAsync(_)) + .WillRepeatedly( + Invoke([&](const std::shared_ptr &context) { + S3Data &tmp = gObjectDataMaps[context->key]; + tmp.len = context->bufferSize; + tmp.buf = new char[context->bufferSize]; + strncpy(tmp.buf, context->buffer, context->bufferSize); + context->retCode = 0; + context->cb(context); + })); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); + inode = inodeWrapper->GetInodeUnlocked(); + + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(1, inode.s3chunkinfomap_size()); + + offset = 323584; + len = 4096; + memset(buf, 'b', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + fsCacheManager = s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + ret = s3ClientAdaptor_->Flush(inode.inodeid()); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(1, inode.s3chunkinfomap_size()); + + s3ClientAdaptor_->ReleaseCache(inode.inodeid()); + inode = inodeWrapper->GetInodeUnlocked(); + + offset = 196608; + len = 131072; + char *readBuf = new char[len + 1]; + memset(readBuf, 'c', len); + memset(readBuf + len, 0, 1); + char *expectBuf = new char[len + 1]; + memset(expectBuf, 'a', len); + memset(expectBuf + 126976, 'b', 4096); + memset(expectBuf + len, 0, 1); + + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + // cleanup + delete buf; + delete readBuf; + delete expectBuf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +/* This is a use case for an inconsistency problem */ +TEST_F(ClientS3IntegrationTest, test_flush_write_and_read12) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 196608; + uint64_t len = 131072; + char *buf = new char[len]; + memset(buf, 'a', len); + + uint64_t chunkId = 1; + uint64_t chunkId1 = 2; + + inode.set_length(offset + len); + EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))) + .WillOnce(DoAll(SetArgPointee<1>(chunkId1), Return(FSStatusCode::OK))); + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Invoke(S3Upload)); + EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) + .WillRepeatedly(Invoke(S3Download)); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillRepeatedly( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + EXPECT_CALL(mockS3Client_, UploadAsync(_)) + .WillRepeatedly( + Invoke([&](const std::shared_ptr &context) { + S3Data &tmp = gObjectDataMaps[context->key]; + tmp.len = context->bufferSize; + tmp.buf = new char[context->bufferSize]; + strncpy(tmp.buf, context->buffer, context->bufferSize); + context->retCode = 0; + context->cb(context); + })); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); + inode = inodeWrapper->GetInodeUnlocked(); + + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(1, inode.s3chunkinfomap_size()); + + offset = 323584; + len = 4096; + memset(buf, 'b', len); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + + fsCacheManager = s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + ret = s3ClientAdaptor_->Flush(inode.inodeid()); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + ASSERT_EQ(1, inode.s3chunkinfomap_size()); + + s3ClientAdaptor_->ReleaseCache(inode.inodeid()); + inode = inodeWrapper->GetInodeUnlocked(); + + offset = 196608; + len = 131072; + char *readBuf = new char[len + 1]; + memset(readBuf, 'c', len); + memset(readBuf + len, 0, 1); + char *expectBuf = new char[len + 1]; + memset(expectBuf, 'a', len); + memset(expectBuf + 126976, 'b', 4096); + memset(expectBuf + len, 0, 1); + + s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + EXPECT_STREQ(expectBuf, readBuf); + + // cleanup + delete buf; + delete readBuf; + delete expectBuf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +TEST_F(ClientS3IntegrationTest, test_fssync_success_and_fail) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 1 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + // mock + uint64_t chunkId = 25; + + EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) + .WillRepeatedly( + DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))); + + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillOnce( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))) + .WillOnce(DoAll(SetArgReferee<1>(inodeWrapper), + Return(CURVEFS_ERROR::INTERNAL))) + .WillOnce(DoAll(SetArgReferee<1>(inodeWrapper), + Return(CURVEFS_ERROR::INTERNAL))); + EXPECT_CALL(mockS3Client_, UploadAsync(_)) + .WillRepeatedly( + Invoke([&](const std::shared_ptr &context) { + S3Data &tmp = gObjectDataMaps[context->key]; + tmp.len = context->bufferSize; + tmp.buf = new char[context->bufferSize]; + strncpy(tmp.buf, context->buffer, context->bufferSize); + context->retCode = 0; + context->cb(context); + })); + + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + + CURVEFS_ERROR ret = s3ClientAdaptor_->FsSync(); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + ret = s3ClientAdaptor_->FsSync(); + ASSERT_EQ(CURVEFS_ERROR::INTERNAL, ret); + + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + ret = s3ClientAdaptor_->FsSync(); + ASSERT_EQ(CURVEFS_ERROR::INTERNAL, ret); + + // cleanup + delete buf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +TEST_F(ClientS3IntegrationTest, test_fssync_overlap_write) { + curvefs::metaserver::Inode inode; + + InitInodeForIntegration(&inode); + uint64_t offset = 0; + uint64_t len = 2 * 1024 * 1024; + char *buf = new char[len]; + memset(buf, 'a', len); + // mock + uint64_t chunkId = 25; + + EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))); + EXPECT_CALL(mockS3Client_, Upload(_, _, _)) + .WillRepeatedly(Return(1 * 1024 * 1024)); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(mockInodeManager_, GetInode(_, _)) + .WillOnce( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + EXPECT_CALL(mockS3Client_, UploadAsync(_)) + .WillRepeatedly( + Invoke([&](const std::shared_ptr &context) { + S3Data &tmp = gObjectDataMaps[context->key]; + tmp.len = context->bufferSize; + tmp.buf = new char[context->bufferSize]; + strncpy(tmp.buf, context->buffer, context->bufferSize); + context->retCode = 0; + context->cb(context); + })); + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + offset = 1 * 1024 * 1024; + s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); + inode.set_length(offset + len); + + std::shared_ptr fsCacheManager = + s3ClientAdaptor_->GetFsCacheManager(); + ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); + + CURVEFS_ERROR ret = s3ClientAdaptor_->FsSync(); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); + ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); + + // cleanup + delete buf; + std::map::iterator iter = gObjectDataMaps.begin(); + for (; iter != gObjectDataMaps.end(); iter++) { + delete iter->second.buf; + iter->second.buf = NULL; + } + gObjectDataMaps.clear(); +} + +} // namespace client +} // namespace curvefs diff --git a/curvefs/test/client/client_s3_adaptor_test.cpp b/curvefs/test/client/client_s3_adaptor_test.cpp index 2385efd812..1a37951407 100644 --- a/curvefs/test/client/client_s3_adaptor_test.cpp +++ b/curvefs/test/client/client_s3_adaptor_test.cpp @@ -16,34 +16,24 @@ /* * Project: curve - * Created Date: Thur Jun 22 2021 + * Created Date: Wed Mar 23 2022 * Author: huyao */ -#include "curvefs/src/client/s3/client_s3_adaptor.h" - #include #include #include -#include "curvefs/test/client/mock_client_s3.h" +#include "curvefs/test/client/mock_client_s3_cache_manager.h" +#include "curvefs/test/client/mock_disk_cache_manager.h" #include "curvefs/test/client/mock_inode_cache_manager.h" -#include "curvefs/test/client/mock_mds_client.h" -#include "curvefs/test/client/mock_metaserver_service.h" -#include "curvefs/test/client/mock_spacealloc_service.h" #include "src/common/curve_define.h" +#include "curvefs/src/client/s3/client_s3_adaptor.h" +#include "curvefs/test/client/mock_client_s3.h" +#include "curvefs/test/client/mock_mds_client.h" namespace curvefs { namespace client { -namespace common { -DECLARE_bool(enableCto); -} // namespace common -} // namespace client -} // namespace curvefs - -namespace curvefs { -namespace client { -using ::curve::common::kMB; using ::testing::_; using ::testing::DoAll; using ::testing::Invoke; @@ -54,57 +44,18 @@ using ::testing::WithArg; using rpcclient::MockMdsClient; -template -void S3RpcService(google::protobuf::RpcController *cntl_base, - const RpcRequestType *request, RpcResponseType *response, - google::protobuf::Closure *done) { - if (RpcFailed) { - brpc::Controller *cntl = static_cast(cntl_base); - cntl->SetFailed(112, "Not connected to"); - } - LOG(INFO) << "run s3 prc service"; - done->Run(); -} - -struct S3Data { - char *buf; - uint64_t len; -}; - -static std::map gObjectDataMaps; - -int S3Upload(std::string name, const char *buf, uint64_t len) { - S3Data &tmp = gObjectDataMaps[name]; - - tmp.len = len; - tmp.buf = new char[len]; - strncpy(tmp.buf, buf, len); - LOG(INFO) << "S3Upload len:" << len << ",name" << name << "buf:" << buf[0]; - return len; -} - -int S3Download(std::string name, char *buf, uint64_t offset, uint64_t len) { - S3Data &tmp = gObjectDataMaps[name]; - - assert((offset + len) <= tmp.len); - strncpy(buf, tmp.buf + offset, len); - LOG(INFO) << "S3Download offset:" << offset << ",len:" << len - << ",name:" << name << "buf:" << buf[0]; - return len; -} - class ClientS3AdaptorTest : public testing::Test { protected: ClientS3AdaptorTest() {} ~ClientS3AdaptorTest() {} void SetUp() override { - Aws::InitAPI(awsOptions_); - ASSERT_EQ(0, server_.AddService(&mockMetaServerService_, - brpc::SERVER_DOESNT_OWN_SERVICE)); - /*ASSERT_EQ(0, server_.AddService(&mockSpaceAllocService_, - brpc::SERVER_DOESNT_OWN_SERVICE));*/ - ASSERT_EQ(0, server_.Start(addr_.c_str(), nullptr)); + s3ClientAdaptor_ = std::make_shared(); + mockInodeManager_ = std::make_shared(); + mockDiskcacheManagerImpl_ = + std::make_shared(); + mockFsCacheManager_ = std::make_shared(); + mockS3Client_ = std::make_shared(); + mockMdsClient_ = std::make_shared(); S3ClientAdaptorOption option; option.blockSize = 1 * 1024 * 1024; option.chunkSize = 4 * 1024 * 1024; @@ -113,35 +64,25 @@ class ClientS3AdaptorTest : public testing::Test { option.flushIntervalSec = 5000; option.readCacheMaxByte = 104857600; option.writeCacheMaxByte = 10485760000; - // option.fuseMaxSize = 131072; + option.fuseMaxSize = 131072; option.diskCacheOpt.diskCacheType = (DiskCacheType)0; - - std::shared_ptr mockInodeManager( - &mockInodeManager_); - std::shared_ptr mockMdsClient(&mockMdsClient_); - s3ClientAdaptor_ = new S3ClientAdaptorImpl(); - s3ClientAdaptor_->Init(option, &mockS3Client_, mockInodeManager, - mockMdsClient); - s3ClientAdaptor_->SetFsId(2); - curvefs::client::common::FLAGS_enableCto = false; + s3ClientAdaptor_->Init(option, mockS3Client_, mockInodeManager_, + mockMdsClient_, mockFsCacheManager_, + mockDiskcacheManagerImpl_); } void TearDown() override { - Aws::ShutdownAPI(awsOptions_); - server_.Stop(0); - server_.Join(); } protected: - S3ClientAdaptorImpl *s3ClientAdaptor_; - MockMetaServerService mockMetaServerService_; - MockS3Client mockS3Client_; - MockInodeCacheManager mockInodeManager_; - MockMdsClient mockMdsClient_; - std::string addr_ = "127.0.0.1:5630"; - brpc::Server server_; - Aws::SDKOptions awsOptions_; + std::shared_ptr s3ClientAdaptor_; + std::shared_ptr mockInodeManager_; + std::shared_ptr mockDiskcacheManagerImpl_; + std::shared_ptr mockFsCacheManager_; + std::shared_ptr mockS3Client_; + std::shared_ptr mockMdsClient_; }; + uint64_t gInodeId = 1; void InitInode(Inode *inode) { inode->set_inodeid(gInodeId); @@ -158,2751 +99,167 @@ void InitInode(Inode *inode) { gInodeId++; } -TEST_F(ClientS3AdaptorTest, test_first_write) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 0; - uint64_t len = 2 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - - int ret = s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(len, ret); - - delete buf; - buf = NULL; -} - -TEST_F(ClientS3AdaptorTest, test_overlap_write) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 1 * 1024 * 1024; - uint64_t len = 2 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - - offset = 0; - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - - offset = 2 * 1024 * 1024; - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - // ASSERT_EQ(0, s3ChunkInfoList.s3chunks(0).version()); - // ASSERT_EQ(1, s3ChunkInfoList.s3chunks(1).version()); - // ASSERT_EQ(2, s3ChunkInfoList.s3chunks(2).version()); - // ASSERT_EQ(3, s3ChunkInfoList.s3chunks(3).version()); - - delete buf; - buf = NULL; -} - -TEST_F(ClientS3AdaptorTest, test_hole_write) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 0; - uint64_t len = 1 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - /* - ::curvefs::space::AllocateS3ChunkResponse response; - response.set_status(::curvefs::space::SpaceStatusCode::SPACE_OK); - response.set_chunkid(25); - - EXPECT_CALL(mockSpaceAllocService_, AllocateS3Chunk(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<2>(response), - Invoke(S3RpcService))); - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Return(1 * 1024 * 1024));*/ - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - offset = 2 * 1024 * 1024; - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(2, fsCacheManager->GetDataCacheNum()); - - delete buf; - buf = NULL; -} - -TEST_F(ClientS3AdaptorTest, test_append_write) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 0; - uint64_t len = 1 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - offset = offset + len; - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - - delete buf; - buf = NULL; -} - -TEST_F(ClientS3AdaptorTest, test_write_more_chunk) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 0; - uint64_t len = 5 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(2, fsCacheManager->GetDataCacheNum()); - - delete buf; - buf = NULL; -} - -TEST_F(ClientS3AdaptorTest, test_write_merge_data1) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 1 * 1024 * 1024; - uint64_t len = 1 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - offset = 3 * 1024 * 1024; - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(2, fsCacheManager->GetDataCacheNum()); - - offset = 1.5 * 1024 * 1024; - len = 2 * 1024 * 1024; - char *buf1 = new char[len]; - memset(buf1, 'b', len); - - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf1); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - - delete buf; - delete buf1; -} - -TEST_F(ClientS3AdaptorTest, test_write_merge_data2) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 1 * 1024 * 1024; - uint64_t len = 1 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - offset = 3 * 1024 * 1024; - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(2, fsCacheManager->GetDataCacheNum()); - - offset = 0; - len = 3.5 * 1024 * 1024; - char *buf1 = new char[len]; - memset(buf1, 'b', len); - - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf1); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - - delete buf; - delete buf1; -} - -TEST_F(ClientS3AdaptorTest, test_read_one_chunk) { - uint64_t readFileLen = 2 * 1024 * 1024; - curvefs::metaserver::Inode inode; - uint64_t offset = 0; - uint64_t len = 1 * 1024 * 1024; - uint64_t chunkSize = s3ClientAdaptor_->GetChunkSize(); - uint64_t chunkIndex = offset / chunkSize; - InitInode(&inode); - inode.set_length(readFileLen); - - auto s3ChunkInfoMap = inode.mutable_s3chunkinfomap(); - S3ChunkInfoList *s3ChunkInfoList = new S3ChunkInfoList(); - S3ChunkInfo *s3ChunkInfo = s3ChunkInfoList->add_s3chunks(); - s3ChunkInfo->set_chunkid(25); - s3ChunkInfo->set_compaction(0); - s3ChunkInfo->set_offset(0); - s3ChunkInfo->set_len(readFileLen); - s3ChunkInfo->set_size(readFileLen); - s3ChunkInfo->set_zero(false); - s3ChunkInfoMap->insert({chunkIndex, *s3ChunkInfoList}); - - char *buf = new char[len]; - char *tmpbuf = new char[len]; - memset(tmpbuf, 'a', len); - - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<1>(*tmpbuf), Return(1 * 1024 * 1024))) - .WillOnce(Return(-1)); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillOnce( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))) - .WillOnce( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - - int ret = s3ClientAdaptor_->Read(inode.inodeid(), offset, len, buf); - ASSERT_EQ(len, ret); - ASSERT_EQ('a', buf[0]); - offset = offset + len; - ret = s3ClientAdaptor_->Read(inode.inodeid(), offset, len, buf); - ASSERT_EQ(-1, ret); - - delete buf; - buf = NULL; +TEST_F(ClientS3AdaptorTest, test_init) { + ASSERT_EQ(1024 * 1024, s3ClientAdaptor_->GetBlockSize()); + ASSERT_EQ(4 * 1024 * 1024, s3ClientAdaptor_->GetChunkSize()); + ASSERT_EQ(64 * 1024, s3ClientAdaptor_->GetPageSize()); + ASSERT_EQ(true, s3ClientAdaptor_->DisableDiskCache()); } -TEST_F(ClientS3AdaptorTest, test_read_overlap_block1) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); +TEST_F(ClientS3AdaptorTest, write_success) { + uint64_t inodeId = 1; uint64_t offset = 0; - uint64_t len = 2 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - len = 1 * 1024 * 1024; - memset(buf, 'b', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - - char *readBuf = new char[len + 1]; - char *expectBuf = new char[len + 1]; - memset(readBuf, 0, len + 1); - memset(expectBuf, 'b', len); - memset(expectBuf + len, 0, 1); - - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - offset = offset + len; - memset(expectBuf, 'a', len); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - // EXPECT_STREQ(expectBuf, readBuf); - - delete readBuf; - delete buf; - delete expectBuf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_read_overlap_block2) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); + uint64_t length = 1024; + char buf[length] = {0}; + memset(buf, 'a', length); + auto fileCache = std::make_shared(); + EXPECT_CALL(*mockFsCacheManager_, FindOrCreateFileCacheManager(_, _)) + .WillOnce(Return(fileCache)); + EXPECT_CALL(*mockFsCacheManager_, GetDataCacheSize()) + .WillOnce(Return(length)); + EXPECT_CALL(*mockFsCacheManager_, GetDataCacheMaxSize()) + .WillOnce(Return(10485760000)); + EXPECT_CALL(*mockFsCacheManager_, MemCacheRatio()).WillOnce(Return(10)); + EXPECT_CALL(*fileCache, Write(_, _, _)).WillOnce(Return(length)); + ASSERT_EQ(length, s3ClientAdaptor_->Write(inodeId, offset, length, buf)); +} + +TEST_F(ClientS3AdaptorTest, read_success) { + uint64_t inodeId = 1; uint64_t offset = 0; - uint64_t len = 2 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - offset = 1 * 1024 * 1024; - len = 2 * 1024 * 1024; - memset(buf, 'b', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - offset = 0; - len = 1 * 1024 * 1024; - char *readBuf = new char[len + 1]; - memset(readBuf, 0, len + 1); - char *expectBuf = new char[len + 1]; - memset(expectBuf, 'a', len); - memset(expectBuf + len, 0, 1); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - // EXPECT_STREQ(expectBuf, readBuf); - - offset = offset + len; - memset(expectBuf, 'b', len); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - delete readBuf; - delete buf; - delete expectBuf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_read_overlap_block3) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); + uint64_t length = 1024; + char buf[length] = {0}; + memset(buf, 'a', length); + auto fileCache = std::make_shared(); + EXPECT_CALL(*mockFsCacheManager_, FindOrCreateFileCacheManager(_, _)) + .WillOnce(Return(fileCache)); + EXPECT_CALL(*fileCache, Read(_, _, _, _)).WillOnce(Return(length)); + ASSERT_EQ(length, s3ClientAdaptor_->Read(inodeId, offset, length, buf)); +} + +TEST_F(ClientS3AdaptorTest, read_fail) { + uint64_t inodeId = 1; uint64_t offset = 0; - uint64_t len = 3 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - offset = 1 * 1024 * 1024; - len = 1 * 1024 * 1024; - memset(buf, 'b', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - - offset = 0; - len = 1 * 1024 * 1024; - char *readBuf = new char[len + 1]; - memset(readBuf, 0, len + 1); - char *expectBuf = new char[len + 1]; - memset(expectBuf, 'a', len); - memset(expectBuf + len, 0, 1); - - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - offset = offset + len; - memset(expectBuf, 'b', len); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - offset = offset + len; - memset(expectBuf, 'a', len); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - delete readBuf; - delete buf; - delete expectBuf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_read_overlap_block4) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t max_len = 3 * 1024 * 1024; - uint64_t offset = 1 * 1024 * 1024; - uint64_t len = 1 * 1024 * 1024; - char *buf = new char[max_len]; - memset(buf, 'a', len); - - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Invoke(S3Upload)); - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - offset = 0; - len = 3 * 1024 * 1024; - memset(buf, 'b', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(len); - offset = 0; - len = 1 * 1024 * 1024; - char *readBuf = new char[len + 1]; - memset(readBuf, 0, len + 1); - char *expectBuf = new char[len + 1]; - memset(expectBuf, 'b', len); - memset(expectBuf + len, 0, 1); - - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - offset = offset + len; - memset(expectBuf, 'b', len); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - offset = offset + len; - memset(expectBuf, 'b', len); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - delete readBuf; - delete buf; - delete expectBuf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_read_overlap_block5) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t max_len = 2 * 1024 * 1024; - uint64_t offset = 1 * 1024 * 1024; - uint64_t len = 2 * 1024 * 1024; - char *buf = new char[max_len]; - memset(buf, 'a', len); - - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Invoke(S3Upload)); - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - offset = 0; - len = 2 * 1024 * 1024; - memset(buf, 'b', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - - offset = 0; - len = 1 * 1024 * 1024; - char *readBuf = new char[len + 1]; - char *expectBuf = new char[len + 1]; - memset(readBuf, 0, len + 1); - memset(expectBuf, 0, len + 1); - - memset(expectBuf, 'b', len); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - offset = offset + len; - memset(expectBuf, 'b', len); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - offset = offset + len; - memset(expectBuf, 'a', len); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - // delete readBuf; - delete buf; - delete expectBuf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_read_hole1) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 1 * 1024 * 1024; - uint64_t len = 1 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - /* - ::curvefs::space::AllocateS3ChunkResponse response; - response.set_status(::curvefs::space::SpaceStatusCode::SPACE_OK); - response.set_chunkid(25); - - EXPECT_CALL(mockSpaceAllocService_, AllocateS3Chunk(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<2>(response), - Invoke(S3RpcService)));*/ - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Invoke(S3Upload)); - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillOnce( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))) - .WillOnce( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - // ASSERT_EQ(2, gObjectDataMaps.size()); - // ASSERT_EQ('a', gObjectDataMaps.begin()->second.buf[0]); - - offset = 0; - len = 1 * 1024 * 1024; - char *readBuf = new char[len + 1]; - memset(readBuf, 'a', len); - memset(readBuf + len, 0, 1); - char *expectBuf = new char[len + 1]; - memset(expectBuf, 0, len + 1); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - offset = 2 * 1024 * 1024; - inode.set_length(offset + len); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - // cleanup - delete buf; - delete readBuf; - delete expectBuf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_read_hole2) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 1 * 1024 * 1024; - uint64_t len = 2 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - /* - ::curvefs::space::AllocateS3ChunkResponse response; - response.set_status(::curvefs::space::SpaceStatusCode::SPACE_OK); - response.set_chunkid(25); - - EXPECT_CALL(mockSpaceAllocService_, AllocateS3Chunk(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<2>(response), - Invoke(S3RpcService)));*/ - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Invoke(S3Upload)); - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillOnce( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - // ASSERT_EQ(2, gObjectDataMaps.size()); - // ASSERT_EQ('a', gObjectDataMaps.begin()->second.buf[0]); - - offset = 0; - len = 2 * 1024 * 1024; - char *readBuf = new char[len + 1]; - memset(readBuf, 0, len + 1); - char *expectBuf = new char[len + 1]; - memset(expectBuf, 0, len + 1); - memset(expectBuf + 1024 * 1024, 'a', 1024 * 1024); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - - EXPECT_STREQ(expectBuf, readBuf); - - // cleanup - delete buf; - delete readBuf; - delete expectBuf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); + uint64_t length = 1024; + char buf[length] = {0}; + memset(buf, 'a', length); + auto fileCache = std::make_shared(); + EXPECT_CALL(*mockFsCacheManager_, FindOrCreateFileCacheManager(_, _)) + .WillOnce(Return(fileCache)); + EXPECT_CALL(*fileCache, Read(_, _, _, _)).WillOnce(Return(-1)); + ASSERT_EQ(-1, s3ClientAdaptor_->Read(inodeId, offset, length, buf)); } -TEST_F(ClientS3AdaptorTest, test_read_hole3) { +TEST_F(ClientS3AdaptorTest, truncate_small) { curvefs::metaserver::Inode inode; - InitInode(&inode); - uint64_t offset = 1 * 1024 * 1024; - uint64_t len = 1 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - /* - ::curvefs::space::AllocateS3ChunkResponse response; - response.set_status(::curvefs::space::SpaceStatusCode::SPACE_OK); - response.set_chunkid(25); - EXPECT_CALL(mockSpaceAllocService_, AllocateS3Chunk(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<2>(response), - Invoke(S3RpcService)));*/ - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Invoke(S3Upload)); - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillOnce( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); + inode.set_length(1000); - // ASSERT_EQ(1, gObjectDataMaps.size()); - // ASSERT_EQ('a', gObjectDataMaps.begin()->second.buf[0]); - - offset = 0; - len = 2 * 1024 * 1024; - char *readBuf = new char[len + 1]; - memset(readBuf, 0, len + 1); - char *expectBuf = new char[len + 1]; - memset(expectBuf, 0, len + 1); - memset(expectBuf + 1024 * 1024, 'a', 1024 * 1024); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - // cleanup - delete buf; - delete readBuf; - delete expectBuf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); + auto fileCache = std::make_shared(); + EXPECT_CALL(*mockFsCacheManager_, FindOrCreateFileCacheManager(_, _)) + .WillOnce(Return(fileCache)); + EXPECT_CALL(*fileCache, TruncateCache(_, _)).WillOnce(Return()); + ASSERT_EQ(CURVEFS_ERROR::OK, s3ClientAdaptor_->Truncate(&inode, 100)); } -TEST_F(ClientS3AdaptorTest, test_read_hole4) { +TEST_F(ClientS3AdaptorTest, truncate_unchange) { curvefs::metaserver::Inode inode; - InitInode(&inode); - uint64_t offset = 0; - uint64_t len = 1 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Invoke(S3Upload)); - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillOnce( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - offset = 2 * 1024 * 1024; - memset(buf, 'b', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - offset = 0; - len = 3 * 1024 * 1024; - char *readBuf = new char[len + 1]; - memset(readBuf, 0, len + 1); - char *expectBuf = new char[len + 1]; - memset(expectBuf, 0, len + 1); - memset(expectBuf, 'a', 1024 * 1024); - memset(expectBuf + 2 * 1024 * 1024, 'b', 1024 * 1024); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); + inode.set_length(1000); - EXPECT_STREQ(expectBuf, readBuf); - - // cleanup - delete buf; - delete readBuf; - delete expectBuf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); + ASSERT_EQ(CURVEFS_ERROR::OK, s3ClientAdaptor_->Truncate(&inode, 1000)); } -TEST_F(ClientS3AdaptorTest, test_read_more_write) { +TEST_F(ClientS3AdaptorTest, truncate_big_alloc_chunkId_fail) { curvefs::metaserver::Inode inode; - InitInode(&inode); - uint64_t offset = 0; - uint64_t len = 100; - char *buf = new char[len]; - memset(buf, 'a', len); - - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Invoke(S3Upload)); - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillOnce( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - offset = 120; - memset(buf, 'b', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - offset = 0; - len = 1024; - inode.set_length(1024); - char *readBuf = new char[len + 1]; - memset(readBuf, 0, len + 1); - char *expectBuf = new char[len + 1]; - memset(expectBuf, 0, len + 1); - memset(expectBuf, 'a', 100); - memset(expectBuf + 120, 'b', 100); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - - EXPECT_STREQ(expectBuf, readBuf); - // cleanup - delete buf; - delete readBuf; - delete expectBuf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); + EXPECT_CALL(*mockMdsClient_, AllocS3ChunkId(_, _)) + .WillOnce(Return(FSStatusCode::UNKNOWN_ERROR)); + ASSERT_EQ(CURVEFS_ERROR::INTERNAL, + s3ClientAdaptor_->Truncate(&inode, 1000)); } -TEST_F(ClientS3AdaptorTest, test_read_more_write2) { +TEST_F(ClientS3AdaptorTest, truncate_big_success) { curvefs::metaserver::Inode inode; - InitInode(&inode); - uint64_t offset = 34339840; - uint64_t len = 512; - char *buf = new char[len]; - memset(buf, 'a', len); - - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Invoke(S3Upload)); - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - offset = 34340864; - memset(buf, 'b', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - offset = 34340352; - memset(buf, 'c', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - - offset = 34340864; - char *readBuf = new char[len + 1]; - memset(readBuf, 0, len + 1); - char *expectBuf = new char[len + 1]; - memset(expectBuf, 0, len + 1); - memset(expectBuf, 'b', len); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - - EXPECT_STREQ(expectBuf, readBuf); - - // cleanup - delete buf; - delete readBuf; - delete expectBuf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); + uint64_t chunkId = 999; + EXPECT_CALL(*mockMdsClient_, AllocS3ChunkId(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))); + ASSERT_EQ(CURVEFS_ERROR::OK, s3ClientAdaptor_->Truncate(&inode, 1000)); } -TEST_F(ClientS3AdaptorTest, test_read_more_chunks) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 4 * 1024 * 1024 - 1024; - uint64_t len = 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Invoke(S3Upload)); - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - offset = 4 * 1024 * 1024; - memset(buf, 'b', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - offset = 4 * 1024 * 1024 - 1024; - len = 2048; - inode.set_length(4 * 1024 * 1024 + 1024); - char *readBuf = new char[len + 1]; - memset(readBuf, 0, len + 1); - char *expectBuf = new char[len + 1]; - memset(expectBuf, 0, len + 1); - memset(expectBuf, 'a', 1024); - memset(expectBuf + 1024, 'b', 1024); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - - EXPECT_STREQ(expectBuf, readBuf); +TEST_F(ClientS3AdaptorTest, flush_no_file_cache) { + uint64_t inodeId = 1; - // cleanup - delete buf; - delete readBuf; - delete expectBuf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); + EXPECT_CALL(*mockFsCacheManager_, FindFileCacheManager(_)) + .WillOnce(Return(nullptr)); + ASSERT_EQ(CURVEFS_ERROR::OK, s3ClientAdaptor_->Flush(inodeId)); } -TEST_F(ClientS3AdaptorTest, test_truncate_small1) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 0; - uint64_t len = 5 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - ASSERT_EQ(len, s3ClientAdaptor_->GetFsCacheManager()->GetDataCacheSize()); - len = 1 * 1024 * 1024; - CURVEFS_ERROR ret = s3ClientAdaptor_->Truncate(&inode, len); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(len, s3ClientAdaptor_->GetFsCacheManager()->GetDataCacheSize()); +TEST_F(ClientS3AdaptorTest, flush_fail) { + uint64_t inodeId = 1; - // cleanup - delete buf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); + auto fileCache = std::make_shared(); + EXPECT_CALL(*mockFsCacheManager_, FindFileCacheManager(_)) + .WillOnce(Return(fileCache)); + EXPECT_CALL(*fileCache, Flush(_, _)) + .WillOnce(Return(CURVEFS_ERROR::INTERNAL)); + ASSERT_EQ(CURVEFS_ERROR::INTERNAL, s3ClientAdaptor_->Flush(inodeId)); } -TEST_F(ClientS3AdaptorTest, test_truncate_small2) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 0; - uint64_t len = 512 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - inode.set_length(8 * 1024 * 1024); - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - for (int i = 0; i < 6; i++) { - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - offset = offset + len * 2; - } - ASSERT_EQ(6, fsCacheManager->GetDataCacheNum()); - - uint64_t truncateLen = 3 * 1024 * 1024; - CURVEFS_ERROR ret = s3ClientAdaptor_->Truncate(&inode, truncateLen); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(3 * len, - s3ClientAdaptor_->GetFsCacheManager()->GetDataCacheSize()); - - truncateLen = 1200 * 1024; - ret = s3ClientAdaptor_->Truncate(&inode, truncateLen); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(704 * 1024, - s3ClientAdaptor_->GetFsCacheManager()->GetDataCacheSize()); - - // cleanup - delete buf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); +TEST_F(ClientS3AdaptorTest, FlushAllCache_no_filecachaeManager) { + EXPECT_CALL(*mockFsCacheManager_, FindFileCacheManager(_)) + .WillOnce(Return(nullptr)); + ASSERT_EQ(CURVEFS_ERROR::OK, s3ClientAdaptor_->FlushAllCache(1)); } -TEST_F(ClientS3AdaptorTest, test_truncate_small3) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 0; - uint64_t len = 512 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - inode.set_length(8 * 1024 * 1024); - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - uint64_t chunkId = 25; - EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) - .WillRepeatedly( - DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))); - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Invoke(S3Upload)); - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillRepeatedly( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - EXPECT_CALL(mockS3Client_, UploadAsync(_)) - .WillRepeatedly( - Invoke([&](const std::shared_ptr &context) { - S3Data &tmp = gObjectDataMaps[context->key]; - tmp.len = context->bufferSize; - tmp.buf = new char[context->bufferSize]; - strncpy(tmp.buf, context->buffer, context->bufferSize); - context->retCode = 0; - context->cb(context); - })); - - - for (int i = 0; i < 6; i++) { - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - offset = offset + len * 2; - } - ASSERT_EQ(6, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(6 * len, fsCacheManager->GetDataCacheSize()); - ASSERT_EQ(0, fsCacheManager->GetLruByte()); - - CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); - inode = inodeWrapper->GetInodeUnlocked(); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(0, fsCacheManager->GetDataCacheSize()); - ASSERT_EQ(6 * len, fsCacheManager->GetLruByte()); - - uint64_t truncateLen = 3 * 1024 * 1024; - ret = s3ClientAdaptor_->Truncate(&inode, truncateLen); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(3 * len, s3ClientAdaptor_->GetFsCacheManager()->GetLruByte()); - - truncateLen = 1200 * 1024; - ret = s3ClientAdaptor_->Truncate(&inode, truncateLen); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(len, s3ClientAdaptor_->GetFsCacheManager()->GetLruByte()); - - // cleanup - delete buf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); +TEST_F(ClientS3AdaptorTest, FlushAllCache_flush_fail) { + auto filecache = std::make_shared(); + EXPECT_CALL(*mockFsCacheManager_, FindFileCacheManager(_)) + .WillOnce(Return(filecache)); + EXPECT_CALL(*filecache, Flush(_, _)) + .WillOnce(Return(CURVEFS_ERROR::INTERNAL)); + ASSERT_EQ(CURVEFS_ERROR::INTERNAL, s3ClientAdaptor_->FlushAllCache(1)); } -TEST_F(ClientS3AdaptorTest, test_truncate_big1) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 0; - uint64_t len = 1 * 1024 * 1024; - CURVEFS_ERROR ret; - uint64_t chunkIndex = offset / s3ClientAdaptor_->GetChunkSize(); - ::curvefs::space::AllocateS3ChunkResponse response; - response.set_status(::curvefs::space::SpaceStatusCode::SPACE_OK); - response.set_chunkid(25); - // mock - /*EXPECT_CALL(mockSpaceAllocService_, AllocateS3Chunk(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<2>(response), - Invoke(S3RpcService)));*/ - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillOnce( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - ret = s3ClientAdaptor_->Truncate(&inode, len); - inode.set_length(len); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - auto s3InfoListIter = inode.s3chunkinfomap().find(chunkIndex); - S3ChunkInfo tmp; - ASSERT_NE(s3InfoListIter, inode.s3chunkinfomap().end()); - ASSERT_EQ(1, s3InfoListIter->second.s3chunks_size()); - tmp = s3InfoListIter->second.s3chunks(0); - ASSERT_EQ(len, tmp.len()); - ASSERT_EQ(offset, tmp.offset()); - ASSERT_EQ(true, tmp.zero()); +TEST_F(ClientS3AdaptorTest, FlushAllCache_with_no_cache) { + s3ClientAdaptor_->SetDiskCache(DiskCacheType::Disable); - char *readBuf = new char[len + 1]; - memset(readBuf, 0, len + 1); - char *expectBuf = new char[len + 1]; - memset(expectBuf, 0, len + 1); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); + LOG(INFO) << "############ case1: do not find file cache"; + auto filecache = std::make_shared(); + EXPECT_CALL(*mockFsCacheManager_, FindFileCacheManager(_)) + .WillOnce(Return(nullptr)); + ASSERT_EQ(CURVEFS_ERROR::OK, s3ClientAdaptor_->FlushAllCache(1)); - // cleanup - delete readBuf; - delete expectBuf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); + LOG(INFO) << "############ case2: find file cache"; + EXPECT_CALL(*mockFsCacheManager_, FindFileCacheManager(_)) + .WillOnce(Return(filecache)); + EXPECT_CALL(*filecache, Flush(_, _)).WillOnce(Return(CURVEFS_ERROR::OK)); + ASSERT_EQ(CURVEFS_ERROR::OK, s3ClientAdaptor_->FlushAllCache(1)); } -TEST_F(ClientS3AdaptorTest, test_truncate_big2) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 0; - uint64_t len = 1 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - uint64_t chunkIndex = offset / s3ClientAdaptor_->GetChunkSize(); - - ::curvefs::space::AllocateS3ChunkResponse response; - response.set_status(::curvefs::space::SpaceStatusCode::SPACE_OK); - response.set_chunkid(25); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillOnce( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - len = 5 * 1024 * 1024; - s3ClientAdaptor_->Truncate(&inode, len); - inode.set_length(len); - auto s3InfoListIter = inode.s3chunkinfomap().find(chunkIndex); - ASSERT_NE(s3InfoListIter, inode.s3chunkinfomap().end()); - ASSERT_EQ(1, s3InfoListIter->second.s3chunks_size()); - - char *readBuf = new char[len + 1]; - memset(readBuf, 0, len + 1); - char *expectBuf = new char[len + 1]; - memset(expectBuf, 0, len + 1); - memset(expectBuf, 'a', 1 * 1024 * 1024); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - - EXPECT_STREQ(expectBuf, readBuf); +TEST_F(ClientS3AdaptorTest, FlushAllCache_with_cache) { + s3ClientAdaptor_->SetDiskCache(DiskCacheType::ReadWrite); - // cleanup - delete buf; - delete readBuf; - delete expectBuf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_truncate_big3) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 0; - uint64_t len = 1 * 1024 * 1024; - CURVEFS_ERROR ret; - uint64_t chunkIndex = offset / s3ClientAdaptor_->GetChunkSize(); - ::curvefs::space::AllocateS3ChunkResponse response; - response.set_status(::curvefs::space::SpaceStatusCode::SPACE_OK); - response.set_chunkid(25); - // mock - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillRepeatedly( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - - ret = s3ClientAdaptor_->Truncate(&inode, len); - inode.set_length(len); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - auto s3InfoListIter = inode.s3chunkinfomap().find(chunkIndex); - S3ChunkInfo tmp; - ASSERT_NE(s3InfoListIter, inode.s3chunkinfomap().end()); - ASSERT_EQ(1, s3InfoListIter->second.s3chunks_size()); - tmp = s3InfoListIter->second.s3chunks(0); - ASSERT_EQ(len, tmp.len()); - ASSERT_EQ(offset, tmp.offset()); - ASSERT_EQ(true, tmp.zero()); - - len = 2 * 1024 * 1024; - ret = s3ClientAdaptor_->Truncate(&inode, len); - inode.set_length(len); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - s3InfoListIter = inode.s3chunkinfomap().find(chunkIndex); - ASSERT_NE(s3InfoListIter, inode.s3chunkinfomap().end()); - ASSERT_EQ(2, s3InfoListIter->second.s3chunks_size()); - tmp = s3InfoListIter->second.s3chunks(1); - ASSERT_EQ(1 * 1024 * 1024, tmp.len()); - ASSERT_EQ(1 * 1024 * 1024, tmp.offset()); - ASSERT_EQ(true, tmp.zero()); - - char *readBuf = new char[len + 1]; - memset(readBuf, 0, len + 1); - char *expectBuf = new char[len + 1]; - memset(expectBuf, 0, len + 1); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - offset = 512; - len = 512; - char *readBuf1 = new char[len + 1]; - memset(readBuf1, 0, len + 1); - char *expectBuf1 = new char[len + 1]; - memset(expectBuf1, 0, len + 1); - - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf1); - EXPECT_STREQ(expectBuf1, readBuf1); - - len = 1 * 1024 * 1024; - inode.set_length(3 * 1024 * 1024); - offset = 1.5 * 1024 * 1024; - char *readBuf2 = new char[len + 1]; - memset(readBuf2, 0, len + 1); - char *expectBuf2 = new char[len + 1]; - memset(expectBuf2, 0, len + 1); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf2); - EXPECT_STREQ(expectBuf2, readBuf2); - - // cleanup - delete readBuf; - delete expectBuf; - delete readBuf1; - delete expectBuf1; - delete readBuf2; - delete expectBuf2; - - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_releaseCache) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 0; - uint64_t len = 1 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - - s3ClientAdaptor_->ReleaseCache(inode.inodeid()); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - - offset = 2 * 1024 * 1024; - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - ASSERT_EQ(2, fsCacheManager->GetDataCacheNum()); - - s3ClientAdaptor_->ReleaseCache(inode.inodeid()); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - - // cleanup - delete buf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_flush_first_write) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 0; - uint64_t len = 2 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - uint64_t chunkIndex = offset / s3ClientAdaptor_->GetChunkSize(); - // mock - uint64_t chunkId = 25; - - EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) - .WillRepeatedly( - DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))); - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Return(1 * 1024 * 1024)); - - EXPECT_CALL(mockS3Client_, UploadAsync(_)) - .WillRepeatedly( - Invoke([&](const std::shared_ptr &context) { - context->retCode = 0; - context->cb(context); - })); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillRepeatedly( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); - - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - ret = s3ClientAdaptor_->Flush(inode.inodeid()); - inode = inodeWrapper->GetInodeUnlocked(); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - auto s3InfoListIter = inode.s3chunkinfomap().find(chunkIndex); - S3ChunkInfo tmp; - ASSERT_NE(s3InfoListIter, inode.s3chunkinfomap().end()); - ASSERT_EQ(1, s3InfoListIter->second.s3chunks_size()); - tmp = s3InfoListIter->second.s3chunks(0); - ASSERT_EQ(len, tmp.len()); - ASSERT_EQ(offset, tmp.offset()); - - // cleanup - delete buf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_flush_overlap_write) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 0; - uint64_t len = 2 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - uint64_t chunkIndex = offset / s3ClientAdaptor_->GetChunkSize(); - // mock - uint64_t chunkId = 25; - - EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) - .WillRepeatedly( - DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))); - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Return(1 * 1024 * 1024)); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillRepeatedly( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - EXPECT_CALL(mockS3Client_, UploadAsync(_)) - .WillRepeatedly( - Invoke([&](const std::shared_ptr &context) { - context->retCode = 0; - context->cb(context); - })); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - offset = 1 * 1024 * 1024; - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - - CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); - inode = inodeWrapper->GetInodeUnlocked(); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - auto s3InfoListIter = inode.s3chunkinfomap().find(chunkIndex); - S3ChunkInfo tmp; - ASSERT_NE(s3InfoListIter, inode.s3chunkinfomap().end()); - ASSERT_EQ(1, s3InfoListIter->second.s3chunks_size()); - tmp = s3InfoListIter->second.s3chunks(0); - ASSERT_EQ(3 * 1024 * 1024, tmp.len()); - ASSERT_EQ(0, tmp.offset()); - - // cleanup - delete buf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_flush_overlap_write2) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 16748032; - uint64_t len = 512; - char *buf = new char[len]; - memset(buf, 'a', len); - uint64_t chunkIndex = offset / s3ClientAdaptor_->GetChunkSize(); - // mock - uint64_t chunkId = 25; - - EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) - .WillRepeatedly( - DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))); - /*EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Return(1 * 1024 * 1024));*/ - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillRepeatedly( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - EXPECT_CALL(mockS3Client_, UploadAsync(_)) - .WillRepeatedly( - Invoke([&](const std::shared_ptr &context) { - context->retCode = 0; - context->cb(context); - })); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - offset = 16749056; - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(2, fsCacheManager->GetDataCacheNum()); - - offset = 16748544; - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - - CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); - inode = inodeWrapper->GetInodeUnlocked(); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - auto s3InfoListIter = inode.s3chunkinfomap().find(chunkIndex); - S3ChunkInfo tmp; - ASSERT_NE(s3InfoListIter, inode.s3chunkinfomap().end()); - ASSERT_EQ(1, s3InfoListIter->second.s3chunks_size()); - tmp = s3InfoListIter->second.s3chunks(0); - ASSERT_EQ(1536, tmp.len()); - ASSERT_EQ(16748032, tmp.offset()); - - // cleanup - delete buf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_flush_hole_write) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 0; - uint64_t len = 1 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - uint64_t chunkIndex = offset / s3ClientAdaptor_->GetChunkSize(); - // mock - uint64_t chunkId = 25; - - EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) - .WillRepeatedly( - DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))); - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Return(1 * 1024 * 1024)); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillRepeatedly( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - EXPECT_CALL(mockS3Client_, UploadAsync(_)) - .WillRepeatedly( - Invoke([&](const std::shared_ptr &context) { - context->retCode = 0; - context->cb(context); - })); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - offset = 2 * 1024 * 1024; - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(2, fsCacheManager->GetDataCacheNum()); - - CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); - inode = inodeWrapper->GetInodeUnlocked(); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - auto s3InfoListIter = inode.s3chunkinfomap().find(chunkIndex); - S3ChunkInfo tmp; - S3ChunkInfoList tmpList; - ASSERT_NE(s3InfoListIter, inode.s3chunkinfomap().end()); - tmpList = s3InfoListIter->second; - ASSERT_EQ(2, tmpList.s3chunks_size()); - tmp = tmpList.s3chunks(0); - ASSERT_EQ(1 * 1024 * 1024, tmp.len()); - ASSERT_EQ(0, tmp.offset()); - tmp = tmpList.s3chunks(1); - ASSERT_EQ(1 * 1024 * 1024, tmp.len()); - ASSERT_EQ(2 * 1024 * 1024, tmp.offset()); - - // cleanup - delete buf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_flush_write_more_chunk) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 0; - uint64_t len = 5 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - // mock - uint64_t chunkId = 25; - - EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) - .WillRepeatedly( - DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))); - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Return(1 * 1024 * 1024)); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillRepeatedly( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - EXPECT_CALL(mockS3Client_, UploadAsync(_)) - .WillRepeatedly( - Invoke([&](const std::shared_ptr &context) { - context->retCode = 0; - context->cb(context); - })); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(2, fsCacheManager->GetDataCacheNum()); - - CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); - inode = inodeWrapper->GetInodeUnlocked(); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(2, inode.s3chunkinfomap_size()); - auto s3InfoListIter = inode.s3chunkinfomap().find(0); - S3ChunkInfo tmp; - S3ChunkInfoList tmpList; - ASSERT_NE(s3InfoListIter, inode.s3chunkinfomap().end()); - VLOG(9) << "index: " << s3InfoListIter->first; - tmpList = s3InfoListIter->second; - ASSERT_EQ(1, tmpList.s3chunks_size()); - tmp = tmpList.s3chunks(0); - ASSERT_EQ(4 * 1024 * 1024, tmp.len()); - ASSERT_EQ(0, tmp.offset()); - s3InfoListIter = inode.s3chunkinfomap().find(1); - tmpList = s3InfoListIter->second; - tmp = tmpList.s3chunks(0); - ASSERT_EQ(1 * 1024 * 1024, tmp.len()); - ASSERT_EQ(4 * 1024 * 1024, tmp.offset()); - - // cleanup - delete buf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_flush_write_and_read1) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 0; - uint64_t len = 2 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - // mock - uint64_t chunkId = 25; - - EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) - .WillRepeatedly( - DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))); - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Invoke(S3Upload)); - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillRepeatedly( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - EXPECT_CALL(mockS3Client_, UploadAsync(_)) - .WillRepeatedly( - Invoke([&](const std::shared_ptr &context) { - S3Data &tmp = gObjectDataMaps[context->key]; - tmp.len = context->bufferSize; - tmp.buf = new char[context->bufferSize]; - strncpy(tmp.buf, context->buffer, context->bufferSize); - context->retCode = 0; - context->cb(context); - })); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - len = 1 * 1024 * 1024; - memset(buf, 'b', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - - CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); - uint64_t len1 = inode.length(); - inode = inodeWrapper->GetInodeUnlocked(); - inode.set_length(len1); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(1, inode.s3chunkinfomap_size()); - auto s3InfoListIter = inode.s3chunkinfomap().begin(); - S3ChunkInfo tmp; - S3ChunkInfoList tmpList; - ASSERT_NE(s3InfoListIter, inode.s3chunkinfomap().end()); - tmpList = s3InfoListIter->second; - ASSERT_EQ(1, tmpList.s3chunks_size()); - tmp = tmpList.s3chunks(0); - ASSERT_EQ(2 * 1024 * 1024, tmp.len()); - ASSERT_EQ(0, tmp.offset()); - - char *readBuf = new char[len + 1]; - char *expectBuf = new char[len + 1]; - memset(readBuf, 0, len + 1); - memset(expectBuf, 'b', len); - memset(expectBuf + len, 0, 1); - - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - // cleanup - delete buf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_flush_write_and_read2) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 0; - uint64_t len = 2 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - // mock - uint64_t chunkId = 25; - - EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) - .WillRepeatedly( - DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))); - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Invoke(S3Upload)); - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillRepeatedly( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - EXPECT_CALL(mockS3Client_, UploadAsync(_)) - .WillRepeatedly( - Invoke([&](const std::shared_ptr &context) { - S3Data &tmp = gObjectDataMaps[context->key]; - tmp.len = context->bufferSize; - tmp.buf = new char[context->bufferSize]; - strncpy(tmp.buf, context->buffer, context->bufferSize); - context->retCode = 0; - context->cb(context); - })); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - - CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); - uint64_t len1 = inode.length(); - inode = inodeWrapper->GetInodeUnlocked(); - inode.set_length(len1); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(1, inode.s3chunkinfomap_size()); - auto s3InfoListIter = inode.s3chunkinfomap().begin(); - S3ChunkInfo tmp; - S3ChunkInfoList tmpList; - ASSERT_NE(s3InfoListIter, inode.s3chunkinfomap().end()); - tmpList = s3InfoListIter->second; - ASSERT_EQ(1, tmpList.s3chunks_size()); - tmp = tmpList.s3chunks(0); - ASSERT_EQ(2 * 1024 * 1024, tmp.len()); - ASSERT_EQ(0, tmp.offset()); - - offset = 512; - len = 1 * 1024 * 1024; - char *readBuf = new char[len + 1]; - char *expectBuf = new char[len + 1]; - memset(readBuf, 0, len + 1); - memset(expectBuf, 'a', len); - memset(expectBuf + len, 0, 1); - - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - s3ClientAdaptor_->ReleaseCache(inode.inodeid()); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - // cleanup - delete buf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_flush_write_and_read3) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 1 * 1024 * 1024; - uint64_t len = 1 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - - uint64_t chunkId = 25; - - EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) - .WillRepeatedly( - DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))); - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Invoke(S3Upload)); - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillRepeatedly( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - EXPECT_CALL(mockS3Client_, UploadAsync(_)) - .WillRepeatedly( - Invoke([&](const std::shared_ptr &context) { - S3Data &tmp = gObjectDataMaps[context->key]; - tmp.len = context->bufferSize; - tmp.buf = new char[context->bufferSize]; - strncpy(tmp.buf, context->buffer, context->bufferSize); - context->retCode = 0; - context->cb(context); - })); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); - uint64_t len1 = inode.length(); - inode = inodeWrapper->GetInodeUnlocked(); - inode.set_length(len1); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(1, inode.s3chunkinfomap_size()); - - offset = 0; - len = 1 * 1024 * 1024; - char *readBuf = new char[len + 1]; - memset(readBuf, 'a', len); - memset(readBuf + len, 0, 1); - char *expectBuf = new char[len + 1]; - memset(expectBuf, 0, len + 1); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - offset = 2 * 1024 * 1024; - inode.set_length(offset + len); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - s3ClientAdaptor_->ReleaseCache(inode.inodeid()); - - offset = 0; - len = 3 * 1024 * 1024; - char *readBuf1 = new char[len + 1]; - char *expectBuf1 = new char[len + 1]; - memset(readBuf1, 'b', len); - memset(readBuf1 + len, 0, 1); - memset(expectBuf1, 0, len + 1); - memset(expectBuf1 + 1024 * 1024, 'a', 1024 * 1024); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf1); - EXPECT_STREQ(expectBuf1, readBuf1); - - s3ClientAdaptor_->ReleaseCache(inode.inodeid()); - offset = 1.5 * 1024 * 1024; - len = 1 * 1024 * 1024; - char *readBuf2 = new char[len + 1]; - char *expectBuf2 = new char[len + 1]; - memset(readBuf2, 'b', len); - memset(readBuf2 + len, 0, 1); - memset(expectBuf2, 0, len + 1); - memset(expectBuf2, 'a', 0.5 * 1024 * 1024); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf2); - EXPECT_STREQ(expectBuf2, readBuf2); - - // cleanup - delete buf; - delete readBuf; - delete expectBuf; - delete readBuf1; - delete expectBuf1; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_flush_write_and_read4) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 0 * 1024 * 1024; - uint64_t len = 2 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - - uint64_t chunkId = 25; - uint64_t chunkId1 = 26; - EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) - .WillOnce(DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))) - .WillOnce(DoAll(SetArgPointee<1>(chunkId1), Return(FSStatusCode::OK))); - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Invoke(S3Upload)); - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillRepeatedly( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - EXPECT_CALL(mockS3Client_, UploadAsync(_)) - .WillRepeatedly( - Invoke([&](const std::shared_ptr &context) { - S3Data &tmp = gObjectDataMaps[context->key]; - tmp.len = context->bufferSize; - tmp.buf = new char[context->bufferSize]; - strncpy(tmp.buf, context->buffer, context->bufferSize); - context->retCode = 0; - context->cb(context); - })); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); - uint64_t len1 = inode.length(); - inode = inodeWrapper->GetInodeUnlocked(); - inode.set_length(len1); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(1, inode.s3chunkinfomap_size()); - - offset = 1 * 1024 * 1024; - memset(buf, 'b', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - fsCacheManager = s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - ret = s3ClientAdaptor_->Flush(inode.inodeid()); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(1, inode.s3chunkinfomap_size()); - - s3ClientAdaptor_->ReleaseCache(inode.inodeid()); - len = 1 * 1024 * 1024; - char *readBuf = new char[len + 1]; - memset(readBuf, 'c', len); - memset(readBuf + len, 0, 1); - char *expectBuf = new char[len + 1]; - memset(expectBuf, 'b', len); - memset(expectBuf + len, 0, 1); - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - // cleanup - delete buf; - delete readBuf; - delete expectBuf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_flush_write_and_read5) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 0; - uint64_t len = 1 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', 512 * 1024); - memset(buf + 512 * 1024, 'b', 512 * 1024); - - uint64_t chunkId = 25; - uint64_t chunkId1 = 26; - EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) - .WillOnce(DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))) - .WillOnce(DoAll(SetArgPointee<1>(chunkId1), Return(FSStatusCode::OK))); - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Invoke(S3Upload)); - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillRepeatedly( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - EXPECT_CALL(mockS3Client_, UploadAsync(_)) - .WillRepeatedly( - Invoke([&](const std::shared_ptr &context) { - S3Data &tmp = gObjectDataMaps[context->key]; - tmp.len = context->bufferSize; - tmp.buf = new char[context->bufferSize]; - strncpy(tmp.buf, context->buffer, context->bufferSize); - context->retCode = 0; - context->cb(context); - })); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); - uint64_t len1 = inode.length(); - inode = inodeWrapper->GetInodeUnlocked(); - inode.set_length(len1); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(1, inode.s3chunkinfomap_size()); - - offset = 0; - len = 512 * 1024; - memset(buf, 'c', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(1024 * 1024); - - fsCacheManager = s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - ret = s3ClientAdaptor_->Flush(inode.inodeid()); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(1, inode.s3chunkinfomap_size()); - - s3ClientAdaptor_->ReleaseCache(inode.inodeid()); - inode = inodeWrapper->GetInodeUnlocked(); - inode.set_length(1024 * 1024); - auto s3ChunkInfoMap = inode.mutable_s3chunkinfomap(); - auto s3chunkInfoListIter = s3ChunkInfoMap->find(0); - ASSERT_EQ(2, s3chunkInfoListIter->second.s3chunks_size()); - - offset = 512 * 1024; - len = 1; - char *readBuf = new char[len + 1]; - memset(readBuf, 'c', len); - memset(readBuf + len, 0, 1); - char *expectBuf = new char[len + 1]; - memset(expectBuf, 'b', len); - memset(expectBuf + len, 0, 1); - - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - // cleanup - delete buf; - delete readBuf; - delete expectBuf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_flush_write_and_read6) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 1024; - uint64_t len = 1 * 1024 * 1024 - 2048; - char *buf = new char[len]; - memset(buf, 'a', len); - - uint64_t chunkId = 25; - uint64_t chunkId1 = 26; - EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) - .WillOnce(DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))) - .WillOnce(DoAll(SetArgPointee<1>(chunkId1), Return(FSStatusCode::OK))); - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Invoke(S3Upload)); - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillRepeatedly( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - EXPECT_CALL(mockS3Client_, UploadAsync(_)) - .WillRepeatedly( - Invoke([&](const std::shared_ptr &context) { - S3Data &tmp = gObjectDataMaps[context->key]; - tmp.len = context->bufferSize; - tmp.buf = new char[context->bufferSize]; - strncpy(tmp.buf, context->buffer, context->bufferSize); - context->retCode = 0; - context->cb(context); - })); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - // inode.set_length(offset + len); - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); - inode = inodeWrapper->GetInodeUnlocked(); - inode.set_length(offset + len); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(1, inode.s3chunkinfomap_size()); - - offset = 2048; - len = 512 * 1024; - memset(buf, 'b', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - - fsCacheManager = s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - ret = s3ClientAdaptor_->Flush(inode.inodeid()); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(1, inode.s3chunkinfomap_size()); - - s3ClientAdaptor_->ReleaseCache(inode.inodeid()); - inode = inodeWrapper->GetInodeUnlocked(); - inode.set_length(1024 * 1024); - auto s3ChunkInfoMap = inode.mutable_s3chunkinfomap(); - auto s3chunkInfoListIter = s3ChunkInfoMap->find(0); - ASSERT_EQ(2, s3chunkInfoListIter->second.s3chunks_size()); - - offset = 1024; - len = 1024 * 1024 - 2048; - char *readBuf = new char[len + 1]; - memset(readBuf, 'c', len); - memset(readBuf + len, 0, 1); - char *expectBuf = new char[len + 1]; - memset(expectBuf, 'a', len); - memset(expectBuf + 1024, 'b', 512 * 1024); - memset(expectBuf + len, 0, 1); - - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - // cleanup - delete buf; - delete readBuf; - delete expectBuf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_flush_write_and_read7) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 0; - uint64_t len = 1 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - - uint64_t chunkId = 25; - uint64_t chunkId1 = 26; - uint64_t chunkId2 = 27; - EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) - .WillOnce(DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))) - .WillOnce(DoAll(SetArgPointee<1>(chunkId1), Return(FSStatusCode::OK))) - .WillOnce(DoAll(SetArgPointee<1>(chunkId2), Return(FSStatusCode::OK))); - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Invoke(S3Upload)); - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillRepeatedly( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - EXPECT_CALL(mockS3Client_, UploadAsync(_)) - .WillRepeatedly( - Invoke([&](const std::shared_ptr &context) { - S3Data &tmp = gObjectDataMaps[context->key]; - tmp.len = context->bufferSize; - tmp.buf = new char[context->bufferSize]; - strncpy(tmp.buf, context->buffer, context->bufferSize); - context->retCode = 0; - context->cb(context); - })); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - // inode.set_length(offset + len); - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); - inode = inodeWrapper->GetInodeUnlocked(); - inode.set_length(offset + len); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(1, inode.s3chunkinfomap_size()); - - offset = 1024; - len = 512; - memset(buf, 'b', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - - fsCacheManager = s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - ret = s3ClientAdaptor_->Flush(inode.inodeid()); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(1, inode.s3chunkinfomap_size()); - - offset = 2048; - len = 512; - memset(buf, 'c', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - ret = s3ClientAdaptor_->Flush(inode.inodeid()); - - s3ClientAdaptor_->ReleaseCache(inode.inodeid()); - inode = inodeWrapper->GetInodeUnlocked(); - inode.set_length(1024 * 1024); - auto s3ChunkInfoMap = inode.mutable_s3chunkinfomap(); - auto s3chunkInfoListIter = s3ChunkInfoMap->find(0); - ASSERT_EQ(3, s3chunkInfoListIter->second.s3chunks_size()); - - offset = 0; - len = 1024 * 1024; - char *readBuf = new char[len + 1]; - memset(readBuf, 'd', len); - memset(readBuf + len, 0, 1); - char *expectBuf = new char[len + 1]; - memset(expectBuf, 'a', len); - memset(expectBuf + 1024, 'b', 512); - memset(expectBuf + 2048, 'c', 512); - memset(expectBuf + len, 0, 1); - - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - // cleanup - delete buf; - delete readBuf; - delete expectBuf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_flush_write_and_read8) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 20971520; - uint64_t len = 4194304; - char *buf = new char[len]; - memset(buf, 'a', len); - - uint64_t chunkId = 25; - uint64_t chunkId1 = 26; - uint64_t chunkId2 = 27; - inode.set_length(offset + len); - EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) - .WillOnce(DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))) - .WillOnce(DoAll(SetArgPointee<1>(chunkId1), Return(FSStatusCode::OK))) - .WillOnce(DoAll(SetArgPointee<1>(chunkId2), Return(FSStatusCode::OK))); - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Invoke(S3Upload)); - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillRepeatedly( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - EXPECT_CALL(mockS3Client_, UploadAsync(_)) - .WillRepeatedly( - Invoke([&](const std::shared_ptr &context) { - S3Data &tmp = gObjectDataMaps[context->key]; - tmp.len = context->bufferSize; - tmp.buf = new char[context->bufferSize]; - strncpy(tmp.buf, context->buffer, context->bufferSize); - context->retCode = 0; - context->cb(context); - })); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); - inode = inodeWrapper->GetInodeUnlocked(); - - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(1, inode.s3chunkinfomap_size()); - - len = 524288; - memset(buf, 'b', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - - fsCacheManager = s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - ret = s3ClientAdaptor_->Flush(inode.inodeid()); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(1, inode.s3chunkinfomap_size()); - - len = 1048576; - memset(buf, 'c', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - ret = s3ClientAdaptor_->Flush(inode.inodeid()); - - s3ClientAdaptor_->ReleaseCache(inode.inodeid()); - inode = inodeWrapper->GetInodeUnlocked(); - - auto s3ChunkInfoMap = inode.mutable_s3chunkinfomap(); - auto s3chunkInfoListIter = s3ChunkInfoMap->find(5); - ASSERT_EQ(3, s3chunkInfoListIter->second.s3chunks_size()); - - offset = 20971520; - len = 4194304; - char *readBuf = new char[len + 1]; - memset(readBuf, 'd', len); - memset(readBuf + len, 0, 1); - char *expectBuf = new char[len + 1]; - memset(expectBuf, 'a', len); - memset(expectBuf, 'c', 1048576); - memset(expectBuf + len, 0, 1); - - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - // cleanup - delete buf; - delete readBuf; - delete expectBuf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_flush_write_and_read9) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 92274688; - uint64_t len = 4194304; - char *buf = new char[len]; - memset(buf, 'a', len); - memset(buf + (93210624 - 92274688), 'b', 1024); - - uint64_t chunkId = 25; - uint64_t chunkId1 = 26; - uint64_t chunkId2 = 27; - inode.set_length(offset + len); - EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) - .WillOnce(DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))) - .WillOnce(DoAll(SetArgPointee<1>(chunkId1), Return(FSStatusCode::OK))) - .WillOnce(DoAll(SetArgPointee<1>(chunkId2), Return(FSStatusCode::OK))); - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Invoke(S3Upload)); - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillRepeatedly( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - EXPECT_CALL(mockS3Client_, UploadAsync(_)) - .WillRepeatedly( - Invoke([&](const std::shared_ptr &context) { - S3Data &tmp = gObjectDataMaps[context->key]; - tmp.len = context->bufferSize; - tmp.buf = new char[context->bufferSize]; - strncpy(tmp.buf, context->buffer, context->bufferSize); - context->retCode = 0; - context->cb(context); - })); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); - inode = inodeWrapper->GetInodeUnlocked(); - - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(1, inode.s3chunkinfomap_size()); - - offset = 92405760; - len = 1024; - memset(buf, 'c', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - - fsCacheManager = s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - ret = s3ClientAdaptor_->Flush(inode.inodeid()); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(1, inode.s3chunkinfomap_size()); - - offset = 93547520; - len = 1024; - memset(buf, 'd', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - ret = s3ClientAdaptor_->Flush(inode.inodeid()); - - s3ClientAdaptor_->ReleaseCache(inode.inodeid()); - inode = inodeWrapper->GetInodeUnlocked(); - - auto s3ChunkInfoMap = inode.mutable_s3chunkinfomap(); - auto s3chunkInfoListIter = s3ChunkInfoMap->find(22); - ASSERT_EQ(3, s3chunkInfoListIter->second.s3chunks_size()); - - offset = 93210624; - len = 1024; - char *readBuf = new char[len + 1]; - memset(readBuf, 'e', len); - memset(readBuf + len, 0, 1); - char *expectBuf = new char[len + 1]; - memset(expectBuf, 'b', len); - memset(expectBuf + len, 0, 1); - - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - // cleanup - delete buf; - delete readBuf; - delete expectBuf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_flush_write_and_read10) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 8388608; - uint64_t len = 4194304; - char *buf = new char[len]; - memset(buf, 'a', len); - - uint64_t chunkId = 1; - uint64_t chunkId1 = 2; - uint64_t chunkId2 = 3; - uint64_t chunkId3 = 4; - uint64_t chunkId4 = 5; - uint64_t chunkId5 = 6; - uint64_t chunkId6 = 7; - inode.set_length(offset + len); - EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) - .WillOnce(DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))) - .WillOnce(DoAll(SetArgPointee<1>(chunkId1), Return(FSStatusCode::OK))) - .WillOnce(DoAll(SetArgPointee<1>(chunkId2), Return(FSStatusCode::OK))) - .WillOnce(DoAll(SetArgPointee<1>(chunkId3), Return(FSStatusCode::OK))) - .WillOnce(DoAll(SetArgPointee<1>(chunkId4), Return(FSStatusCode::OK))) - .WillOnce(DoAll(SetArgPointee<1>(chunkId5), Return(FSStatusCode::OK))) - .WillOnce(DoAll(SetArgPointee<1>(chunkId6), Return(FSStatusCode::OK))); - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Invoke(S3Upload)); - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillRepeatedly( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - EXPECT_CALL(mockS3Client_, UploadAsync(_)) - .WillRepeatedly( - Invoke([&](const std::shared_ptr &context) { - S3Data &tmp = gObjectDataMaps[context->key]; - tmp.len = context->bufferSize; - tmp.buf = new char[context->bufferSize]; - strncpy(tmp.buf, context->buffer, context->bufferSize); - context->retCode = 0; - context->cb(context); - })); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); - inode = inodeWrapper->GetInodeUnlocked(); - - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(1, inode.s3chunkinfomap_size()); - - offset = 8818688; - len = 4096; - memset(buf, 'b', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - - fsCacheManager = s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - ret = s3ClientAdaptor_->Flush(inode.inodeid()); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(1, inode.s3chunkinfomap_size()); - - offset = 9961472; - len = 1048576; - memset(buf, 'c', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - ret = s3ClientAdaptor_->Flush(inode.inodeid()); - - offset = 8523776; - len = 4096; - memset(buf, 'd', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - ret = s3ClientAdaptor_->Flush(inode.inodeid()); - - offset = 8732672; - len = 512; - memset(buf, 'e', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - ret = s3ClientAdaptor_->Flush(inode.inodeid()); - - offset = 9184768; - len = 512; - memset(buf, 'f', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - ret = s3ClientAdaptor_->Flush(inode.inodeid()); - - offset = 9437184; - len = 1048576; - memset(buf, 'g', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - ret = s3ClientAdaptor_->Flush(inode.inodeid()); - - - s3ClientAdaptor_->ReleaseCache(inode.inodeid()); - inode = inodeWrapper->GetInodeUnlocked(); - /* - auto s3ChunkInfoMap = inode.mutable_s3chunkinfomap(); - auto s3chunkInfoListIter = s3ChunkInfoMap->find(22); - ASSERT_EQ(3, s3chunkInfoListIter->second.s3chunks_size()); - */ - offset = 9437184; - len = 131072; - char *readBuf = new char[len + 1]; - memset(readBuf, 'h', len); - memset(readBuf + len, 0, 1); - char *expectBuf = new char[len + 1]; - memset(expectBuf, 'g', len); - memset(expectBuf + len, 0, 1); - - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - // cleanup - delete buf; - delete readBuf; - delete expectBuf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_flush_write_and_read11) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 196608; - uint64_t len = 131072; - char *buf = new char[len]; - memset(buf, 'a', len); - - uint64_t chunkId = 1; - uint64_t chunkId1 = 2; - - inode.set_length(offset + len); - EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) - .WillOnce(DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))) - .WillOnce(DoAll(SetArgPointee<1>(chunkId1), Return(FSStatusCode::OK))); - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Invoke(S3Upload)); - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillRepeatedly( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - EXPECT_CALL(mockS3Client_, UploadAsync(_)) - .WillRepeatedly( - Invoke([&](const std::shared_ptr &context) { - S3Data &tmp = gObjectDataMaps[context->key]; - tmp.len = context->bufferSize; - tmp.buf = new char[context->bufferSize]; - strncpy(tmp.buf, context->buffer, context->bufferSize); - context->retCode = 0; - context->cb(context); - })); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); - inode = inodeWrapper->GetInodeUnlocked(); - - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(1, inode.s3chunkinfomap_size()); - - offset = 323584; - len = 4096; - memset(buf, 'b', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - - fsCacheManager = s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - ret = s3ClientAdaptor_->Flush(inode.inodeid()); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(1, inode.s3chunkinfomap_size()); - - s3ClientAdaptor_->ReleaseCache(inode.inodeid()); - inode = inodeWrapper->GetInodeUnlocked(); - - offset = 196608; - len = 131072; - char *readBuf = new char[len + 1]; - memset(readBuf, 'c', len); - memset(readBuf + len, 0, 1); - char *expectBuf = new char[len + 1]; - memset(expectBuf, 'a', len); - memset(expectBuf + 126976, 'b', 4096); - memset(expectBuf + len, 0, 1); - - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - // cleanup - delete buf; - delete readBuf; - delete expectBuf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_flush_write_and_read12) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 196608; - uint64_t len = 131072; - char *buf = new char[len]; - memset(buf, 'a', len); - - uint64_t chunkId = 1; - uint64_t chunkId1 = 2; - - inode.set_length(offset + len); - EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) - .WillOnce(DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))) - .WillOnce(DoAll(SetArgPointee<1>(chunkId1), Return(FSStatusCode::OK))); - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Invoke(S3Upload)); - EXPECT_CALL(mockS3Client_, Download(_, _, _, _)) - .WillRepeatedly(Invoke(S3Download)); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillRepeatedly( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - EXPECT_CALL(mockS3Client_, UploadAsync(_)) - .WillRepeatedly( - Invoke([&](const std::shared_ptr &context) { - S3Data &tmp = gObjectDataMaps[context->key]; - tmp.len = context->bufferSize; - tmp.buf = new char[context->bufferSize]; - strncpy(tmp.buf, context->buffer, context->bufferSize); - context->retCode = 0; - context->cb(context); - })); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - CURVEFS_ERROR ret = s3ClientAdaptor_->Flush(inode.inodeid()); - inode = inodeWrapper->GetInodeUnlocked(); - - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(1, inode.s3chunkinfomap_size()); - - offset = 323584; - len = 4096; - memset(buf, 'b', len); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - - fsCacheManager = s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - ret = s3ClientAdaptor_->Flush(inode.inodeid()); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - ASSERT_EQ(1, inode.s3chunkinfomap_size()); - - s3ClientAdaptor_->ReleaseCache(inode.inodeid()); - inode = inodeWrapper->GetInodeUnlocked(); - - offset = 196608; - len = 131072; - char *readBuf = new char[len + 1]; - memset(readBuf, 'c', len); - memset(readBuf + len, 0, 1); - char *expectBuf = new char[len + 1]; - memset(expectBuf, 'a', len); - memset(expectBuf + 126976, 'b', 4096); - memset(expectBuf + len, 0, 1); - - s3ClientAdaptor_->Read(inode.inodeid(), offset, len, readBuf); - EXPECT_STREQ(expectBuf, readBuf); - - // cleanup - delete buf; - delete readBuf; - delete expectBuf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_fssync_success_and_fail) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 0; - uint64_t len = 1 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - // mock - uint64_t chunkId = 25; - - EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) - .WillRepeatedly( - DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))); - - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillOnce( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))) - .WillOnce(DoAll(SetArgReferee<1>(inodeWrapper), - Return(CURVEFS_ERROR::INTERNAL))) - .WillOnce(DoAll(SetArgReferee<1>(inodeWrapper), - Return(CURVEFS_ERROR::INTERNAL))); - EXPECT_CALL(mockS3Client_, UploadAsync(_)) - .WillRepeatedly( - Invoke([&](const std::shared_ptr &context) { - S3Data &tmp = gObjectDataMaps[context->key]; - tmp.len = context->bufferSize; - tmp.buf = new char[context->bufferSize]; - strncpy(tmp.buf, context->buffer, context->bufferSize); - context->retCode = 0; - context->cb(context); - })); - - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - - CURVEFS_ERROR ret = s3ClientAdaptor_->FsSync(); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - ret = s3ClientAdaptor_->FsSync(); - ASSERT_EQ(CURVEFS_ERROR::INTERNAL, ret); - - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - ret = s3ClientAdaptor_->FsSync(); - ASSERT_EQ(CURVEFS_ERROR::INTERNAL, ret); - - // cleanup - delete buf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); -} - -TEST_F(ClientS3AdaptorTest, test_fssync_overlap_write) { - curvefs::metaserver::Inode inode; - - InitInode(&inode); - uint64_t offset = 0; - uint64_t len = 2 * 1024 * 1024; - char *buf = new char[len]; - memset(buf, 'a', len); - // mock - uint64_t chunkId = 25; - - EXPECT_CALL(mockMdsClient_, AllocS3ChunkId(_, _)) - .WillOnce(DoAll(SetArgPointee<1>(chunkId), Return(FSStatusCode::OK))); - EXPECT_CALL(mockS3Client_, Upload(_, _, _)) - .WillRepeatedly(Return(1 * 1024 * 1024)); - auto inodeWrapper = std::make_shared(inode, nullptr); - EXPECT_CALL(mockInodeManager_, GetInode(_, _)) - .WillOnce( - DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); - EXPECT_CALL(mockS3Client_, UploadAsync(_)) - .WillRepeatedly( - Invoke([&](const std::shared_ptr &context) { - S3Data &tmp = gObjectDataMaps[context->key]; - tmp.len = context->bufferSize; - tmp.buf = new char[context->bufferSize]; - strncpy(tmp.buf, context->buffer, context->bufferSize); - context->retCode = 0; - context->cb(context); - })); - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - offset = 1 * 1024 * 1024; - s3ClientAdaptor_->Write(inode.inodeid(), offset, len, buf); - inode.set_length(offset + len); - - std::shared_ptr fsCacheManager = - s3ClientAdaptor_->GetFsCacheManager(); - ASSERT_EQ(1, fsCacheManager->GetDataCacheNum()); - - CURVEFS_ERROR ret = s3ClientAdaptor_->FsSync(); - ASSERT_EQ(CURVEFS_ERROR::OK, ret); - ASSERT_EQ(0, fsCacheManager->GetDataCacheNum()); - /* - auto size = inode.s3chunkinfomap_size(); - auto s3InfoListIter = inode.s3chunkinfomap().find(chunkIndex); - S3ChunkInfo tmp; - ASSERT_NE(s3InfoListIter, inode.s3chunkinfomap().end()); - ASSERT_EQ(1, s3InfoListIter->second.s3chunks_size()); - tmp = s3InfoListIter->second.s3chunks(0); - ASSERT_EQ(3 * 1024 * 1024, tmp.len()); - ASSERT_EQ(0, tmp.offset());*/ - - // cleanup - delete buf; - std::map::iterator iter = gObjectDataMaps.begin(); - for (; iter != gObjectDataMaps.end(); iter++) { - delete iter->second.buf; - iter->second.buf = NULL; - } - gObjectDataMaps.clear(); + LOG(INFO) << "############ case1: clear write cache fail"; + auto filecache = std::make_shared(); + EXPECT_CALL(*mockFsCacheManager_, FindFileCacheManager(_)) + .WillOnce(Return(filecache)); + EXPECT_CALL(*filecache, Flush(_, _)).WillOnce(Return(CURVEFS_ERROR::OK)); + EXPECT_CALL(*mockDiskcacheManagerImpl_, UploadWriteCacheByInode(_)) + .WillOnce(Return(-1)); + ASSERT_EQ(CURVEFS_ERROR::INTERNAL, s3ClientAdaptor_->FlushAllCache(1)); + + LOG(INFO) + << "############ case2: clear write cache ok, update write cache ok "; + EXPECT_CALL(*mockFsCacheManager_, FindFileCacheManager(_)) + .WillOnce(Return(filecache)); + EXPECT_CALL(*filecache, Flush(_, _)).WillOnce(Return(CURVEFS_ERROR::OK)); + EXPECT_CALL(*mockDiskcacheManagerImpl_, UploadWriteCacheByInode(_)) + .WillOnce(Return(0)); + ASSERT_EQ(CURVEFS_ERROR::OK, s3ClientAdaptor_->FlushAllCache(1)); } } // namespace client diff --git a/curvefs/test/client/client_s3_adaptor_test2.cpp b/curvefs/test/client/client_s3_adaptor_test2.cpp deleted file mode 100644 index d93adfee99..0000000000 --- a/curvefs/test/client/client_s3_adaptor_test2.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2021 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: Thur Jun 22 2021 - * Author: huyao - */ - - -#include -#include -#include - -#include "curvefs/test/client/mock_disk_cache_manager.h" -#include "curvefs/test/client/mock_inode_cache_manager.h" -#include "src/common/curve_define.h" -#include "curvefs/src/client/s3/client_s3_adaptor.h" - - -namespace curvefs { -namespace client { -using ::curve::common::kMB; -using ::testing::_; -using ::testing::DoAll; -using ::testing::Invoke; -using ::testing::Return; -using ::testing::SetArgPointee; -using ::testing::SetArgReferee; -using ::testing::WithArg; - -class ClientS3AdaptorTest2 : public testing::Test { - protected: - ClientS3AdaptorTest2() {} - ~ClientS3AdaptorTest2() {} - void SetUp() override { - s3ClientAdaptor_ = std::make_shared(); - mockInodeManager_ = std::make_shared(); - mockDiskcacheManagerImpl_ = - std::make_shared(); - mockFsCacheManager_ = std::make_shared(); - - s3ClientAdaptor_->InitForTest(mockDiskcacheManagerImpl_, - mockFsCacheManager_, mockInodeManager_); - } - - void TearDown() override {} - - void GetInode(curvefs::metaserver::Inode *inode) { - inode->set_inodeid(1); - inode->set_fsid(2); - inode->set_length(0); - inode->set_ctime(1623835517); - inode->set_ctime_ns(1623835517); - inode->set_mtime(1623835517); - inode->set_atime(1623835517); - inode->set_atime_ns(1623835517); - inode->set_uid(1); - inode->set_gid(1); - inode->set_mode(1); - inode->set_nlink(1); - inode->set_type(curvefs::metaserver::FsFileType::TYPE_S3); - } - - protected: - std::shared_ptr s3ClientAdaptor_; - std::shared_ptr mockInodeManager_; - std::shared_ptr mockDiskcacheManagerImpl_; - std::shared_ptr mockFsCacheManager_; -}; - - -TEST_F(ClientS3AdaptorTest2, FlushAllCache_no_filecachaeManager) { - EXPECT_CALL(*mockFsCacheManager_, FindFileCacheManager(_)) - .WillOnce(Return(nullptr)); - ASSERT_EQ(CURVEFS_ERROR::OK, s3ClientAdaptor_->FlushAllCache(1)); -} - -TEST_F(ClientS3AdaptorTest2, FlushAllCache_flush_fail) { - auto filecache = std::make_shared(); - EXPECT_CALL(*mockFsCacheManager_, FindFileCacheManager(_)) - .WillOnce(Return(filecache)); - EXPECT_CALL(*filecache, Flush(_, _)) - .WillOnce(Return(CURVEFS_ERROR::INTERNAL)); - ASSERT_EQ(CURVEFS_ERROR::INTERNAL, s3ClientAdaptor_->FlushAllCache(1)); -} - -TEST_F(ClientS3AdaptorTest2, FlushAllCache_with_no_cache) { - s3ClientAdaptor_->SetDiskCache(DiskCacheType::Disable); - - LOG(INFO) << "############ case1: do not find file cache"; - auto filecache = std::make_shared(); - EXPECT_CALL(*mockFsCacheManager_, FindFileCacheManager(_)) - .WillOnce(Return(nullptr)); - ASSERT_EQ(CURVEFS_ERROR::OK, s3ClientAdaptor_->FlushAllCache(1)); - - LOG(INFO) << "############ case2: find file cache"; - EXPECT_CALL(*mockFsCacheManager_, FindFileCacheManager(_)) - .WillOnce(Return(filecache)); - EXPECT_CALL(*filecache, Flush(_, _)).WillOnce(Return(CURVEFS_ERROR::OK)); - ASSERT_EQ(CURVEFS_ERROR::OK, s3ClientAdaptor_->FlushAllCache(1)); -} - -TEST_F(ClientS3AdaptorTest2, FlushAllCache_with_cache) { - s3ClientAdaptor_->SetDiskCache(DiskCacheType::ReadWrite); - - LOG(INFO) << "############ case1: clear write cache fail"; - auto filecache = std::make_shared(); - EXPECT_CALL(*mockFsCacheManager_, FindFileCacheManager(_)) - .WillOnce(Return(filecache)); - EXPECT_CALL(*filecache, Flush(_, _)).WillOnce(Return(CURVEFS_ERROR::OK)); - EXPECT_CALL(*mockDiskcacheManagerImpl_, UploadWriteCacheByInode(_)) - .WillOnce(Return(-1)); - ASSERT_EQ(CURVEFS_ERROR::INTERNAL, s3ClientAdaptor_->FlushAllCache(1)); - - LOG(INFO) - << "############ case2: clear write cache ok, update write cache ok "; - EXPECT_CALL(*mockFsCacheManager_, FindFileCacheManager(_)) - .WillOnce(Return(filecache)); - EXPECT_CALL(*filecache, Flush(_, _)).WillOnce(Return(CURVEFS_ERROR::OK)); - EXPECT_CALL(*mockDiskcacheManagerImpl_, UploadWriteCacheByInode(_)) - .WillOnce(Return(0)); - ASSERT_EQ(CURVEFS_ERROR::OK, s3ClientAdaptor_->FlushAllCache(1)); -} - -} // namespace client -} // namespace curvefs diff --git a/curvefs/test/client/data_cache_test.cpp b/curvefs/test/client/data_cache_test.cpp new file mode 100644 index 0000000000..ef7c3c664d --- /dev/null +++ b/curvefs/test/client/data_cache_test.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2021 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: Wed Mar 23 2022 + * Author: huyao + */ + +#include +#include + +#include "curvefs/src/client/s3/client_s3_adaptor.h" +#include "curvefs/src/client/s3/client_s3_cache_manager.h" +#include "curvefs/test/client/mock_client_s3_cache_manager.h" + +namespace curvefs { +namespace client { +using ::testing::_; +using ::testing::DoAll; +using ::testing::Invoke; +using ::testing::Return; +using ::testing::SetArgPointee; +using ::testing::SetArgReferee; +using ::testing::WithArg; + +class DataCacheTest : public testing::Test { + protected: + DataCacheTest() {} + ~DataCacheTest() {} + void SetUp() override { + S3ClientAdaptorOption option; + option.blockSize = 1 * 1024 * 1024; + option.chunkSize = 4 * 1024 * 1024; + option.pageSize = 64 * 1024; + option.intervalSec = 5000; + option.flushIntervalSec = 5000; + option.readCacheMaxByte = 104857600; + option.diskCacheOpt.diskCacheType = (DiskCacheType)0; + s3ClientAdaptor_ = new S3ClientAdaptorImpl(); + auto fsCacheManager = std::make_shared( + s3ClientAdaptor_, option.readCacheMaxByte, + option.writeCacheMaxByte); + s3ClientAdaptor_->Init(option, nullptr, nullptr, nullptr, + fsCacheManager, nullptr); + mockChunkCacheManager_ = std::make_shared(); + uint64_t offset = 512 * 1024; + uint64_t len = 1024 * 1024; + char *buf = new char[len]; + dataCache_ = std::make_shared( + s3ClientAdaptor_, mockChunkCacheManager_, offset, len, buf); + delete buf; + } + void TearDown() override {} + + protected: + S3ClientAdaptorImpl *s3ClientAdaptor_; + std::shared_ptr dataCache_; + std::shared_ptr mockChunkCacheManager_; +}; + +TEST_F(DataCacheTest, test_write1) { + uint64_t offset = 0; + uint64_t len = 1024 * 1024; + char *buf = new char[len]; + std::vector mergeDataCacheVer; + dataCache_->Write(offset, len, buf, mergeDataCacheVer); + ASSERT_EQ(0, dataCache_->GetChunkPos()); + ASSERT_EQ(1536 * 1024, dataCache_->GetLen()); + delete buf; +} + +TEST_F(DataCacheTest, test_write2) { + uint64_t offset = 0; + uint64_t len = 2 * 1024 * 1024; + char *buf = new char[len]; + std::vector mergeDataCacheVer; + dataCache_->Write(offset, len, buf, mergeDataCacheVer); + ASSERT_EQ(0, dataCache_->GetChunkPos()); + ASSERT_EQ(2048 * 1024, dataCache_->GetLen()); + delete buf; +} + +TEST_F(DataCacheTest, test_write3) { + uint64_t offset = 0; + uint64_t len = 2 * 1024 * 1024; + char *buf = new char[len]; + std::vector mergeDataCacheVer; + uint64_t offset1 = len; + auto dataCache = std::make_shared( + s3ClientAdaptor_, mockChunkCacheManager_, offset1, len, buf); + mergeDataCacheVer.push_back(dataCache); + dataCache_->Write(offset, len, buf, mergeDataCacheVer); + ASSERT_EQ(0, dataCache_->GetChunkPos()); + ASSERT_EQ(4096 * 1024, dataCache_->GetLen()); + delete buf; +} + +TEST_F(DataCacheTest, test_write4) { + uint64_t offset = 512 * 1204; + uint64_t len = 512 * 1024; + char *buf = new char[len]; + std::vector mergeDataCacheVer; + dataCache_->Write(offset, len, buf, mergeDataCacheVer); + ASSERT_EQ(512 * 1024, dataCache_->GetChunkPos()); + ASSERT_EQ(1024 * 1024, dataCache_->GetLen()); + delete buf; +} + +TEST_F(DataCacheTest, test_write5) { + uint64_t offset = 1024 * 1024; + uint64_t len = 1024 * 1024; + char *buf = new char[len]; + std::vector mergeDataCacheVer; + dataCache_->Write(offset, len, buf, mergeDataCacheVer); + ASSERT_EQ(512 * 1024, dataCache_->GetChunkPos()); + ASSERT_EQ(1536 * 1024, dataCache_->GetLen()); + delete buf; +} + +TEST_F(DataCacheTest, test_write6) { + uint64_t offset = 1024 * 1024; + uint64_t len = 1024 * 1024; + char *buf = new char[len]; + std::vector mergeDataCacheVer; + uint64_t offset1 = offset + len; + auto dataCache = std::make_shared( + s3ClientAdaptor_, mockChunkCacheManager_, offset1, len, buf); + mergeDataCacheVer.push_back(dataCache); + dataCache_->Write(offset, len, buf, mergeDataCacheVer); + ASSERT_EQ(512 * 1024, dataCache_->GetChunkPos()); + ASSERT_EQ(2560 * 1024, dataCache_->GetLen()); + delete buf; +} + +TEST_F(DataCacheTest, test_truncate1) { + uint64_t size = 0; + dataCache_->Truncate(size); + ASSERT_EQ(0, dataCache_->GetLen()); +} + +TEST_F(DataCacheTest, test_truncate2) { + uint64_t size = 512 * 1024; + dataCache_->Truncate(size); + ASSERT_EQ(512 * 1024, dataCache_->GetLen()); +} + +TEST_F(DataCacheTest, test_truncate3) { + uint64_t size = 2; + dataCache_->Truncate(size); + ASSERT_EQ(2, dataCache_->GetLen()); +} + +} // namespace client +} // namespace curvefs diff --git a/curvefs/test/client/file_cache_manager_test.cpp b/curvefs/test/client/file_cache_manager_test.cpp new file mode 100644 index 0000000000..b07ad61e43 --- /dev/null +++ b/curvefs/test/client/file_cache_manager_test.cpp @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2021 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: Wed Mar 23 2022 + * Author: huyao + */ + +#include +#include + +#include "curvefs/src/client/s3/client_s3_adaptor.h" +#include "curvefs/src/client/s3/client_s3_cache_manager.h" +#include "curvefs/test/client/mock_client_s3_cache_manager.h" +#include "curvefs/test/client/mock_inode_cache_manager.h" +#include "curvefs/test/client/mock_client_s3.h" + +namespace curvefs { +namespace client { +using ::testing::_; +using ::testing::DoAll; +using ::testing::Invoke; +using ::testing::Return; +using ::testing::SetArgPointee; +using ::testing::SetArgReferee; +using ::testing::WithArg; + +class FileCacheManagerTest : public testing::Test { + protected: + FileCacheManagerTest() {} + ~FileCacheManagerTest() {} + void SetUp() override { + uint64_t inodeId = 1; + uint64_t fsId = 2; + S3ClientAdaptorOption option; + option.blockSize = 1 * 1024 * 1024; + option.chunkSize = 4 * 1024 * 1024; + option.pageSize = 64 * 1024; + option.intervalSec = 5000; + option.flushIntervalSec = 5000; + option.readCacheMaxByte = 104857600; + option.writeCacheMaxByte = 10485760000; + option.diskCacheOpt.diskCacheType = (DiskCacheType)0; + s3ClientAdaptor_ = new S3ClientAdaptorImpl(); + auto fsCacheManager_ = std::make_shared( + s3ClientAdaptor_, option.readCacheMaxByte, + option.writeCacheMaxByte); + mockInodeManager_ = std::make_shared(); + mockS3Client_ = std::make_shared(); + s3ClientAdaptor_->Init(option, mockS3Client_, mockInodeManager_, + nullptr, fsCacheManager_, nullptr); + s3ClientAdaptor_->SetFsId(fsId); + fileCacheManager_ = + std::make_shared(fsId, inodeId, s3ClientAdaptor_); + mockChunkCacheManager_ = std::make_shared(); + } + + void TearDown() override { + // s3ClientAdaptor_->Stop(); + delete s3ClientAdaptor_; + s3ClientAdaptor_ = nullptr; + } + + protected: + S3ClientAdaptorImpl *s3ClientAdaptor_; + std::shared_ptr fileCacheManager_; + std::shared_ptr mockChunkCacheManager_; + std::shared_ptr mockInodeManager_; + std::shared_ptr mockS3Client_; +}; + +TEST_F(FileCacheManagerTest, test_FindOrCreateChunkCacheManager) { + uint64_t index = 0; + + auto chunkCaCheManager = + fileCacheManager_->FindOrCreateChunkCacheManager(index); + ASSERT_EQ(chunkCaCheManager, + fileCacheManager_->FindOrCreateChunkCacheManager(index)); +} + +TEST_F(FileCacheManagerTest, test_release_cache) { + uint64_t index = 0; + + auto chunkCaCheManager = + fileCacheManager_->FindOrCreateChunkCacheManager(index); + fileCacheManager_->ReleaseCache(); + auto chunkCaCheManager1 = + fileCacheManager_->FindOrCreateChunkCacheManager(index); + ASSERT_NE(chunkCaCheManager, chunkCaCheManager1); +} + +TEST_F(FileCacheManagerTest, test_flush_ok) { + uint64_t index = 0; + + EXPECT_CALL(*mockChunkCacheManager_, Flush(_, _, _)) + .WillOnce(Return(CURVEFS_ERROR::OK)); + fileCacheManager_->SetChunkCacheManagerForTest(index, + mockChunkCacheManager_); + ASSERT_EQ(CURVEFS_ERROR::OK, fileCacheManager_->Flush(true, true)); +} + +TEST_F(FileCacheManagerTest, test_flush_fail) { + uint64_t index = 0; + + EXPECT_CALL(*mockChunkCacheManager_, Flush(_, _, _)) + .WillOnce(Return(CURVEFS_ERROR::INTERNAL)); + fileCacheManager_->SetChunkCacheManagerForTest(index, + mockChunkCacheManager_); + ASSERT_EQ(CURVEFS_ERROR::INTERNAL, fileCacheManager_->Flush(true, true)); +} + +TEST_F(FileCacheManagerTest, test_new_write) { + uint64_t offset = 0; + uint64_t len = 5 * 1024 * 1024; + char buf[len] = {0}; + + memset(buf, 'a', len); + EXPECT_CALL(*mockChunkCacheManager_, FindWriteableDataCache(_, _, _, _)) + .WillOnce(Return(nullptr)) + .WillOnce(Return(nullptr)); + EXPECT_CALL(*mockChunkCacheManager_, WriteNewDataCache(_, _, _, _)) + .WillOnce(Return()) + .WillOnce(Return()); + fileCacheManager_->SetChunkCacheManagerForTest(0, mockChunkCacheManager_); + fileCacheManager_->SetChunkCacheManagerForTest(1, mockChunkCacheManager_); + ASSERT_EQ(len, fileCacheManager_->Write(offset, len, buf)); +} + +TEST_F(FileCacheManagerTest, test_old_write) { + uint64_t offset = 0; + uint64_t len = 1024; + char buf[len] = {0}; + + auto dataCache = std::make_shared(s3ClientAdaptor_, nullptr, + offset, 0, nullptr); + EXPECT_CALL(*dataCache, Write(_, _, _, _)).WillOnce(Return()); + EXPECT_CALL(*mockChunkCacheManager_, FindWriteableDataCache(_, _, _, _)) + .WillOnce(Return(dataCache)); + EXPECT_CALL(*mockChunkCacheManager_, ReleaseCache()).WillOnce(Return()); + fileCacheManager_->SetChunkCacheManagerForTest(0, mockChunkCacheManager_); + ASSERT_EQ(len, fileCacheManager_->Write(offset, len, buf)); + fileCacheManager_->ReleaseCache(); +} + +TEST_F(FileCacheManagerTest, test_read_cache) { + uint64_t inodeId = 1; + uint64_t offset = 0; + uint64_t len = 5 * 1024 * 1024; + char buf[len] = {0}; + ReadRequest request; + std::vector requests; + std::vector emptyRequests; + requests.emplace_back(request); + EXPECT_CALL(*mockChunkCacheManager_, ReadByWriteCache(_, _, _, _, _)) + .WillOnce(DoAll(SetArgPointee<4>(requests), Return())) + .WillOnce(DoAll(SetArgPointee<4>(requests), Return())); + EXPECT_CALL(*mockChunkCacheManager_, ReadByReadCache(_, _, _, _, _)) + .WillOnce(DoAll(SetArgPointee<4>(emptyRequests), Return())) + .WillOnce(DoAll(SetArgPointee<4>(emptyRequests), Return())); + fileCacheManager_->SetChunkCacheManagerForTest(0, mockChunkCacheManager_); + fileCacheManager_->SetChunkCacheManagerForTest(1, mockChunkCacheManager_); + + ASSERT_EQ(len, fileCacheManager_->Read(inodeId, offset, len, buf)); +} + +TEST_F(FileCacheManagerTest, test_read_getinode_fail) { + uint64_t inodeId = 1; + uint64_t offset = 0; + uint64_t len = 1024; + char buf[len] = {0}; + + ReadRequest request; + std::vector requests; + request.index = 0; + request.chunkPos = offset; + request.len = len; + request.bufOffset = 0; + requests.emplace_back(request); + EXPECT_CALL(*mockChunkCacheManager_, ReadByWriteCache(_, _, _, _, _)) + .WillOnce(DoAll(SetArgPointee<4>(requests), Return())); + EXPECT_CALL(*mockChunkCacheManager_, ReadByReadCache(_, _, _, _, _)) + .WillOnce(DoAll(SetArgPointee<4>(requests), Return())); + fileCacheManager_->SetChunkCacheManagerForTest(0, mockChunkCacheManager_); + EXPECT_CALL(*mockInodeManager_, GetInode(_, _)) + .WillOnce(Return(CURVEFS_ERROR::NOTEXIST)); + ASSERT_EQ(-1, fileCacheManager_->Read(inodeId, offset, len, buf)); +} + +TEST_F(FileCacheManagerTest, test_read_s3) { + uint64_t inodeId = 1; + uint64_t offset = 0; + uint64_t len = 1024; + int length = len; + char *buf = new char[len]; + char *tmpbuf = new char[len]; + + memset(tmpbuf, 'a', len); + ReadRequest request; + std::vector requests; + request.index = 0; + request.chunkPos = offset; + request.len = len; + request.bufOffset = 0; + requests.emplace_back(request); + EXPECT_CALL(*mockChunkCacheManager_, ReadByWriteCache(_, _, _, _, _)) + .WillOnce(DoAll(SetArgPointee<4>(requests), Return())) + .WillOnce(DoAll(SetArgPointee<4>(requests), Return())); + EXPECT_CALL(*mockChunkCacheManager_, ReadByReadCache(_, _, _, _, _)) + .WillOnce(DoAll(SetArgPointee<4>(requests), Return())) + .WillOnce(DoAll(SetArgPointee<4>(requests), Return())); + EXPECT_CALL(*mockChunkCacheManager_, AddReadDataCache(_)) + .WillOnce(Return()); + fileCacheManager_->SetChunkCacheManagerForTest(0, mockChunkCacheManager_); + Inode inode; + inode.set_length(len); + auto s3ChunkInfoMap = inode.mutable_s3chunkinfomap(); + S3ChunkInfoList *s3ChunkInfoList = new S3ChunkInfoList(); + S3ChunkInfo *s3ChunkInfo = s3ChunkInfoList->add_s3chunks(); + s3ChunkInfo->set_chunkid(25); + s3ChunkInfo->set_compaction(0); + s3ChunkInfo->set_offset(offset); + s3ChunkInfo->set_len(len); + s3ChunkInfo->set_size(len); + s3ChunkInfo->set_zero(false); + s3ChunkInfoMap->insert({0, *s3ChunkInfoList}); + auto inodeWrapper = std::make_shared(inode, nullptr); + EXPECT_CALL(*mockInodeManager_, GetInode(_, _)) + .WillOnce( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))) + .WillOnce( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + EXPECT_CALL(*mockS3Client_, Download(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<1>(*tmpbuf), Return(len))) + .WillOnce(Return(-1)); + + ASSERT_EQ(len, fileCacheManager_->Read(inodeId, offset, len, buf)); + ASSERT_EQ(-1, fileCacheManager_->Read(inodeId, offset, len, buf)); + + delete buf; + delete tmpbuf; +} + +} // namespace client +} // namespace curvefs diff --git a/curvefs/test/client/fs_cache_manager_test.cpp b/curvefs/test/client/fs_cache_manager_test.cpp index 2ac49e6a88..250fb4f2e6 100644 --- a/curvefs/test/client/fs_cache_manager_test.cpp +++ b/curvefs/test/client/fs_cache_manager_test.cpp @@ -17,51 +17,108 @@ /* * Project: curve * Date: Friday Oct 22 15:09:30 CST 2021 - * Author: wuhanqing + * Author: huyao */ #include +#include #include "curvefs/src/client/s3/client_s3_adaptor.h" #include "curvefs/src/client/s3/client_s3_cache_manager.h" -#include "curvefs/test/client/mock_chunk_cache_manager.h" #include "src/common/concurrent/count_down_event.h" +#include "curvefs/test/client/mock_client_s3_cache_manager.h" namespace curvefs { namespace client { - using ::testing::_; +using ::testing::DoAll; using ::testing::Invoke; +using ::testing::Return; +using ::testing::SetArgPointee; +using ::testing::SetArgReferee; +using ::testing::WithArg; + +class FsCacheManagerTest : public testing::Test { + protected: + FsCacheManagerTest() {} + ~FsCacheManagerTest() {} + void SetUp() override { + maxReadCacheByte_ = 16ull * 1024 * 1024; // 16MiB + uint64_t maxWriteCacheByte = maxReadCacheByte_; + S3ClientAdaptorOption option; + option.blockSize = 1 * 1024 * 1024; + option.chunkSize = 4 * 1024 * 1024; + option.pageSize = 64 * 1024; + option.intervalSec = 5000; + option.flushIntervalSec = 5000; + option.readCacheMaxByte = 104857600; + option.diskCacheOpt.diskCacheType = (DiskCacheType)0; + s3ClientAdaptor_ = new S3ClientAdaptorImpl(); + fsCacheManager_ = std::make_shared( + s3ClientAdaptor_, maxReadCacheByte_, maxWriteCacheByte); + s3ClientAdaptor_->Init(option, nullptr, nullptr, nullptr, + fsCacheManager_, nullptr); + s3ClientAdaptor_->SetFsId(2); + + mockChunkCacheManager_ = std::make_shared(); + } + + void TearDown() override { + delete s3ClientAdaptor_; + } + + protected: + S3ClientAdaptorImpl *s3ClientAdaptor_; + std::shared_ptr fsCacheManager_; + std::shared_ptr mockChunkCacheManager_; + uint64_t maxReadCacheByte_; +}; + +TEST_F(FsCacheManagerTest, test_FindFileCacheManager) { + uint64_t inodeId = 1; + uint64_t fsId = 1; + + ASSERT_EQ(nullptr, fsCacheManager_->FindFileCacheManager(inodeId)); + auto fileCacheManager = + fsCacheManager_->FindOrCreateFileCacheManager(fsId, inodeId); + ASSERT_EQ(fileCacheManager, fsCacheManager_->FindFileCacheManager(inodeId)); +} + +TEST_F(FsCacheManagerTest, test_FindOrCreateFileCacheManager) { + uint64_t inodeId = 1; + uint64_t fsId = 1; + + auto fileCacheManager = + fsCacheManager_->FindOrCreateFileCacheManager(fsId, inodeId); + ASSERT_EQ(fileCacheManager, + fsCacheManager_->FindOrCreateFileCacheManager(fsId, inodeId)); +} + +TEST_F(FsCacheManagerTest, test_ReleaseFileCacheManager) { + uint64_t inodeId = 1; + uint64_t fsId = 1; -TEST(FsCacheManagerTest, test_read_lru_cache_size) { - uint64_t smallDataCacheByte = 128ull * 1024; // 128KiB - uint64_t dataCacheByte = 4ull * 1024 * 1024; // 4MiB - uint64_t maxReadCacheByte = 16ull * 1024 * 1024; // 16MiB - uint64_t maxWriteCacheByte = maxReadCacheByte; + fsCacheManager_->ReleaseFileCacheManager(inodeId); + ASSERT_EQ(nullptr, fsCacheManager_->FindFileCacheManager(inodeId)); + auto fileCacheManager = + fsCacheManager_->FindOrCreateFileCacheManager(fsId, inodeId); + ASSERT_EQ(fileCacheManager, fsCacheManager_->FindFileCacheManager(inodeId)); + fsCacheManager_->ReleaseFileCacheManager(inodeId); + ASSERT_EQ(nullptr, fsCacheManager_->FindFileCacheManager(inodeId)); +} + +TEST_F(FsCacheManagerTest, test_lru_set_and_delete) { + uint64_t smallDataCacheByte = 128ull * 1024; // 128KiB + uint64_t dataCacheByte = 4ull * 1024 * 1024; // 4MiB char *buf = new char[dataCacheByte]; - S3ClientAdaptorOption option; - option.blockSize = 1 * 1024 * 1024; - option.chunkSize = 4 * 1024 * 1024; - option.pageSize = 64 * 1024; - option.intervalSec = 5000; - option.flushIntervalSec = 5000; - option.readCacheMaxByte = 104857600; - option.diskCacheOpt.diskCacheType = (DiskCacheType)0; - S3ClientAdaptorImpl *s3ClientAdaptor_ = new S3ClientAdaptorImpl(); - s3ClientAdaptor_->Init(option, nullptr, nullptr, nullptr); - s3ClientAdaptor_->SetFsId(2); - FsCacheManager manager(s3ClientAdaptor_, maxReadCacheByte, - maxWriteCacheByte); - auto mockCacheMgr = std::make_shared(); std::list::iterator outIter; - { - EXPECT_CALL(*mockCacheMgr, ReleaseReadDataCache(_)).Times(0); - for (size_t i = 0; i < maxReadCacheByte / smallDataCacheByte; ++i) { - manager.Set(std::make_shared(s3ClientAdaptor_, - mockCacheMgr, 0, - smallDataCacheByte, buf), - &outIter); + { + for (size_t i = 0; i < maxReadCacheByte_ / smallDataCacheByte; ++i) { + fsCacheManager_->Set(std::make_shared( + s3ClientAdaptor_, mockChunkCacheManager_, + 0, smallDataCacheByte, buf), + &outIter); } } @@ -69,13 +126,13 @@ TEST(FsCacheManagerTest, test_read_lru_cache_size) { const uint32_t expectCallTimes = 1; curve::common::CountDownEvent counter(expectCallTimes); - EXPECT_CALL(*mockCacheMgr, ReleaseReadDataCache(_)) + EXPECT_CALL(*mockChunkCacheManager_, ReleaseReadDataCache(_)) .Times(expectCallTimes) .WillRepeatedly(Invoke([&counter](uint64_t) { counter.Signal(); })); - manager.Set(std::make_shared(s3ClientAdaptor_, - mockCacheMgr, 0, - dataCacheByte, buf), - &outIter); + fsCacheManager_->Set(std::make_shared(s3ClientAdaptor_, + mockChunkCacheManager_, + 0, dataCacheByte, buf), + &outIter); counter.Wait(); } @@ -84,17 +141,48 @@ TEST(FsCacheManagerTest, test_read_lru_cache_size) { const uint32_t expectCallTimes = 32; curve::common::CountDownEvent counter(expectCallTimes); - EXPECT_CALL(*mockCacheMgr, ReleaseReadDataCache(_)) + EXPECT_CALL(*mockChunkCacheManager_, ReleaseReadDataCache(_)) .Times(expectCallTimes) .WillRepeatedly(Invoke([&counter](uint64_t) { counter.Signal(); })); - manager.Set(std::make_shared(s3ClientAdaptor_, - mockCacheMgr, 0, - dataCacheByte, buf), - &outIter); + fsCacheManager_->Set(std::make_shared(s3ClientAdaptor_, + mockChunkCacheManager_, + 0, dataCacheByte, buf), + &outIter); counter.Wait(); } } +TEST_F(FsCacheManagerTest, test_fsSync_ok) { + uint64_t inodeId = 1; + auto fileCache = std::make_shared(); + + EXPECT_CALL(*fileCache, Flush(_, _)).WillOnce(Return(CURVEFS_ERROR::OK)); + fsCacheManager_->SetFileCacheManagerForTest(inodeId, fileCache); + ASSERT_EQ(CURVEFS_ERROR::OK, fsCacheManager_->FsSync(true)); +} + +TEST_F(FsCacheManagerTest, test_fsSync_not_exist) { + uint64_t inodeId = 1; + + auto fileCache = std::make_shared(); + EXPECT_CALL(*fileCache, Flush(_, _)) + .WillOnce(Return(CURVEFS_ERROR::NOTEXIST)); + fsCacheManager_->SetFileCacheManagerForTest(inodeId, fileCache); + ASSERT_EQ(fileCache, fsCacheManager_->FindFileCacheManager(inodeId)); + ASSERT_EQ(CURVEFS_ERROR::OK, fsCacheManager_->FsSync(true)); + ASSERT_EQ(nullptr, fsCacheManager_->FindFileCacheManager(inodeId)); +} + +TEST_F(FsCacheManagerTest, test_fsSync_fail) { + uint64_t inodeId = 1; + auto fileCache = std::make_shared(); + + EXPECT_CALL(*fileCache, Flush(_, _)) + .WillOnce(Return(CURVEFS_ERROR::INTERNAL)); + fsCacheManager_->SetFileCacheManagerForTest(inodeId, fileCache); + ASSERT_EQ(CURVEFS_ERROR::INTERNAL, fsCacheManager_->FsSync(true)); +} + } // namespace client } // namespace curvefs diff --git a/curvefs/test/client/mock_chunk_cache_manager.h b/curvefs/test/client/mock_chunk_cache_manager.h deleted file mode 100644 index cad4e6d6ff..0000000000 --- a/curvefs/test/client/mock_chunk_cache_manager.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2021 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 - * Date: Friday Oct 22 15:12:14 CST 2021 - * Author: wuhanqing - */ - -#ifndef CURVEFS_TEST_CLIENT_MOCK_CHUNK_CACHE_MANAGER_H_ -#define CURVEFS_TEST_CLIENT_MOCK_CHUNK_CACHE_MANAGER_H_ - -#include - -#include "curvefs/src/client/s3/client_s3_cache_manager.h" - -namespace curvefs { -namespace client { - -class MockChunkCacheManager : public ChunkCacheManager { - public: - MockChunkCacheManager() : ChunkCacheManager(0, nullptr) {} - ~MockChunkCacheManager() = default; - - MOCK_METHOD1(ReleaseReadDataCache, void(uint64_t)); -}; - -} // namespace client -} // namespace curvefs - -#endif // CURVEFS_TEST_CLIENT_MOCK_CHUNK_CACHE_MANAGER_H_ diff --git a/curvefs/test/client/mock_client_s3.h b/curvefs/test/client/mock_client_s3.h index b6fb34d828..5588fd73c5 100644 --- a/curvefs/test/client/mock_client_s3.h +++ b/curvefs/test/client/mock_client_s3.h @@ -29,8 +29,8 @@ #include #include "curvefs/src/client/s3/client_s3.h" -using ::testing::Return; using ::testing::_; +using ::testing::Return; namespace curvefs { namespace client { @@ -40,16 +40,16 @@ class MockS3Client : public S3Client { MockS3Client() {} ~MockS3Client() {} - MOCK_METHOD1(Init, void(const curve::common::S3AdapterOption& options)); + MOCK_METHOD1(Init, void(const curve::common::S3AdapterOption &options)); MOCK_METHOD0(Deinit, void()); - MOCK_METHOD3(Upload, int(const std::string& name, - const char* buf, uint64_t length)); - MOCK_METHOD1(UploadAsync, void( - std::shared_ptr context)); - MOCK_METHOD4(Download, int(const std::string& name, - char* buf, uint64_t offset, uint64_t length)); - MOCK_METHOD1(DownloadAsync, void( - std::shared_ptr context)); + MOCK_METHOD3(Upload, int(const std::string &name, const char *buf, + uint64_t length)); + MOCK_METHOD1(UploadAsync, + void(std::shared_ptr context)); + MOCK_METHOD4(Download, int(const std::string &name, char *buf, + uint64_t offset, uint64_t length)); + MOCK_METHOD1(DownloadAsync, + void(std::shared_ptr context)); }; diff --git a/curvefs/test/client/mock_client_s3_adaptor.h b/curvefs/test/client/mock_client_s3_adaptor.h index 5b7e023eb2..4e072728a3 100644 --- a/curvefs/test/client/mock_client_s3_adaptor.h +++ b/curvefs/test/client/mock_client_s3_adaptor.h @@ -35,12 +35,28 @@ class MockS3ClientAdaptor : public S3ClientAdaptor { public: MockS3ClientAdaptor() {} ~MockS3ClientAdaptor() {} - +/* + MOCK_METHOD5(Init, + CURVEFS_ERROR(const S3ClientAdaptorOption &option, + std::shared_ptr client, + std::shared_ptr inodeManager, + std::shared_ptr mdsClient, + std::shared_ptr + diskcacheManagerImpl)); MOCK_METHOD4(Init, CURVEFS_ERROR(const S3ClientAdaptorOption& option, - S3Client* client, + std::shared_ptr client, + std::shared_ptr inodeManager, + std::shared_ptr mdsClient));*/ + MOCK_METHOD7(Init, + CURVEFS_ERROR(const S3ClientAdaptorOption &option, + std::shared_ptr client, std::shared_ptr inodeManager, - std::shared_ptr mdsClient)); + std::shared_ptr mdsClient, + std::shared_ptr fsCacheManager, + std::shared_ptr + diskCacheManagerImpl, + bool startBackGround)); MOCK_METHOD4(Write, int(uint64_t inodeId, uint64_t offset, uint64_t length, const char* buf)); diff --git a/curvefs/test/client/mock_client_s3_cache_manager.h b/curvefs/test/client/mock_client_s3_cache_manager.h new file mode 100644 index 0000000000..75fd9cf449 --- /dev/null +++ b/curvefs/test/client/mock_client_s3_cache_manager.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2021 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 + * Date: Friday Oct 22 15:12:14 CST 2021 + * Author: wuhanqing + */ + +#ifndef CURVEFS_TEST_CLIENT_MOCK_CLIENT_S3_CACHE_MANAGER_H_ +#define CURVEFS_TEST_CLIENT_MOCK_CLIENT_S3_CACHE_MANAGER_H_ + +#include +#include +#include "curvefs/src/client/s3/client_s3_cache_manager.h" + +namespace curvefs { +namespace client { + +class MockFsCacheManager : public FsCacheManager { + public: + MockFsCacheManager() : FsCacheManager() {} + ~MockFsCacheManager() {} + MOCK_METHOD2(FindOrCreateFileCacheManager, + FileCacheManagerPtr(uint64_t fsId, uint64_t inodeId)); + MOCK_METHOD1(FindFileCacheManager, FileCacheManagerPtr(uint64_t inodeId)); + MOCK_METHOD0(GetDataCacheMaxSize, uint64_t()); + MOCK_METHOD0(GetDataCacheSize, uint64_t()); + MOCK_METHOD0(MemCacheRatio, uint64_t()); +}; + +class MockFileCacheManager : public FileCacheManager { + public: + MockFileCacheManager() : FileCacheManager() {} + ~MockFileCacheManager() {} + MOCK_METHOD3(Write, + int(uint64_t offset, uint64_t length, const char *dataBuf)); + MOCK_METHOD4(Read, int(uint64_t inodeId, uint64_t offset, uint64_t length, + char *dataBuf)); + MOCK_METHOD2(Flush, CURVEFS_ERROR(bool force, bool toS3)); + MOCK_METHOD2(TruncateCache, void(uint64_t offset, uint64_t fileSize)); +}; + +class MockChunkCacheManager : public ChunkCacheManager { + public: + MockChunkCacheManager() : ChunkCacheManager(0, nullptr) {} + ~MockChunkCacheManager() = default; + + MOCK_METHOD1(ReleaseReadDataCache, void(uint64_t)); + MOCK_METHOD3(Flush, CURVEFS_ERROR(uint64_t inodeId, bool force, bool toS3)); + MOCK_METHOD4(FindWriteableDataCache, + DataCachePtr(uint64_t chunkPos, uint64_t len, + std::vector *mergeDataCacheVer, + uint64_t inodeId)); + MOCK_METHOD4(WriteNewDataCache, + void(S3ClientAdaptorImpl *s3ClientAdaptor, uint32_t chunkPos, + uint32_t len, const char *data)); + MOCK_METHOD5(ReadByWriteCache, void(uint64_t chunkPos, uint64_t readLen, + char *dataBuf, uint64_t dataBufOffset, + std::vector *requests)); + MOCK_METHOD5(ReadByReadCache, void(uint64_t chunkPos, uint64_t readLen, + char *dataBuf, uint64_t dataBufOffset, + std::vector *requests)); + MOCK_METHOD0(ReleaseCache, void()); + MOCK_METHOD1(AddReadDataCache, void(DataCachePtr dataCache)); +}; + +class MockDataCache : public DataCache { + public: + MockDataCache(S3ClientAdaptorImpl *s3ClientAdaptor, + ChunkCacheManagerPtr chunkCacheManager, uint64_t chunkPos, + uint64_t len, const char *data) + : DataCache(s3ClientAdaptor, chunkCacheManager, chunkPos, len, data) {} + ~MockDataCache() = default; + + MOCK_METHOD4(Write, + void(uint64_t chunkPos, uint64_t len, const char *data, + const std::vector &mergeDataCacheVer)); + MOCK_METHOD3(Flush, CURVEFS_ERROR(uint64_t inodeId, bool force, bool toS3)); + MOCK_METHOD1(Truncate, void(uint64_t size)); +}; + +} // namespace client +} // namespace curvefs + +#endif // CURVEFS_TEST_CLIENT_MOCK_CLIENT_S3_CACHE_MANAGER_H_ diff --git a/curvefs/test/client/mock_disk_cache_manager.h b/curvefs/test/client/mock_disk_cache_manager.h index 1d0fb61a7f..9c99f1574a 100644 --- a/curvefs/test/client/mock_disk_cache_manager.h +++ b/curvefs/test/client/mock_disk_cache_manager.h @@ -76,21 +76,6 @@ class MockDiskCacheManagerImpl : public DiskCacheManagerImpl { MOCK_METHOD1(ClearReadCache, int(const std::list &files)); }; -class MockFsCacheManager : public FsCacheManager { - public: - MockFsCacheManager() : FsCacheManager() {} - ~MockFsCacheManager() {} - - MOCK_METHOD1(FindFileCacheManager, FileCacheManagerPtr(uint64_t inodeId)); -}; - -class MockFileCacheManager : public FileCacheManager { - public: - MockFileCacheManager() : FileCacheManager() {} - ~MockFileCacheManager() {} - MOCK_METHOD2(Flush, CURVEFS_ERROR(bool force, bool toS3)); -}; - } // namespace client } // namespace curvefs