2025-08-10 01:34:16 +02:00

250 lines
7.7 KiB
C++

#include "SyncSlaveBase.h"
#include <common/net/message/storage/mirroring/ResyncRawInodesRespMsg.h>
#include <net/message/storage/mirroring/ResyncRawInodesMsgEx.h>
#include <net/msghelpers/MsgHelperXAttr.h>
#include <program/Program.h>
#include <toolkit/XAttrTk.h>
void SyncSlaveBase::run()
{
setIsRunning(true);
try
{
LOG(MIRRORING, DEBUG, "Component started");
registerSignalHandler();
syncLoop();
LOG(MIRRORING, DEBUG, "Component stopped");
}
catch (std::exception& e)
{
PThread::getCurrentThreadApp()->handleComponentException(e);
}
setIsRunning(false);
}
FhgfsOpsErr SyncSlaveBase::receiveAck(Socket& socket)
{
auto resp = MessagingTk::recvMsgBuf(socket);
if (resp.empty())
return FhgfsOpsErr_INTERNAL;
const auto respMsg = PThread::getCurrentThreadApp()->getNetMessageFactory()->createFromBuf(
std::move(resp));
if (respMsg->getMsgType() != NETMSGTYPE_ResyncRawInodesResp)
return FhgfsOpsErr_COMMUNICATION;
return static_cast<ResyncRawInodesRespMsg&>(*respMsg).getResult();
}
FhgfsOpsErr SyncSlaveBase::resyncAt(const Path& basePath, bool wholeDirectory,
FhgfsOpsErr (*streamFn)(Socket*, void*), void* context)
{
const bool sendXAttrs = Program::getApp()->getConfig()->getStoreClientXAttrs();
this->basePath = META_BUDDYMIRROR_SUBDIR_NAME / basePath;
ResyncRawInodesMsgEx msg(basePath, sendXAttrs, wholeDirectory);
RequestResponseNode rrNode(buddyNodeID, Program::getApp()->getMetaNodes());
RequestResponseArgs rrArgs(nullptr, &msg, NETMSGTYPE_ResyncRawInodesResp,
streamFn, context);
// resync processing may take a very long time for each step, eg if a very large directory must
// be cleaned out on the secondary. do not use timeouts for resync communication right now.
rrArgs.minTimeoutMS = -1;
const auto commRes = MessagingTk::requestResponseNode(&rrNode, &rrArgs);
if (commRes != FhgfsOpsErr_SUCCESS)
{
LOG(MIRRORING, ERR, "Error during communication with secondary.", commRes);
return commRes;
}
const auto resyncRes = static_cast<ResyncRawInodesRespMsg&>(*rrArgs.outRespMsg).getResult();
if (resyncRes != FhgfsOpsErr_SUCCESS)
LOG(MIRRORING, ERR, "Error while resyncing directory.", basePath, resyncRes);
return resyncRes;
}
FhgfsOpsErr SyncSlaveBase::streamDentry(Socket& socket, const Path& contDirRelPath,
const std::string& name)
{
std::unique_ptr<DirEntry> dentry(
DirEntry::createFromFile((basePath / contDirRelPath).str(), name));
if (!dentry)
{
LOG(MIRRORING, ERR, "Could not open dentry.", basePath, contDirRelPath, name);
return FhgfsOpsErr_INTERNAL;
}
if (dentry->getIsInodeInlined())
{
auto err = sendResyncPacket(socket, LinkDentryInfo(
MetaSyncFileType::Dentry,
(contDirRelPath / name).str(),
true,
dentry->getID(),
false));
if (err != FhgfsOpsErr_SUCCESS)
return err;
return receiveAck(socket);
}
std::vector<char> dentryContent;
{
Serializer ser;
dentry->serializeDentry(ser);
dentryContent.resize(ser.size());
ser = Serializer(&dentryContent[0], dentryContent.size());
dentry->serializeDentry(ser);
if (!ser.good())
{
LOG(MIRRORING, ERR, "Could not serialize dentry for secondary.");
return FhgfsOpsErr_INTERNAL;
}
}
const FhgfsOpsErr sendRes = sendResyncPacket(socket, FullDentryInfo(
MetaSyncFileType::Dentry,
(contDirRelPath / name).str(),
false,
dentryContent,
false));
if (sendRes != FhgfsOpsErr_SUCCESS)
return sendRes;
return receiveAck(socket);
}
FhgfsOpsErr SyncSlaveBase::streamInode(Socket& socket, const Path& inodeRelPath,
const bool isDirectory)
{
const Path fullPath(basePath / inodeRelPath);
MetaStore& store = *Program::getApp()->getMetaStore();
// Map to store attribute name and its data
std::map<std::string, std::vector<char>> contents;
if (!isDirectory)
{
std::vector<char> attrData;
FhgfsOpsErr readRes;
// Helper function to read and store attribute data in map
auto readAndStoreMetaAttribute = [&](const std::string& attrName)
{
attrData.clear();
readRes = store.getRawMetadata(fullPath, attrName.c_str(), attrData);
if (readRes != FhgfsOpsErr_SUCCESS)
return false;
contents.insert(std::make_pair(attrName, std::move(attrData)));
return true;
};
// Handle META_XATTR_NAME ("user.fhgfs") separately because it can be stored as either
// file contents or an extended attribute, depending on the 'storeUseExtendedAttribs'
// configuration setting in the meta config. In contrast, all other metadata-specific
// attributes are strictly stored as extended attributes and do not have the option to
// be stored as file contents.
if (!readAndStoreMetaAttribute(META_XATTR_NAME))
return readRes;
// Now handle all remaining metadata attributes
std::pair<FhgfsOpsErr, std::vector<std::string>> listXAttrs = XAttrTk::listXAttrs(fullPath.str());
if (listXAttrs.first != FhgfsOpsErr_SUCCESS)
return listXAttrs.first;
for (auto const& attrName : listXAttrs.second)
{
// Process all metadata-specific attributes except META_XATTR_NAME (already handled above)
// This approach ensures we only process attribute(s) that:
// 1. Exist on the inode.
// 2. Are listed in METADATA_XATTR_NAME_LIST, our collection of known metadata attributes.
// 3. Is not META_XATTR_NAME, to prevent duplicate processing.
if (std::find(METADATA_XATTR_NAME_LIST.begin(), METADATA_XATTR_NAME_LIST.end(), attrName)
!= METADATA_XATTR_NAME_LIST.end() && (attrName != META_XATTR_NAME))
{
if (!readAndStoreMetaAttribute(attrName))
return readRes;
}
}
}
const FhgfsOpsErr sendRes = sendResyncPacket(socket, InodeInfo(
isDirectory
? MetaSyncFileType::Directory
: MetaSyncFileType::Inode,
inodeRelPath.str(),
contents,
false));
if (sendRes != FhgfsOpsErr_SUCCESS)
return sendRes;
if (Program::getApp()->getConfig()->getStoreClientXAttrs())
{
auto xattrs = XAttrTk::listUserXAttrs(fullPath.str());
if (xattrs.first != FhgfsOpsErr_SUCCESS)
{
LOG(MIRRORING, ERR, "Could not list resync candidate xattrs.", fullPath, ("error", xattrs.first));
xattrs.second.clear();
return FhgfsOpsErr_INTERNAL;
}
MsgHelperXAttr::StreamXAttrState state(fullPath.str(), std::move(xattrs.second));
const FhgfsOpsErr xattrRes = MsgHelperXAttr::StreamXAttrState::streamXattrFn(&socket, &state);
if (xattrRes != FhgfsOpsErr_SUCCESS)
{
LOG(MIRRORING, ERR, "Error while sending xattrs to secondary.", fullPath, xattrRes);
return FhgfsOpsErr_INTERNAL;
}
}
return receiveAck(socket);
}
FhgfsOpsErr SyncSlaveBase::deleteDentry(Socket& socket, const Path& contDirRelPath,
const std::string& name)
{
auto err = sendResyncPacket(socket, LinkDentryInfo(
MetaSyncFileType::Dentry,
(contDirRelPath / name).str(),
true,
{},
true));
if (err != FhgfsOpsErr_SUCCESS)
return err;
return receiveAck(socket);
}
FhgfsOpsErr SyncSlaveBase::deleteInode(Socket& socket, const Path& inodeRelPath,
const bool isDirectory)
{
auto err = sendResyncPacket(socket, InodeInfo(
isDirectory
? MetaSyncFileType::Directory
: MetaSyncFileType::Inode,
inodeRelPath.str(),
{},
true));
if (err != FhgfsOpsErr_SUCCESS)
return err;
return receiveAck(socket);
}