curve/test/client/libcurve_interface_unittest...

1028 lines
36 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:16:52 pm
* Author: tongguangxun
*/
#include <fiu-control.h>
#include <gflags/gflags.h>
#include <glog/logging.h>
#include <gtest/gtest.h>
#include <chrono> // NOLINT
#include <condition_variable> // NOLINT
#include <iostream>
#include <mutex> // NOLINT
#include <string>
#include <thread> //NOLINT
#include "include/client/libcurve.h"
#include "src/client/chunk_closure.h"
#include "src/client/client_common.h"
#include "src/client/file_instance.h"
#include "src/client/libcurve_file.h"
#include "test/client/fake/fakeMDS.h"
#include "test/client/fake/mock_schedule.h"
extern std::string configpath;
extern uint32_t chunk_size;
extern uint32_t segment_size;
DECLARE_string(chunkserver_list);
DECLARE_uint32(logic_pool_id);
DECLARE_uint32(copyset_num);
DECLARE_uint64(test_disk_size);
namespace curve {
namespace client {
bool writeflag = false;
bool readflag = false;
std::mutex writeinterfacemtx;
std::condition_variable writeinterfacecv;
std::mutex interfacemtx;
std::condition_variable interfacecv;
void writecallbacktest(CurveAioContext *context) {
std::lock_guard<std::mutex> lk(writeinterfacemtx);
writeflag = true;
writeinterfacecv.notify_one();
LOG(INFO) << "aio call back here, errorcode = " << context->ret;
}
void readcallbacktest(CurveAioContext *context) {
std::lock_guard<std::mutex> lk(writeinterfacemtx);
readflag = true;
interfacecv.notify_one();
LOG(INFO) << "aio call back here, errorcode = " << context->ret;
}
TEST(TestLibcurveInterface, InterfaceTest) {
FLAGS_chunkserver_list =
"127.0.0.1:9115:0,127.0.0.1:9116:0,127.0.0.1:9117:0";
std::string filename = "/1_userinfo_";
C_UserInfo_t userinfo;
memcpy(userinfo.owner, "userinfo", 9);
memcpy(userinfo.password, "", 1);
// 设置leaderid
EndPoint ep;
butil::str2endpoint("127.0.0.1", 9115, &ep);
PeerId pd(ep);
// init mds service
FakeMDS mds(filename);
mds.Initialize();
mds.StartCliService(pd);
mds.StartService();
mds.CreateCopysetNode(true);
// test get cluster id
const int CLUSTERIDMAX = 256;
char clusterId[CLUSTERIDMAX];
ASSERT_EQ(GetClusterId(clusterId, CLUSTERIDMAX), -LIBCURVE_ERROR::FAILED);
ASSERT_EQ(0, Init(configpath.c_str()));
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
ASSERT_EQ(GetClusterId(nullptr, 0), -LIBCURVE_ERROR::FAILED);
memset(clusterId, 0, sizeof(clusterId));
ASSERT_EQ(GetClusterId(clusterId, CLUSTERIDMAX), LIBCURVE_ERROR::OK);
ASSERT_GT(strlen(clusterId), 0);
ASSERT_EQ(strlen(clusterId), 36);
memset(clusterId, 0, sizeof(clusterId));
ASSERT_EQ(GetClusterId(clusterId, 0), -LIBCURVE_ERROR::FAILED);
ASSERT_EQ(GetClusterId(clusterId, 1), -LIBCURVE_ERROR::FAILED);
// libcurve file operation
(void)Create(filename.c_str(), &userinfo, FLAGS_test_disk_size);
int fd = Open(filename.c_str(), &userinfo);
ASSERT_NE(fd, -1);
char *buffer = new char[8 * 1024];
memset(buffer, 'a', 1024);
memset(buffer + 1024, 'b', 1024);
memset(buffer + 2 * 1024, 'c', 1024);
memset(buffer + 3 * 1024, 'd', 1024);
memset(buffer + 4 * 1024, 'e', 1024);
memset(buffer + 5 * 1024, 'f', 1024);
memset(buffer + 6 * 1024, 'g', 1024);
memset(buffer + 7 * 1024, 'h', 1024);
CurveAioContext writeaioctx;
writeaioctx.buf = buffer;
writeaioctx.offset = 0;
writeaioctx.length = 8 * 1024;
writeaioctx.cb = writecallbacktest;
AioWrite(fd, &writeaioctx);
{
std::unique_lock<std::mutex> lk(writeinterfacemtx);
writeinterfacecv.wait(lk, []() -> bool { return writeflag; });
}
writeflag = false;
AioWrite(fd, &writeaioctx);
{
std::unique_lock<std::mutex> lk(writeinterfacemtx);
writeinterfacecv.wait(lk, []() -> bool { return writeflag; });
}
char *readbuffer = new char[8 * 1024];
CurveAioContext readaioctx;
readaioctx.buf = readbuffer;
readaioctx.offset = 0;
readaioctx.length = 8 * 1024;
readaioctx.cb = readcallbacktest;
AioRead(fd, &readaioctx);
{
std::unique_lock<std::mutex> lk(interfacemtx);
interfacecv.wait(lk, []() -> bool { return readflag; });
}
for (int i = 0; i < 1024; i++) {
ASSERT_EQ(readbuffer[i], 'a');
ASSERT_EQ(readbuffer[i + 1024], 'b');
ASSERT_EQ(readbuffer[i + 2 * 1024], 'c');
ASSERT_EQ(readbuffer[i + 3 * 1024], 'd');
ASSERT_EQ(readbuffer[i + 4 * 1024], 'e');
ASSERT_EQ(readbuffer[i + 5 * 1024], 'f');
ASSERT_EQ(readbuffer[i + 6 * 1024], 'g');
ASSERT_EQ(readbuffer[i + 7 * 1024], 'h');
}
mds.EnableNetUnstable(400);
int count = 0;
while (count < 20) {
uint64_t offset = 0;
uint64_t length = 8 * 1024;
memset(buffer, 'i', 1024);
memset(buffer + 1024, 'j', 1024);
memset(buffer + 2 * 1024, 'k', 1024);
memset(buffer + 3 * 1024, 'l', 1024);
memset(buffer + 4 * 1024, 'm', 1024);
memset(buffer + 5 * 1024, 'n', 1024);
memset(buffer + 6 * 1024, 'o', 1024);
memset(buffer + 7 * 1024, 'p', 1024);
ASSERT_EQ(length, Write(fd, buffer, offset, length));
ASSERT_EQ(length, Read(fd, readbuffer, offset, length));
for (int i = 0; i < 1024; i++) {
ASSERT_EQ(readbuffer[i], 'i');
ASSERT_EQ(readbuffer[i + 1024], 'j');
ASSERT_EQ(readbuffer[i + 2 * 1024], 'k');
ASSERT_EQ(readbuffer[i + 3 * 1024], 'l');
ASSERT_EQ(readbuffer[i + 4 * 1024], 'm');
ASSERT_EQ(readbuffer[i + 5 * 1024], 'n');
ASSERT_EQ(readbuffer[i + 6 * 1024], 'o');
ASSERT_EQ(readbuffer[i + 7 * 1024], 'p');
}
count++;
std::this_thread::sleep_for(std::chrono::milliseconds(400));
}
/**
* the disk is faked, the size is just = 10 * 1024 * 1024 * 1024.
* when the offset pass the boundary, it will return failed.
*/
off_t off = 10 * 1024 * 1024 * 1024ul;
uint64_t len = 8 * 1024;
ASSERT_EQ(-1 * LIBCURVE_ERROR::FAILED, Write(fd, buffer, off, len));
ASSERT_EQ(-1 * LIBCURVE_ERROR::FAILED, Read(fd, readbuffer, off, len));
off_t off1 = 1 * 1024 * 1024 * 1024ul - 8 * 1024;
uint64_t len1 = 8 * 1024;
LOG(ERROR) << "normal read write";
ASSERT_EQ(len, Write(fd, buffer, off1, len1));
ASSERT_EQ(len, Read(fd, readbuffer, off1, len1));
Close(fd);
mds.UnInitialize();
delete[] buffer;
delete[] readbuffer;
UnInit();
}
TEST(TestLibcurveInterface, FileClientTest) {
fiu_init(0);
FLAGS_chunkserver_list =
"127.0.0.1:9115:0,127.0.0.1:9116:0,127.0.0.1:9117:0";
std::string filename = "/1";
UserInfo_t userinfo;
userinfo.owner = "userinfo";
FileClient fc;
// 设置leaderid
EndPoint ep;
butil::str2endpoint("127.0.0.1", 9115, &ep);
PeerId pd(ep);
// init mds service
FakeMDS mds(filename);
mds.Initialize();
mds.StartCliService(pd);
mds.StartService();
mds.CreateCopysetNode(true);
ASSERT_EQ(0, fc.Init(configpath));
// init twice also return 0
ASSERT_EQ(0, fc.Init(configpath));
ASSERT_EQ(0, fc.GetOpenedFileNum());
int fd = fc.Open4ReadOnly(filename, userinfo);
int fd2 = fc.Open(filename, userinfo);
int fd3 = fc.Open(filename, UserInfo_t{});
int fd4 = fc.Open4ReadOnly(filename, UserInfo_t{});
ASSERT_NE(fd, -1);
ASSERT_NE(fd2, -1);
// user info invalid
ASSERT_EQ(-1, fd3);
ASSERT_EQ(-1, fd4);
ASSERT_EQ(2, fc.GetOpenedFileNum());
fiu_enable("test/client/fake/fakeMDS.GetOrAllocateSegment", 1, nullptr, 0);
char *buffer = new char[8 * 1024];
memset(buffer, 'a', 1024);
memset(buffer + 1024, 'b', 1024);
memset(buffer + 2 * 1024, 'c', 1024);
memset(buffer + 3 * 1024, 'd', 1024);
memset(buffer + 4 * 1024, 'e', 1024);
memset(buffer + 5 * 1024, 'f', 1024);
memset(buffer + 6 * 1024, 'g', 1024);
memset(buffer + 7 * 1024, 'h', 1024);
CurveAioContext writeaioctx;
writeaioctx.buf = buffer;
writeaioctx.offset = 0;
writeaioctx.length = 8 * 1024;
writeaioctx.cb = writecallbacktest;
ASSERT_EQ(-1, fc.AioWrite(fd, &writeaioctx));
writeflag = false;
ASSERT_EQ(0, fc.AioWrite(fd2, &writeaioctx));
{
std::unique_lock<std::mutex> lk(writeinterfacemtx);
writeinterfacecv.wait(lk, []() -> bool { return writeflag; });
}
char *readbuffer = new char[8 * 1024];
memset(readbuffer, 0xFF, 8 * 1024);
CurveAioContext readaioctx;
readaioctx.buf = readbuffer;
readaioctx.offset = 0;
readaioctx.length = 8 * 1024;
readaioctx.cb = readcallbacktest;
readflag = false;
fc.AioRead(fd, &readaioctx);
{
std::unique_lock<std::mutex> lk(interfacemtx);
interfacecv.wait(lk, []() -> bool { return readflag; });
}
ASSERT_EQ(readaioctx.ret, readaioctx.length);
for (int i = 0; i < 1024; i++) {
ASSERT_EQ(readbuffer[i], 'a');
ASSERT_EQ(readbuffer[i + 1024], 'b');
ASSERT_EQ(readbuffer[i + 2 * 1024], 'c');
ASSERT_EQ(readbuffer[i + 3 * 1024], 'd');
ASSERT_EQ(readbuffer[i + 4 * 1024], 'e');
ASSERT_EQ(readbuffer[i + 5 * 1024], 'f');
ASSERT_EQ(readbuffer[i + 6 * 1024], 'g');
ASSERT_EQ(readbuffer[i + 7 * 1024], 'h');
}
fc.Close(fd);
fc.Close(fd2);
ASSERT_EQ(0, fc.GetOpenedFileNum());
mds.UnInitialize();
delete[] buffer;
delete[] readbuffer;
fc.UnInit();
// uninit twice
fc.UnInit();
}
/*
TEST(TestLibcurveInterface, ChunkserverUnstableTest) {
std::string filename = "/1_userinfo_";
UserInfo_t userinfo;
MDSClient mdsclient_;
FileServiceOption fopt;
FileInstance fileinstance_;
FLAGS_chunkserver_list =
"127.0.0.1:9151:0,127.0.0.1:9152:0,127.0.0.1:9153:0";
userinfo.owner = "userinfo";
userinfo.password = "12345";
fopt.metaServerOpt.mdsAddrs.push_back("127.0.0.1:9104");
fopt.metaServerOpt.chunkserverRPCTimeoutMS = 500;
fopt.loginfo.logLevel = 0;
fopt.ioOpt.ioSplitOpt.fileIOSplitMaxSizeKB = 64;
fopt.ioOpt.ioSenderOpt.chunkserverEnableAppliedIndexRead = 1;
fopt.ioOpt.ioSenderOpt.chunkserverRPCTimeoutMS = 1000;
fopt.ioOpt.ioSenderOpt.failRequestOpt.chunkserverOPMaxRetry = 3;
fopt.ioOpt.ioSenderOpt.failRequestOpt.chunkserverOPRetryIntervalUS = 500;
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.leaseOpt.mdsRefreshTimesPerLease = 4;
mdsclient_.Initialize(fopt.metaServerOpt);
fileinstance_.Initialize("/test", &mdsclient_, userinfo, fopt);
// 设置leaderid
EndPoint ep;
butil::str2endpoint("127.0.0.1", 9151, &ep);
PeerId pd(ep);
// init mds service
FakeMDS mds(filename);
mds.Initialize();
mds.StartCliService(pd);
mds.StartService();
mds.CreateCopysetNode(true);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
int fd = fileinstance_.Open(filename.c_str(), userinfo);
MetaCache* mc = fileinstance_.GetIOManager4File()->GetMetaCache();
ASSERT_NE(fd, -1);
CliServiceFake* cliservice = mds.GetCliService();
std::vector<FakeChunkService*> chunkservice = mds.GetFakeChunkService();
char* buffer = new char[8 * 1024];
uint64_t offset = 0;
uint64_t length = 8 * 1024;
memset(buffer, 'i', 1024);
memset(buffer + 1024, 'j', 1024);
memset(buffer + 2 * 1024, 'k', 1024);
memset(buffer + 3 * 1024, 'l', 1024);
memset(buffer + 4 * 1024, 'm', 1024);
memset(buffer + 5 * 1024, 'n', 1024);
memset(buffer + 6 * 1024, 'o', 1024);
memset(buffer + 7 * 1024, 'p', 1024);
ASSERT_EQ(length, fileinstance_.Write(buffer, offset, length));
ASSERT_EQ(length, fileinstance_.Read(buffer, offset, length));
// 正常情况下只有第一次会去get leader
ASSERT_EQ(1, cliservice->GetInvokeTimes());
// metacache中被写过的copyset leadermaychange都处于正常状态
ChunkIDInfo_t chunkinfo1;
MetaCacheErrorType rc = mc->GetChunkInfoByIndex(0, &chunkinfo1);
ASSERT_EQ(rc, MetaCacheErrorType::OK);
for (int i = 0; i < FLAGS_copyset_num; i++) {
CopysetPeerInfo ci = mc->GetCopysetinfo(FLAGS_logic_pool_id, i);
if (i == chunkinfo1.cpid_) {
ASSERT_NE(-1, ci.GetCurrentLeaderIndex());
ASSERT_FALSE(ci.LeaderMayChange());
} else {
ASSERT_EQ(-1, ci.GetCurrentLeaderIndex());
ASSERT_FALSE(ci.LeaderMayChange());
}
}
// 设置chunkservice返回失败那么mds每次重试都会去拉新的leader
// 127.0.0.1:9151:0,127.0.0.1:9152:0,127.0.0.1:9153:0是当前集群信息
// 127.0.0.1:9151对应第一个chunkservice
// 设置rpc失败会导致client将该chunkserverid上的leader copyset都标记为
// leadermaychange
chunkservice[0]->SetRPCFailed();
//
现在写第二个chunk第二个chunk与第一个chunk不在同一个copyset里这次读写失败
ASSERT_EQ(-2, fileinstance_.Write(buffer, 1 * chunk_size, length));
ASSERT_EQ(-2, fileinstance_.Read(buffer, 1 * chunk_size, length));
// 获取第2个chunk的chunkid信息
ChunkIDInfo_t chunkinfo2;
rc = mc->GetChunkInfoByIndex(1, &chunkinfo2);
ASSERT_EQ(rc, MetaCacheErrorType::OK);
ASSERT_NE(chunkinfo2.cpid_, chunkinfo1.cpid_);
for (int i = 0; i < FLAGS_copyset_num; i++) {
CopysetPeerInfo ci = mc->GetCopysetinfo(FLAGS_logic_pool_id, i);
if (i == chunkinfo1.cpid_ || i == chunkinfo2.cpid_) {
ASSERT_NE(-1, ci.GetCurrentLeaderIndex());
// 这两个leader为该chunkserver的copyset的LeaderMayChange置位
ASSERT_TRUE(ci.LeaderMayChange());
} else {
// 对于当前copyset没有leader信息的就直接置位LeaderMayChange
ASSERT_EQ(-1, ci.GetCurrentLeaderIndex());
ASSERT_TRUE(ci.LeaderMayChange());
}
}
chunkservice[0]->ReSetRPCFailed();
// 再次写第二个chunk这时候获取leader成功后会将LeaderMayChange置位fasle
// 第一个chunk对应的copyset依然LeaderMayChange为true
ASSERT_EQ(8192, fileinstance_.Write(buffer, 1 * chunk_size, length));
ASSERT_EQ(8192, fileinstance_.Read(buffer, 1 * chunk_size, length));
for (int i = 0; i < FLAGS_copyset_num; i++) {
CopysetPeerInfo ci = mc->GetCopysetinfo(FLAGS_logic_pool_id, i);
if (i == chunkinfo2.cpid_) {
ASSERT_NE(-1, ci.GetCurrentLeaderIndex());
// copyset2的LeaderMayChange置位
ASSERT_FALSE(ci.LeaderMayChange());
} else if (i == chunkinfo1.cpid_) {
ASSERT_NE(-1, ci.GetCurrentLeaderIndex());
// copyset1的LeaderMayChange保持原有状态
ASSERT_TRUE(ci.LeaderMayChange());
} else {
// 对于当前copyset没有leader信息的就直接置位LeaderMayChange
ASSERT_EQ(-1, ci.GetCurrentLeaderIndex());
ASSERT_TRUE(ci.LeaderMayChange());
}
}
cliservice->ReSetInvokeTimes();
EndPoint ep2;
butil::str2endpoint("127.0.0.1", 9152, &ep2);
PeerId pd2(ep2);
cliservice->SetPeerID(pd2);
// 设置rpc失败迫使copyset切换leader切换leader后读写成功
chunkservice[0]->SetRPCFailed();
// 读写第一个和第二个chunk
ASSERT_EQ(8192, fileinstance_.Write(buffer, 0 * chunk_size, length));
ASSERT_EQ(8192, fileinstance_.Read(buffer, 0 * chunk_size, length));
ASSERT_EQ(8192, fileinstance_.Write(buffer, 0 * chunk_size, length));
ASSERT_EQ(8192, fileinstance_.Read(buffer, 0 * chunk_size, length));
ASSERT_EQ(1, cliservice->GetInvokeTimes());
// 这个时候
for (int i = 0; i < FLAGS_copyset_num; i++) {
CopysetPeerInfo ci = mc->GetCopysetinfo(FLAGS_logic_pool_id, i);
if (i == chunkinfo2.cpid_) {
ASSERT_NE(-1, ci.GetCurrentLeaderIndex());
// copyset2的LeaderMayChange置位
ASSERT_FALSE(ci.LeaderMayChange());
} else if (i == chunkinfo1.cpid_) {
ASSERT_NE(-1, ci.GetCurrentLeaderIndex());
// copyset1的LeaderMayChange置位
ASSERT_FALSE(ci.LeaderMayChange());
} else {
// 对于当前copyset没有leader信息的就直接置位LeaderMayChange
ASSERT_EQ(-1, ci.GetCurrentLeaderIndex());
ASSERT_TRUE(ci.LeaderMayChange());
}
}
// 验证copyset id信息更新
// copyset id = 888 chunkserver id = 100 101 102
// copyset id = 999 chunkserver id = 102 103 104
CopysetPeerInfo csinfo1;
PeerAddr addr;
csinfo1.cpid_ = 888;
curve::client::CopysetPeerInfo peer1(100, addr);
csinfo1.csinfos_.push_back(peer1);
curve::client::CopysetPeerInfo peer2(101, addr);
csinfo1.csinfos_.push_back(peer2);
curve::client::CopysetPeerInfo peer3(102, addr);
csinfo1.csinfos_.push_back(peer3);
CopysetPeerInfo csinfo2;
csinfo2.cpid_ = 999;
curve::client::CopysetPeerInfo peer4(102, addr);
csinfo2.csinfos_.push_back(peer4);
curve::client::CopysetPeerInfo peer5(103, addr);
csinfo2.csinfos_.push_back(peer5);
curve::client::CopysetPeerInfo peer6(104, addr);
csinfo2.csinfos_.push_back(peer6);
mc->UpdateCopysetInfo(FLAGS_logic_pool_id, 888, csinfo1);
mc->UpdateCopysetInfo(FLAGS_logic_pool_id, 999, csinfo2);
auto cpinfo1 = mc->GetCopysetinfo(FLAGS_logic_pool_id, 888);
auto cpinfo2 = mc->GetCopysetinfo(FLAGS_logic_pool_id, 999);
ASSERT_EQ(888, cpinfo1.cpid_);
ASSERT_EQ(999, cpinfo2.cpid_);
mc->AddCopysetIDInfo(100, CopysetIDInfo(FLAGS_logic_pool_id, 888));
mc->AddCopysetIDInfo(101, CopysetIDInfo(FLAGS_logic_pool_id, 888));
mc->AddCopysetIDInfo(102, CopysetIDInfo(FLAGS_logic_pool_id, 888));
mc->AddCopysetIDInfo(102, CopysetIDInfo(FLAGS_logic_pool_id, 999));
mc->AddCopysetIDInfo(103, CopysetIDInfo(FLAGS_logic_pool_id, 999));
mc->AddCopysetIDInfo(104, CopysetIDInfo(FLAGS_logic_pool_id, 999));
ASSERT_TRUE(mc->CopysetIDInfoIn(100, FLAGS_logic_pool_id, 888));
ASSERT_TRUE(mc->CopysetIDInfoIn(101, FLAGS_logic_pool_id, 888));
ASSERT_TRUE(mc->CopysetIDInfoIn(102, FLAGS_logic_pool_id, 888));
ASSERT_TRUE(mc->CopysetIDInfoIn(102, FLAGS_logic_pool_id, 999));
ASSERT_TRUE(mc->CopysetIDInfoIn(103, FLAGS_logic_pool_id, 999));
ASSERT_TRUE(mc->CopysetIDInfoIn(104, FLAGS_logic_pool_id, 999));
ASSERT_FALSE(mc->CopysetIDInfoIn(101, FLAGS_logic_pool_id, 999));
CopysetPeerInfo csinfo3;
csinfo3.cpid_ = 999;
curve::client::CopysetPeerInfo peer7(100, addr);
csinfo3.csinfos_.push_back(peer7);
curve::client::CopysetPeerInfo peer8(101, addr);
csinfo3.csinfos_.push_back(peer8);
curve::client::CopysetPeerInfo peer9(103, addr);
csinfo3.csinfos_.push_back(peer9);
// 更新copyset信息chunkserver 104的信息被清除
// 100和 101上添加了新的copyset信息
mc->UpdateChunkserverCopysetInfo(FLAGS_logic_pool_id, csinfo3);
ASSERT_TRUE(mc->CopysetIDInfoIn(100, FLAGS_logic_pool_id, 888));
ASSERT_TRUE(mc->CopysetIDInfoIn(100, FLAGS_logic_pool_id, 999));
ASSERT_TRUE(mc->CopysetIDInfoIn(101, FLAGS_logic_pool_id, 888));
ASSERT_TRUE(mc->CopysetIDInfoIn(101, FLAGS_logic_pool_id, 999));
ASSERT_TRUE(mc->CopysetIDInfoIn(102, FLAGS_logic_pool_id, 888));
ASSERT_TRUE(mc->CopysetIDInfoIn(103, FLAGS_logic_pool_id, 999));
ASSERT_FALSE(mc->CopysetIDInfoIn(104, FLAGS_logic_pool_id, 999));
ASSERT_FALSE(mc->CopysetIDInfoIn(102, FLAGS_logic_pool_id, 999));
mdsclient_.UnInitialize();
fileinstance_.UnInitialize();
mds.UnInitialize();
delete[] buffer;
}
*/
TEST(TestLibcurveInterface, InterfaceExceptionTest) {
std::string filename = "/1_userinfo_";
C_UserInfo_t userinfo;
memcpy(userinfo.owner, "userinfo", 9);
memcpy(userinfo.password, "", 1);
// open not create file
ASSERT_EQ(-1 * LIBCURVE_ERROR::FAILED, Open(filename.c_str(), &userinfo));
// 设置leaderid
EndPoint ep;
butil::str2endpoint("127.0.0.1", 9106, &ep);
PeerId pd(ep);
// init mds service
FakeMDS mds(filename);
mds.Initialize();
mds.StartCliService(pd);
mds.StartService();
mds.CreateCopysetNode(true);
ASSERT_EQ(0, Init(configpath.c_str()));
char *buffer = new char[8 * 1024];
memset(buffer, 'a', 8 * 1024);
CurveAioContext writeaioctx;
writeaioctx.buf = buffer;
writeaioctx.offset = 0;
writeaioctx.length = 8 * 1024;
writeaioctx.cb = writecallbacktest;
// aiowrite not opened file
ASSERT_EQ(-LIBCURVE_ERROR::BAD_FD, AioWrite(1234, &writeaioctx));
// aioread not opened file
char *readbuffer = new char[8 * 1024];
CurveAioContext readaioctx;
readaioctx.buf = readbuffer;
readaioctx.offset = 0;
readaioctx.length = 8 * 1024;
readaioctx.cb = readcallbacktest;
ASSERT_EQ(-1 * LIBCURVE_ERROR::BAD_FD, AioRead(1234, &readaioctx));
uint64_t offset = 0;
uint64_t length = 8 * 1024;
// write not opened file
ASSERT_EQ(-1 * LIBCURVE_ERROR::BAD_FD, Write(1234, buffer, offset, length));
// read not opened file
ASSERT_EQ(-1 * LIBCURVE_ERROR::BAD_FD,
Read(1234, readbuffer, offset, length));
delete[] buffer;
delete[] readbuffer;
UnInit();
mds.UnInitialize();
}
TEST(TestLibcurveInterface, UnstableChunkserverTest) {
std::string filename = "/1_userinfo_";
UserInfo_t userinfo;
std::shared_ptr<MDSClient> mdsclient_ = std::make_shared<MDSClient>();
FileServiceOption fopt;
FileInstance fileinstance_;
FLAGS_chunkserver_list =
"127.0.0.1:9151:0,127.0.0.1:9152:0,127.0.0.1:9153:0";
userinfo.owner = "userinfo";
userinfo.password = "UnstableChunkserverTest";
fopt.metaServerOpt.rpcRetryOpt.addrs.push_back("127.0.0.1:9104");
fopt.metaServerOpt.rpcRetryOpt.rpcTimeoutMs = 500;
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;
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.leaseOpt.mdsRefreshTimesPerLease = 4;
fopt.ioOpt.metaCacheOpt.chunkserverUnstableOption
.maxStableChunkServerTimeoutTimes = 10; // NOLINT
LOG(INFO) << "fopt size " << sizeof(fopt);
// curve::client::ClientClosure::SetFailureRequestOption(
// fopt.ioOpt.ioSenderOpt.failRequestOpt);
LOG(INFO) << "here";
mdsclient_->Initialize(fopt.metaServerOpt);
fileinstance_.Initialize(
"/UnstableChunkserverTest", mdsclient_, userinfo, OpenFlags{}, fopt);
// 设置leaderid
EndPoint ep;
butil::str2endpoint("127.0.0.1", 9151, &ep);
PeerId pd(ep);
// init mds service
FakeMDS mds(filename);
mds.Initialize();
mds.StartCliService(pd);
mds.StartService();
mds.CreateCopysetNode(true);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
int fd = fileinstance_.Open();
MetaCache *mc = fileinstance_.GetIOManager4File()->GetMetaCache();
ASSERT_NE(fd, -1);
CliServiceFake *cliservice = mds.GetCliService();
std::vector<FakeChunkService *> chunkservice = mds.GetFakeChunkService();
char *buffer = new char[8 * 1024];
uint64_t offset = 0;
uint64_t length = 8 * 1024;
memset(buffer, 'i', 1024);
memset(buffer + 1024, 'j', 1024);
memset(buffer + 2 * 1024, 'k', 1024);
memset(buffer + 3 * 1024, 'l', 1024);
memset(buffer + 4 * 1024, 'm', 1024);
memset(buffer + 5 * 1024, 'n', 1024);
memset(buffer + 6 * 1024, 'o', 1024);
memset(buffer + 7 * 1024, 'p', 1024);
ASSERT_EQ(length, fileinstance_.Write(buffer, offset, length));
ASSERT_EQ(length, fileinstance_.Read(buffer, offset, length));
// metacache中被写过的copyset leadermaychange都处于正常状态
ChunkIDInfo_t chunkinfo1;
MetaCacheErrorType rc = mc->GetChunkInfoByIndex(0, &chunkinfo1);
ASSERT_EQ(rc, MetaCacheErrorType::OK);
for (int i = 0; i < FLAGS_copyset_num; i++) {
CopysetInfo<ChunkServerID> ci =
mc->GetCopysetinfo(FLAGS_logic_pool_id, i);
if (i == chunkinfo1.cpid_) {
ASSERT_NE(-1, ci.GetCurrentLeaderIndex());
ASSERT_FALSE(ci.LeaderMayChange());
} else {
ASSERT_EQ(-1, ci.GetCurrentLeaderIndex());
ASSERT_FALSE(ci.LeaderMayChange());
}
}
mds.EnableNetUnstable(10000);
// 写2次读2次每次请求重试3次
// 因为在chunkserver端设置了延迟导致每次请求都会超时
// unstable阈值为10所以第11次请求返回时对应的chunkserver被标记为unstable
// leader在对应chunkserver上的copyset会设置leaderMayChange为true
// 下次发起请求时会先去刷新leader信息
// 由于leader没有发生改变而且延迟仍然存在
// 所以第12次请求仍然超时leaderMayChange仍然为true
ASSERT_EQ(-2, fileinstance_.Write(buffer, 1 * chunk_size, length));
ASSERT_EQ(-2, fileinstance_.Write(buffer, 1 * chunk_size, length));
ASSERT_EQ(-2, fileinstance_.Read(buffer, 1 * chunk_size, length));
ASSERT_EQ(-2, fileinstance_.Read(buffer, 1 * chunk_size, length));
// 获取第2个chunk的chunkid信息
ChunkIDInfo_t chunkinfo2;
rc = mc->GetChunkInfoByIndex(1, &chunkinfo2);
ASSERT_EQ(rc, MetaCacheErrorType::OK);
ASSERT_NE(chunkinfo2.cpid_, chunkinfo1.cpid_);
for (int i = 0; i < FLAGS_copyset_num; ++i) {
CopysetInfo<ChunkServerID> ci =
mc->GetCopysetinfo(FLAGS_logic_pool_id, i);
if (i == chunkinfo1.cpid_ || i == chunkinfo2.cpid_) {
ASSERT_NE(-1, ci.GetCurrentLeaderIndex());
ASSERT_TRUE(ci.LeaderMayChange());
} else {
ASSERT_EQ(-1, ci.GetCurrentLeaderIndex());
ASSERT_TRUE(ci.LeaderMayChange());
}
}
// 当copyset处于unstable状态时
// 不进入超时时间指数退避逻辑rpc超时时间设置为默认值
// 所以每个请求总时间为3s4个请求需要12s
auto start = TimeUtility::GetTimeofDayMs();
ASSERT_EQ(-2, fileinstance_.Write(buffer, 1 * chunk_size, length));
ASSERT_EQ(-2, fileinstance_.Write(buffer, 1 * chunk_size, length));
ASSERT_EQ(-2, fileinstance_.Read(buffer, 1 * chunk_size, length));
ASSERT_EQ(-2, fileinstance_.Read(buffer, 1 * chunk_size, length));
auto end = TimeUtility::GetTimeofDayMs();
ASSERT_GT(end - start, 11 * 1000);
ASSERT_LT(end - start, 13 * 1000);
mds.DisableNetUnstable();
// 取消延迟再次读写第2个chunk
// 获取leader信息后会将leaderMayChange置为false
// 第一个chunk对应的copyset依赖leaderMayChange为true
ASSERT_EQ(8192, fileinstance_.Write(buffer, 1 * chunk_size, length));
ASSERT_EQ(8192, fileinstance_.Read(buffer, 1 * chunk_size, length));
for (int i = 0; i < FLAGS_copyset_num; ++i) {
CopysetInfo<ChunkServerID> ci =
mc->GetCopysetinfo(FLAGS_logic_pool_id, i);
if (i == chunkinfo2.cpid_) {
ASSERT_NE(-1, ci.GetCurrentLeaderIndex());
ASSERT_FALSE(ci.LeaderMayChange());
} else if (i == chunkinfo1.cpid_) {
ASSERT_NE(-1, ci.GetCurrentLeaderIndex());
ASSERT_TRUE(ci.LeaderMayChange());
} else {
ASSERT_EQ(-1, ci.GetCurrentLeaderIndex());
ASSERT_TRUE(ci.LeaderMayChange());
}
}
cliservice->ReSetInvokeTimes();
EndPoint ep2;
butil::str2endpoint("127.0.0.1", 9153, &ep2);
PeerId pd2(ep2);
cliservice->SetPeerID(pd2);
// 设置rcp返回失败迫使copyset切换leader, 切换leader后读写成功
chunkservice[0]->SetRPCFailed();
ASSERT_EQ(8192, fileinstance_.Write(buffer, 0 * chunk_size, length));
ASSERT_EQ(8192, fileinstance_.Read(buffer, 0 * chunk_size, length));
ASSERT_EQ(8192, fileinstance_.Write(buffer, 1 * chunk_size, length));
ASSERT_EQ(8192, fileinstance_.Read(buffer, 1 * chunk_size, length));
for (int i = 0; i < FLAGS_copyset_num; ++i) {
CopysetInfo<ChunkServerID> ci =
mc->GetCopysetinfo(FLAGS_logic_pool_id, i);
if (i == chunkinfo2.cpid_) {
ASSERT_NE(-1, ci.GetCurrentLeaderIndex());
ASSERT_FALSE(ci.LeaderMayChange());
} else if (i == chunkinfo1.cpid_) {
ASSERT_NE(-1, ci.GetCurrentLeaderIndex());
ASSERT_FALSE(ci.LeaderMayChange());
} else {
ASSERT_EQ(-1, ci.GetCurrentLeaderIndex());
ASSERT_TRUE(ci.LeaderMayChange());
}
}
fileinstance_.Close();
fileinstance_.UnInitialize();
mds.UnInitialize();
delete[] buffer;
}
TEST(TestLibcurveInterface, ResumeTimeoutBackoff) {
std::string filename = "/1_userinfo_";
UserInfo_t userinfo;
std::shared_ptr<MDSClient> mdsclient_ = std::make_shared<MDSClient>();
FileServiceOption fopt;
FileInstance fileinstance_;
FLAGS_chunkserver_list =
"127.0.0.1:9151:0,127.0.0.1:9152:0,127.0.0.1:9153:0";
userinfo.owner = "userinfo";
userinfo.password = "ResumeTimeoutBackoff";
fopt.metaServerOpt.rpcRetryOpt.addrs.push_back("127.0.0.1:9104");
fopt.metaServerOpt.rpcRetryOpt.rpcTimeoutMs = 500;
fopt.loginfo.logLevel = 0;
fopt.ioOpt.ioSplitOpt.fileIOSplitMaxSizeKB = 64;
fopt.ioOpt.ioSenderOpt.chunkserverEnableAppliedIndexRead = 1;
fopt.ioOpt.ioSenderOpt.failRequestOpt.chunkserverRPCTimeoutMS = 1000;
fopt.ioOpt.ioSenderOpt.failRequestOpt.chunkserverMaxRPCTimeoutMS = 8000;
fopt.ioOpt.ioSenderOpt.failRequestOpt.chunkserverOPMaxRetry = 11;
fopt.ioOpt.ioSenderOpt.failRequestOpt.chunkserverOPRetryIntervalUS = 500;
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.leaseOpt.mdsRefreshTimesPerLease = 4;
fopt.ioOpt.metaCacheOpt.chunkserverUnstableOption
.maxStableChunkServerTimeoutTimes = 10; // NOLINT
mdsclient_->Initialize(fopt.metaServerOpt);
fileinstance_.Initialize("/ResumeTimeoutBackoff", mdsclient_, userinfo,
OpenFlags{}, fopt);
// 设置leaderid
EndPoint ep;
butil::str2endpoint("127.0.0.1", 9151, &ep);
PeerId pd(ep);
// init mds service
FakeMDS mds(filename);
mds.Initialize();
mds.StartCliService(pd);
mds.StartService();
mds.CreateCopysetNode(true);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
int fd = fileinstance_.Open();
MetaCache *mc = fileinstance_.GetIOManager4File()->GetMetaCache();
ASSERT_NE(fd, -1);
std::vector<FakeChunkService *> chunkservice = mds.GetFakeChunkService();
char *buffer = new char[8 * 1024];
uint64_t offset = 0;
uint64_t length = 8 * 1024;
memset(buffer, 'i', 1024);
memset(buffer + 1024, 'j', 1024);
memset(buffer + 2 * 1024, 'k', 1024);
memset(buffer + 3 * 1024, 'l', 1024);
memset(buffer + 4 * 1024, 'm', 1024);
memset(buffer + 5 * 1024, 'n', 1024);
memset(buffer + 6 * 1024, 'o', 1024);
memset(buffer + 7 * 1024, 'p', 1024);
ASSERT_EQ(length, fileinstance_.Write(buffer, offset, length));
ASSERT_EQ(length, fileinstance_.Read(buffer, offset, length));
// metacache中被写过的copyset leadermaychange都处于正常状态
ChunkIDInfo_t chunkinfo1;
MetaCacheErrorType rc = mc->GetChunkInfoByIndex(0, &chunkinfo1);
ASSERT_EQ(rc, MetaCacheErrorType::OK);
for (int i = 0; i < FLAGS_copyset_num; i++) {
CopysetInfo<ChunkServerID> ci =
mc->GetCopysetinfo(FLAGS_logic_pool_id, i);
if (i == chunkinfo1.cpid_) {
ASSERT_NE(-1, ci.GetCurrentLeaderIndex());
ASSERT_FALSE(ci.LeaderMayChange());
} else {
ASSERT_EQ(-1, ci.GetCurrentLeaderIndex());
ASSERT_FALSE(ci.LeaderMayChange());
}
}
mds.EnableNetUnstable(10000);
// 写2次, 每次请求重试11次
// 因为在chunkserver端设置了延迟导致每次请求都会超时
// 第一个请求重试11次会把chunkserver标记为unstable
ASSERT_EQ(-2, fileinstance_.Write(buffer, 1 * chunk_size, length));
// 第二个写请求由于其对应的copyset leader may change
// 第1次请求超时时间为1s
// 后面4次重试由于leader may change所以超时时间也是1s
// 第5-11次请求由于重试次数超过minRetryTimesForceTimeoutBackoff
// 所以超时时间都进入指数退避为8s * 6 = 48s
// 所以第二次写请求总共耗时53s并写入失败
auto start = TimeUtility::GetTimeofDayMs();
ASSERT_EQ(-2, fileinstance_.Write(buffer, 1 * chunk_size, length));
auto elapsedMs = TimeUtility::GetTimeofDayMs() - start;
ASSERT_GE(elapsedMs, 52 * 1000);
ASSERT_LE(elapsedMs, 55 * 1000);
fileinstance_.Close();
fileinstance_.UnInitialize();
mds.UnInitialize();
delete[] buffer;
}
TEST(TestLibcurveInterface, InterfaceStripeTest) {
FLAGS_chunkserver_list =
"127.0.0.1:9115:0,127.0.0.1:9116:0,127.0.0.1:9117:0";
std::string filename = "/1";
std::string filename2 = "/2";
UserInfo_t userinfo;
userinfo.owner = "userinfo";
uint64_t size = 100 * 1024 * 1024 * 1024ul;
FileClient fc;
// 设置leaderid
EndPoint ep;
butil::str2endpoint("127.0.0.1", 9115, &ep);
PeerId pd(ep);
// init mds service
FakeMDS mds(filename);
mds.Initialize();
mds.StartCliService(pd);
mds.StartService();
mds.CreateCopysetNode(true);
ASSERT_EQ(0, fc.Init(configpath));
FakeMDSCurveFSService *service = NULL;
service = mds.GetMDSService();
::curve::mds::CreateFileResponse response;
response.set_statuscode(::curve::mds::StatusCode::kOK);
FakeReturn *fakeret =
new FakeReturn(nullptr, static_cast<void *>(&response));
service->SetCreateFileFakeReturn(fakeret);
CreateFileContext context;
context.pagefile = true;
context.name = filename;
context.user = userinfo;
context.length = size;
int ret = fc.Create2(context);
ASSERT_EQ(LIBCURVE_ERROR::OK, ret);
response.set_statuscode(::curve::mds::StatusCode::kFileExists);
fakeret = new FakeReturn(nullptr, static_cast<void *>(&response));
service->SetCreateFileFakeReturn(fakeret);
context.pagefile = true;
context.name = filename2;
context.user = userinfo;
context.length = size;
context.stripeUnit = 1024 * 1024;
context.stripeCount = 4;
ret = fc.Create2(context);
ASSERT_EQ(LIBCURVE_ERROR::EXISTS, -ret);
FileStatInfo_t fsinfo;
::curve::mds::FileInfo *info = new curve::mds::FileInfo;
::curve::mds::GetFileInfoResponse getinforesponse;
info->set_filename(filename2);
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(4 * 1024 * 1024 * 1024ul);
info->set_ctime(12345678);
info->set_segmentsize(1 * 1024 * 1024 * 1024ul);
info->set_stripeunit(1024 * 1024);
info->set_stripecount(4);
getinforesponse.set_allocated_fileinfo(info);
getinforesponse.set_statuscode(::curve::mds::StatusCode::kOK);
FakeReturn *fakegetinfo =
new FakeReturn(nullptr, static_cast<void *>(&getinforesponse));
service->SetGetFileInfoFakeReturn(fakegetinfo);
ret = fc.StatFile(filename2, userinfo, &fsinfo);
ASSERT_EQ(1024 * 1024, fsinfo.stripeUnit);
ASSERT_EQ(4, fsinfo.stripeCount);
mds.UnInitialize();
fc.UnInit();
}
} // namespace client
} // namespace curve