curve/test/client/iotracker_splitor_unittest.cpp

1516 lines
53 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2020 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: curve
* File Created: Tuesday, 9th October 2018 5:17:04 pm
* Author: tongguangxun
*/
#include <brpc/server.h>
#include <fiu-control.h>
#include <gflags/gflags.h>
#include <glog/logging.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <chrono> //NOLINT
#include <condition_variable> //NOLINT
#include <mutex> // NOLINT
#include <string>
#include <thread> //NOLINT
#include "src/client/client_common.h"
#include "src/client/client_config.h"
#include "src/client/config_info.h"
#include "src/client/file_instance.h"
#include "src/client/io_tracker.h"
#include "src/client/iomanager4file.h"
#include "include/client/libcurve.h"
#include "src/client/libcurve_file.h"
#include "src/client/mds_client.h"
#include "src/client/metacache.h"
#include "src/client/metacache_struct.h"
#include "src/client/request_context.h"
#include "src/client/splitor.h"
#include "src/client/source_reader.h"
#include "test/client/fake/fakeMDS.h"
#include "test/client/fake/mockMDS.h"
#include "test/client/fake/mock_schedule.h"
extern std::string mdsMetaServerAddr;
extern uint32_t chunk_size;
extern std::string configpath;
extern butil::IOBuf writeData;
namespace curve {
namespace client {
bool ioreadflag = false;
std::mutex readmtx;
std::condition_variable readcv;
bool iowriteflag = false;
std::mutex writemtx;
std::condition_variable writecv;
void readcallback(CurveAioContext* context) {
LOG(INFO) << "aio call back here, errorcode = " << context->ret;
ioreadflag = true;
readcv.notify_one();
}
void writecallback(CurveAioContext* context) {
LOG(INFO) << "aio call back here, errorcode = " << context->ret;
iowriteflag = true;
writecv.notify_one();
}
class IOTrackerSplitorTest : public ::testing::Test {
public:
void SetUp() {
fiu_init(0);
fopt.metaServerOpt.rpcRetryOpt.addrs.push_back("127.0.0.1:9104");
fopt.metaServerOpt.rpcRetryOpt.rpcTimeoutMs = 500;
fopt.metaServerOpt.rpcRetryOpt.rpcRetryIntervalUS = 50000;
fopt.loginfo.logLevel = 0;
fopt.ioOpt.ioSplitOpt.fileIOSplitMaxSizeKB = 64;
fopt.ioOpt.ioSenderOpt.chunkserverEnableAppliedIndexRead = 1;
fopt.ioOpt.ioSenderOpt.failRequestOpt.chunkserverRPCTimeoutMS = 1000;
fopt.ioOpt.ioSenderOpt.failRequestOpt.chunkserverOPMaxRetry = 3;
fopt.ioOpt.ioSenderOpt.failRequestOpt.chunkserverOPRetryIntervalUS = 500; // NOLINT
fopt.ioOpt.metaCacheOpt.metacacheGetLeaderRetry = 3;
fopt.ioOpt.metaCacheOpt.metacacheRPCRetryIntervalUS = 500;
fopt.ioOpt.reqSchdulerOpt.scheduleQueueCapacity = 4096;
fopt.ioOpt.reqSchdulerOpt.scheduleThreadpoolSize = 2;
fopt.ioOpt.reqSchdulerOpt.ioSenderOpt = fopt.ioOpt.ioSenderOpt;
fopt.ioOpt.closeFdThreadOption.fdTimeout = 3;
fopt.ioOpt.closeFdThreadOption.fdCloseTimeInterval = 5;
fopt.leaseOpt.mdsRefreshTimesPerLease = 4;
fileinstance_ = new FileInstance();
userinfo.owner = "userinfo";
userinfo.password = "12345";
mdsclient_ = std::make_shared<MDSClient>();
mdsclient_->Initialize(fopt.metaServerOpt);
fileinstance_->Initialize("/test", mdsclient_, userinfo, OpenFlags{},
fopt);
InsertMetaCache();
SourceReader::GetInstance().SetOption(fopt);
SourceReader::GetInstance().SetReadHandlers({});
SourceReader::GetInstance().Run();
}
void TearDown() {
writeData.clear();
fileinstance_->Close();
fileinstance_->UnInitialize();
mdsclient_.reset();
delete fileinstance_;
SourceReader::GetInstance().Stop();
LOG(INFO) << "DONE!";
server.Stop(0);
server.Join();
}
void InsertMetaCache() {
if (server.AddService(&curvefsservice,
brpc::SERVER_DOESNT_OWN_SERVICE) != 0) {
LOG(FATAL) << "Fail to add service";
}
if (server.AddService(&topologyservice,
brpc::SERVER_DOESNT_OWN_SERVICE) != 0) {
LOG(FATAL) << "Fail to add service";
}
brpc::ServerOptions options;
options.idle_timeout_sec = -1;
if (server.Start(mdsMetaServerAddr.c_str(), &options) != 0) {
LOG(ERROR) << "Fail to start Server";
}
/**
* 1. set openfile response
*/
::curve::mds::OpenFileResponse* openresponse =
new ::curve::mds::OpenFileResponse();
::curve::mds::ProtoSession* se = new ::curve::mds::ProtoSession;
se->set_sessionid("1");
se->set_createtime(12345);
se->set_leasetime(10000000);
se->set_sessionstatus(::curve::mds::SessionStatus::kSessionOK);
::curve::mds::FileInfo* fin = new ::curve::mds::FileInfo;
fin->set_filename("1_userinfo_.txt");
fin->set_owner("userinfo");
fin->set_id(1);
fin->set_parentid(0);
fin->set_filetype(curve::mds::FileType::INODE_PAGEFILE);
fin->set_chunksize(4 * 1024 * 1024);
fin->set_length(1 * 1024 * 1024 * 1024ul);
fin->set_ctime(12345678);
fin->set_seqnum(0);
fin->set_segmentsize(1 * 1024 * 1024 * 1024ul);
openresponse->set_statuscode(::curve::mds::StatusCode::kOK);
openresponse->set_allocated_protosession(se);
openresponse->set_allocated_fileinfo(fin);
FakeReturn* openfakeret = new FakeReturn(nullptr, static_cast<void*>(openresponse)); // NOLINT
curvefsservice.SetOpenFile(openfakeret);
fileinstance_->Open();
/**
* 2. set closefile response
*/
::curve::mds::CloseFileResponse* closeresp = new ::curve::mds::CloseFileResponse; // NOLINT
closeresp->set_statuscode(::curve::mds::StatusCode::kOK);
FakeReturn* closefileret
= new FakeReturn(nullptr, static_cast<void*>(closeresp));
curvefsservice.SetCloseFile(closefileret);
/**
* 3. 设置GetOrAllocateSegmentresponse
*/
curve::mds::GetOrAllocateSegmentResponse* response =
new curve::mds::GetOrAllocateSegmentResponse();
curve::mds::PageFileSegment* pfs = new curve::mds::PageFileSegment;
response->set_statuscode(::curve::mds::StatusCode::kOK);
response->set_allocated_pagefilesegment(pfs);
response->mutable_pagefilesegment()->
set_logicalpoolid(1234);
response->mutable_pagefilesegment()->
set_segmentsize(1 * 1024 * 1024 * 1024);
response->mutable_pagefilesegment()->
set_chunksize(4 * 1024 * 1024);
response->mutable_pagefilesegment()->
set_startoffset(0);
for (int i = 0; i < 256; i ++) {
auto chunk = response->mutable_pagefilesegment()->add_chunks();
chunk->set_copysetid(i);
chunk->set_chunkid(i);
}
getsegmentfakeret = new FakeReturn(nullptr,
static_cast<void*>(response));
curvefsservice.SetGetOrAllocateSegmentFakeReturn(getsegmentfakeret);
curve::mds::GetOrAllocateSegmentResponse* notallocateresponse =
new curve::mds::GetOrAllocateSegmentResponse();
notallocateresponse->set_statuscode(::curve::mds::StatusCode
::kSegmentNotAllocated);
notallocatefakeret = new FakeReturn(nullptr,
static_cast<void*>(notallocateresponse));
// set GetOrAllocateSegmentResponse for read from clone source
curve::mds::GetOrAllocateSegmentResponse* cloneSourceResponse =
new curve::mds::GetOrAllocateSegmentResponse();
curve::mds::PageFileSegment* clonepfs = new curve::mds::PageFileSegment;
cloneSourceResponse->set_statuscode(::curve::mds::StatusCode::kOK);
cloneSourceResponse->set_allocated_pagefilesegment(clonepfs);
cloneSourceResponse->mutable_pagefilesegment()->
set_logicalpoolid(1);
cloneSourceResponse->mutable_pagefilesegment()->
set_segmentsize(1 * 1024 * 1024 * 1024);
cloneSourceResponse->mutable_pagefilesegment()->
set_chunksize(4 * 1024 * 1024);
cloneSourceResponse->mutable_pagefilesegment()->
set_startoffset(1 * 1024 * 1024 * 1024);
for (int i = 256; i < 512; i++) {
auto chunk = cloneSourceResponse->mutable_pagefilesegment()
->add_chunks();
chunk->set_copysetid(i);
chunk->set_chunkid(i);
}
getsegmentfakeretclone = new FakeReturn(nullptr,
static_cast<void*>(cloneSourceResponse));
/**
* 4. set refresh response
*/
curve::mds::FileInfo * info = new curve::mds::FileInfo;
info->set_filename("1_userinfo_.txt");
info->set_seqnum(2);
info->set_id(1);
info->set_parentid(0);
info->set_filetype(curve::mds::FileType::INODE_PAGEFILE);
info->set_chunksize(4 * 1024 * 1024);
info->set_length(1 * 1024 * 1024 * 1024ul);
info->set_ctime(12345678);
::curve::mds::ReFreshSessionResponse* refreshresp =
new ::curve::mds::ReFreshSessionResponse;
refreshresp->set_statuscode(::curve::mds::StatusCode::kOK);
refreshresp->set_sessionid("1234");
refreshresp->set_allocated_fileinfo(info);
FakeReturn* refreshfakeret
= new FakeReturn(nullptr, static_cast<void*>(refreshresp));
curvefsservice.SetRefreshSession(refreshfakeret, nullptr);
/**
* 5. 设置topology返回值
*/
::curve::mds::topology::GetChunkServerListInCopySetsResponse* response_1
= new ::curve::mds::topology::GetChunkServerListInCopySetsResponse;
response_1->set_statuscode(0);
uint64_t chunkserveridc = 1;
for (int i = 0; i < 256; i ++) {
auto csinfo = response_1->add_csinfo();
csinfo->set_copysetid(i);
for (int j = 0; j < 3; j++) {
auto cslocs = csinfo->add_cslocs();
cslocs->set_chunkserverid(chunkserveridc++);
cslocs->set_hostip("127.0.0.1");
cslocs->set_port(9104);
}
}
FakeReturn* faktopologyeret = new FakeReturn(nullptr,
static_cast<void*>(response_1));
topologyservice.SetFakeReturn(faktopologyeret);
curve::client::MetaCache* mc = fileinstance_->GetIOManager4File()->
GetMetaCache();
curve::client::FInfo_t fi;
fi.userinfo = userinfo;
fi.chunksize = 4 * 1024 * 1024;
fi.segmentsize = 1 * 1024 * 1024 * 1024ul;
SegmentInfo sinfo;
LogicalPoolCopysetIDInfo_t lpcsIDInfo;
mdsclient_->GetOrAllocateSegment(true, 0, &fi, nullptr, &sinfo);
int count = 0;
for (auto iter : sinfo.chunkvec) {
uint64_t index = (sinfo.startoffset + count*fi.chunksize )
/ fi.chunksize;
mc->UpdateChunkInfoByIndex(index, iter);
++count;
}
std::vector<CopysetInfo<ChunkServerID>> cpinfoVec;
mdsclient_->GetServerList(lpcsIDInfo.lpid, lpcsIDInfo.cpidVec,
&cpinfoVec);
for (auto iter : cpinfoVec) {
mc->UpdateCopysetInfo(lpcsIDInfo.lpid, iter.cpid_, iter);
}
// 5. set close response
auto* closeResp = new ::curve::mds::CloseFileResponse();
closeResp->set_statuscode(::curve::mds::StatusCode::kOK);
auto* closeFakeRet =
new FakeReturn(nullptr, static_cast<void*>(closeResp));
curvefsservice.SetCloseFile(closeFakeRet);
}
void PrepareOpenFile() {
openResp_.set_statuscode(curve::mds::StatusCode::kOK);
auto* session = openResp_.mutable_protosession();
session->set_sessionid("xxx");
session->set_leasetime(10000);
session->set_createtime(10000);
session->set_sessionstatus(curve::mds::SessionStatus::kSessionOK);
auto* fileinfo = openResp_.mutable_fileinfo();
fileinfo->set_id(1);
fileinfo->set_filename("filename");
fileinfo->set_parentid(0);
fileinfo->set_length(10ULL * 1024 * 1024 * 1024);
fileinfo->set_blocksize(4096);
fakeOpen_.reset(
new FakeReturn(nullptr, static_cast<void*>(&openResp_)));
curvefsservice.SetOpenFile(fakeOpen_.get());
}
FileClient *fileClient_;
UserInfo_t userinfo;
std::shared_ptr<MDSClient> mdsclient_;
FileServiceOption fopt;
FileInstance *fileinstance_;
brpc::Server server;
FakeMDSCurveFSService curvefsservice;
FakeTopologyService topologyservice;
FakeReturn *getsegmentfakeret;
FakeReturn *notallocatefakeret;
FakeReturn *getsegmentfakeretclone;
OpenFileResponse openResp_;
std::unique_ptr<FakeReturn> fakeOpen_;
};
TEST_F(IOTrackerSplitorTest, AsyncStartRead) {
MockRequestScheduler* mockschuler = new MockRequestScheduler;
mockschuler->DelegateToFake();
curve::client::IOManager4File* iomana = fileinstance_->GetIOManager4File();
iomana->SetRequestScheduler(mockschuler);
CurveAioContext aioctx;
aioctx.offset = 4 * 1024 * 1024 - 4 * 1024; // 4M - 4k
aioctx.length = 4 * 1024 * 1024 + 8 * 1024; // 4M + 8K
aioctx.ret = LIBCURVE_ERROR::OK;
aioctx.cb = readcallback;
aioctx.buf = new char[aioctx.length];
aioctx.op = LIBCURVE_OP::LIBCURVE_OP_READ;
ioreadflag = false;
char* data = static_cast<char*>(aioctx.buf);
iomana->AioRead(&aioctx, mdsclient_.get(), UserDataType::RawBuffer);
{
std::unique_lock<std::mutex> lk(readmtx);
readcv.wait(lk, []()->bool{return ioreadflag;});
}
LOG(ERROR) << "address = " << &data;
ASSERT_EQ('a', data[0]);
ASSERT_EQ('a', data[4 * 1024 - 1]);
ASSERT_EQ('b', data[4 * 1024]);
ASSERT_EQ('e', data[4 * 1024 + chunk_size - 1]);
ASSERT_EQ('f', data[4 * 1024 + chunk_size]);
ASSERT_EQ('f', data[aioctx.length - 1]);
delete[] data;
}
TEST_F(IOTrackerSplitorTest, AsyncStartWrite) {
MockRequestScheduler* mockschuler = new MockRequestScheduler;
mockschuler->DelegateToFake();
curve::client::IOManager4File* iomana = fileinstance_->GetIOManager4File();
iomana->SetRequestScheduler(mockschuler);
CurveAioContext aioctx;
aioctx.offset = 4 * 1024 * 1024 - 4 * 1024;
aioctx.length = 4 * 1024 * 1024 + 8 * 1024;
aioctx.ret = LIBCURVE_ERROR::OK;
aioctx.cb = writecallback;
aioctx.buf = new char[aioctx.length];
aioctx.op = LIBCURVE_OP::LIBCURVE_OP_WRITE;
char* data = static_cast<char*>(aioctx.buf);
memset(data, 'a', 4 * 1024);
memset(data + 4 * 1024, 'b', chunk_size);
memset(data + 4 * 1024 + chunk_size, 'c', 4 * 1024);
FInfo_t fi;
fi.chunksize = 4 * 1024 * 1024;
fi.segmentsize = 1 * 1024 * 1024 * 1024ul;
iowriteflag = false;
iomana->AioWrite(&aioctx, mdsclient_.get(), UserDataType::RawBuffer);
{
std::unique_lock<std::mutex> lk(writemtx);
writecv.wait(lk, []() -> bool { return iowriteflag; });
}
std::unique_ptr<char[]> writebuffer(new char[aioctx.length]);
memcpy(writebuffer.get(), writeData.to_string().c_str(), aioctx.length);
// check butil::IOBuf write data
ASSERT_EQ('a', writebuffer[0]);
ASSERT_EQ('a', writebuffer[4 * 1024 - 1]);
ASSERT_EQ('b', writebuffer[4 * 1024]);
ASSERT_EQ('b', writebuffer[4 * 1024 + chunk_size - 1]);
ASSERT_EQ('c', writebuffer[4 * 1024 + chunk_size]);
ASSERT_EQ('c', writebuffer[aioctx.length - 1]);
delete[] data;
}
TEST_F(IOTrackerSplitorTest, StartRead) {
MockRequestScheduler* mockschuler = new MockRequestScheduler;
mockschuler->DelegateToFake();
curve::client::IOManager4File* iomana = fileinstance_->GetIOManager4File();
iomana->SetRequestScheduler(mockschuler);
uint64_t offset = 4 * 1024 * 1024 - 4 * 1024;
uint64_t length = 4 * 1024 * 1024 + 8 * 1024;
char* data = new char[length];
auto threadfunc = [&]() {
iomana->Read(data, offset, length, mdsclient_.get());
};
std::thread process(threadfunc);
if (process.joinable()) {
process.join();
}
ASSERT_EQ('a', data[0]);
ASSERT_EQ('a', data[4 * 1024 - 1]);
ASSERT_EQ('b', data[4 * 1024]);
ASSERT_EQ('e', data[4 * 1024 + chunk_size - 1]);
ASSERT_EQ('f', data[4 * 1024 + chunk_size]);
ASSERT_EQ('f', data[length - 1]);
delete[] data;
}
TEST_F(IOTrackerSplitorTest, StartWrite) {
MockRequestScheduler* mockschuler = new MockRequestScheduler;
mockschuler->DelegateToFake();
curve::client::IOManager4File* iomana = fileinstance_->GetIOManager4File();
iomana->SetRequestScheduler(mockschuler);
uint64_t offset = 4 * 1024 * 1024 - 4 * 1024;
uint64_t length = 4 * 1024 * 1024 + 8 * 1024;
char* buf = new char[length];
memset(buf, 'a', 4 * 1024);
memset(buf + 4 * 1024, 'b', chunk_size);
memset(buf + 4 * 1024 + chunk_size, 'c', 4 * 1024);
auto threadfunc = [&]() {
iomana->Write(buf, offset, length, mdsclient_.get());
};
std::thread process(threadfunc);
if (process.joinable()) {
process.join();
}
std::unique_ptr<char[]> writebuffer(new char[length]);
memcpy(writebuffer.get(), writeData.to_string().c_str(), length);
ASSERT_EQ('a', writebuffer[0]);
ASSERT_EQ('a', writebuffer[4 * 1024 - 1]);
ASSERT_EQ('b', writebuffer[4 * 1024]);
ASSERT_EQ('b', writebuffer[4 * 1024 + chunk_size - 1]);
ASSERT_EQ('c', writebuffer[4 * 1024 + chunk_size]);
ASSERT_EQ('c', writebuffer[length - 1]);
delete[] buf;
}
TEST_F(IOTrackerSplitorTest, ManagerAsyncStartRead) {
MockRequestScheduler* mockschuler = new MockRequestScheduler;
mockschuler->DelegateToFake();
auto ioctxmana = fileinstance_->GetIOManager4File();
ioctxmana->SetRequestScheduler(mockschuler);
CurveAioContext* aioctx = new CurveAioContext;
aioctx->offset = 4 * 1024 * 1024 - 4 * 1024;
aioctx->length = 4 * 1024 * 1024 + 8 * 1024;
aioctx->ret = LIBCURVE_ERROR::OK;
aioctx->cb = readcallback;
aioctx->buf = new char[aioctx->length];
aioctx->op = LIBCURVE_OP::LIBCURVE_OP_READ;
ioreadflag = false;
char* data = static_cast<char*>(aioctx->buf);
ioctxmana->AioRead(aioctx, mdsclient_.get(), UserDataType::RawBuffer);
{
std::unique_lock<std::mutex> lk(readmtx);
readcv.wait(lk, []()->bool{return ioreadflag;});
}
ASSERT_EQ('a', data[0]);
ASSERT_EQ('a', data[4 * 1024 - 1]);
ASSERT_EQ('b', data[4 * 1024]);
ASSERT_EQ('e', data[4 * 1024 + chunk_size - 1]);
ASSERT_EQ('f', data[4 * 1024 + chunk_size]);
ASSERT_EQ('f', data[aioctx->length - 1]);
}
TEST_F(IOTrackerSplitorTest, ManagerAsyncStartWrite) {
MockRequestScheduler* mockschuler = new MockRequestScheduler;
mockschuler->DelegateToFake();
auto ioctxmana = fileinstance_->GetIOManager4File();
ioctxmana->SetRequestScheduler(mockschuler);
CurveAioContext* aioctx = new CurveAioContext;
aioctx->offset = 4 * 1024 * 1024 - 4 * 1024;
aioctx->length = 4 * 1024 * 1024 + 8 * 1024;
aioctx->ret = LIBCURVE_ERROR::OK;
aioctx->cb = writecallback;
aioctx->buf = new char[aioctx->length];
aioctx->op = LIBCURVE_OP::LIBCURVE_OP_WRITE;
char* data = static_cast<char*>(aioctx->buf);
memset(data, 'a', 4 * 1024);
memset(data + 4 * 1024, 'b', chunk_size);
memset(data + 4 * 1024 + chunk_size, 'c', 4 * 1024);
iowriteflag = false;
ioctxmana->AioWrite(aioctx, mdsclient_.get(), UserDataType::RawBuffer);
{
std::unique_lock<std::mutex> lk(writemtx);
writecv.wait(lk, []()->bool{return iowriteflag;});
}
std::unique_ptr<char[]> writebuffer(new char[aioctx->length]);
memcpy(writebuffer.get(), writeData.to_string().c_str(), aioctx->length);
ASSERT_EQ('a', writebuffer[0]);
ASSERT_EQ('a', writebuffer[4 * 1024 - 1]);
ASSERT_EQ('b', writebuffer[4 * 1024]);
ASSERT_EQ('b', writebuffer[4 * 1024 + chunk_size - 1]);
ASSERT_EQ('c', writebuffer[4 * 1024 + chunk_size]);
ASSERT_EQ('c', writebuffer[aioctx->length - 1]);
}
/*
TEST_F(IOTrackerSplitorTest, ManagerAsyncStartWriteReadGetSegmentFail) {
MockRequestScheduler* mockschuler = new MockRequestScheduler;
mockschuler->DelegateToFake();
curve::mds::GetOrAllocateSegmentResponse* response =
new curve::mds::GetOrAllocateSegmentResponse();
brpc::Controller* controller1 = new brpc::Controller;
controller1->SetFailed(-1, "error");
FakeReturn* fakeret = new FakeReturn(controller1,
static_cast<void*>(response));
curvefsservice.SetGetOrAllocateSegmentFakeReturn(fakeret);
MetaCache* mc = fileinstance_->GetIOManager4File()->GetMetaCache();
auto ioctxmana = fileinstance_->GetIOManager4File();
ioctxmana->SetRequestScheduler(mockschuler);
ioctxmana->SetIOOpt(fopt.ioOpt);
CurveAioContext* aioctx = new CurveAioContext;
aioctx->offset = 10*1024*1024*1024ul;
aioctx->length = chunk_size + 8 * 1024;
aioctx->ret = LIBCURVE_ERROR::OK;
aioctx->cb = writecallback;
aioctx->buf = new char[aioctx->length];
aioctx->op = LIBCURVE_OP::LIBCURVE_OP_WRITE;
char* data = static_cast<char*>(aioctx->buf);
memset(data, 'a', 4 * 1024);
memset(data + 4 * 1024, 'b', chunk_size);
memset(data + 4 * 1024 + chunk_size, 'c', 4 * 1024);
// 设置mds一侧get segment接口返回失败底层task thread层会一直重试
// 但是不会阻塞上层继续向下发送IO请求
int reqcount = 32;
auto threadFunc1 = [&]() {
while (reqcount > 0) {
fileinstance_->AioWrite(aioctx);
reqcount--;
}
};
std::thread t1(threadFunc1);
std::thread t2(threadFunc1);
t1.join();
t2.join();
}
TEST_F(IOTrackerSplitorTest, ManagerAsyncStartWriteReadGetServerlistFail) {
MockRequestScheduler* mockschuler = new MockRequestScheduler;
mockschuler->DelegateToFake();
::curve::mds::topology::GetChunkServerListInCopySetsResponse* response
= new ::curve::mds::topology::GetChunkServerListInCopySetsResponse;
brpc::Controller* controller1 = new brpc::Controller;
controller1->SetFailed(-1, "error");
FakeReturn* fakeret = new FakeReturn(controller1,
static_cast<void*>(response));
topologyservice.SetFakeReturn(fakeret);
MetaCache* mc = fileinstance_->GetIOManager4File()->GetMetaCache();
auto ioctxmana = fileinstance_->GetIOManager4File();
ioctxmana->SetRequestScheduler(mockschuler);
ioctxmana->SetIOOpt(fopt.ioOpt);
// offset 10*1024*1024*1024ul 不在metacache里
// client回去mds拿segment和serverlist
CurveAioContext* aioctx = new CurveAioContext;
aioctx->offset = 10*1024*1024*1024ul;
aioctx->length = chunk_size + 8 * 1024;
aioctx->ret = LIBCURVE_ERROR::OK;
aioctx->cb = writecallback;
aioctx->buf = new char[aioctx->length];
aioctx->op = LIBCURVE_OP::LIBCURVE_OP_WRITE;
char* data = static_cast<char*>(aioctx->buf);
memset(data, 'a', 4 * 1024);
memset(data + 4 * 1024, 'b', chunk_size);
memset(data + 4 * 1024 + chunk_size, 'c', 4 * 1024);
// 设置mds一侧get server list接口返回失败底层task thread层会一直重试
// 但是不会阻塞上层继续向下发送IO请求
int reqcount = 32;
auto threadFunc1 = [&]() {
while (reqcount > 0) {
fileinstance_->AioWrite(aioctx);
reqcount--;
}
};
std::thread t1(threadFunc1);
std::thread t2(threadFunc1);
t1.join();
t2.join();
}
*/
TEST_F(IOTrackerSplitorTest, ManagerStartRead) {
MockRequestScheduler* mockschuler = new MockRequestScheduler;
mockschuler->DelegateToFake();
auto ioctxmana = fileinstance_->GetIOManager4File();
ioctxmana->SetRequestScheduler(mockschuler);
uint64_t offset = 4 * 1024 * 1024 - 4 * 1024;
uint64_t length = 4 * 1024 * 1024 + 8 * 1024;
char* data = new char[length];
auto threadfunc = [&]() {
ASSERT_EQ(length,
ioctxmana->Read(data, offset, length, mdsclient_.get()));
};
std::thread process(threadfunc);
if (process.joinable()) {
process.join();
}
ASSERT_EQ('a', data[0]);
ASSERT_EQ('a', data[4 * 1024 - 1]);
ASSERT_EQ('b', data[4 * 1024]);
ASSERT_EQ('e', data[4 * 1024 + chunk_size - 1]);
ASSERT_EQ('f', data[4 * 1024 + chunk_size]);
ASSERT_EQ('f', data[length - 1]);
delete[] data;
}
TEST_F(IOTrackerSplitorTest, ManagerStartWrite) {
MockRequestScheduler* mockschuler = new MockRequestScheduler;
mockschuler->DelegateToFake();
auto ioctxmana = fileinstance_->GetIOManager4File();
ioctxmana->SetRequestScheduler(mockschuler);
uint64_t offset = 4 * 1024 * 1024 - 4 * 1024;
uint64_t length = 4 * 1024 * 1024 + 8 * 1024;
char* buf = new char[length];
memset(buf, 'a', 4 * 1024);
memset(buf + 4 * 1024, 'b', chunk_size);
memset(buf + 4 * 1024 + chunk_size, 'c', 4 * 1024);
auto threadfunc = [&]() {
ioctxmana->Write(buf, offset, length, mdsclient_.get());
};
std::thread process(threadfunc);
if (process.joinable()) {
process.join();
}
std::unique_ptr<char[]> writebuffer(new char[length]);
memcpy(writebuffer.get(), writeData.to_string().c_str(), length);
ASSERT_EQ('a', writebuffer[0]);
ASSERT_EQ('a', writebuffer[4 * 1024 - 1]);
ASSERT_EQ('b', writebuffer[4 * 1024]);
ASSERT_EQ('b', writebuffer[4 * 1024 + chunk_size - 1]);
ASSERT_EQ('c', writebuffer[4 * 1024 + chunk_size]);
ASSERT_EQ('c', writebuffer[length - 1]);
delete[] buf;
}
TEST_F(IOTrackerSplitorTest, ExceptionTest_TEST) {
MockRequestScheduler* mockschuler = new MockRequestScheduler;
mockschuler->DelegateToFake();
FInfo_t fi;
fi.chunksize = 4 * 1024 * 1024;
fi.segmentsize = 1 * 1024 * 1024 * 1024ul;
auto fileserv = new FileInstance();
UserInfo_t rootuserinfo;
rootuserinfo.owner = "root";
rootuserinfo.password = "root_password";
ASSERT_TRUE(fileserv->Initialize("/test", mdsclient_, rootuserinfo,
OpenFlags{}, fopt));
ASSERT_EQ(LIBCURVE_ERROR::OK, fileserv->Open());
curve::client::IOManager4File* iomana = fileserv->GetIOManager4File();
MetaCache* mc = fileserv->GetIOManager4File()->GetMetaCache();
FileMetric fileMetric("/test");
IOTracker* iotracker = new IOTracker(iomana, mc, mockschuler, &fileMetric);
ASSERT_NE(nullptr, iotracker);
uint64_t offset = 4 * 1024 * 1024 - 4 * 1024;
uint64_t length = 4 * 1024 * 1024 + 8 * 1024;
char* buf = new char[length];
auto waitfunc = [&]() {
int retlen = iotracker->Wait();
ASSERT_EQ(-LIBCURVE_ERROR::FAILED, retlen);
};
auto threadfunc = [&]() {
iotracker->SetUserDataType(UserDataType::RawBuffer);
iotracker->StartWrite(nullptr, offset, length, mdsclient_.get(),
&fi, nullptr);
};
std::thread process(threadfunc);
std::thread waitthread(waitfunc);
uint64_t off = 4 * 1024 * 1024 * 1024ul - 4 * 1024;
uint64_t len = 4 * 1024 * 1024 + 8 * 1024;
iomana->Write(buf, off, len, mdsclient_.get());
if (process.joinable()) {
process.join();
}
if (waitthread.joinable()) {
waitthread.join();
}
fileserv->Close();
fileserv->UnInitialize();
delete fileserv;
delete mockschuler;
}
TEST_F(IOTrackerSplitorTest, BoundaryTEST) {
MockRequestScheduler* mockschuler = new MockRequestScheduler;
mockschuler->DelegateToFake();
auto ioctxmana = fileinstance_->GetIOManager4File();
ioctxmana->SetRequestScheduler(mockschuler);
// this offset and length will make splitor split fail.
// we set disk size = 1G.
uint64_t offset = 1 * 1024 * 1024 * 1024 -
4 * 1024 * 1024 - 4 *1024;
uint64_t length = 4 * 1024 * 1024 + 8 * 1024;
char* buf = new char[length];
memset(buf, 'a', 4 * 1024);
memset(buf + 4 * 1024, 'b', chunk_size);
memset(buf + 4 * 1024 + chunk_size, 'c', 4 * 1024);
auto threadfunc = [&]() {
ASSERT_EQ(-1 * LIBCURVE_ERROR::FAILED,
ioctxmana->Write(buf, offset, length, mdsclient_.get()));
};
std::thread process(threadfunc);
if (process.joinable()) {
process.join();
}
delete[] buf;
}
TEST_F(IOTrackerSplitorTest, largeIOTest) {
MockRequestScheduler mockschuler;
mockschuler.DelegateToFake();
/**
* this offset and length will make splitor split into two 8k IO.
*/
uint64_t length = 2 * 64 * 1024; // 128KB
uint64_t offset = 4 * 1024 * 1024 - length; // 4MB - 128KB
char* buf = new char[length];
memset(buf, 'a', 64 * 1024); // 64KB
memset(buf + 64 * 1024, 'b', 64 * 1024); // 64KB
butil::IOBuf writeData;
writeData.append(buf, length);
FInfo_t fi;
fi.seqnum = 0;
fi.chunksize = 4 * 1024 * 1024;
fi.segmentsize = 1 * 1024 * 1024 * 1024ul;
curve::client::IOManager4File* iomana = fileinstance_->GetIOManager4File();
MetaCache* mc = fileinstance_->GetIOManager4File()->GetMetaCache();
IOTracker* iotracker = new IOTracker(iomana, mc, &mockschuler);
iotracker->SetOpType(OpType::WRITE);
curve::client::ChunkIDInfo chinfo(1, 2, 3);
mc->UpdateChunkInfoByIndex(0, chinfo);
std::vector<RequestContext*> reqlist;
auto dataCopy = writeData;
ASSERT_EQ(0, curve::client::Splitor::IO2ChunkRequests(
iotracker, mc, &reqlist, &dataCopy, offset, length,
mdsclient_.get(), &fi, nullptr));
ASSERT_EQ(2, reqlist.size());
RequestContext* first = reqlist.front();
reqlist.erase(reqlist.begin());
RequestContext* second = reqlist.front();
reqlist.erase(reqlist.begin());
// first 64KB is 'a'
// seconds 64KB is 'b'
butil::IOBuf splitData;
splitData.append(first->writeData_);
splitData.append(second->writeData_);
ASSERT_EQ(writeData, splitData);
ASSERT_EQ(1, first->idinfo_.cid_);
ASSERT_EQ(3, first->idinfo_.cpid_);
ASSERT_EQ(2, first->idinfo_.lpid_);
ASSERT_EQ(4 * 1024 * 1024 - length, first->offset_);
ASSERT_EQ(64 * 1024, first->rawlength_);
ASSERT_EQ(0, first->seq_);
ASSERT_EQ(0, first->appliedindex_);
ASSERT_EQ(1, second->idinfo_.cid_);
ASSERT_EQ(3, second->idinfo_.cpid_);
ASSERT_EQ(2, second->idinfo_.lpid_);
ASSERT_EQ(4 * 1024 * 1024 - 64 * 1024, second->offset_);
ASSERT_EQ(64 * 1024, second->rawlength_);
ASSERT_EQ(0, second->seq_);
ASSERT_EQ(0, second->appliedindex_);
delete[] buf;
}
TEST_F(IOTrackerSplitorTest, InvalidParam) {
uint64_t length = 2 * 64 * 1024;
uint64_t offset = 4 * 1024 * 1024 - length;
char* buf = new char[length];
butil::IOBuf iobuf;
MetaCache* mc = fileinstance_->GetIOManager4File()->GetMetaCache();
std::vector<RequestContext*> reqlist;
FInfo_t fi;
IOTracker* iotracker = new IOTracker(nullptr, nullptr, nullptr);
curve::client::ChunkIDInfo cid(0, 0, 0);
ASSERT_EQ(-1, curve::client::Splitor::IO2ChunkRequests(
nullptr, mc, &reqlist, &iobuf, offset, length,
mdsclient_.get(), &fi, nullptr));
ASSERT_EQ(-1, curve::client::Splitor::SingleChunkIO2ChunkRequests(
nullptr, mc,
&reqlist, cid, &iobuf, offset, length, 0));
ASSERT_EQ(-1, curve::client::Splitor::IO2ChunkRequests(
iotracker, nullptr, &reqlist, &iobuf, offset, length,
mdsclient_.get(), nullptr, nullptr));
ASSERT_EQ(-1, curve::client::Splitor::SingleChunkIO2ChunkRequests(
iotracker, nullptr,
&reqlist, cid, &iobuf, offset, length, 0));
ASSERT_EQ(-1, curve::client::Splitor::IO2ChunkRequests(
iotracker, mc, &reqlist, &iobuf, offset, length,
mdsclient_.get(), nullptr, nullptr));
ASSERT_EQ(
-1, curve::client::Splitor::IO2ChunkRequests(
iotracker, mc, &reqlist, &iobuf, offset, length, nullptr,
&fi, nullptr));
ASSERT_EQ(0, curve::client::Splitor::SingleChunkIO2ChunkRequests(
iotracker, mc,
&reqlist, cid, &iobuf, offset, length, 0));
ASSERT_EQ(-1, curve::client::Splitor::IO2ChunkRequests(
iotracker, mc, nullptr, &iobuf, offset, length,
mdsclient_.get(), nullptr, nullptr));
ASSERT_EQ(-1, curve::client::Splitor::SingleChunkIO2ChunkRequests(
iotracker, mc,
nullptr, cid, &iobuf, offset, length, 0));
ASSERT_EQ(-1, curve::client::Splitor::IO2ChunkRequests(
iotracker, mc, &reqlist, nullptr, offset, length,
mdsclient_.get(), nullptr, nullptr));
iotracker->SetOpType(OpType::WRITE);
ASSERT_EQ(-1,
curve::client::Splitor::SingleChunkIO2ChunkRequests(
iotracker, mc, &reqlist, cid, nullptr, offset, length, 0));
// write request, but write data is nullptr
iotracker->SetOpType(OpType::WRITE);
ASSERT_EQ(-1, curve::client::Splitor::IO2ChunkRequests(
iotracker, mc, &reqlist, nullptr, offset, length,
mdsclient_.get(), &fi, nullptr));
// ASSERT_EQ(-1, Splitor::CalcDiscardSegments(nullptr));
delete iotracker;
delete[] buf;
}
TEST_F(IOTrackerSplitorTest, RequestSourceInfoTest) {
IOTracker ioTracker(nullptr, nullptr, nullptr);
ioTracker.SetOpType(OpType::READ);
MetaCache metaCache;
FInfo_t fileInfo;
fileInfo.chunksize = 16 * 1024 * 1024; // 16M
fileInfo.filestatus = FileStatus::CloneMetaInstalled;
CloneSourceInfo cloneSourceInfo;
cloneSourceInfo.name = "/clonesource";
cloneSourceInfo.length = 10ull * 1024 * 1024 * 1024; // 10GB
cloneSourceInfo.segmentSize = 1ull * 1024 * 1024 * 1024; // 1GB
// 源卷只分配了第一个和最后一个segment
cloneSourceInfo.allocatedSegmentOffsets.insert(0);
cloneSourceInfo.allocatedSegmentOffsets.insert(cloneSourceInfo.length -
cloneSourceInfo.segmentSize);
fileInfo.sourceInfo = cloneSourceInfo;
metaCache.UpdateFileInfo(fileInfo);
ChunkIndex chunkIdx = 0;
RequestSourceInfo sourceInfo;
// 第一个chunk
sourceInfo =
Splitor::CalcRequestSourceInfo(&ioTracker, &metaCache, chunkIdx);
ASSERT_TRUE(sourceInfo.IsValid());
ASSERT_EQ(sourceInfo.cloneFileSource, fileInfo.sourceInfo.name);
ASSERT_EQ(sourceInfo.cloneFileOffset, 0);
// 克隆卷最后一个chunk
chunkIdx = fileInfo.sourceInfo.length / fileInfo.chunksize - 1;
LOG(INFO) << "clone length = " << fileInfo.sourceInfo.length
<< ", chunk size = " << fileInfo.chunksize
<< ", chunk idx = " << chunkIdx;
// offset = 10*1024*1024*1024 - 16 * 1024 * 1024 = 10720641024
sourceInfo =
Splitor::CalcRequestSourceInfo(&ioTracker, &metaCache, chunkIdx);
ASSERT_TRUE(sourceInfo.IsValid());
ASSERT_EQ(sourceInfo.cloneFileSource, fileInfo.sourceInfo.name);
ASSERT_EQ(sourceInfo.cloneFileOffset, 10720641024);
// 源卷未分配segment
// 读取每个segment的第一个chunk
for (int i = 1; i < 9; ++i) {
ChunkIndex chunkIdx =
i * cloneSourceInfo.segmentSize / fileInfo.chunksize;
RequestSourceInfo sourceInfo = Splitor::CalcRequestSourceInfo(
&ioTracker, &metaCache, chunkIdx);
ASSERT_FALSE(sourceInfo.IsValid());
ASSERT_TRUE(sourceInfo.cloneFileSource.empty());
ASSERT_EQ(sourceInfo.cloneFileOffset, 0);
}
// 超过长度
chunkIdx = fileInfo.sourceInfo.length / fileInfo.chunksize;
sourceInfo =
Splitor::CalcRequestSourceInfo(&ioTracker, &metaCache, chunkIdx);
ASSERT_FALSE(sourceInfo.IsValid());
ASSERT_TRUE(sourceInfo.cloneFileSource.empty());
ASSERT_EQ(sourceInfo.cloneFileOffset, 0);
// 源卷长度为0
chunkIdx = 0;
fileInfo.sourceInfo.length = 0;
metaCache.UpdateFileInfo(fileInfo);
sourceInfo =
Splitor::CalcRequestSourceInfo(&ioTracker, &metaCache, chunkIdx);
ASSERT_FALSE(sourceInfo.IsValid());
ASSERT_TRUE(sourceInfo.cloneFileSource.empty());
ASSERT_EQ(sourceInfo.cloneFileOffset, 0);
// 不是read/write请求
chunkIdx = 1;
ioTracker.SetOpType(OpType::READ_SNAP);
sourceInfo =
Splitor::CalcRequestSourceInfo(&ioTracker, &metaCache, chunkIdx);
ASSERT_FALSE(sourceInfo.IsValid());
ASSERT_TRUE(sourceInfo.cloneFileSource.empty());
ASSERT_EQ(sourceInfo.cloneFileOffset, 0);
fileInfo.filestatus = FileStatus::Cloned;
metaCache.UpdateFileInfo(fileInfo);
chunkIdx = 0;
// 不是克隆卷
sourceInfo =
Splitor::CalcRequestSourceInfo(&ioTracker, &metaCache, chunkIdx);
ASSERT_FALSE(sourceInfo.IsValid());
ASSERT_TRUE(sourceInfo.cloneFileSource.empty());
ASSERT_EQ(sourceInfo.cloneFileOffset, 0);
}
TEST_F(IOTrackerSplitorTest, stripeTest) {
MockRequestScheduler mockschuler;
mockschuler.DelegateToFake();
FInfo_t fi;
uint64_t offset = 1 * 1024 * 1024 - 64 * 1024;
uint64_t length = 128 * 1024;
butil::IOBuf dataCopy;
char* buf = new char[length];
fi.seqnum = 0;
fi.chunksize = 4 * 1024 * 1024;
fi.segmentsize = 1 * 1024 * 1024 * 1024ul;
fi.stripeUnit = 1 * 1024 * 1024;
fi.stripeCount = 4;
memset(buf, 'a', length); // 64KB
dataCopy.append(buf, length);
curve::client::IOManager4File* iomana = fileinstance_->GetIOManager4File();
MetaCache* mc = iomana->GetMetaCache();
IOTracker* iotracker = new IOTracker(iomana, mc, &mockschuler);
iotracker->SetOpType(OpType::WRITE);
curve::client::ChunkIDInfo chinfo(1, 2, 3);
curve::client::ChunkIDInfo chinfo1(4, 5, 6);
mc->UpdateChunkInfoByIndex(0, chinfo);
mc->UpdateChunkInfoByIndex(1, chinfo1);
std::vector<RequestContext*> reqlist;
ASSERT_EQ(0, curve::client::Splitor::IO2ChunkRequests(
iotracker, mc, &reqlist, &dataCopy, offset, length,
mdsclient_.get(), &fi, nullptr));
ASSERT_EQ(2, reqlist.size());
RequestContext* first = reqlist.front();
reqlist.erase(reqlist.begin());
RequestContext* second = reqlist.front();
reqlist.erase(reqlist.begin());
ASSERT_EQ(1, first->idinfo_.cid_);
ASSERT_EQ(3, first->idinfo_.cpid_);
ASSERT_EQ(2, first->idinfo_.lpid_);
ASSERT_EQ(1 * 1024 * 1024 - 64 * 1024, first->offset_);
ASSERT_EQ(64 * 1024, first->rawlength_);
ASSERT_EQ(4, second->idinfo_.cid_);
ASSERT_EQ(6, second->idinfo_.cpid_);
ASSERT_EQ(5, second->idinfo_.lpid_);
ASSERT_EQ(0, second->offset_);
ASSERT_EQ(64 * 1024, second->rawlength_);
reqlist.clear();
offset = 16 * 1024 * 1024 - 64 * 1024;
length = 128 * 1024;
memset(buf, 'b', length);
dataCopy.append(buf, length);
mc->UpdateChunkInfoByIndex(3, chinfo);
mc->UpdateChunkInfoByIndex(4, chinfo1);
ASSERT_EQ(0, curve::client::Splitor::IO2ChunkRequests(
iotracker, mc, &reqlist, &dataCopy, offset, length,
mdsclient_.get(), &fi, nullptr));
ASSERT_EQ(2, reqlist.size());
first = reqlist.front();
reqlist.erase(reqlist.begin());
second = reqlist.front();
reqlist.erase(reqlist.begin());
ASSERT_EQ(1, first->idinfo_.cid_);
ASSERT_EQ(3, first->idinfo_.cpid_);
ASSERT_EQ(2, first->idinfo_.lpid_);
ASSERT_EQ(4 * 1024 * 1024 - 64 * 1024, first->offset_);
ASSERT_EQ(64 * 1024, first->rawlength_);
ASSERT_EQ(4, second->idinfo_.cid_);
ASSERT_EQ(6, second->idinfo_.cpid_);
ASSERT_EQ(5, second->idinfo_.lpid_);
ASSERT_EQ(0, second->offset_);
ASSERT_EQ(64 * 1024, second->rawlength_);
delete[] buf;
}
TEST_F(IOTrackerSplitorTest, TestDisableStripeForStripeFile) {
MockRequestScheduler scheduler;
scheduler.DelegateToFake();
FInfo fi;
fi.seqnum = 0;
fi.chunksize = 4 * 1024 * 1024;
fi.segmentsize = 1 * 1024 * 1024 * 1024ul;
fi.stripeUnit = 1 * 1024 * 1024;
fi.stripeCount = 4;
uint64_t offset = 1 * 1024 * 1024 - 64 * 1024;
uint64_t length = 128 * 1024;
std::unique_ptr<char[]> buf(new char[length]);
memset(buf.get(), 'a', length);
butil::IOBuf dataCopy;
dataCopy.append(buf.get(), length);
auto* iomanager = fileinstance_->GetIOManager4File();
MetaCache* cache = iomanager->GetMetaCache();
curve::client::ChunkIDInfo chinfo(1, 2, 3);
curve::client::ChunkIDInfo chinfo1(4, 5, 6);
cache->UpdateChunkInfoByIndex(0, chinfo);
cache->UpdateChunkInfoByIndex(1, chinfo1);
IOTracker ioTracker(iomanager, cache, &scheduler, nullptr, true);
std::vector<RequestContext*> reqlist;
ASSERT_EQ(0,
Splitor::IO2ChunkRequests(&ioTracker, cache, &reqlist, &dataCopy,
offset, length, mdsclient_.get(), &fi, nullptr));
ASSERT_EQ(2, reqlist.size());
auto* first = reqlist[0];
ASSERT_EQ(1, first->idinfo_.cid_);
ASSERT_EQ(3, first->idinfo_.cpid_);
ASSERT_EQ(2, first->idinfo_.lpid_);
ASSERT_EQ(1 * 1024 * 1024 - 64 * 1024, first->offset_);
ASSERT_EQ(length / 2, first->rawlength_);
auto* second = reqlist[1];
ASSERT_EQ(1, second->idinfo_.cid_);
ASSERT_EQ(3, second->idinfo_.cpid_);
ASSERT_EQ(2, second->idinfo_.lpid_);
ASSERT_EQ(1 * 1024 * 1024, second->offset_);
ASSERT_EQ(length / 2, second->rawlength_);
}
// read the chunks all haven't been write from normal volume with no clonesource
TEST_F(IOTrackerSplitorTest, StartReadNotAllocateSegment) {
curvefsservice.SetGetOrAllocateSegmentFakeReturn(notallocatefakeret);
MockRequestScheduler* mockschuler = new MockRequestScheduler;
mockschuler->DelegateToFake();
curve::client::IOManager4File* iomana = fileinstance_->GetIOManager4File();
iomana->SetRequestScheduler(mockschuler);
uint64_t offset = 1 * 1024 * 1024 * 1024 + 4 * 1024 * 1024 - 4 * 1024;
uint64_t length = 4 * 1024 * 1024 + 8 * 1024;
char* data = new char[length];
auto threadfunc = [&]() {
iomana->Read(data, offset, length, mdsclient_.get());
};
std::thread process(threadfunc);
if (process.joinable()) {
process.join();
}
for (int i = 0; i < length; i++) {
ASSERT_EQ(0, data[i]);
}
delete[] data;
}
TEST_F(IOTrackerSplitorTest, AsyncStartReadNotAllocateSegment) {
curvefsservice.SetGetOrAllocateSegmentFakeReturn(notallocatefakeret);
MockRequestScheduler* mockschuler = new MockRequestScheduler;
mockschuler->DelegateToFake();
curve::client::IOManager4File* iomana = fileinstance_->GetIOManager4File();
iomana->SetRequestScheduler(mockschuler);
CurveAioContext aioctx;
aioctx.offset = 1 * 1024 * 1024 * 1024 + 4 * 1024 * 1024 - 4 * 1024;
aioctx.length = 4 * 1024 * 1024 + 8 * 1024;
aioctx.ret = LIBCURVE_ERROR::OK;
aioctx.cb = readcallback;
aioctx.buf = new char[aioctx.length];
aioctx.op = LIBCURVE_OP::LIBCURVE_OP_READ;
ioreadflag = false;
char* data = static_cast<char*>(aioctx.buf);
iomana->AioRead(&aioctx, mdsclient_.get(), UserDataType::RawBuffer);
{
std::unique_lock<std::mutex> lk(readmtx);
readcv.wait(lk, []()->bool{return ioreadflag;});
}
for (int i = 0; i < aioctx.length; i++) {
ASSERT_EQ(0, data[i]);
}
delete[] data;
}
// read the chunks some of them haven't been writtern from normal volume
// with no clonesource
TEST_F(IOTrackerSplitorTest, StartReadNotAllocateSegment2) {
curvefsservice.SetGetOrAllocateSegmentFakeReturn(notallocatefakeret);
MockRequestScheduler* mockschuler = new MockRequestScheduler;
mockschuler->DelegateToFake();
curve::client::IOManager4File* iomana = fileinstance_->GetIOManager4File();
MetaCache* mc = fileinstance_->GetIOManager4File()->GetMetaCache();
ChunkIDInfo chunkIdInfo(1, 1, 256);
mc->UpdateChunkInfoByIndex(256, chunkIdInfo);
iomana->SetRequestScheduler(mockschuler);
uint64_t offset = 1 * 1024 * 1024 * 1024 + 4 * 1024 * 1024 - 4 * 1024;
uint64_t length = 4 * 1024 * 1024 + 8 * 1024;
char* data = new char[length];
auto threadfunc = [&]() {
iomana->Read(data, offset, length, mdsclient_.get());
};
std::thread process(threadfunc);
if (process.joinable()) {
process.join();
}
for (int i = 0; i < 4 * 1024; i++) {
ASSERT_EQ('a', data[i]);
}
for (int i = 4 * 1024; i < length; i++) {
ASSERT_EQ(0, data[i]);
}
delete[] data;
}
TEST_F(IOTrackerSplitorTest, AsyncStartReadNotAllocateSegment2) {
curvefsservice.SetGetOrAllocateSegmentFakeReturn(notallocatefakeret);
MockRequestScheduler* mockschuler = new MockRequestScheduler;
mockschuler->DelegateToFake();
curve::client::IOManager4File* iomana = fileinstance_->GetIOManager4File();
MetaCache* mc = fileinstance_->GetIOManager4File()->GetMetaCache();
ChunkIDInfo chunkIdInfo(1, 1, 256);
mc->UpdateChunkInfoByIndex(256, chunkIdInfo);
iomana->SetRequestScheduler(mockschuler);
CurveAioContext aioctx;
aioctx.offset = 1 * 1024 * 1024 * 1024 + 4 * 1024 * 1024 - 4 * 1024;
aioctx.length = 4 * 1024 * 1024 + 8 * 1024;
aioctx.ret = LIBCURVE_ERROR::OK;
aioctx.cb = readcallback;
aioctx.buf = new char[aioctx.length];
aioctx.op = LIBCURVE_OP::LIBCURVE_OP_READ;
ioreadflag = false;
char* data = static_cast<char*>(aioctx.buf);
iomana->AioRead(&aioctx, mdsclient_.get(), UserDataType::RawBuffer);
{
std::unique_lock<std::mutex> lk(readmtx);
readcv.wait(lk, []()->bool{return ioreadflag;});
}
for (int i = 0; i < 4 * 1024; i++) {
ASSERT_EQ('a', data[i]);
}
for (int i = 4 * 1024; i < aioctx.length; i++) {
ASSERT_EQ(0, data[i]);
}
delete[] data;
}
// read the chunks some haven't been write from clone volume with clonesource
TEST_F(IOTrackerSplitorTest, StartReadNotAllocateSegmentFromOrigin) {
curvefsservice.SetGetOrAllocateSegmentFakeReturn(notallocatefakeret);
curvefsservice.SetGetOrAllocateSegmentFakeReturnForClone(
getsegmentfakeretclone);
PrepareOpenFile();
MockRequestScheduler* mockschuler = new MockRequestScheduler;
mockschuler->DelegateToFake();
FileInstance* fileinstance2 = new FileInstance();
userinfo.owner = "cloneuser-test1";
userinfo.password = "12345";
mdsclient_->Initialize(fopt.metaServerOpt);
fileinstance2->Initialize("/clonesource", mdsclient_, userinfo, OpenFlags{},
fopt);
ASSERT_EQ(LIBCURVE_ERROR::OK, fileinstance2->Open());
MockRequestScheduler* mockschuler2 = new MockRequestScheduler;
mockschuler2->DelegateToFake();
fileinstance2->GetIOManager4File()->SetRequestScheduler(mockschuler2);
auto& handlers = SourceReader::GetInstance().GetReadHandlers();
handlers.emplace(
std::piecewise_construct,
std::forward_as_tuple("/clonesource"),
std::forward_as_tuple(fileinstance2, ::time(nullptr), false));
curve::client::IOManager4File* iomana = fileinstance_->GetIOManager4File();
MetaCache* mc = fileinstance_->GetIOManager4File()->GetMetaCache();
ChunkIDInfo chunkIdInfo(1, 1, 257);
mc->UpdateChunkInfoByIndex(257, chunkIdInfo);
FInfo_t fileInfo;
fileInfo.chunksize = 4 * 1024 * 1024; // 4M
fileInfo.fullPathName = "/1_userinfo_.txt";
fileInfo.owner = "userinfo";
fileInfo.filestatus = FileStatus::CloneMetaInstalled;
fileInfo.sourceInfo.name = "/clonesource";
fileInfo.sourceInfo.segmentSize = 1ull * 1024 * 1024 * 1024;
fileInfo.sourceInfo.length = 10ull * 1024 * 1024 * 1024;
for (uint64_t i = 0; i < fileInfo.sourceInfo.length;
i += fileInfo.sourceInfo.segmentSize) {
fileInfo.sourceInfo.allocatedSegmentOffsets.insert(i);
}
fileInfo.userinfo = userinfo;
mc->UpdateFileInfo(fileInfo);
iomana->SetRequestScheduler(mockschuler);
uint64_t offset = 1 * 1024 * 1024 * 1024 + 4 * 1024 * 1024 - 4 * 1024;
uint64_t length = 4 * 1024 * 1024 + 8 * 1024;
char* data = new char[length];
auto threadfunc = [&]() {
iomana->Read(data, offset, length, mdsclient_.get());
};
std::thread process(threadfunc);
if (process.joinable()) {
process.join();
}
LOG(ERROR) << "address = " << &data;
ASSERT_EQ('a', data[0]);
ASSERT_EQ('a', data[4 * 1024 - 1]);
ASSERT_EQ('a', data[4 * 1024]);
ASSERT_EQ('d', data[4 * 1024 + chunk_size - 1]);
ASSERT_EQ('a', data[4 * 1024 + chunk_size]);
ASSERT_EQ('a', data[length - 1]);
fileinstance2->UnInitialize();
delete fileinstance2;
delete[] data;
}
TEST_F(IOTrackerSplitorTest, AsyncStartReadNotAllocateSegmentFromOrigin) {
curvefsservice.SetGetOrAllocateSegmentFakeReturn(notallocatefakeret);
curvefsservice.SetGetOrAllocateSegmentFakeReturnForClone
(getsegmentfakeretclone);
PrepareOpenFile();
MockRequestScheduler* mockschuler = new MockRequestScheduler;
mockschuler->DelegateToFake();
FileInstance* fileinstance2 = new FileInstance();
userinfo.owner = "cloneuser-test2";
userinfo.password = "12345";
mdsclient_->Initialize(fopt.metaServerOpt);
fileinstance2->Initialize("/clonesource", mdsclient_, userinfo, OpenFlags{},
fopt);
ASSERT_EQ(LIBCURVE_ERROR::OK, fileinstance2->Open());
MockRequestScheduler* mockschuler2 = new MockRequestScheduler;
mockschuler2->DelegateToFake();
fileinstance2->GetIOManager4File()->SetRequestScheduler(mockschuler2);
auto& handlers = SourceReader::GetInstance().GetReadHandlers();
handlers.emplace(
std::piecewise_construct,
std::forward_as_tuple("/clonesource"),
std::forward_as_tuple(fileinstance2, ::time(nullptr), false));
curve::client::IOManager4File* iomana = fileinstance_->GetIOManager4File();
MetaCache* mc = fileinstance_->GetIOManager4File()->GetMetaCache();
ChunkIDInfo chunkIdInfo(1, 1, 257);
mc->UpdateChunkInfoByIndex(257, chunkIdInfo);
FInfo_t fileInfo;
fileInfo.chunksize = 4 * 1024 * 1024;
fileInfo.filename = "1_userinfo_.txt";
fileInfo.owner = "userinfo";
fileInfo.filestatus = FileStatus::CloneMetaInstalled;
fileInfo.sourceInfo.name = "/clonesource";
fileInfo.sourceInfo.segmentSize = 1ull * 1024 * 1024 * 1024;
fileInfo.sourceInfo.length = 10ull * 1024 * 1024 * 1024;
for (uint64_t i = 0; i < fileInfo.sourceInfo.length;
i += fileInfo.sourceInfo.segmentSize) {
fileInfo.sourceInfo.allocatedSegmentOffsets.insert(i);
}
fileInfo.userinfo = userinfo;
mc->UpdateFileInfo(fileInfo);
iomana->SetRequestScheduler(mockschuler);
CurveAioContext aioctx;
aioctx.offset = 1 * 1024 * 1024 * 1024 + 4 * 1024 * 1024 - 4 * 1024;
aioctx.length = 4 * 1024 * 1024 + 8 * 1024;
aioctx.ret = LIBCURVE_ERROR::OK;
aioctx.cb = readcallback;
aioctx.buf = new char[aioctx.length];
aioctx.op = LIBCURVE_OP::LIBCURVE_OP_READ;
ioreadflag = false;
char* data = static_cast<char*>(aioctx.buf);
iomana->AioRead(&aioctx, mdsclient_.get(), UserDataType::RawBuffer);
{
std::unique_lock<std::mutex> lk(readmtx);
readcv.wait(lk, []()->bool{return ioreadflag;});
}
LOG(ERROR) << "address = " << &data;
ASSERT_EQ('a', data[0]);
ASSERT_EQ('a', data[4 * 1024 - 1]);
ASSERT_EQ('a', data[4 * 1024]);
ASSERT_EQ('d', data[4 * 1024 + chunk_size - 1]);
ASSERT_EQ('a', data[4 * 1024 + chunk_size]);
ASSERT_EQ('a', data[aioctx.length - 1]);
fileinstance2->UnInitialize();
delete fileinstance2;
delete[] data;
}
TEST_F(IOTrackerSplitorTest, TimedCloseFd) {
std::unordered_map<std::string, SourceReader::ReadHandler> fakeHandlers;
fakeHandlers.emplace(
std::piecewise_construct,
std::forward_as_tuple("/1"),
std::forward_as_tuple(
nullptr,
::time(nullptr) - fopt.ioOpt.closeFdThreadOption.fdTimeout,
true));
fakeHandlers.emplace(
std::piecewise_construct,
std::forward_as_tuple("/2"),
std::forward_as_tuple(
nullptr,
::time(nullptr) - fopt.ioOpt.closeFdThreadOption.fdTimeout,
false));
FileInstance* instance = new FileInstance();
fakeHandlers.emplace(
std::piecewise_construct,
std::forward_as_tuple("/3"),
std::forward_as_tuple(
instance,
::time(nullptr) - fopt.ioOpt.closeFdThreadOption.fdTimeout,
false));
SourceReader::GetInstance().SetReadHandlers(fakeHandlers);
std::this_thread::sleep_for(std::chrono::seconds(30));
SourceReader::GetInstance().Stop();
ASSERT_EQ(0, SourceReader::GetInstance().GetReadHandlers().size());
}
} // namespace client
} // namespace curve