* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
* ubs-io is licensed under the Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#ifndef BIO_SERVER_H
#define BIO_SERVER_H
#include <mutex>
#include <utility>
#include "bio_config_instance.h"
#include "bio_err.h"
#include "bio_ref.h"
#include "bio_tracepoint_helper.h"
#include "cm.h"
#include "mirror_server.h"
#include "mirror_server_crb.h"
#include "net_engine.h"
namespace ock {
namespace bio {
using InitFunc = std::function<int32_t()>;
using StartFunc = std::function<int32_t()>;
using ShutdownFunc = std::function<int32_t()>;
using ExitFunc = std::function<void()>;
struct ModuleDesc {
std::string name;
InitFunc init;
StartFunc start;
ShutdownFunc shutdown;
ExitFunc exit;
ModuleDesc() = default;
ModuleDesc(std::string name, InitFunc initFunc, StartFunc startFunc, ShutdownFunc shutdownFunc, ExitFunc exitFunc)
: name(std::move(name)),
init(std::move(initFunc)),
start(std::move(startFunc)),
shutdown(std::move(shutdownFunc)),
exit(std::move(exitFunc))
{
}
};
class BioServiceProc {
public:
explicit BioServiceProc(std::vector<ModuleDesc> modules) noexcept : mModules(std::move(modules)) {}
~BioServiceProc() noexcept
{
mModules.clear();
}
BResult Process()
{
auto ret = OnServiceInitialize();
if (ret != BIO_OK) {
return ret;
}
ret = OnServiceStart();
if (ret != BIO_OK) {
return ret;
}
return BIO_OK;
}
void Exit()
{
OnServiceShutdown();
OnServiceUninitialize();
}
BResult OnServiceInitialize()
{
for (auto it = mModules.cbegin(); it != mModules.cend(); ++it) {
if (it->init == nullptr) {
LOG_INFO("Module (" << it->name << ") no initialize function, skip.");
continue;
}
LOG_INFO("Module (" << it->name << ") initialize begin...");
auto ret = it->init();
if (ret == BIO_OK) {
LOG_INFO("Module (" << it->name << ") initialize success.");
} else {
LOG_ERROR("Module (" << it->name << ") initialize failed, result:" << ret << ".");
BIO_TP_START(NO_PROCESS_ROLLBACK_SERVICE_INIT, 0);
RollbackInit(it);
BIO_TP_END;
return BIO_ERR;
}
}
return BIO_OK;
}
BResult OnServiceStart()
{
for (auto it = mModules.cbegin(); it != mModules.cend(); ++it) {
if (it->start == nullptr) {
LOG_INFO("Module (" << it->name << ") no start function, skip.");
continue;
}
LOG_INFO("Module (" << it->name << ") start begin...");
int32_t ret = it->start();
if (ret == BIO_OK) {
LOG_INFO("Module (" << it->name << ") start success.");
} else {
LOG_ERROR("Module (" << it->name << ") start failed, result:" << ret << ".");
RollbackStart(it);
return BIO_ERR;
}
}
return BIO_OK;
}
void OnServiceShutdown()
{
for (auto it = mModules.crbegin(); it != mModules.crend(); ++it) {
if (it->shutdown == nullptr) {
LOG_INFO("Module (" << it->name << ") no shutdown function, skip.");
continue;
}
LOG_INFO("Module (" << it->name << ") shutdown begin...");
it->shutdown();
LOG_INFO("Module (" << it->name << ") shutdown finished.");
}
}
void OnServiceUninitialize()
{
for (auto it = mModules.crbegin(); it != mModules.crend(); ++it) {
if (it->exit == nullptr) {
LOG_INFO("Module (" << it->name << ") no exit function, skip.");
continue;
}
LOG_INFO("Module (" << it->name << ") exit begin...");
it->exit();
LOG_INFO("Module (" << it->name << ") exit finished.");
}
}
DEFINE_REF_COUNT_FUNCTIONS
private:
void RollbackInit(const std::vector<ModuleDesc>::const_iterator &end) noexcept
{
auto next = end;
auto pos = end;
for (--pos; next != mModules.cbegin(); --next, --pos) {
if (pos->exit != nullptr) {
pos->exit();
}
}
}
void RollbackStart(const std::vector<ModuleDesc>::const_iterator &end) noexcept
{
auto next = end;
auto pos = end;
for (--pos; next != mModules.cbegin(); --next, --pos) {
if (pos->shutdown != nullptr) {
pos->shutdown();
}
}
}
private:
std::vector<ModuleDesc> mModules;
DEFINE_REF_COUNT_VARIABLE
};
using BioServiceProcPtr = Ref<BioServiceProc>;
class BioServer;
using BioServerPtr = Ref<BioServer>;
class BioServer {
public:
BioServer() noexcept;
BResult Start();
void Exit();
static BioServerPtr &Instance()
{
static auto instance = MakeRef<BioServer>();
return instance;
}
inline NetEnginePtr GetNetEngine()
{
return mNetEngine;
}
inline MirrorServerPtr GetMirrorServer()
{
return mMirror;
}
inline MirrorServerCrbPtr GetMirrorCrb()
{
return mMirrorCrb;
}
inline bool GetCrbProcessing()
{
return mCrbProcessing.load();
}
inline CmPtr GetCm()
{
return mCm;
}
inline bool GetCrcFlag()
{
return mConfig->GetDaemonConfig().enableCrc;
}
inline bool GetCliFlag()
{
return mConfig->GetDaemonConfig().enableCli;
}
inline bool GetPrometheusToggle()
{
return mConfig->GetDaemonConfig().enablePrometheus;
}
inline std::string GetPrometheusListenAddress()
{
return mConfig->GetDaemonConfig().listenAddress;
}
inline uint32_t GetNegoWorkIoTimeOut()
{
return mConfig->GetDaemonConfig().workIoTimeOut;
}
inline uint32_t GetPrometheusScrapeIntervalSec()
{
return mConfig->GetDaemonConfig().scrapeIntervalSec;
}
inline BioConfigPtr GetConfig()
{
return mConfig;
}
inline CmNodeId GetLocalNid()
{
return mLocalNid;
}
inline uint16_t GetNetProtocol()
{
return static_cast<uint16_t>(mConfig->GetNetConfig().protocol);
}
inline bool CheckIsOnline(uint16_t nodeId, std::string &ip, uint16_t &port)
{
CmNodeId node(mLocalNid.groupId, nodeId);
bool isOnline = false;
if (mNodeView.find(node) != mNodeView.end()) {
if (mNodeView[node].status == CM_NODE_NORMAL) {
isOnline = true;
ip = mNodeView[node].ip;
port = mNodeView[node].port;
}
return isOnline;
}
return false;
}
inline bool GetServiceState()
{
return mCm->GetServiceState();
}
inline std::map<CmNodeId, CmNodeInfo, CmNodeIdCmp> GetNodeView(uint64_t *curNodeTimes)
{
std::lock_guard<std::mutex> lock(mNodeViewMutex);
*curNodeTimes = mCurNodeTimes;
return mNodeView;
}
BResult GetDiskStatusFromNodeView(uint16_t diskId, CmDiskStatus &diskStatus)
{
std::lock_guard<std::mutex> lock(mNodeViewMutex);
if (mNodeView.find(mLocalNid) != mNodeView.end()) {
CmNodeInfo nodeInfo = mNodeView[mLocalNid];
for (uint32_t idx = 0; idx < nodeInfo.disks.size(); idx++) {
if (nodeInfo.disks[idx].diskId == diskId) {
diskStatus = nodeInfo.disks[idx].diskStatus;
return BIO_OK;
}
}
}
LOG_ERROR("Get disk status failed, diskId " << diskId);
return BIO_ERR;
}
inline std::map<uint16_t, CmPtInfo> GetPtView(uint64_t *curPtTimes)
{
std::lock_guard<std::mutex> lock(mPtViewMutex);
*curPtTimes = mCurPtTimes;
return mPtView;
}
inline CmPtInfo GetPtEntry(uint16_t ptId)
{
std::lock_guard<std::mutex> lock(mPtViewMutex);
if (mPtView.find(ptId) == mPtView.end()) {
return CmPtInfo();
}
return mPtView[ptId];
}
inline uint64_t GetLocalMrKey()
{
uint64_t key = 0;
mNetEngine->GetLocalMrKey(key);
return key;
}
inline BResult MemAlloc(uint64_t size, NetMrInfo &mr)
{
if (size > mNetEngine->GetDataPage()) {
return BIO_ALLOC_FAIL;
}
auto ret = mNetEngine->AllocLocalMrSingle(mr.address, mr.key);
mr.size = size;
return ret;
}
inline BResult MemAlloc(uint64_t size, uint64_t *addr)
{
uintptr_t address;
uint64_t outKey;
auto ret = mNetEngine->AllocLocalMrSingle(address, outKey);
if (UNLIKELY(ret != BIO_OK)) {
return ret;
}
*addr = address;
return BIO_OK;
}
inline void MemFree(uint64_t addr)
{
mNetEngine->FreeLocalMrSingle(addr);
}
inline BResult GetNodeInfo(CmNodeId nid, CmNodeInfo &nodeInfo)
{
if (UNLIKELY(mCm == nullptr)) {
return BIO_NOT_READY;
}
return mCm->GetNodeInfo(nid, nodeInfo);
}
inline void *LoadFunction(const char *name, void *handler)
{
void *ptr = nullptr;
ptr = dlsym(handler, name);
return ptr;
}
BResult HandleCmNodeEvent(const std::map<CmNodeId, CmNodeInfo, CmNodeIdCmp> &nodeInfos);
BResult BioBdmUpdate(std::string diskPath);
BResult BioDiskReset(uint16_t diskId);
DEFINE_REF_COUNT_FUNCTIONS;
protected:
BResult BioConfigInit();
BResult BioLoggerInit(std::string pathName);
void BioLoggerExit();
BResult BioTraceInit();
void BioTraceExit();
BResult BioUnderFsInit();
void BioUnderFsExit();
BResult BioBdmInit();
void BioBdmExit();
BResult BioNetInit();
void BioNetExit();
BResult BioCmInit();
void BioCmExit();
BResult BioMirrorServerInit();
void BioMirrorServerExit();
BResult BioCacheInit();
void BioCacheExit();
BResult BioFlowInit();
void BioFlowExit();
BResult BioServerDiagnoseInit();
BResult BioServerDiagnoseInitInner();
#ifdef USE_DEBUG_TP_TOOLS
BResult BioServerTracePointInit();
#endif
void Connection();
BResult HandleCmPtEvent(const std::map<uint16_t, CmPtInfo> &ptInfos);
bool CheckNeedCrb(const std::map<uint16_t, CmPtInfo> &ptInfos);
private:
BResult StartRpcService(const NetOptions &opt);
BResult StartIpcService(const NetOptions &opt);
void ReConnect(uint32_t peerId);
private:
bool mStarted = false;
std::mutex mStartLock;
BioServiceProcPtr mService = nullptr;
BioConfigPtr mConfig = nullptr;
NetEnginePtr mNetEngine = nullptr;
CmPtr mCm = nullptr;
MirrorServerPtr mMirror = nullptr;
MirrorServerCrbPtr mMirrorCrb = nullptr;
CmNodeId mLocalNid;
std::map<CmNodeId, CmNodeInfo, CmNodeIdCmp> mNodeView;
std::map<uint16_t, CmPtInfo> mPtView;
std::atomic<bool> mCrbProcessing{false};
std::mutex mNodeViewMutex;
std::mutex mPtViewMutex;
uint64_t mCurNodeTimes = 0;
uint64_t mCurPtTimes = 0;
bool mNetEngineInited = false;
bool mCacheInited = false;
bool mMirrorInited = false;
DEFINE_REF_COUNT_VARIABLE;
};
}
}
#endif