curve源码分析 nebd part1

本文对curve-release2.2\\nebd\\src\\part1\\libnebd.cpp文件源码进行详细分析。代码用C++实现,主要对NEBD的C接口进行封装,实现了客户端核心功能、心跳管理器、元数据缓存、异步请求闭包等,还包含错误处理和日志记录,确保操作可靠可追踪。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代码路径
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客户端在后台执行异步操作,同时提供了错误处理和重试逻辑,确保了操作的可靠性和效率。代码中使用了智能指针来管理对象的生命周期,避免了内存泄漏。此外,代码中还包括了详细的日志记录,以便在出现问题时能够及时发现和定位问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值