New upstream version 8.1.0

This commit is contained in:
geos_one
2025-08-10 01:34:16 +02:00
commit c891bb7105
4398 changed files with 838833 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
#include "FindLinkOwnerMsgEx.h"
#include <program/Program.h>
bool FindLinkOwnerMsgEx::processIncoming(ResponseContext& ctx)
{
MetaStore *metaStore = Program::getApp()->getMetaStore();
std::string entryID = this->getEntryID();
int result = 1;
std::string parentEntryID;
NumNodeID parentNodeID;
MetaFileHandle file;
DirInode *dir = NULL;
// we don't know if the ID belongs to a file or a directory, so we try the file first and if that
// does not work, we try directory
/* TODO: Used by fhgfs-ctl ModeReverseLookup, but this mode does not support to send the
* parentID. With the 2014.01 format this should be possible for most files/chunks, though.
*/
// TODO: buddy mirroring => but this is not used anymore, so maybe it's better to just delete it
file = metaStore->referenceLoadedFile(parentEntryID, false, entryID);
if (file != NULL)
{
// file->getParentInfo(&parentEntryID, &parentNodeID);
result = 0;
metaStore->releaseFile(parentEntryID, file);
goto send_response;
}
// TODO: buddy mirroring => but this is not used anymore, so maybe it's better to just delete it
dir = metaStore->referenceDir(entryID, false, true);
if (dir != NULL)
{
dir->getParentInfo(&parentEntryID, &parentNodeID);
result = 0;
metaStore->releaseDir(entryID);
goto send_response;
}
send_response:
ctx.sendResponse(FindLinkOwnerRespMsg(result, parentNodeID, parentEntryID) );
return true;
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include <common/net/message/storage/lookup/FindLinkOwnerMsg.h>
#include <common/net/message/storage/lookup/FindLinkOwnerRespMsg.h>
class FindLinkOwnerMsgEx : public FindLinkOwnerMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,120 @@
#include <program/Program.h>
#include <common/net/message/storage/lookup/FindOwnerRespMsg.h>
#include "FindOwnerMsgEx.h"
bool FindOwnerMsgEx::processIncoming(ResponseContext& ctx)
{
#ifdef BEEGFS_DEBUG
const char* logContext = "FindOwnerMsg incoming";
#endif // BEEGFS_DEBUG
LOG_DEBUG(logContext, Log_SPAM, "Path: '" + getPath().str() + "'");
EntryInfoWithDepth ownerInfo;
FhgfsOpsErr findRes;
if(!getSearchDepth() )
{ // looking for the root node
NumNodeID rootNodeID = Program::getApp()->getRootDir()->getOwnerNodeID();
if (rootNodeID)
{
ownerInfo.set(rootNodeID, "", META_ROOTDIR_ID_STR, "/", DirEntryType_DIRECTORY, 0, 0);
if (Program::getApp()->getRootDir()->getIsBuddyMirrored())
ownerInfo.setBuddyMirroredFlag(true);
findRes = FhgfsOpsErr_SUCCESS;
}
else
{ // we don't know the root node
findRes = FhgfsOpsErr_INTERNAL;
}
}
else
{ // a normal path lookup
findRes = findOwner(&ownerInfo);
}
ctx.sendResponse(FindOwnerRespMsg(findRes, &ownerInfo) );
App* app = Program::getApp();
app->getNodeOpStats()->updateNodeOp(ctx.getSocket()->getPeerIP(), MetaOpCounter_FINDOWNER,
getMsgHeaderUserID() );
return true;
}
/**
* Note: This does not work for finding the root dir owner (because it relies on the existence
* of a parent dir).
*/
FhgfsOpsErr FindOwnerMsgEx::findOwner(EntryInfoWithDepth* outInfo)
{
FhgfsOpsErr findRes = FhgfsOpsErr_INTERNAL;
App* app = Program::getApp();
MetaStore* metaStore = app->getMetaStore();
unsigned searchDepth = this->getSearchDepth();
unsigned currentDepth = this->getCurrentDepth();
EntryInfo *currentEntryInfo = this->getEntryInfo();
std::string currentEntryID = currentEntryInfo->getEntryID();
bool currentEntryIsBuddyMirrored = currentEntryInfo->getIsBuddyMirrored();
const Path path(getPath());
// search
while(currentDepth < searchDepth)
{
DirInode* currentDir = metaStore->referenceDir(currentEntryID, currentEntryIsBuddyMirrored,
true);
if(!currentDir)
{ // someone said we own the dir with this ID, but we do not => it was deleted
// note: this might also be caused by a change of ownership, but a feature like that is
// currently not implemented
return (findRes == FhgfsOpsErr_SUCCESS) ? FhgfsOpsErr_SUCCESS : FhgfsOpsErr_PATHNOTEXISTS;
}
EntryInfo subInfo;
auto [getEntryRes, isFileOpen] = metaStore->getEntryData(currentDir, path[currentDepth],
&subInfo, NULL);
if (getEntryRes == FhgfsOpsErr_SUCCESS || getEntryRes == FhgfsOpsErr_DYNAMICATTRIBSOUTDATED)
{ // next entry exists and is a dir or a file
currentDepth++;
*outInfo = subInfo;
outInfo->setEntryDepth(currentDepth);
findRes = FhgfsOpsErr_SUCCESS;
}
else
{ // entry does not exist
findRes = FhgfsOpsErr_PATHNOTEXISTS;
}
metaStore->releaseDir(currentEntryID);
if(findRes != FhgfsOpsErr_SUCCESS)
break;
// is next entry owned by a different node?
if (subInfo.getIsBuddyMirrored())
{
if(subInfo.getOwnerNodeID()
!= NumNodeID(app->getMetaBuddyGroupMapper()->getLocalGroupID() ) )
break;
}
else
if (subInfo.getOwnerNodeID() != app->getLocalNode().getNumID())
break;
// prepare for next round
currentEntryID = outInfo->getEntryID();
}
return findRes;
}

View File

@@ -0,0 +1,22 @@
#pragma once
#include <common/net/message/storage/lookup/FindOwnerMsg.h>
#include <common/storage/StorageDefinitions.h>
#include <common/storage/StorageErrors.h>
#include <common/toolkit/MetadataTk.h>
#include <common/Common.h>
#include <storage/MetaStore.h>
// Get the meta-data server of a file
class FindOwnerMsgEx : public FindOwnerMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
private:
FhgfsOpsErr findOwner(EntryInfoWithDepth* outInfo);
};

