New upstream version 8.1.0
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
11
meta/source/net/message/storage/lookup/FindLinkOwnerMsgEx.h
Normal file
11
meta/source/net/message/storage/lookup/FindLinkOwnerMsgEx.h
Normal 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);
|
||||
};
|
||||
|
||||
120
meta/source/net/message/storage/lookup/FindOwnerMsgEx.cpp
Normal file
120
meta/source/net/message/storage/lookup/FindOwnerMsgEx.cpp
Normal 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;
|
||||
}
|
||||
22
meta/source/net/message/storage/lookup/FindOwnerMsgEx.h
Normal file
22
meta/source/net/message/storage/lookup/FindOwnerMsgEx.h
Normal 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);
|
||||
|
||||
};
|
||||
|
||||
|
||||
550
meta/source/net/message/storage/lookup/LookupIntentMsgEx.cpp
Normal file
550
meta/source/net/message/storage/lookup/LookupIntentMsgEx.cpp
Normal 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);
|
||||
}
|
||||
222
meta/source/net/message/storage/lookup/LookupIntentMsgEx.h
Normal file
222
meta/source/net/message/storage/lookup/LookupIntentMsgEx.h
Normal 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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user