代码路径
curve-release2.2\nebd\src\part1\libnebd.cpp
libnebd.cpp
libnebd_file.cpp
nebd_client.cpp
heartbeat_manager.cpp
nebd_metacache.cpp
async_request_closure.cpp
下面是对libnebd.cpp
文件中源码的详细分析,我将通过注释的方式逐行解释代码的功能和作用。
/*
* 版权声明,该文件属于网易公司,并且遵循Apache License 2.0。
*/
/*
* Project: nebd
* 文件创建日期: 2019-08-07
* 作者: hzchenwei7
*/
// 引入必要的头文件
#include "nebd/src/part1/libnebd.h" // 包含neb文件操作的定义
#include "nebd/src/part1/libnebd_file.h" // 包含neb文件操作的实现
// 声明一个全局变量,用于标识libnebd是否已经初始化
extern "C" {
bool g_inited = false;
// 定义配置文件路径,这里硬编码了路径,可能需要根据实际情况修改
const char* confpath = "/etc/nebd/nebd-client.conf";
// nebd库初始化函数
int nebd_lib_init() {
if (g_inited) { // 如果已经初始化过,则直接返回0
return 0;
}
int ret = Init4Nebd(confpath); // 调用实际的初始化函数
if (ret != 0) { // 如果初始化失败,返回错误码
return ret;
}
g_inited = true; // 标记为已初始化
return ret; // 返回初始化结果
}
// 带有配置路径的neb库初始化函数
int nebd_lib_init_with_conf(const char* confPath) {
if (g_inited) { // 如果已经初始化过,则直接返回0
return 0;
}
int ret = Init4Nebd(confPath); // 调用实际的初始化函数,传入配置路径
if (ret != 0) { // 如果初始化失败,返回错误码
return ret;
}
g_inited = true; // 标记为已初始化
return ret; // 返回初始化结果
}
// neb库卸载函数
int nebd_lib_uninit() {
if (g_inited) { // 如果之前已经初始化过
Uninit4Nebd(); // 调用实际的卸载函数
g_inited = false; // 标记为未初始化
}
return 0; // 返回0表示成功
}
// 打开文件函数
int nebd_lib_open(const char* filename) {
return Open4Nebd(filename, nullptr); // 调用实际的打开文件函数,不传任何标志
}
// 带有标志的打开文件函数
int nebd_lib_open_with_flags(const char* filename, const NebdOpenFlags* flags) {
return Open4Nebd(filename, flags); // 调用实际的打开文件函数,传入文件操作标志
}
// 关闭文件函数
int nebd_lib_close(int fd) {
return Close4Nebd(fd); // 调用实际的关闭文件函数
}
// 预读函数,这里不支持同步读操作,返回-1
int nebd_lib_pread(int fd, void* buf, off_t offset, size_t length) {
// not support sync read
return -1;
}
// 预写函数,这里不支持同步写操作,返回-1
int nebd_lib_pwrite(int fd, const void* buf, off_t offset, size_t length) {
// not support sync write
return -1;
}
// 废弃函数,这里不支持,返回-1
int nebd_lib_discard(int fd, NebdClientAioContext* context) {
return Discard4Nebd(fd, context); // 调用实际的废弃函数
}
// 异步预读函数
int nebd_lib_aio_pread(int fd, NebdClientAioContext* context) {
return AioRead4Nebd(fd, context); // 调用实际的异步预读函数
}
// 异步预写函数
int nebd_lib_aio_pwrite(int fd, NebdClientAioContext* context) {
return AioWrite4Nebd(fd, context); // 调用实际的异步预写函数
}
// 同步函数,这里不支持,返回0
int nebd_lib_sync(int fd) {
return 0;
}
// 获取文件大小函数
int64_t nebd_lib_filesize(int fd) {
return GetFileSize4Nebd(fd); // 调用实际的获取文件大小函数
}
// 调整文件大小函数
int nebd_lib_resize(int fd, int64_t size) {
return Extend4Nebd(fd, size); // 调用实际的调整文件大小函数
}
// 刷新函数,这里不支持,返回0
int nebd_lib_flush(int fd, NebdClientAioContext* context) {
return Flush4Nebd(fd, context); // 调用实际的刷新函数
}
// 获取文件信息函数
int64_t nebd_lib_getinfo(int fd) {
return GetInfo4Nebd(fd); // 调用实际的获取文件信息函数
}
// 使缓存失效函数
int nebd_lib_invalidcache(int fd) {
return InvalidCache4Nebd(fd); // 调用实际的使缓存失效函数
}
// 初始化打开文件的标志
void nebd_lib_init_open_flags(NebdOpenFlags* flags) {
flags->exclusive = 1; // 设置为独占模式
}
}
// extern "C" 结束,表示这部分代码可以被C语言和其他C++代码调用
以上是对libnebd.cpp
文件中源码的详细分析,代码主要是对NEBD(网易块存储服务)的C接口进行封装,提供了一系列的函数,用于初始化、打开、关闭文件等操作。这些函数封装了对NEBD客户端库的调用,使得可以通过C接口与NEBD服务进行交互。
下面是对libnebd_file.cpp
文件中源码的详细分析,我将通过注释的方式逐行解释代码的功能和作用。
/*
* 版权声明,该文件属于网易公司,并且遵循Apache License 2.0。
*/
/*
* Project: nebd
* 文件创建日期: 2019-08-07
* 作者: hzchenwei7
*/
// 引入必要的头文件
#include "nebd/src/part1/libnebd_file.h" // 包含neb文件操作的定义和声明
// 实现neb文件操作的相关函数
/**
* 初始化NEBD客户端。
* @param confpath 配置文件路径。
* @return 0表示成功,其他表示失败。
*/
int Init4Nebd(const char* confpath) {
return nebd::client::nebdClient.Init(confpath); // 调用NEBD客户端的初始化函数
}
/**
* 卸载NEBD客户端。
* 清理资源,将客户端恢复到未初始化状态。
*/
void Uninit4Nebd() {
nebd::client::nebdClient.Uninit(); // 调用NEBD客户端的卸载函数
}
/**
* 打开文件。
* @param filename 要打开的文件名。
* @param openflags 打开文件的标志,可以为nullptr。
* @return 文件描述符,或者在失败时返回-1。
*/
int Open4Nebd(const char* filename, const NebdOpenFlags* openflags) {
return nebd::client::nebdClient.Open(filename, openflags); // 调用NEBD客户端的打开文件函数
}
/**
* 关闭文件。
* @param fd 文件描述符。
* @return 0表示成功,其他表示失败。
*/
int Close4Nebd(int fd) {
return nebd::client::nebdClient.Close(fd); // 调用NEBD客户端的关闭文件函数
}
/**
* 扩展文件大小。
* @param fd 文件描述符。
* @param newsize 新的大小。
* @return 0表示成功,其他表示失败。
*/
int Extend4Nebd(int fd, int64_t newsize) {
return nebd::client::nebdClient.Extend(fd, newsize); // 调用NEBD客户端的扩展文件大小函数
}
/**
* 获取文件大小。
* @param fd 文件描述符。
* @return 文件大小,或者在失败时返回-1。
*/
int64_t GetFileSize4Nebd(int fd) {
return nebd::client::nebdClient.GetFileSize(fd); // 调用NEBD客户端的获取文件大小函数
}
/**
* 异步丢弃数据。
* @param fd 文件描述符。
* @param aioctx AIO上下文。
* @return 0表示成功,其他表示失败。
*/
int Discard4Nebd(int fd, NebdClientAioContext* aioctx) {
return nebd::client::nebdClient.Discard(fd, aioctx); // 调用NEBD客户端的异步丢弃数据函数
}
/**
* 异步读取数据。
* @param fd 文件描述符。
* @param aioctx AIO上下文。
* @return 0表示成功,其他表示失败。
*/
int AioRead4Nebd(int fd, NebdClientAioContext* aioctx) {
return nebd::client::nebdClient.AioRead(fd, aioctx); // 调用NEBD客户端的异步读取数据函数
}
/**
* 异步写入数据。
* @param fd 文件描述符。
* @param aioctx AIO上下文。
* @return 0表示成功,其他表示失败。
*/
int AioWrite4Nebd(int fd, NebdClientAioContext* aioctx) {
return nebd::client::nebdClient.AioWrite(fd, aioctx); // 调用NEBD客户端的异步写入数据函数
}
/**
* 刷新数据到存储设备。
* @param fd 文件描述符。
* @param aioctx AIO上下文。
* @return 0表示成功,其他表示失败。
*/
int Flush4Nebd(int fd, NebdClientAioContext* aioctx) {
return nebd::client::nebdClient.Flush(fd, aioctx); // 调用NEBD客户端的刷新数据函数
}
/**
* 获取文件信息。
* @param fd 文件描述符。
* @return 文件信息,或者在失败时返回-1。
*/
int64_t GetInfo4Nebd(int fd) {
return nebd::client::nebdClient.GetInfo(fd); // 调用NEBD客户端的获取文件信息函数
}
/**
* 使缓存失效。
* @param fd 文件描述符。
* @return 0表示成功,其他表示失败。
*/
int InvalidCache4Nebd(int fd) {
return nebd::client::nebdClient.InvalidCache(fd); // 调用NEBD客户端的使缓存失效函数
}
以上是对libnebd_file.cpp
文件中源码的详细分析,代码主要是实现了NEBD客户端库的C接口函数,提供了与NEBD服务进行交互的一系列底层函数。这些函数被封装在NEBD客户端库中,通过这些函数可以实现文件的打开、关闭、读取、写入等操作。每个函数都对应NEBD客户端库中的一个操作,并返回操作的结果或错误码。这些函数的实现都是通过调用NEBD客户端库中的成员函数来完成的。
好的,下面是对nebd_client.cpp
文件中源码的详细分析,我将通过注释的方式逐行解释代码的功能和作用。
/*
* 版权声明,该文件属于网易公司,并且遵循Apache License 2.0。
*/
/*
* Project: nebd
* 文件创建日期: 2019-10-08
* 作者: hzchenwei7
*/
// 引入必要的头文件
#include "nebd/src/part1/nebd_client.h" // 包含NEBD客户端的声明
#include <unistd.h> // POSIX标准定义的通用函数
#include <sys/file.h> // 文件锁相关函数
#include <brpc/controller.h> // brpc框架的控制器头文件
#include <brpc/channel.h> // brpc框架的通道头文件
#include <glog/logging.h> // glog日志库
#include <gflags/gflags.h> // gflags配置库
#include <bthread/bthread.h> // bthread线程库
#include <string> // 字符串头文件
#include "nebd/src/part1/async_request_closure.h" // 异步请求闭包
#include "nebd/src/common/configuration.h" // 配置管理
// 定义返回值如果为false则直接返回-1的宏
#define RETURN_IF_FALSE(val) if (val == false) { return -1; }
// 修改brpc的健康检查间隔参数
// 健康检查间隔用于控制检查服务是否正常的周期
namespace brpc {
DECLARE_int32(health_check_interval); // 声明健康检查间隔的全局变量
DECLARE_int32(circuit_breaker_max_isolation_duration_ms); // 声明断路器最大隔离时长的全局变量
}
namespace nebd {
namespace client {
// 定义NEBD客户端的实例
NebdClient &nebdClient = NebdClient::GetInstance(); // 获取NEBD客户端的实例
// 定义缓冲区大小
constexpr int32_t kBufSize = 128;
// 将C风格的打开文件标志转换为Protobuf风格的
ProtoOpenFlags ConverToProtoOpenFlags(const NebdOpenFlags* flags) {
ProtoOpenFlags protoFlags;
protoFlags.set_exclusive(flags->exclusive); // 将独占标志转换为Protobuf风格
return protoFlags; // 返回转换后的Protobuf风格的标志
}
// NEBD客户端的初始化函数
int NebdClient::Init(const char* confpath) {
// 加载配置文件
nebd::common::Configuration conf;
conf.SetConfigPath(confpath); // 设置配置文件路径
if (!conf.LoadConfig()) { // 如果加载失败
LOG(ERROR) << "Load config failed, conf path = " << confpath; // 记录错误日志
return -1; // 返回错误码
}
int ret = InitNebdClientOption(&conf); // 初始化NEBD客户端选项
if (ret != 0) { // 如果初始化失败
LOG(ERROR) << "InitNebdClientOption failed"; // 记录错误日志
return -1; // 返回错误码
}
// 初始化日志系统
InitLogger(option_.logOption);
// 初始化心跳管理器选项
HeartbeatOption heartbeatOption;
ret = InitHeartBeatOption(&conf, &heartbeatOption); // 初始化心跳选项
if (ret != 0) { // 如果初始化失败
LOG(ERROR) << "InitHeartBeatOption failed"; // 记录错误日志
return -1; // 返回错误码
}
LOG(INFO) << "Load config success!"; // 记录配置加载成功的日志
ret = InitChannel(); // 初始化通道
if (ret != 0) { // 如果初始化失败
LOG(ERROR) << "InitChannel failed"; // 记录错误日志
return -1; // 返回错误码
}
// 创建元数据缓存实例
metaCache_ = std::make_shared<NebdClientMetaCache>(); // 创建元数据缓存对象
heartbeatMgr_ = std::make_shared<HeartbeatManager>(metaCache_); // 创建心跳管理器对象
ret = heartbeatMgr_->Init(heartbeatOption); // 初始化心跳管理器
if (ret != 0) { // 如果初始化失败
LOG(ERROR) << "Heartbeat Manager InitChannel failed"; // 记录错误日志
return -1; // 返回错误码
}
heartbeatMgr_->Run(); // 启动心跳管理器
// 初始化RPC发送执行队列
rpcTaskQueues_.resize(option_.requestOption.rpcSendExecQueueNum); // 根据配置初始化队列大小
for (auto& q : rpcTaskQueues_) { // 遍历所有队列
int rc = bthread::execution_queue_start(&q, nullptr, &NebdClient::ExecAsyncRpcTask, this); // 启动队列
if (rc != 0) { // 如果启动失败
LOG(ERROR) << "Init AsyncRpcQueues failed"; // 记录错误日志
return -1; // 返回错误码
}
}
return 0; // 返回成功码
}
// NEBD客户端的反初始化函数
void NebdClient::Uninit() {
if (heartbeatMgr_ != nullptr) { // 如果心跳管理器存在
heartbeatMgr_->Stop(); // 停止心跳管理器
}
// 停止执行队列
for (auto& q : rpcTaskQueues_) { // 遍历所有队列
bthread::execution_queue_stop(q); // 停止队列
bthread::execution_queue_join(q); // 等待队列线程结束
}
LOG(INFO) << "NebdClient uninit success."; // 记录客户端成功反初始化的日志
google::ShutdownGoogleLogging(); // 关闭日志系统
}
// NEBD客户端打开文件的函数
int NebdClient::Open(const char* filename, const NebdOpenFlags* flags) {
// 获取文件锁
std::string fileLockName = option_.fileLockPath + "/" + ReplaceSlash(filename); // 构造文件锁名称
FileLock fileLock(fileLockName); // 创建文件锁对象
int res = fileLock.AcquireFileLock(); // 尝试获取文件锁
if (res < 0) { // 如果获取失败
LOG(ERROR) << "Open file failed when AcquireFileLock, filename = " << filename; // 记录错误日志
return -1; // 返回错误码
}
// 封装RPC任务
auto task = [&](brpc::Controller* cntl, brpc::Channel* channel, bool* rpcFailed) -> int64_t {
// 创建stub对象
NebdFileService_Stub stub(channel);
OpenFileRequest request;
OpenFileResponse response;
// 设置请求参数
request.set_filename(filename);
if (flags != nullptr) { // 如果提供了文件打开标志
auto* p = request.mutable_flags(); // 获取请求中的文件打开标志对象
*p = ConverToProtoOpenFlags(flags); // 转换并设置文件打开标志
}
// 调用OpenFile RPC方法
stub.OpenFile(cntl, &request, &response, nullptr);
*rpcFailed = cntl->Failed(); // 记录RPC是否失败
if (*rpcFailed) { // 如果RPC失败
LOG(WARNING) << "OpenFile rpc failed, error = " << cntl->ErrorText() // 记录警告日志
<< ", filename = " << filename // 文件名
<< ", log id = " << cntl->log_id(); // 日志ID
return -1; // 返回错误码
} else { // 如果RPC成功
if (response.retcode() != RetCode::kOK) { // 如果响应码不是OK
LOG(ERROR) << "OpenFile failed, " // 记录错误日志
<< "retcode = " << response.retcode() // 响应码
<< ", retmsg = " << response.retmsg() // 响应消息
<< ", filename = " << filename // 文件名
<< ", log id = " << cntl->log_id(); // 日志ID
return -1; // 返回错误码
}
return response.fd(); // 返回文件描述符
}
};
// 执行同步RPC任务
int fd = ExecuteSyncRpc(task); // 执行打开文件的RPC任务
if (fd < 0) { // 如果文件描述符小于0,表示失败
LOG(ERROR) << "Open file failed, filename = " << filename; // 记录错误日志
fileLock.ReleaseFileLock(); // 释放文件锁
return -1; // 返回错误码
}
//将打开的文件信息添加到元数据缓存
metaCache_->AddFileInfo({fd, filename, fileLock}); // 添加文件信息到元数据缓存
return fd; // 返回文件描述符
}
// NEBD客户端关闭文件的函数
int NebdClient::Close(int fd) {
// 封装RPC任务
auto task = [&](brpc::Controller* cntl, brpc::Channel* channel, bool* rpcFailed) -> int64_t {
NebdFileService_Stub stub(channel);
CloseFileRequest request;
CloseFileResponse response;
// 设置请求参数
request.set_fd(fd);
// 调用CloseFile RPC方法
stub.CloseFile(cntl, &request, &response, nullptr);
*rpcFailed = cntl->Failed(); // 记录RPC是否失败
if (*rpcFailed) { // 如果RPC失败
LOG(WARNING) << "CloseFile rpc failed, error = " << cntl->ErrorText() // 记录警告日志
<< ", log id = " << cntl->log_id(); // 日志ID
return -1; // 返回错误码
} else { // 如果RPC成功
if (response.retcode() != RetCode::kOK) { // 如果响应码不是OK
LOG(ERROR) << "CloseFile failed, " // 记录错误日志
<< "retcode = " << response.retcode() // 响应码
<< ", retmsg = " << response.retmsg() // 响应消息
<< ", fd = " << fd // 文件描述符
<< ", log id = " << cntl->log_id(); // 日志ID
return -1; // 返回错误码
}
return 0; // 返回成功码
}
};
// 执行同步RPC任务
int rpcRet = ExecuteSyncRpc(task); // 执行关闭文件的RPC任务
NebdClientFileInfo fileInfo; // 定义文件信息对象
int ret = metaCache_->GetFileInfo(fd, &fileInfo); // 从元数据缓存获取文件信息
if (ret == 0) { // 如果成功获取文件信息
fileInfo.fileLock.ReleaseFileLock(); // 释放文件锁
metaCache_->RemoveFileInfo(fd); // 从元数据缓存移除文件信息
}
return rpcRet; // 返回RPC任务的返回码
}
// ... 省略其他成员函数的实现 ...
} // 结束nebdk客户端命名空间
} // 结束nebdk命名空间
以上是对nebd_client.cpp
文件中源码的详细分析,代码主要是实现了NEBD客户端的核心功能,包括初始化、反初始化、打开文件、关闭文件等操作。每个函数都对应NEBD客户端库中的一个操作,并返回操作的结果或错误码。这些函数的实现都是通过封装RPC任务并调用NEBD服务端的对应接口来完成的。代码中还包含了错误处理和日志记录,确保了操作的可靠性和可追踪性。
好的,下面是对heartbeat_manager.cpp
文件中源码的详细分析,我将通过注释的方式逐行解释代码的功能和作用。
/*
* 版权声明,该文件属于网易公司,并且遵循Apache License 2.0。
*/
/*
* Project: nebd
* 创建日期: 2020-01-20
* 作者: wuhanqing
*/
// 引入必要的头文件
#include "nebd/src/part1/heartbeat_manager.h" // 心跳管理器的声明
#include <unistd.h> // POSIX标准定义的通用函数
#include <ostream> // 标准输出流
#include <vector> // 标准容器
#include <string> // 字符串头文件
#include "nebd/proto/heartbeat.pb.h" // 心跳消息的Protobuf定义
#include "nebd/src/common/nebd_version.h" // NEBD版本定义
namespace nebd {
namespace client {
// 心跳管理器的构造函数
HeartbeatManager::HeartbeatManager(std::shared_ptr<NebdClientMetaCache> metaCache)
: metaCache_(metaCache), // 初始化元数据缓存的共享指针
running_(false), // 初始化心跳线程运行标志为false
logId_(1) { // 初始化日志ID生成器为1
}
// 心跳管理器的初始化函数
int HeartbeatManager::Init(const HeartbeatOption& option) {
heartbeatOption_ = option; // 保存心跳选项
int ret = channel_.InitWithSockFile(option.serverAddress.c_str(), nullptr); // 初始化与服务器的连接
if (ret != 0) { // 如果初始化失败
LOG(ERROR) << "Connection Manager channel init failed"; // 记录错误日志
return -1; // 返回错误码
}
pid_ = getpid(); // 获取当前进程ID
nebdVersion_ = nebd::common::NebdVersion(); // 获取NEBD版本信息
return 0; // 返回成功码
}
// 心跳线程的执行函数
void HeartbeatManager::HeartBetaThreadFunc() {
LOG(INFO) << "Heartbeat thread started"; // 记录心跳线程启动的日志
while (running_) { // 当心跳线程正在运行时
SendHeartBeat(); // 发送心跳
sleeper_.wait_for(std::chrono::seconds(heartbeatOption_.intervalS)); // 等待设定的心跳间隔
}
}
// 启动心跳线程
void HeartbeatManager::Run() {
running_ = true; // 设置心跳线程运行标志为true
heartbeatThread_ = std::thread(&HeartbeatManager::HeartBetaThreadFunc, this); // 创建并启动心跳线程
}
// 停止心跳线程
void HeartbeatManager::Stop() {
if (running_ == true) { // 如果心跳线程正在运行
running_ = false; // 设置心跳线程运行标志为false
sleeper_.interrupt(); // 中断等待
heartbeatThread_.join(); // 等待心跳线程结束
}
}
// 发送心跳函数
void HeartbeatManager::SendHeartBeat() {
std::vector<NebdClientFileInfo> fileInfos(metaCache_->GetAllFileInfo()); // 获取所有文件信息
if (fileInfos.empty()) { // 如果没有文件信息
return; // 直接返回
}
HeartbeatRequest request; // 创建心跳请求
HeartbeatResponse response; // 创建心跳响应
brpc::Controller cntl; // 创建brpc控制器
cntl.set_log_id(logId_.fetch_add(1, std::memory_order_relaxed)); // 设置日志ID
cntl.set_timeout_ms(heartbeatOption_.rpcTimeoutMs); // 设置RPC超时时间
NebdHeartbeatService_Stub stub(&channel_); // 创建服务stub
request.set_pid(pid_); // 设置发送心跳的进程ID
request.set_nebdversion(nebdVersion_); // 设置NEBD版本信息
std::ostringstream oss; // 创建字符串流对象
for (const auto& fileInfo : fileInfos) { // 遍历所有文件信息
nebd::client::HeartbeatFileInfo* info = request.add_info(); // 添加文件信息到请求
info->set_fd(fileInfo.fd); // 设置文件描述符
info->set_name(fileInfo.fileName); // 设置文件名
oss << fileInfo.fd << ": " << fileInfo.fileName << ", "; // 将文件信息添加到字符串流
}
LOG(INFO) << "Send Heartbeat request, log id = " << cntl.log_id() // 记录发送心跳请求的日志
<< ", pid = " << request.pid() // 发送心跳的进程ID
<< ", nebd version = " << request.nebdversion() // NEBD版本信息
<< ", files [" << oss.str() << ']'; // 文件信息列表
stub.KeepAlive(&cntl, &request, &response, nullptr); // 调用KeepAlive RPC方法
bool isCntlFailed = cntl.Failed(); // 检查RPC是否失败
if (isCntlFailed) { // 如果RPC失败
LOG(WARNING) << "Heartbeat request failed, error = " << cntl.ErrorText() // 记录警告日志
<< ", log id = " << cntl.log_id(); // 日志ID
}
}
} // 结束nebdk客户端命名空间
} // 结束nebdk命名空间
以上是对heartbeat_manager.cpp
文件中源码的详细分析,代码实现了NEBD客户端的心跳管理器,负责定期向NEBD服务端发送心跳以维持连接。心跳管理器通过一个单独的线程来执行心跳任务,确保了客户端与服务端之间的连接是活跃的。代码中还包括了错误处理和日志记录,以便在出现问题时能够及时发现和定位问题。
下面是对nebd_metacache.cpp
文件中源码的详细分析,我将通过注释的方式逐行解释代码的功能和作用。
/*
* 版权声明,该文件属于网易公司,并且遵循Apache License 2.0。
*/
/**
* Project: nebd
* 创建日期: 2020-01-20
* 作者: wuhanqing
*/
// 引入必要的头文件
#include "nebd/src/part1/nebd_metacache.h" // 包含NEBD元数据缓存的声明
namespace nebd {
namespace client {
// NEBD客户端元数据缓存的添加文件信息函数
void NebdClientMetaCache::AddFileInfo(const NebdClientFileInfo& fileInfo) {
WriteLockGuard guard(rwLock_); // 获取写锁保护
fileinfos_.emplace(fileInfo.fd, fileInfo); // 将文件信息添加到map中
}
// NEBD客户端元数据缓存的移除文件信息函数
void NebdClientMetaCache::RemoveFileInfo(int fd) {
WriteLockGuard guard(rwLock_); // 获取写锁保护
fileinfos_.erase(fd); // 根据文件描述符从map中移除文件信息
}
// NEBD客户端元数据缓存的获取文件信息函数
int NebdClientMetaCache::GetFileInfo(int fd, NebdClientFileInfo* fileInfo) const {
ReadLockGuard guard(rwLock_); // 获取读锁保护
auto iter = fileinfos_.find(fd); // 查找map中的文件信息
if (iter != fileinfos_.end()) { // 如果找到了文件信息
*fileInfo = iter->second; // 将文件信息复制到提供的指针中
return 0; // 返回成功码
}
return -1; // 如果未找到,返回失败码
}
// NEBD客户端元数据缓存的获取所有文件信息函数
std::vector<NebdClientFileInfo> NebdClientMetaCache::GetAllFileInfo() const {
ReadLockGuard guard(rwLock_); // 获取读锁保护
std::vector<NebdClientFileInfo> result; // 创建一个空的文件信息向量
result.reserve(fileinfos_.size()); // 预分配足够的空间
for (const auto& kv : fileinfos_) { // 遍历map中的所有文件信息
result.push_back(kv.second); // 将文件信息添加到向量中
}
return result; // 返回文件信息向量
}
} // 结束nebdk客户端命名空间
} // 结束nebdk命名空间
以上是对nebd_metacache.cpp
文件中源码的详细分析,代码实现了NEBD客户端的元数据缓存功能。元数据缓存用于存储打开的文件的信息,如文件描述符和文件锁等。通过这个缓存,NEBD客户端可以有效地管理文件状态,提高文件操作的性能。代码中使用了读写锁来保护元数据缓存,确保在多线程环境下的线程安全。此外,代码中还包括了错误处理和日志记录,以便在出现问题时能够及时发现和定位问题。
下面是对async_request_closure.cpp
文件中源码的详细分析,我将通过注释的方式逐行解释代码的功能和作用。
/*
* 版权声明,该文件属于网易公司,并且遵循Apache License 2.0。
*/
/*
* Project: nebd
* 创建日期: 2020-01-20
* 作者: wuhanqing
*/
// 引入必要的头文件
#include "nebd/src/part1/async_request_closure.h" // 包含异步请求闭包的声明
#include <glog/logging.h> // 引入glog日志库
#include <bthread/bthread.h> // 引入bthread线程库
#include <algorithm> // 引入算法库
#include <memory> // 引入智能指针库
namespace nebd {
namespace client {
// 异步请求闭包的执行函数
void AsyncRequestClosure::Run() {
std::unique_ptr<AsyncRequestClosure> selfGuard(this); // 创建一个智能指针来管理当前对象的生命周期
bool isCntlFailed = cntl.Failed(); // 检查控制器是否失败
if (isCntlFailed) { // 如果RPC调用失败
++aioCtx->retryCount; // 增加重试计数
int64_t sleepUs = GetRpcRetryIntervalUs(aioCtx->retryCount); // 获取重试间隔时间
LOG_EVERY_SECOND(WARNING) << OpTypeToString(aioCtx->op) // 记录警告日志,每秒一次
<< " rpc failed" // RPC调用失败
<< ", error = " // 错误信息
<< cntl.ErrorText() // 错误文本
<< ", fd = " // 文件描述符
<< aioCtx->fd // 文件描述符的值
<< ", log id = " // 日志ID
<< cntl.log_id() // 日志ID的值
<< ", retryCount = " // 重试次数
<< aioCtx->retryCount // 重试次数的值
<< ", sleep " // 睡眠时间
<< (sleepUs / 1000) // 睡眠时间,单位毫秒
<< " ms"; // 时间单位
bthread_usleep(sleepUs); // 根据重试间隔时间休眠
Retry(); // 重试RPC调用
} else { // 如果RPC调用成功
auto retCode = GetResponseRetCode(); // 获取响应的返回码
if (nebd::client::RetCode::kOK == retCode) { // 如果返回码为成功
DVLOG(6) << OpTypeToString(aioCtx->op) // 记录详细日志
<< " success, fd = " // 操作成功,文件描述符
<< aioCtx->fd; // 文件描述符的值
// 如果是读操作,复制响应数据到用户缓冲区
if (aioCtx->op == LIBAIO_OP::LIBAIO_OP_READ) {
cntl.response_attachment().copy_to(aioCtx->buf, cntl.response_attachment().size());
}
aioCtx->ret = 0; // 设置返回码为0,表示成功
aioCtx->cb(aioCtx); // 调用用户的回调函数
} else { // 如果返回码不为成功
LOG(ERROR) << OpTypeToString(aioCtx->op) // 记录错误日志
<< " failed, fd = " // 操作失败,文件描述符
<< aioCtx->fd // 文件描述符的值
<< ", offset = " // 偏移量
<< aioCtx->offset // 偏移量的值
<< ", length = " // 长度
<< aioCtx->length // 长度的值
<< ", retCode = " // 返回码
<< GetResponseRetCode() // 获取响应的返回码
<< ", log id = " // 日志ID
<< cntl.log_id(); // 日志ID的值
aioCtx->ret = -1; // 设置返回码为-1,表示失败
aioCtx->cb(aioCtx); // 调用用户的回调函数
}
}
}
// 获取RPC重试间隔时间的函数
int64_t AsyncRequestClosure::GetRpcRetryIntervalUs(int64_t retryCount) const {
// 如果控制错误码是EHOSTDOWN,表示找不到可用的server
if (cntl.ErrorCode() == EHOSTDOWN) {
return requestOption_.rpcHostDownRetryIntervalUs; // 返回host宕机重试间隔
}
if (retryCount <= 1) {
return requestOption_.rpcRetryIntervalUs; // 如果是第一次或第二次重试,返回基础重试间隔
}
// 根据重试次数计算重试间隔,但不超过最大重试间隔
return std::max(
requestOption_.rpcRetryIntervalUs, // 基础重试间隔
std::min(
requestOption_.rpcRetryIntervalUs * retryCount, // 重试次数乘以基础重试间隔
requestOption_.rpcRetryMaxIntervalUs // 最大重试间隔
)
);
}
// 重试RPC调用的函数
void AsyncRequestClosure::Retry() const {
switch (aioCtx->op) {
case LIBAIO_OP::LIBAIO_OP_WRITE: // 根据操作类型重试
nebdClient.AioWrite(fd, aioCtx); // 异步写操作
break;
case LIBAIO_OP::LIBAIO_OP_READ:
nebdClient.AioRead(fd, aioCtx); // 异步读操作
break;
case LIBAIO_OP::LIBAIO_OP_FLUSH:
nebdClient.Flush(fd, aioCtx); // 异步刷新操作
break;
case LIBAIO_OP::LIBAIO_OP_DISCARD:
nebdClient.Discard(fd, aioCtx); // 异步丢弃操作
break;
default:
LOG(ERROR) << "Aio Operation Type error, op = " // 记录错误日志
<< OpTypeToString(aioCtx->op) // 操作类型
<< ", fd = " // 文件描述符
<< fd; // 文件描述符的值
aioCtx->ret = -1; // 设置返回码为-1,表示失败
aioCtx->cb(aioCtx); // 调用用户的回调函数
}
}
} // 结束nebdk客户端命名空间
} // 结束nebdk命名空间
以上是对async_request_closure.cpp
文件中源码的详细分析,代码实现了NEBD客户端的异步请求闭包功能。异步请求闭包是一个回调机制,用于在异步RPC调用完成后执行相应的操作。这个机制允许NEBD客户端在后台执行异步操作,同时提供了错误处理和重试逻辑,确保了操作的可靠性和效率。代码中使用了智能指针来管理对象的生命周期,避免了内存泄漏。此外,代码中还包括了详细的日志记录,以便在出现问题时能够及时发现和定位问题。