View File

@@ -0,0 +1,550 @@
#include <common/net/message/control/GenericResponseMsg.h>
#include <program/Program.h>
#include <common/net/message/storage/creating/MkFileMsg.h>
#include <common/net/message/storage/creating/MkFileRespMsg.h>
#include <common/net/message/storage/lookup/LookupIntentRespMsg.h>
#include <common/storage/striping/Raid0Pattern.h>
#include <common/toolkit/SessionTk.h>
#include <components/FileEventLogger.h>
#include <net/msghelpers/MsgHelperMkFile.h>
#include <net/msghelpers/MsgHelperOpen.h>
#include <net/msghelpers/MsgHelperStat.h>
#include <session/EntryLock.h>
#include <session/SessionStore.h>
#include <storage/DentryStoreData.h>
#include <common/storage/StoragePool.h>
#include "LookupIntentMsgEx.h"
std::tuple<FileIDLock, ParentNameLock, FileIDLock> LookupIntentMsgEx::lock(EntryLockStore& store)
{
ParentNameLock dentryLock;
FileIDLock entryIDLockForDir;
FileIDLock entryIDLockForFile;
enum DirEntryType entryType = getEntryInfo()->getEntryType();
if (getIntentFlags() & LOOKUPINTENTMSG_FLAG_CREATE)
{
entryIDLockForDir = {&store, getParentInfo()->getEntryID(), true};
dentryLock = {&store, getParentInfo()->getEntryID(), getEntryName()};
entryIDLockForFile = {&store, entryID, true};
}
else
{
//XXX Note: If you are addding new flag for lookupintent, make sure to
//check if shared lock for parent dir and file is sufficient.
//Otherwise add another else if condition.
// For other lookup flag, we don't have entryID yet. So rather than
// taking lock on the emptry EntryID(which can serialize lookup on all
// files even if from different parent directory), lookup the entryID
// while holding parent lock. And take the lock on the actual entryID.
entryIDLockForDir = {&store, getParentInfo()->getEntryID(), false};
lookupRes = lookup(getParentInfo()->getEntryID(), getEntryName(), isMirrored(),
&diskEntryInfo, &inodeData, inodeDataOutdated);
if (lookupRes == FhgfsOpsErr_SUCCESS)
{
entryID = diskEntryInfo.getEntryID();
entryType = diskEntryInfo.getEntryType();
}
// for revalidate entryInfo is valid, so use the info from it
if (entryID.empty() && (getIntentFlags() & LOOKUPINTENTMSG_FLAG_REVALIDATE))
{
entryID = getEntryInfo()->getEntryID();
entryType = getEntryInfo()->getEntryType();
}
if (getIntentFlags() & LOOKUPINTENTMSG_FLAG_OPEN)
{
entryIDLockForFile = {&store, entryID, true};
}
else
{
if (DirEntryType_ISDIR(entryType) &&
(entryID < getParentInfo()->getEntryID()))
{
// Release parent lock because child lock needs to be taken first.
entryIDLockForDir = {};
// Take the lock in reverse order
entryIDLockForFile = {&store, entryID, false};
entryIDLockForDir = {&store, getParentInfo()->getEntryID(), false};
}
else
{
entryIDLockForFile = {&store, entryID, false};
}
}
}
return std::make_tuple(std::move(entryIDLockForDir), std::move(dentryLock),
std::move(entryIDLockForFile));
}
bool LookupIntentMsgEx::processIncoming(ResponseContext& ctx)
{
App* app = Program::getApp();
const std::string& parentEntryID = getParentInfo()->getEntryID();
const std::string& entryName = getEntryName();
inodeDataOutdated = false; // true if the file/inode is currently open (referenced)
lookupRes = FhgfsOpsErr_INTERNAL;
LOG_DBG(GENERAL, DEBUG, "", parentEntryID, entryName, getParentInfo()->getIsBuddyMirrored());
// sanity checks
if (unlikely(parentEntryID.empty() || entryName.empty()))
{
LOG(GENERAL, WARNING, "Sanity check failed", parentEntryID, entryName);
ctx.sendResponse(LookupIntentRespMsg(FhgfsOpsErr_INTERNAL));
return true;
}
if (getIntentFlags() & LOOKUPINTENTMSG_FLAG_CREATE)
entryID = StorageTk::generateFileID(app->getLocalNode().getNumID());
return BaseType::processIncoming(ctx);
}
std::unique_ptr<MirroredMessageResponseState> LookupIntentMsgEx::executeLocally(
ResponseContext& ctx, bool isSecondary)
{
LookupIntentResponseState response;
int createFlag = getIntentFlags() & LOOKUPINTENTMSG_FLAG_CREATE;
FhgfsOpsErr createRes = FhgfsOpsErr_INTERNAL;
// Note: Actually we should first do a lookup. However, a successful create also implies a
// failed Lookup, so we can take a shortcut.
// lookup-create
if (createFlag)
{
LOG_DBG(GENERAL, SPAM, "Create");
createRes = create(getParentInfo(), getEntryName(), &diskEntryInfo, &inodeData, isSecondary);
switch (createRes)
{
case FhgfsOpsErr_SUCCESS:
// Successful Create, which implies Lookup-before-create would have been failed.
response.setLookupResult(FhgfsOpsErr_PATHNOTEXISTS);
response.setEntryInfo(diskEntryInfo);
response.addResponseCreate(createRes);
break;
case FhgfsOpsErr_EXISTS:
// NOTE: we need to do a Lookup to get required lookup data
if (getIntentFlags() & LOOKUPINTENTMSG_FLAG_CREATEEXCLUSIVE)
response.addResponseCreate(FhgfsOpsErr_EXISTS);
else
response.addResponseCreate(FhgfsOpsErr_SUCCESS);
break;
case FhgfsOpsErr_DQUOT:
response.addResponseCreate(FhgfsOpsErr_DQUOT);
break;
default:
response.addResponseCreate(FhgfsOpsErr_INTERNAL);
}
// note: don't quit here on error because caller might still have requested stat info
}
// lookup
if ((!createFlag) || (createRes == FhgfsOpsErr_EXISTS) )
{
LOG_DBG(GENERAL, SPAM, "Lookup");
// Lookup will happen for secondary node or create failed or lookup
// failed earlier.
if (isSecondary || (createRes == FhgfsOpsErr_EXISTS) ||
lookupRes != FhgfsOpsErr_SUCCESS)
{
// lock is not taken on secondary, so we need to perform lookup()
// for secondary here.
lookupRes = lookup(getParentInfo()->getEntryID(), getEntryName(), isMirrored(),
&diskEntryInfo, &inodeData, inodeDataOutdated);
}
// Lookup was already done in lock() function after taking lock on parent.
response.setLookupResult(lookupRes);
response.setEntryInfo(diskEntryInfo);
if (unlikely(lookupRes != FhgfsOpsErr_SUCCESS && createFlag))
{
// so createFlag is set, so createRes is either Success or Exists, but now lookup fails
// create/unlink race?
StatData statData;
statData.setAllFake(); // set arbitrary stat values (receiver won't use the values)
response.addResponseStat(lookupRes, statData);
return boost::make_unique<ResponseState>(std::move(response));
}
}
// lookup-revalidate
if (getIntentFlags() & LOOKUPINTENTMSG_FLAG_REVALIDATE)
{
LOG_DBG(GENERAL, SPAM, "Revalidate");
auto revalidateRes = revalidate(&diskEntryInfo, inodeData.getMetaVersion());
response.addResponseRevalidate(revalidateRes);
if (revalidateRes != FhgfsOpsErr_SUCCESS)
return boost::make_unique<ResponseState>(std::move(response));
}
// lookup-stat
// note: we do stat before open to avoid the dyn attribs refresh if the file is not opened by
// someone else currently.
if ((getIntentFlags() & LOOKUPINTENTMSG_FLAG_STAT) &&
(lookupRes == FhgfsOpsErr_SUCCESS || createRes == FhgfsOpsErr_SUCCESS))
{
LOG_DBG(GENERAL, SPAM, "Stat");
// check if lookup and create failed (we don't have an entryID to stat then)
if (diskEntryInfo.getEntryID().empty())
return boost::make_unique<ResponseState>(std::move(response));
if ((diskEntryInfo.getFeatureFlags() & ENTRYINFO_FEATURE_INLINED) && !inodeDataOutdated)
{
// For inlined inodes with up-to-date inode data, use stat data fetched during lookup()
response.addResponseStat(FhgfsOpsErr_SUCCESS, *inodeData.getInodeStatData());
}
else
{ // read stat data separately
StatData statData;
FhgfsOpsErr statRes = stat(&diskEntryInfo, true, statData);
response.addResponseStat(statRes, statData);
if (statRes != FhgfsOpsErr_SUCCESS)
return boost::make_unique<ResponseState>(std::move(response));
}
}
// lookup-open
if(getIntentFlags() & LOOKUPINTENTMSG_FLAG_OPEN)
{
LOG_DBG(GENERAL, SPAM, "Open");
std::string fileHandleID;
PathInfo pathInfo;
Raid0Pattern dummyPattern(1, UInt16Vector() );
// don't open if create failed
if ((createRes != FhgfsOpsErr_SUCCESS) && (getIntentFlags() & LOOKUPINTENTMSG_FLAG_CREATE))
return boost::make_unique<ResponseState>(std::move(response));
// if it's not a regular file, we don't open that
if (!DirEntryType_ISREGULARFILE(diskEntryInfo.getEntryType()))
return boost::make_unique<ResponseState>(std::move(response));
// check if lookup and/or create failed (we don't have an entryID to open then)
if (diskEntryInfo.getEntryID().empty())
return boost::make_unique<ResponseState>(std::move(response));
StripePattern* pattern = NULL;
FhgfsOpsErr openRes = open(&diskEntryInfo, &fileHandleID, &pattern, &pathInfo, isSecondary);
if(openRes != FhgfsOpsErr_SUCCESS)
{ // open failed => use dummy pattern for response
response.addResponseOpen(openRes, std::move(fileHandleID),
std::unique_ptr<StripePattern>(dummyPattern.clone()), pathInfo);
return boost::make_unique<ResponseState>(std::move(response));
}
response.addResponseOpen(openRes, std::move(fileHandleID),
std::unique_ptr<StripePattern>(pattern->clone()), pathInfo);
}
updateNodeOp(ctx, getOpCounterType());
return boost::make_unique<ResponseState>(std::move(response));
}
FhgfsOpsErr LookupIntentMsgEx::lookup(const std::string& parentEntryID,
const std::string& entryName, bool isBuddyMirrored, EntryInfo* outEntryInfo,
FileInodeStoreData* outInodeStoreData, bool& outInodeDataOutdated)
{
MetaStore* metaStore = Program::getApp()->getMetaStore();
DirInode* parentDir = metaStore->referenceDir(parentEntryID, isBuddyMirrored, false);
if (unlikely(!parentDir))
{ // out of memory
return FhgfsOpsErr_INTERNAL;
}
auto [lookupRes1, isFileOpen] = metaStore->getEntryData(parentDir, entryName, outEntryInfo,
outInodeStoreData);
if (lookupRes1 == FhgfsOpsErr_DYNAMICATTRIBSOUTDATED)
{
lookupRes1 = FhgfsOpsErr_SUCCESS;
outInodeDataOutdated = isFileOpen;
// If the file inode is not inlined and the intent includes the creation flag,
// we need to use a different overload of getEntryData() to correctly retrieve the
// inode disk data for non-inlined inode(s) and prevent potential crashes due to
// race conditions between create and hardlink creation.
// If create flag is set, fetch full inode disk data using non-inlined inode.
int createFlag = getIntentFlags() & LOOKUPINTENTMSG_FLAG_CREATE;
if (!outEntryInfo->getIsInlined() && createFlag)
{
FhgfsOpsErr getRes = metaStore->getEntryData(outEntryInfo, outInodeStoreData);
if (getRes != FhgfsOpsErr_SUCCESS)
lookupRes1 = getRes;
}
}
metaStore->releaseDir(parentEntryID);
return lookupRes1;
}
/**
* compare entryInfo on disk with EntryInfo send by the client
* @return FhgfsOpsErr_SUCCESS if revalidation successful, FhgfsOpsErr_PATHNOTEXISTS otherwise, FhgfsOpsErr_METAVERSIONMISMATCH in case of version change.
*/
FhgfsOpsErr LookupIntentMsgEx::revalidate(EntryInfo* diskEntryInfo, uint32_t metaVersion)
{
EntryInfo* clientEntryInfo = this->getEntryInfo();
uint32_t clientMetaVersion = this->getMetaVersion();
if ( (diskEntryInfo->getEntryID() == clientEntryInfo->getEntryID() ) &&
(diskEntryInfo->getOwnerNodeID() == clientEntryInfo->getOwnerNodeID() ) )
{
if (clientMetaVersion != metaVersion)
return FhgfsOpsErr_METAVERSIONMISMATCH;
return FhgfsOpsErr_SUCCESS;
}
return FhgfsOpsErr_PATHNOTEXISTS;
}
FhgfsOpsErr LookupIntentMsgEx::create(EntryInfo* parentInfo, const std::string& entryName,
EntryInfo *outEntryInfo, FileInodeStoreData* outInodeData, bool isSecondary)
{
MkFileDetails mkDetails(entryName, getUserID(), getGroupID(), getMode(), getUmask(),
TimeAbs().getTimeval()->tv_sec);
StripePattern* pattern = nullptr;
std::unique_ptr<RemoteStorageTarget> rstInfo;
FhgfsOpsErr res;
DirInode* dir = Program::getApp()->getMetaStore()->referenceDir(
parentInfo->getEntryID(), parentInfo->getIsBuddyMirrored(), true);
if (!dir)
return FhgfsOpsErr_PATHNOTEXISTS;
// create new RST object and set remote storage target info from parentDir if available
if (dir->getIsRstAvailable())
{
rstInfo = std::make_unique<RemoteStorageTarget>();
rstInfo->set(dir->getRemoteStorageTargetInfo());
}
if (isSecondary)
{
mkDetails.setNewEntryID(getNewEntryID().c_str());
mkDetails.createTime = fileTimestamps.creationTimeSecs;
pattern = getNewStripePattern()->clone();
}
else
{
if (!entryID.empty())
mkDetails.setNewEntryID(entryID.c_str());
pattern = dir->createFileStripePattern(&getPreferredTargets(), 0, 0, StoragePoolId(0));
}
if (!pattern)
{
LogContext("Lookup Create").logErr(
"StripePattern is NULL. Can't proceed. Filename: " + getEntryName());
res = FhgfsOpsErr_INTERNAL;
goto releasedir_and_return;
}
if (isMsgHeaderFeatureFlagSet(LOOKUPINTENTMSG_FLAG_USE_QUOTA) &&
Program::getApp()->getConfig()->getQuotaEnableEnforcement())
{
const char* logContext = "Quota Enforcement for create";
StoragePoolPtr storagePool =
Program::getApp()->getStoragePoolStore()->getPool(pattern->getStoragePoolId());
if (!storagePool)
{
LOG(QUOTA, WARNING, "Requested storage pool doesn't exist on metadata server.",
("StoragePoolId", pattern->getStoragePoolId()));
res = FhgfsOpsErr_UNKNOWNPOOL;
goto releasedir_and_return;
}
UInt16Set targetIds = storagePool->getTargets();
for (auto targetId : targetIds)
{
ExceededQuotaStorePtr exceededQuotaStore = Program::getApp()->getExceededQuotaStores()->get(targetId);
if (exceededQuotaStore && exceededQuotaStore->someQuotaExceeded())
{
QuotaExceededErrorType quotaExceeded = exceededQuotaStore->isQuotaExceeded(mkDetails.userID, mkDetails.groupID);
if (quotaExceeded != QuotaExceededErrorType_NOT_EXCEEDED)
{
LogContext(logContext).log(Log_NOTICE,
QuotaData::QuotaExceededErrorTypeToString(quotaExceeded) + " "
"UID: " + StringTk::uintToStr(mkDetails.userID) + "; "
"GID: " + StringTk::uintToStr(mkDetails.groupID));
res = FhgfsOpsErr_DQUOT;
goto releasedir_and_return;
}
}
}
}
res = MsgHelperMkFile::mkFile(*dir, &mkDetails, &getPreferredTargets(), 0, 0,
pattern, rstInfo.get(), outEntryInfo, outInodeData);
if (res == FhgfsOpsErr_SUCCESS && shouldFixTimestamps())
{
fixInodeTimestamp(*dir, dirTimestamps);
if (!isSecondary)
fileTimestamps = outInodeData->getInodeStatData()->getMirroredTimestamps();
}
if (!isSecondary && res == FhgfsOpsErr_SUCCESS && Program::getApp()->getFileEventLogger()
&& getFileEvent())
{
EventContext eventCtx = makeEventContext(outEntryInfo, outEntryInfo->getParentEntryID(),
getMsgHeaderUserID(), "", outInodeData->getInodeStatData()->getNumHardlinks(), isSecondary);
logEvent(Program::getApp()->getFileEventLogger(), *getFileEvent(), eventCtx);
}
releasedir_and_return:
Program::getApp()->getMetaStore()->releaseDir(dir->getID());
return res;
}
FhgfsOpsErr LookupIntentMsgEx::stat(EntryInfo* entryInfo, bool loadFromDisk, StatData& outStatData)
{
Node& localNode = Program::getApp()->getLocalNode();
MirrorBuddyGroupMapper* metaBuddyGroupMapper = Program::getApp()->getMetaBuddyGroupMapper();
FhgfsOpsErr statRes = FhgfsOpsErr_NOTOWNER;
// check if we can stat on this machine or if entry is owned by another server
NumNodeID expectedOwner;
if (entryInfo->getIsBuddyMirrored())
expectedOwner = NumNodeID(metaBuddyGroupMapper->getLocalGroupID());
else
expectedOwner = localNode.getNumID();
if(entryInfo->getOwnerNodeID() == expectedOwner)
statRes = MsgHelperStat::stat(entryInfo, loadFromDisk, getMsgHeaderUserID(), outStatData);
return statRes;
}
/**
* @param outPattern only set if success is returned; points to referenced open file, so it does
* not need to be free'd/deleted.
*/
FhgfsOpsErr LookupIntentMsgEx::open(EntryInfo* entryInfo, std::string* outFileHandleID,
StripePattern** outPattern, PathInfo* outPathInfo, bool isSecondary)
{
App* app = Program::getApp();
SessionStore* sessions = entryInfo->getIsBuddyMirrored()
? app->getMirroredSessions()
: app->getSessions();
MetaFileHandle inode;
bool useQuota = isMsgHeaderFeatureFlagSet(LOOKUPINTENTMSG_FLAG_USE_QUOTA);
FhgfsOpsErr openRes = MsgHelperOpen::openFile(
entryInfo, getAccessFlags(), useQuota, /* bypassFileAccessCheck */ false,
getMsgHeaderUserID(), inode, isSecondary);
if (openRes == FhgfsOpsErr_SUCCESS && shouldFixTimestamps())
fixInodeTimestamp(*inode, fileTimestamps, entryInfo);
if(openRes != FhgfsOpsErr_SUCCESS)
return openRes; // error occurred
// open successful => insert session
SessionFile* sessionFile = new SessionFile(std::move(inode), getAccessFlags(), entryInfo);
Session* session = sessions->referenceSession(getSessionID(), true);
*outPattern = sessionFile->getInode()->getStripePattern();
sessionFile->getInode()->getPathInfo(outPathInfo);
unsigned sessionFileID;
if (!hasFlag(NetMessageHeader::Flag_BuddyMirrorSecond))
{
sessionFileID = session->getFiles()->addSession(sessionFile);
newOwnerFD = sessionFileID;
}
else
{
sessionFileID = newOwnerFD;
bool addRes = session->getFiles()->addSession(sessionFile, sessionFileID);
if (!addRes)
LOG(GENERAL, NOTICE, "Couldn't add sessionFile on secondary",
("sessionID", this->getSessionID()), sessionFileID);
}
sessions->releaseSession(session);
*outFileHandleID = SessionTk::generateFileHandleID(sessionFileID, entryInfo->getEntryID() );
return openRes;
}
/**
* Decide which type of client stats op counter we increase for this msg (based on given msg flags).
*/
MetaOpCounterTypes LookupIntentMsgEx::getOpCounterType()
{
/* note: as introducting a speparate opCounter type for each flag would have been too much,
we assign prioritiess here as follows: create > open > revalidate > stat > simple_no_flags */
/* NOTE: Those if's are rather slow, maybe we should create a table that has the values?
* Problem is that the table has to be filled for flag combinations, which is also ugly
*/
if(this->getIntentFlags() & LOOKUPINTENTMSG_FLAG_CREATE)
return MetaOpCounter_LOOKUPINTENT_CREATE;
if(this->getIntentFlags() & LOOKUPINTENTMSG_FLAG_OPEN)
return MetaOpCounter_LOOKUPINTENT_OPEN;
if(this->getIntentFlags() & LOOKUPINTENTMSG_FLAG_REVALIDATE)
return MetaOpCounter_LOOKUPINTENT_REVALIDATE;
if(this->getIntentFlags() & LOOKUPINTENTMSG_FLAG_STAT)
return MetaOpCounter_LOOKUPINTENT_STAT;
return MetaOpCounter_LOOKUPINTENT_SIMPLE;
}
void LookupIntentMsgEx::forwardToSecondary(ResponseContext& ctx)
{
addBuddyInfo(entryID, inodeData.getStripePattern());
sendToSecondary(ctx, *this, NETMSGTYPE_LookupIntentResp);
}

