beegfs/meta/source/net/msghelpers/MsgHelperStat.cpp
2025-08-10 01:34:16 +02:00

259 lines
8.7 KiB
C++

#include <common/net/message/storage/attribs/GetChunkFileAttribsMsg.h>
#include <common/net/message/storage/attribs/GetChunkFileAttribsRespMsg.h>
#include <common/toolkit/MessagingTk.h>
#include <common/toolkit/SynchronizedCounter.h>
#include <components/worker/GetChunkFileAttribsWork.h>
#include <program/Program.h>
#include "MsgHelperStat.h"
/**
* Note: This will automatically refresh dynamic attribs if they are outdated.
*
* @param loadFromDisk do we need to load the data from disk or do we want to have data from
* an already opened inode only
* @param msgUserID will only be used in msg header info.
* @param outParentNodeID may be NULL (default) if the caller is not interested
* @param outParentEntryID may NULL (if outParentNodeID is NULL)
*/
FhgfsOpsErr MsgHelperStat::stat(EntryInfo* entryInfo, bool loadFromDisk, unsigned msgUserID,
StatData& outStatData, NumNodeID* outParentNodeID, std::string* outParentEntryID)
{
const char* logContext = "Stat Helper (stat entry)";
MetaStore* metaStore = Program::getApp()->getMetaStore();
FhgfsOpsErr retVal;
retVal = metaStore->stat(entryInfo, loadFromDisk, outStatData, outParentNodeID,
outParentEntryID);
if(retVal == FhgfsOpsErr_DYNAMICATTRIBSOUTDATED)
{ // dynamic attribs outdated => get fresh dynamic attribs from storage servers and stat again
MsgHelperStat::refreshDynAttribs(entryInfo, false, msgUserID);
//note: if we are here it is regular file and we don't need to request parentData
retVal = metaStore->stat(entryInfo, loadFromDisk, outStatData);
// this time we ignore outdated dynamic attribs because refreshing them again would
// be useless (or we could keep on doing it forever)
if(retVal == FhgfsOpsErr_DYNAMICATTRIBSOUTDATED)
retVal = FhgfsOpsErr_SUCCESS;
}
else
if(retVal == FhgfsOpsErr_PATHNOTEXISTS && loadFromDisk)
{ /* metadata not found: it is hard to tell whether this is an error (e.g. metadata was never
created) or just a normal case (e.g. someone removed a file during an "ls -l") */
LogContext(logContext).log(Log_DEBUG, "Missing metadata for entryID: " +
entryInfo->getEntryID() + ". "
"(Possibly a valid race of two processes or a cached entry that is now being "
"checked by a client revalidate() method.)");
}
return retVal;
}
/**
* Refresh current file size and other dynamic attribs from storage servers.
*
* @makePersistent whether or not this method should also update persistent metadata.
* @param msgUserID only used for msg header info.
*/
FhgfsOpsErr MsgHelperStat::refreshDynAttribs(EntryInfo* entryInfo, bool makePersistent,
unsigned msgUserID)
{
MetaStore* metaStore = Program::getApp()->getMetaStore();
FhgfsOpsErr retVal;
std::string parentEntryID = entryInfo->getParentEntryID();
std::string entryID = entryInfo->getEntryID();
auto [inode, referenceRes] = metaStore->referenceFile(entryInfo);
if(!inode)
{
std::string logContext("Stat Helper (refresh filesize: parentID: " + parentEntryID
+ " entryID: " + entryID + ")");
LogContext(logContext).log(Log_DEBUG, std::string("File could not be referenced") );
return referenceRes;
}
if(inode->getStripePattern()->getAssignedNumTargets() == 1)
retVal = refreshDynAttribsSequential(*inode, entryID, msgUserID);
else
retVal = refreshDynAttribsParallel(*inode, entryID, msgUserID);
if( (retVal == FhgfsOpsErr_SUCCESS) && makePersistent)
{
bool persistenceRes = inode->updateInodeOnDisk(entryInfo);
if(!persistenceRes)
retVal = FhgfsOpsErr_INTERNAL;
}
metaStore->releaseFile(entryInfo->getParentEntryID(), inode);
return retVal;
}
/**
* Note: This method does support getting attrs from buddymirrors, but only from group's primary.
*
* @param msgUserID only used for msg header info.
*/
FhgfsOpsErr MsgHelperStat::refreshDynAttribsSequential(FileInode& inode, const std::string& entryID,
unsigned msgUserID)
{
const char* logContext = "Stat Helper (refresh chunk files S)";
FhgfsOpsErr retVal = FhgfsOpsErr_SUCCESS; // will be set to node error, if any
App* app = Program::getApp();
StripePattern* pattern = inode.getStripePattern();
const UInt16Vector* targetIDs = pattern->getStripeTargetIDs();
DynamicFileAttribsVec dynAttribsVec(targetIDs->size() );
PathInfo pathInfo;
inode.getPathInfo(&pathInfo);
// send request to each node and receive the response message
unsigned currentStripeNodeIndex = 0;
for(UInt16VectorConstIter iter = targetIDs->begin();
iter != targetIDs->end();
iter++, currentStripeNodeIndex++)
{
uint16_t targetID = *iter;
// prepare request message
GetChunkFileAttribsMsg getSizeMsg(entryID, *iter, &pathInfo);
if(pattern->getPatternType() == StripePatternType_BuddyMirror)
getSizeMsg.addMsgHeaderFeatureFlag(GETCHUNKFILEATTRSMSG_FLAG_BUDDYMIRROR);
getSizeMsg.setMsgHeaderUserID(msgUserID);
// prepare communication
RequestResponseTarget rrTarget(targetID, app->getTargetMapper(), app->getStorageNodes() );
rrTarget.setTargetStates(app->getTargetStateStore() );
if(pattern->getPatternType() == StripePatternType_BuddyMirror)
rrTarget.setMirrorInfo(app->getStorageBuddyGroupMapper(), false);
RequestResponseArgs rrArgs(NULL, &getSizeMsg, NETMSGTYPE_GetChunkFileAttribsResp);
// communicate
FhgfsOpsErr requestRes = MessagingTk::requestResponseTarget(&rrTarget, &rrArgs);
if(unlikely(requestRes != FhgfsOpsErr_SUCCESS) )
{ // communication error
LogContext(logContext).log(Log_WARNING,
std::string("Communication with storage target failed. ") +
(pattern->getPatternType() == StripePatternType_BuddyMirror ? "Mirror " : "") +
"TargetID: " + StringTk::uintToStr(targetID) + "; "
"EntryID: " + entryID);
retVal = requestRes;
continue;
}
// correct response type received
auto* getSizeRespMsg = (GetChunkFileAttribsRespMsg*)rrArgs.outRespMsg.get();
FhgfsOpsErr getSizeResult = getSizeRespMsg->getResult();
if(getSizeResult != FhgfsOpsErr_SUCCESS)
{ // error: got no fresh attributes
LogContext(logContext).log(Log_WARNING,
std::string("Getting fresh chunk file attributes from target failed. ") +
(pattern->getPatternType() == StripePatternType_BuddyMirror ? "Mirror " : "") +
"TargetID: " + StringTk::uintToStr(targetID) + "; "
"EntryID: " + entryID);
retVal = getSizeResult;
continue;
}
// success: got fresh chunk file attributes
//log.log(3, std::string("Got fresh filesize from node: ") + nodeID);
DynamicFileAttribs currentDynAttribs(getSizeRespMsg->getStorageVersion(),
getSizeRespMsg->getSize(), getSizeRespMsg->getAllocedBlocks(),
getSizeRespMsg->getModificationTimeSecs(), getSizeRespMsg->getLastAccessTimeSecs() );
dynAttribsVec[currentStripeNodeIndex] = currentDynAttribs;
}
inode.setDynAttribs(dynAttribsVec); // the actual update
if(retVal != FhgfsOpsErr_SUCCESS)
{
LogContext(logContext).log(Log_WARNING,
"Problems occurred during chunk file attributes refresh. "
"EntryID: " + entryID);
}
return retVal;
}
/**
* Note: For buddymirrored files, only group's primary is used.
*/
FhgfsOpsErr MsgHelperStat::refreshDynAttribsParallel(FileInode& inode, const std::string& entryID,
unsigned msgUserID)
{
const char* logContext = "Stat Helper (refresh chunk files)";
FhgfsOpsErr retVal = FhgfsOpsErr_SUCCESS; // will be set to node error, if any
App* app = Program::getApp();
MultiWorkQueue* slaveQ = app->getCommSlaveQueue();
StripePattern* pattern = inode.getStripePattern();
const UInt16Vector* targetIDs = pattern->getStripeTargetIDs();
DynamicFileAttribsVec dynAttribsVec(targetIDs->size() );
size_t numWorks = targetIDs->size();
FhgfsOpsErrVec nodeResults(numWorks);
SynchronizedCounter counter;
PathInfo pathInfo;
inode.getPathInfo(&pathInfo);
for(size_t i=0; i < numWorks; i++)
{
GetChunkFileAttribsWork* work = new GetChunkFileAttribsWork(entryID, pattern, (*targetIDs)[i],
&pathInfo, &(dynAttribsVec[i]), &(nodeResults[i]), &counter);
work->setMsgUserID(msgUserID);
slaveQ->addDirectWork(work);
}
counter.waitForCount(numWorks);
for(size_t i=0; i < numWorks; i++)
{
if(nodeResults[i] != FhgfsOpsErr_SUCCESS)
{
LogContext(logContext).log(Log_WARNING,
"Problems occurred during file attribs refresh. entryID: " + entryID);
retVal = nodeResults[i];
break;
}
}
inode.setDynAttribs(dynAttribsVec); // the actual update
return retVal;
}