beegfs/meta/source/net/message/storage/creating/MkFileWithPatternMsgEx.cpp
2025-08-10 01:34:16 +02:00

207 lines
7.5 KiB
C++

#include <common/net/message/storage/creating/MkFileMsg.h>
#include <common/net/message/storage/creating/MkFileRespMsg.h>
#include <program/Program.h>
#include <common/net/message/storage/creating/UnlinkLocalFileMsg.h>
#include <common/net/message/storage/creating/UnlinkLocalFileRespMsg.h>
#include <common/storage/striping/StripePattern.h>
#include <common/toolkit/MathTk.h>
#include <common/toolkit/MessagingTk.h>
#include <components/FileEventLogger.h>
#include <net/msghelpers/MsgHelperMkFile.h>
#include <session/EntryLock.h>
#include "MkFileWithPatternMsgEx.h"
// Called from fhgfs-ctl (online_cfg) to create a file on a specific node.
std::tuple<FileIDLock, ParentNameLock, FileIDLock> MkFileWithPatternMsgEx::lock(
EntryLockStore& store)
{
// no need to lock the created file as well, since
// a) no other operation can create the same file id
// b) until we finish, no part of the system except us knows the new file id
// c) if bulk resync gets the file while it is incomplete, individual resync will get it again
FileIDLock dirLock(&store, getParentInfo()->getEntryID(), true);
ParentNameLock dentryLock(&store, getParentInfo()->getEntryID(), getNewFileName());
FileIDLock fileLock(&store, entryID, true);
return std::make_tuple(std::move(dirLock), std::move(dentryLock), std::move(fileLock));
}
bool MkFileWithPatternMsgEx::processIncoming(ResponseContext& ctx)
{
const EntryInfo* parentInfo = getParentInfo();
std::string newFileName = getNewFileName();
EntryInfo newEntryInfo;
LOG_DEBUG("MkFileWithPatternMsg", Log_DEBUG,
" parentDirID: " + parentInfo->getEntryID() + " newFileName: " + newFileName
+ " isBuddyMirrored: " + (parentInfo->getIsBuddyMirrored() ? "'true'" : "'false'"));
// create ID first
if (parentInfo->getIsBuddyMirrored())
entryID = StorageTk::generateFileID(Program::getApp()->getLocalNode().getNumID());
return BaseType::processIncoming(ctx);
}
std::unique_ptr<MirroredMessageResponseState> MkFileWithPatternMsgEx::executeLocally(
ResponseContext& ctx, bool isSecondary)
{
EntryInfo newEntryInfo;
MkFileDetails mkDetails(getNewFileName(), getUserID(), getGroupID(), getMode(), getUmask(),
TimeAbs().getTimeval()->tv_sec);
if (!entryID.empty())
mkDetails.setNewEntryID(entryID.c_str());
FhgfsOpsErr mkRes = mkFile(getParentInfo(), mkDetails, &newEntryInfo, inodeDiskData);
updateNodeOp(ctx, MetaOpCounter_MKFILE);
return boost::make_unique<ResponseState>(mkRes, std::move(newEntryInfo));
}
/**
* @param dir current directory
* @param currentDepth 1-based path depth
*/
FhgfsOpsErr MkFileWithPatternMsgEx::mkFile(const EntryInfo* parentInfo, MkFileDetails& mkDetails,
EntryInfo* outEntryInfo, FileInodeStoreData& inodeDiskData)
{
MetaStore* metaStore = Program::getApp()->getMetaStore();
FhgfsOpsErr retVal;
// reference parent
DirInode* dir = metaStore->referenceDir(parentInfo->getEntryID(),
parentInfo->getIsBuddyMirrored(), true);
if ( !dir )
return FhgfsOpsErr_PATHNOTEXISTS;
// create meta file
retVal = mkMetaFile(*dir, mkDetails, outEntryInfo, inodeDiskData);
if (shouldFixTimestamps())
fixInodeTimestamp(*dir, dirTimestamps);
// clean-up
metaStore->releaseDir(parentInfo->getEntryID());
return retVal;
}
/**
* Create an inode and directory-entry
*/
FhgfsOpsErr MkFileWithPatternMsgEx::mkMetaFile(DirInode& dir, MkFileDetails& mkDetails,
EntryInfo* outEntryInfo, FileInodeStoreData& inodeDiskData)
{
// note: to guarantee amtomicity of file creation (from the view of a client), we have
// to create the inode first and insert the directory entry afterwards
std::unique_ptr<StripePattern> stripePattern(getPattern().clone());
const UInt16Vector* stripeTargets = stripePattern->getStripeTargetIDs();
StoragePoolId storagePoolId = stripePattern->getStoragePoolId();
if (stripeTargets->empty())
{
StoragePoolPtr storagePool =
Program::getApp()->getStoragePoolStore()->getPool(storagePoolId);
if (!storagePool)
{
LOG(GENERAL, ERR, "Given Storage Pool ID "
+ StringTk::uintToStr(storagePoolId.val()) + " doesn't exist.");
return FhgfsOpsErr_INTERNAL;
}
UInt16Vector chosenStripeTargets;
if(stripePattern->getPatternType() == StripePatternType_BuddyMirror)
{
storagePool->getBuddyCapacityPools()->chooseStorageTargets(
stripePattern->getDefaultNumTargets(), stripePattern->getMinNumTargets(),
nullptr, &chosenStripeTargets);
}
else
{
storagePool->getTargetCapacityPools()->chooseStorageTargets(
stripePattern->getDefaultNumTargets(), stripePattern->getMinNumTargets(),
nullptr, &chosenStripeTargets);
}
stripePattern->getStripeTargetIDsModifyable()->swap(chosenStripeTargets);
}
// check if num targets and target list match and if targets actually exist
if(stripeTargets->empty() || (stripeTargets->size() < stripePattern->getMinNumTargets() ) )
{
LOG(GENERAL, ERR, "No (or not enough) storage targets defined.",
("numTargets", stripeTargets->size()),
("expectedMinNumTargets", stripePattern->getMinNumTargets()));
return FhgfsOpsErr_INTERNAL;
}
for (auto iter = stripeTargets->begin(); iter != stripeTargets->end(); iter++)
{
if(stripePattern->getPatternType() == StripePatternType_BuddyMirror)
{
if (!Program::getApp()->getStorageBuddyGroupMapper()->getPrimaryTargetID(*iter))
{
LOG(GENERAL, ERR, "Unknown buddy group targets defined.",
("targetId", *iter));
return FhgfsOpsErr_UNKNOWNTARGET;
}
}
else
{
if (!Program::getApp()->getTargetMapper()->targetExists(*iter))
{
LOG(GENERAL, ERR, "Unknown storage targets defined.",
("targetId", *iter));
return FhgfsOpsErr_UNKNOWNTARGET;
}
}
}
// check if chunk size satisfies constraints
if (!MathTk::isPowerOfTwo(stripePattern->getChunkSize()))
{
LOG(GENERAL, DEBUG, "Invalid chunk size: Must be a power of two.",
stripePattern->getChunkSize());
return FhgfsOpsErr_INTERNAL;
}
if (stripePattern->getChunkSize() < STRIPEPATTERN_MIN_CHUNKSIZE)
{
LOG(GENERAL, DEBUG, "Invalid chunk size: Below minimum size.",
stripePattern->getChunkSize(),
("minChunkSize", STRIPEPATTERN_MIN_CHUNKSIZE));
return FhgfsOpsErr_INTERNAL;
}
return Program::getApp()->getMetaStore()->mkNewMetaFile(
dir, &mkDetails, std::move(stripePattern), getRemoteStorageTarget(), outEntryInfo,
&inodeDiskData);
// (note: internally deletes stripePattern)
}
void MkFileWithPatternMsgEx::forwardToSecondary(ResponseContext& ctx)
{
UInt16List preferredTargets; // can be an empty dummy
std::string newFileName = getNewFileName();
MkFileMsg mkFileMsg(getParentInfo(), newFileName, getUserID(), getGroupID(), getMode(),
getUmask(), &preferredTargets);
mkFileMsg.addFlag(NetMessageHeader::Flag_BuddyMirrorSecond);
// secondary needs to know the created entryID ans stripe pattern, because it needs to use the
// same information
mkFileMsg.setNewEntryID(entryID.c_str());
mkFileMsg.setPattern(inodeDiskData.getStripePattern());
mkFileMsg.setDirTimestamps(dirTimestamps);
mkFileMsg.setCreateTime(inodeDiskData.getInodeStatData()->getCreationTimeSecs());
mkFileMsg.setRemoteStorageTarget(getRemoteStorageTarget());
sendToSecondary(ctx, mkFileMsg, NETMSGTYPE_MkFileResp);
}