View File

@@ -0,0 +1,222 @@
#pragma once
#include <common/net/message/storage/lookup/LookupIntentMsg.h>
#include <common/net/message/storage/lookup/LookupIntentRespMsg.h>
#include <common/nodes/OpCounterTypes.h>
#include <common/storage/StorageDefinitions.h>
#include <common/storage/StorageErrors.h>
#include <common/toolkit/MetadataTk.h>
#include <common/Common.h>
#include <storage/MetaStore.h>
#include <net/message/MirroredMessage.h>
class LookupIntentResponseState : public MirroredMessageResponseState
{
public:
LookupIntentResponseState() :
responseFlags(0), lookupResult(FhgfsOpsErr_INTERNAL), statResult(FhgfsOpsErr_INTERNAL),
revalidateResult(FhgfsOpsErr_INTERNAL), createResult(FhgfsOpsErr_INTERNAL),
openResult(FhgfsOpsErr_INTERNAL)
{}
explicit LookupIntentResponseState(Deserializer& des)
{
serialize(this, des);
}
LookupIntentResponseState(LookupIntentResponseState&& other) :
responseFlags(other.responseFlags),
lookupResult(other.lookupResult),
statResult(other.statResult),
statData(other.statData),
revalidateResult(other.revalidateResult),
createResult(other.createResult),
openResult(other.openResult),
fileHandleID(std::move(other.fileHandleID)),
entryInfo(std::move(other.entryInfo)),
pattern(std::move(other.pattern)),
pathInfo(std::move(other.pathInfo))
{}
void sendResponse(NetMessage::ResponseContext& ctx) override
{
LookupIntentRespMsg resp(lookupResult);
if (responseFlags & LOOKUPINTENTRESPMSG_FLAG_STAT)
resp.addResponseStat(statResult, &statData);
if (responseFlags & LOOKUPINTENTRESPMSG_FLAG_REVALIDATE)
resp.addResponseRevalidate(revalidateResult);
if (responseFlags & LOOKUPINTENTRESPMSG_FLAG_CREATE)
resp.addResponseCreate(createResult);
if (responseFlags & LOOKUPINTENTRESPMSG_FLAG_OPEN)
resp.addResponseOpen(openResult, fileHandleID, pattern.get(), &pathInfo);
resp.setEntryInfo(&entryInfo);
ctx.sendResponse(resp);
}
bool changesObservableState() const override
{
if ((responseFlags & LOOKUPINTENTRESPMSG_FLAG_CREATE)
&& createResult == FhgfsOpsErr_SUCCESS)
return true;
if ((responseFlags & LOOKUPINTENTRESPMSG_FLAG_OPEN) && openResult == FhgfsOpsErr_SUCCESS)
return true;
return false;
}
protected:
uint32_t serializerTag() const override { return NETMSGTYPE_LookupIntent; }
template<typename This, typename Ctx>
static void serialize(This* obj, Ctx& ctx)
{
ctx
% obj->responseFlags
% serdes::as<int32_t>(obj->lookupResult);
if (obj->responseFlags & LOOKUPINTENTRESPMSG_FLAG_STAT)
ctx
% obj->statData.serializeAs(StatDataFormat_NET)
% serdes::as<int32_t>(obj->statResult);
ctx
% serdes::as<int32_t>(obj->revalidateResult)
% serdes::as<int32_t>(obj->createResult);
if (obj->responseFlags & LOOKUPINTENTRESPMSG_FLAG_OPEN)
ctx
% serdes::as<int32_t>(obj->openResult)
% obj->fileHandleID
% obj->entryInfo
% obj->pattern
% obj->pathInfo;
}
void serializeContents(Serializer& ser) const override
{
serialize(this, ser);
}
private:
int32_t responseFlags;
FhgfsOpsErr lookupResult;
FhgfsOpsErr statResult;
StatData statData;
FhgfsOpsErr revalidateResult;
FhgfsOpsErr createResult;
FhgfsOpsErr openResult;
std::string fileHandleID;
EntryInfo entryInfo;
std::unique_ptr<StripePattern> pattern;
PathInfo pathInfo;
public:
void setLookupResult(FhgfsOpsErr lookupRes) { lookupResult = lookupRes; }
void addResponseRevalidate(FhgfsOpsErr revalidateResult)
{
responseFlags |= LOOKUPINTENTRESPMSG_FLAG_REVALIDATE;
this->revalidateResult = revalidateResult;
}
void addResponseCreate(FhgfsOpsErr createResult)
{
responseFlags |= LOOKUPINTENTRESPMSG_FLAG_CREATE;
this->createResult = createResult;
}
void addResponseOpen(FhgfsOpsErr openResult, std::string fileHandleID,
std::unique_ptr<StripePattern> pattern, const PathInfo& pathInfo)
{
responseFlags |= LOOKUPINTENTRESPMSG_FLAG_OPEN;
this->openResult = openResult;
this->fileHandleID = std::move(fileHandleID);
this->pattern = std::move(pattern);
this->pathInfo = pathInfo;
}
void addResponseStat(FhgfsOpsErr statResult, const StatData& statData)
{
responseFlags |= LOOKUPINTENTRESPMSG_FLAG_STAT;
this->statResult = statResult;
this->statData = statData;
}
void setEntryInfo(EntryInfo value) { entryInfo = std::move(value); }
};
/**
* This combines the normal lookup of a directory entry with intents, i.e. options to create,
* open and stat the entry in a single message.
*
* Note: The intent options currently work only for files.
*/
class LookupIntentMsgEx : public MirroredMessage<LookupIntentMsg,
std::tuple<FileIDLock, ParentNameLock, FileIDLock>>
{
public:
typedef LookupIntentResponseState ResponseState;
virtual bool processIncoming(ResponseContext& ctx) override;
std::tuple<FileIDLock, ParentNameLock, FileIDLock> lock(EntryLockStore& store) override;
bool isMirrored() override { return getParentInfo()->getIsBuddyMirrored(); }
const char* mirrorLogContext() const override { return "LookupIntentMsgEx/forward"; }
std::unique_ptr<MirroredMessageResponseState> executeLocally(ResponseContext& ctx,
bool isSecondary) override;
FhgfsOpsErr processSecondaryResponse(NetMessage& resp) override
{
auto& respMsg = static_cast<LookupIntentRespMsg&>(resp);
// since we only forward for open and create, we need only check those two.
if ((respMsg.getResponseFlags() & LOOKUPINTENTRESPMSG_FLAG_CREATE)
&& respMsg.getCreateResult() != FhgfsOpsErr_SUCCESS)
return respMsg.getCreateResult();
if ((respMsg.getResponseFlags() & LOOKUPINTENTRESPMSG_FLAG_OPEN)
&& respMsg.getOpenResult() != FhgfsOpsErr_SUCCESS)
return respMsg.getOpenResult();
return FhgfsOpsErr_SUCCESS;
}
private:
FhgfsOpsErr lookup(const std::string& parentEntryID, const std::string& entryName,
bool isBuddyMirrored, EntryInfo* outEntryInfo, FileInodeStoreData* outInodeStoreData,
bool& outInodeDataOutdated);
FhgfsOpsErr revalidate(EntryInfo* diskEntryInfo, uint32_t metaVersion);
FhgfsOpsErr create(EntryInfo* parentInfo, const std::string& entryName,
EntryInfo* outEntryInfo, FileInodeStoreData* outInodeData, bool isSecondary);
FhgfsOpsErr stat(EntryInfo* entryInfo, bool loadFromDisk, StatData& outStatData);
FhgfsOpsErr open(EntryInfo* entryInfo, std::string* outFileHandleID,
StripePattern** outPattern, PathInfo* outPathInfo, bool isSecondary);
void forwardToSecondary(ResponseContext& ctx) override;
MetaOpCounterTypes getOpCounterType();
FileInodeStoreData inodeData;
std::string entryID;
FhgfsOpsErr lookupRes;
bool inodeDataOutdated;
EntryInfo diskEntryInfo;
};