New upstream version 8.1.0
This commit is contained in:
38
meta/source/net/message/session/AckNotifyMsgEx.h
Normal file
38
meta/source/net/message/session/AckNotifyMsgEx.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/net/message/session/AckNotifyMsg.h>
|
||||
#include <common/net/message/session/AckNotifyRespMsg.h>
|
||||
#include <net/message/MirroredMessage.h>
|
||||
#include <session/MirrorMessageResponseState.h>
|
||||
|
||||
class AckNotifiyMsgEx : public MirroredMessage<AckNotifiyMsg, std::tuple<>>
|
||||
{
|
||||
public:
|
||||
typedef ErrorCodeResponseState<
|
||||
AckNotifiyRespMsg,
|
||||
NETMSGTYPE_AckNotify> ResponseState;
|
||||
|
||||
std::unique_ptr<MirroredMessageResponseState> executeLocally(ResponseContext&, bool) override
|
||||
{
|
||||
// do nothing at all. MirroredMessage has taken care of everything
|
||||
return boost::make_unique<ResponseState>(FhgfsOpsErr_SUCCESS);
|
||||
}
|
||||
|
||||
std::tuple<> lock(EntryLockStore&) override { return {}; }
|
||||
|
||||
bool isMirrored() override { return true; }
|
||||
|
||||
private:
|
||||
void forwardToSecondary(ResponseContext& ctx) override
|
||||
{
|
||||
sendToSecondary(ctx, *this, NETMSGTYPE_AckNotifyResp);
|
||||
}
|
||||
|
||||
FhgfsOpsErr processSecondaryResponse(NetMessage& resp) override
|
||||
{
|
||||
return static_cast<AckNotifiyRespMsg&>(resp).getResult();
|
||||
}
|
||||
|
||||
const char* mirrorLogContext() const override { return "AckNotifiyMsgEx/forward"; }
|
||||
};
|
||||
|
||||
62
meta/source/net/message/session/BumpFileVersionMsgEx.cpp
Normal file
62
meta/source/net/message/session/BumpFileVersionMsgEx.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
#include "BumpFileVersionMsgEx.h"
|
||||
|
||||
#include <components/FileEventLogger.h>
|
||||
#include <program/Program.h>
|
||||
|
||||
bool BumpFileVersionMsgEx::processIncoming(ResponseContext& ctx)
|
||||
{
|
||||
LOG_DBG(SESSIONS, DEBUG, "", getEntryInfo().getEntryID(), getEntryInfo().getIsBuddyMirrored(),
|
||||
hasFlag(NetMessageHeader::Flag_BuddyMirrorSecond),
|
||||
isMsgHeaderFeatureFlagSet(BUMPFILEVERSIONMSG_FLAG_PERSISTENT),
|
||||
isMsgHeaderFeatureFlagSet(BUMPFILEVERSIONMSG_FLAG_HASEVENT));
|
||||
if (isMsgHeaderFeatureFlagSet(BUMPFILEVERSIONMSG_FLAG_HASEVENT))
|
||||
LOG_DBG(SESSIONS, DEBUG, "", int(getFileEvent()->type), getFileEvent()->path);
|
||||
|
||||
return BaseType::processIncoming(ctx);
|
||||
}
|
||||
|
||||
FileIDLock BumpFileVersionMsgEx::lock(EntryLockStore& store)
|
||||
{
|
||||
return {&store, getEntryInfo().getEntryID(), true};
|
||||
}
|
||||
|
||||
std::unique_ptr<MirroredMessageResponseState> BumpFileVersionMsgEx::executeLocally(
|
||||
ResponseContext& ctx, bool isSecondary)
|
||||
{
|
||||
auto* app = Program::getApp();
|
||||
auto* metaStore = app->getMetaStore();
|
||||
|
||||
auto [inode, referenceRes] = metaStore->referenceFile(&getEntryInfo());
|
||||
if (!inode)
|
||||
return boost::make_unique<ResponseState>(FhgfsOpsErr_INTERNAL);
|
||||
|
||||
if (isMsgHeaderFeatureFlagSet(BUMPFILEVERSIONMSG_FLAG_PERSISTENT) &&
|
||||
!inode->incrementFileVersion(&getEntryInfo()))
|
||||
{
|
||||
metaStore->releaseFile(getEntryInfo().getParentEntryID(), inode);
|
||||
return boost::make_unique<ResponseState>(FhgfsOpsErr_SAVEERROR);
|
||||
}
|
||||
|
||||
if (!isSecondary && app->getFileEventLogger() && getFileEvent())
|
||||
{
|
||||
EventContext eventCtx = makeEventContext(
|
||||
&getEntryInfo(),
|
||||
getEntryInfo().getParentEntryID(),
|
||||
getMsgHeaderUserID(),
|
||||
"",
|
||||
inode->getNumHardlinks(),
|
||||
isSecondary
|
||||
);
|
||||
|
||||
logEvent(app->getFileEventLogger(), *getFileEvent(), eventCtx);
|
||||
}
|
||||
|
||||
metaStore->releaseFile(getEntryInfo().getParentEntryID(), inode);
|
||||
return boost::make_unique<ResponseState>(FhgfsOpsErr_SUCCESS);
|
||||
}
|
||||
|
||||
void BumpFileVersionMsgEx::forwardToSecondary(ResponseContext& ctx)
|
||||
{
|
||||
unsetMsgHeaderFeatureFlag(BUMPFILEVERSIONMSG_FLAG_HASEVENT);
|
||||
sendToSecondary(ctx, *this, NETMSGTYPE_BumpFileVersionResp);
|
||||
}
|
||||
32
meta/source/net/message/session/BumpFileVersionMsgEx.h
Normal file
32
meta/source/net/message/session/BumpFileVersionMsgEx.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/net/message/session/BumpFileVersionMsg.h>
|
||||
#include <common/net/message/session/BumpFileVersionRespMsg.h>
|
||||
#include <net/message/MirroredMessage.h>
|
||||
|
||||
class BumpFileVersionMsgEx : public MirroredMessage<BumpFileVersionMsg, FileIDLock>
|
||||
{
|
||||
public:
|
||||
typedef ErrorCodeResponseState<BumpFileVersionRespMsg, NETMSGTYPE_BumpFileVersion>
|
||||
ResponseState;
|
||||
|
||||
virtual bool processIncoming(ResponseContext& ctx) override;
|
||||
|
||||
std::unique_ptr<MirroredMessageResponseState> executeLocally(ResponseContext& ctx,
|
||||
bool isSecondary) override;
|
||||
|
||||
FileIDLock lock(EntryLockStore& store) override;
|
||||
|
||||
bool isMirrored() override { return getEntryInfo().getIsBuddyMirrored(); }
|
||||
|
||||
private:
|
||||
void forwardToSecondary(ResponseContext& ctx) override;
|
||||
|
||||
FhgfsOpsErr processSecondaryResponse(NetMessage& resp) override
|
||||
{
|
||||
return (FhgfsOpsErr) static_cast<BumpFileVersionRespMsg&>(resp).getValue();
|
||||
}
|
||||
|
||||
const char* mirrorLogContext() const override { return "BumpFileVersionMsgEx/forward"; }
|
||||
};
|
||||
|
||||
35
meta/source/net/message/session/GetFileVersionMsgEx.cpp
Normal file
35
meta/source/net/message/session/GetFileVersionMsgEx.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#include "GetFileVersionMsgEx.h"
|
||||
#include <program/Program.h>
|
||||
|
||||
bool GetFileVersionMsgEx::processIncoming(ResponseContext& ctx)
|
||||
{
|
||||
LOG_DBG(SESSIONS, DEBUG, "", getEntryInfo().getEntryID(), getEntryInfo().getIsBuddyMirrored());
|
||||
return BaseType::processIncoming(ctx);
|
||||
}
|
||||
|
||||
FileIDLock GetFileVersionMsgEx::lock(EntryLockStore& store)
|
||||
{
|
||||
return {&store, getEntryInfo().getEntryID(), false};
|
||||
}
|
||||
|
||||
std::unique_ptr<MirroredMessageResponseState> GetFileVersionMsgEx::executeLocally(ResponseContext& ctx,
|
||||
bool isSecondary)
|
||||
{
|
||||
GetFileVersionMsgResponseState resp;
|
||||
|
||||
auto& metaStore = *Program::getApp()->getMetaStore();
|
||||
auto [inode, referenceRes] = metaStore.referenceFile(&getEntryInfo());
|
||||
if (!inode)
|
||||
{
|
||||
// The GetFileVersionMsgResponseState constructor sets default values for 'result' and
|
||||
// 'version', indicating an error condition, eliminating the need to specify them
|
||||
// separately. Hence, returning a ResponseState with the moved 'resp'.
|
||||
return boost::make_unique<ResponseState>(std::move(resp));
|
||||
}
|
||||
|
||||
resp.setGetFileVersionResult(FhgfsOpsErr_SUCCESS);
|
||||
resp.setFileVersion(inode->getFileVersion());
|
||||
metaStore.releaseFile(getEntryInfo().getParentEntryID(), inode);
|
||||
|
||||
return boost::make_unique<ResponseState>(std::move(resp));
|
||||
}
|
||||
74
meta/source/net/message/session/GetFileVersionMsgEx.h
Normal file
74
meta/source/net/message/session/GetFileVersionMsgEx.h
Normal file
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/net/message/session/GetFileVersionMsg.h>
|
||||
#include <common/net/message/session/GetFileVersionRespMsg.h>
|
||||
#include <common/net/message/session/GetFileVersionRespMsg.h>
|
||||
#include <net/message/MirroredMessage.h>
|
||||
|
||||
class GetFileVersionMsgResponseState : public MirroredMessageResponseState
|
||||
{
|
||||
public:
|
||||
GetFileVersionMsgResponseState() : result(FhgfsOpsErr_INTERNAL), version(0)
|
||||
{
|
||||
}
|
||||
|
||||
GetFileVersionMsgResponseState(GetFileVersionMsgResponseState&& other) :
|
||||
result(other.result),
|
||||
version(other.version)
|
||||
{
|
||||
}
|
||||
|
||||
void sendResponse(NetMessage::ResponseContext& ctx) override
|
||||
{
|
||||
GetFileVersionRespMsg resp(result, version);
|
||||
ctx.sendResponse(resp);
|
||||
}
|
||||
|
||||
// GetFileVersionMsgEx is transformed into a mirrored message to leverage
|
||||
// MirroredMessage::lock(), preventing races with operations such as unlink.
|
||||
// However, forwarding this message to the secondary is unnecessary.
|
||||
// Overriding the changeObservableState() function to always return false ensures
|
||||
// that this message is never forwarded unnecessarily.
|
||||
bool changesObservableState() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void setGetFileVersionResult(FhgfsOpsErr result) { this->result = result; }
|
||||
void setFileVersion(uint32_t version) { this->version = version; }
|
||||
|
||||
protected:
|
||||
uint32_t serializerTag() const override { return NETMSGTYPE_GetFileVersion; }
|
||||
void serializeContents(Serializer& ser) const override {}
|
||||
|
||||
private:
|
||||
FhgfsOpsErr result;
|
||||
uint32_t version;
|
||||
};
|
||||
|
||||
class GetFileVersionMsgEx : public MirroredMessage<GetFileVersionMsg, FileIDLock>
|
||||
{
|
||||
public:
|
||||
typedef GetFileVersionMsgResponseState ResponseState;
|
||||
virtual bool processIncoming(ResponseContext& ctx) override;
|
||||
|
||||
FileIDLock lock(EntryLockStore& store) override;
|
||||
bool isMirrored() override
|
||||
{
|
||||
return getEntryInfo().getIsBuddyMirrored();
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
std::unique_ptr<MirroredMessageResponseState> executeLocally(ResponseContext& ctx,
|
||||
bool isSecondary) override;
|
||||
|
||||
void forwardToSecondary(ResponseContext& ctx) override {}
|
||||
FhgfsOpsErr processSecondaryResponse(NetMessage& resp) override
|
||||
{
|
||||
return FhgfsOpsErr_SUCCESS;
|
||||
}
|
||||
|
||||
const char* mirrorLogContext() const override { return "GetFileVersionMsgEx/forward"; }
|
||||
};
|
||||
|
||||
57
meta/source/net/message/session/locking/FLockAppendMsgEx.cpp
Normal file
57
meta/source/net/message/session/locking/FLockAppendMsgEx.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#include <common/net/message/session/locking/FLockAppendRespMsg.h>
|
||||
#include <common/toolkit/MessagingTk.h>
|
||||
#include <common/toolkit/SessionTk.h>
|
||||
#include <net/msghelpers/MsgHelperLocking.h>
|
||||
#include <program/Program.h>
|
||||
#include <session/SessionStore.h>
|
||||
#include <storage/MetaStore.h>
|
||||
#include "FLockAppendMsgEx.h"
|
||||
|
||||
|
||||
bool FLockAppendMsgEx::processIncoming(ResponseContext& ctx)
|
||||
{
|
||||
/* note: this code is very similar to FLockRangeMsgEx::processIncoming(), so if you change
|
||||
something here, you probably want to change it there, too. */
|
||||
|
||||
#ifdef BEEGFS_DEBUG
|
||||
const char* logContext = "FLockAppendMsg incoming";
|
||||
#endif // BEEGFS_DEBUG
|
||||
|
||||
LOG_DEBUG(logContext, Log_DEBUG, "entryID: " + this->getEntryInfo()->getEntryID());
|
||||
|
||||
clientResult = FhgfsOpsErr_INTERNAL;
|
||||
return BaseType::processIncoming(ctx);
|
||||
}
|
||||
|
||||
FileIDLock FLockAppendMsgEx::lock(EntryLockStore& store)
|
||||
{
|
||||
return {&store, getEntryInfo()->getEntryID(), true};
|
||||
}
|
||||
|
||||
std::unique_ptr<MirroredMessageResponseState> FLockAppendMsgEx::executeLocally(ResponseContext& ctx,
|
||||
bool isSecondary)
|
||||
{
|
||||
const char* logContext = "FLock Append Msg";
|
||||
|
||||
unsigned ownerFD = SessionTk::ownerFDFromHandleID(getFileHandleID() );
|
||||
|
||||
EntryLockDetails lockDetails(getClientNumID(), getClientFD(), getOwnerPID(), getLockAckID(),
|
||||
getLockTypeFlags() );
|
||||
|
||||
LogContext(logContext).log(Log_DEBUG, lockDetails.toString());
|
||||
|
||||
EntryInfo* entryInfo = getEntryInfo();
|
||||
clientResult = MsgHelperLocking::flockAppend(entryInfo, ownerFD, lockDetails);
|
||||
|
||||
LogContext(logContext).log(Log_DEBUG, "FLock Append result: " + std::to_string(clientResult));
|
||||
|
||||
Program::getApp()->getNodeOpStats()->updateNodeOp(ctx.getSocket()->getPeerIP(),
|
||||
MetaOpCounter_FLOCKAPPEND, getMsgHeaderUserID() );
|
||||
|
||||
return boost::make_unique<ResponseState>(clientResult);
|
||||
}
|
||||
|
||||
void FLockAppendMsgEx::forwardToSecondary(ResponseContext& ctx)
|
||||
{
|
||||
sendToSecondary(ctx, *this, NETMSGTYPE_FLockAppendResp, clientResult);
|
||||
}
|
||||
32
meta/source/net/message/session/locking/FLockAppendMsgEx.h
Normal file
32
meta/source/net/message/session/locking/FLockAppendMsgEx.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/net/message/session/locking/FLockAppendMsg.h>
|
||||
#include <common/net/message/session/locking/FLockAppendRespMsg.h>
|
||||
#include <net/message/MirroredMessage.h>
|
||||
#include <common/storage/StorageErrors.h>
|
||||
#include <storage/FileInode.h>
|
||||
|
||||
class FLockAppendMsgEx : public MirroredMessage<FLockAppendMsg, FileIDLock>
|
||||
{
|
||||
public:
|
||||
typedef ErrorCodeResponseState<FLockAppendRespMsg, NETMSGTYPE_FLockAppend> ResponseState;
|
||||
virtual bool processIncoming(ResponseContext& ctx) override;
|
||||
|
||||
std::unique_ptr<MirroredMessageResponseState> executeLocally(ResponseContext& ctx,
|
||||
bool isSecondary) override;
|
||||
|
||||
FileIDLock lock(EntryLockStore& store) override;
|
||||
bool isMirrored() override { return getEntryInfo()->getIsBuddyMirrored(); }
|
||||
|
||||
private:
|
||||
FhgfsOpsErr clientResult;
|
||||
|
||||
void forwardToSecondary(ResponseContext& ctx) override;
|
||||
FhgfsOpsErr processSecondaryResponse(NetMessage& resp) override
|
||||
{
|
||||
return static_cast<FLockAppendRespMsg&>(resp).getResult();
|
||||
}
|
||||
|
||||
const char* mirrorLogContext() const override { return "FLockAppendMsgEx/forward"; }
|
||||
};
|
||||
|
||||
135
meta/source/net/message/session/locking/FLockEntryMsgEx.cpp
Normal file
135
meta/source/net/message/session/locking/FLockEntryMsgEx.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
#include <common/net/message/session/locking/FLockEntryRespMsg.h>
|
||||
#include <common/toolkit/MessagingTk.h>
|
||||
#include <common/toolkit/SessionTk.h>
|
||||
#include <net/msghelpers/MsgHelperLocking.h>
|
||||
#include <program/Program.h>
|
||||
#include <session/SessionStore.h>
|
||||
#include <storage/MetaStore.h>
|
||||
#include "FLockEntryMsgEx.h"
|
||||
|
||||
|
||||
bool FLockEntryMsgEx::processIncoming(ResponseContext& ctx)
|
||||
{
|
||||
/* note: this code is very similar to FLockRangeMsgEx::processIncoming(), so if you change
|
||||
something here, you probably want to change it there, too. */
|
||||
|
||||
clientResult = FhgfsOpsErr_INTERNAL;
|
||||
|
||||
updateNodeOp(ctx, MetaOpCounter_FLOCKENTRY);
|
||||
|
||||
return BaseType::processIncoming(ctx);
|
||||
}
|
||||
|
||||
FileIDLock FLockEntryMsgEx::lock(EntryLockStore& store)
|
||||
{
|
||||
return {&store, getEntryInfo()->getEntryID(), true};
|
||||
}
|
||||
|
||||
std::unique_ptr<MirroredMessageResponseState> FLockEntryMsgEx::executeLocally(ResponseContext& ctx,
|
||||
bool isSecondary)
|
||||
{
|
||||
App* app = Program::getApp();
|
||||
MetaStore* metaStore = app->getMetaStore();
|
||||
|
||||
unsigned ownerFD = SessionTk::ownerFDFromHandleID(getFileHandleID() );
|
||||
|
||||
EntryLockDetails lockDetails(getClientNumID(), getClientFD(), getOwnerPID(), getLockAckID(),
|
||||
getLockTypeFlags() );
|
||||
|
||||
LOG_DBG(GENERAL, SPAM, lockDetails.toString());
|
||||
|
||||
EntryInfo* entryInfo = getEntryInfo();
|
||||
|
||||
SessionStore* sessions = entryInfo->getIsBuddyMirrored()
|
||||
? app->getMirroredSessions()
|
||||
: app->getSessions();
|
||||
|
||||
// find sessionFile
|
||||
Session* session = sessions->referenceSession(getClientNumID(), true);
|
||||
SessionFileStore* sessionFiles = session->getFiles();
|
||||
|
||||
SessionFile* sessionFile = sessionFiles->referenceSession(ownerFD);
|
||||
if(!sessionFile)
|
||||
{ // sessionFile not exists (mds restarted?)
|
||||
|
||||
// check if this is just an UNLOCK REQUEST
|
||||
|
||||
if(getLockTypeFlags() & ENTRYLOCKTYPE_UNLOCK)
|
||||
{ // it's an unlock => we'll just ignore it (since the locks are gone anyways)
|
||||
clientResult = FhgfsOpsErr_SUCCESS;
|
||||
|
||||
goto cleanup_session;
|
||||
}
|
||||
|
||||
// check if this is a LOCK CANCEL REQUEST
|
||||
|
||||
if(getLockTypeFlags() & ENTRYLOCKTYPE_CANCEL)
|
||||
{ // it's a lock cancel
|
||||
/* this is an important special case, because client might have succeeded in closing the
|
||||
file but the conn might have been interrupted during unlock, so we definitely have to try
|
||||
canceling the lock here */
|
||||
|
||||
// if the file still exists, just do the lock cancel without session recovery attempt
|
||||
|
||||
auto [lockCancelFile, referenceRes] = metaStore->referenceFile(entryInfo);
|
||||
if(lockCancelFile)
|
||||
{
|
||||
lockCancelFile->flockEntry(lockDetails);
|
||||
metaStore->releaseFile(entryInfo->getParentEntryID(), lockCancelFile);
|
||||
}
|
||||
|
||||
clientResult = FhgfsOpsErr_SUCCESS;
|
||||
|
||||
goto cleanup_session;
|
||||
}
|
||||
|
||||
// it's a LOCK REQUEST => try to recover session file to do the locking
|
||||
|
||||
clientResult = MsgHelperLocking::trySesssionRecovery(entryInfo, getClientNumID(),
|
||||
ownerFD, sessionFiles, &sessionFile);
|
||||
|
||||
// (note: sessionFile==NULL now if recovery was not successful)
|
||||
|
||||
} // end of session file session recovery attempt
|
||||
|
||||
if(sessionFile)
|
||||
{ // sessionFile exists (or was successfully recovered)
|
||||
auto& file = sessionFile->getInode();
|
||||
|
||||
auto lockGranted = file->flockEntry(lockDetails);
|
||||
if (!lockGranted.first)
|
||||
clientResult = FhgfsOpsErr_WOULDBLOCK;
|
||||
else
|
||||
clientResult = FhgfsOpsErr_SUCCESS;
|
||||
|
||||
if ((getLockTypeFlags() & ENTRYLOCKTYPE_UNLOCK) && !file->incrementFileVersion(entryInfo))
|
||||
{
|
||||
LOG(GENERAL, ERR, "Could not bump file version.", file->getEntryID());
|
||||
sessionFiles->releaseSession(sessionFile, entryInfo);
|
||||
clientResult = FhgfsOpsErr_INTERNAL;
|
||||
goto cleanup_session;
|
||||
}
|
||||
|
||||
if (!lockGranted.second.empty() && !isSecondary)
|
||||
LockingNotifier::notifyWaitersEntryLock(LockEntryNotifyType_FLOCK,
|
||||
file->getReferenceParentID(), file->getEntryID(), file->getIsBuddyMirrored(),
|
||||
std::move(lockGranted.second));
|
||||
|
||||
// cleanup
|
||||
sessionFiles->releaseSession(sessionFile, entryInfo);
|
||||
}
|
||||
|
||||
|
||||
// cleanup
|
||||
cleanup_session:
|
||||
sessions->releaseSession(session);
|
||||
|
||||
LOG_DBG(GENERAL, SPAM, "", getClientNumID(), clientResult);
|
||||
|
||||
return boost::make_unique<ResponseState>(clientResult);
|
||||
}
|
||||
|
||||
void FLockEntryMsgEx::forwardToSecondary(ResponseContext& ctx)
|
||||
{
|
||||
sendToSecondary(ctx, *this, NETMSGTYPE_FLockEntryResp, clientResult);
|
||||
}
|
||||
36
meta/source/net/message/session/locking/FLockEntryMsgEx.h
Normal file
36
meta/source/net/message/session/locking/FLockEntryMsgEx.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/net/message/session/locking/FLockEntryMsg.h>
|
||||
#include <common/net/message/session/locking/FLockEntryRespMsg.h>
|
||||
#include <common/storage/StorageErrors.h>
|
||||
#include <net/message/MirroredMessage.h>
|
||||
#include <storage/FileInode.h>
|
||||
|
||||
|
||||
class FLockEntryMsgEx : public MirroredMessage<FLockEntryMsg, FileIDLock>
|
||||
{
|
||||
public:
|
||||
typedef ErrorCodeResponseState<FLockEntryRespMsg, NETMSGTYPE_FLockEntry> ResponseState;
|
||||
|
||||
virtual bool processIncoming(ResponseContext& ctx) override;
|
||||
|
||||
std::unique_ptr<MirroredMessageResponseState> executeLocally(ResponseContext& ctx,
|
||||
bool isSecondary) override;
|
||||
|
||||
FileIDLock lock(EntryLockStore& store) override;
|
||||
|
||||
bool isMirrored() override { return getEntryInfo()->getIsBuddyMirrored(); }
|
||||
|
||||
private:
|
||||
FhgfsOpsErr clientResult;
|
||||
|
||||
void forwardToSecondary(ResponseContext& ctx) override;
|
||||
|
||||
FhgfsOpsErr processSecondaryResponse(NetMessage& resp) override
|
||||
{
|
||||
return static_cast<FLockEntryRespMsg&>(resp).getResult();
|
||||
}
|
||||
|
||||
const char* mirrorLogContext() const override { return "FLockEntryMsgEx/forward"; }
|
||||
};
|
||||
|
||||
134
meta/source/net/message/session/locking/FLockRangeMsgEx.cpp
Normal file
134
meta/source/net/message/session/locking/FLockRangeMsgEx.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
#include <common/net/message/session/locking/FLockRangeRespMsg.h>
|
||||
#include <common/toolkit/MessagingTk.h>
|
||||
#include <common/toolkit/SessionTk.h>
|
||||
#include <net/msghelpers/MsgHelperLocking.h>
|
||||
#include <program/Program.h>
|
||||
#include <session/SessionStore.h>
|
||||
#include <storage/MetaStore.h>
|
||||
#include "FLockRangeMsgEx.h"
|
||||
|
||||
|
||||
bool FLockRangeMsgEx::processIncoming(ResponseContext& ctx)
|
||||
{
|
||||
/* note: this code is very similar to FLockEntryMsgEx::processIncoming(), so if you change
|
||||
something here, you probably want to change it there, too. */
|
||||
|
||||
clientResult = FhgfsOpsErr_INTERNAL;
|
||||
|
||||
updateNodeOp(ctx, MetaOpCounter_FLOCKRANGE);
|
||||
|
||||
return BaseType::processIncoming(ctx);
|
||||
}
|
||||
|
||||
FileIDLock FLockRangeMsgEx::lock(EntryLockStore& store)
|
||||
{
|
||||
return {&store, getEntryInfo()->getEntryID(), true};
|
||||
}
|
||||
|
||||
std::unique_ptr<MirroredMessageResponseState> FLockRangeMsgEx::executeLocally(ResponseContext& ctx,
|
||||
bool isSecondary)
|
||||
{
|
||||
App* app = Program::getApp();
|
||||
MetaStore* metaStore = app->getMetaStore();
|
||||
|
||||
unsigned ownerFD = SessionTk::ownerFDFromHandleID(getFileHandleID() );
|
||||
|
||||
RangeLockDetails lockDetails(getClientNumID(), getOwnerPID(), getLockAckID(),
|
||||
getLockTypeFlags(), getStart(), getEnd() );
|
||||
|
||||
LOG_DBG(GENERAL, SPAM, lockDetails.toString());
|
||||
|
||||
EntryInfo* entryInfo = getEntryInfo();
|
||||
|
||||
SessionStore* sessions = entryInfo->getIsBuddyMirrored()
|
||||
? app->getMirroredSessions()
|
||||
: app->getSessions();
|
||||
|
||||
// find sessionFile
|
||||
Session* session = sessions->referenceSession(getClientNumID(), true);
|
||||
SessionFileStore* sessionFiles = session->getFiles();
|
||||
|
||||
SessionFile* sessionFile = sessionFiles->referenceSession(ownerFD);
|
||||
if(!sessionFile)
|
||||
{ // sessionFile not exists (mds restarted?)
|
||||
|
||||
// check if this is just an UNLOCK REQUEST
|
||||
|
||||
if(getLockTypeFlags() & ENTRYLOCKTYPE_LOCKOPS_REMOVE)
|
||||
{ // it's an unlock => we'll just ignore it (since the locks are gone anyways)
|
||||
clientResult = FhgfsOpsErr_SUCCESS;
|
||||
|
||||
goto cleanup_session;
|
||||
}
|
||||
|
||||
// check if this is a LOCK CANCEL REQUEST
|
||||
|
||||
if(getLockTypeFlags() & ENTRYLOCKTYPE_CANCEL)
|
||||
{ // it's a lock cancel
|
||||
/* this is an important special case, because client might have succeeded in closing the
|
||||
file but the conn might have been interrupted during unlock, so we definitely have to try
|
||||
canceling the lock here */
|
||||
|
||||
// if the file still exists, just do the lock cancel without session recovery attempt
|
||||
|
||||
auto [lockCancelFile, referenceRes] = metaStore->referenceFile(entryInfo);
|
||||
if(lockCancelFile)
|
||||
{
|
||||
lockCancelFile->flockRange(lockDetails);
|
||||
metaStore->releaseFile(entryInfo->getParentEntryID(), lockCancelFile);
|
||||
}
|
||||
|
||||
clientResult = FhgfsOpsErr_SUCCESS;
|
||||
|
||||
goto cleanup_session;
|
||||
}
|
||||
|
||||
// it's a LOCK REQUEST => try to recover session file to do the locking
|
||||
|
||||
clientResult = MsgHelperLocking::trySesssionRecovery(entryInfo, getClientNumID(),
|
||||
ownerFD, sessionFiles, &sessionFile);
|
||||
|
||||
// (note: sessionFile==NULL now if recovery was not successful)
|
||||
|
||||
} // end of session file session recovery attempt
|
||||
|
||||
if(sessionFile)
|
||||
{ // sessionFile exists (or was successfully recovered)
|
||||
auto& file = sessionFile->getInode();
|
||||
|
||||
auto lockGranted = file->flockRange(lockDetails);
|
||||
if (!lockGranted.first)
|
||||
clientResult = FhgfsOpsErr_WOULDBLOCK;
|
||||
else
|
||||
clientResult = FhgfsOpsErr_SUCCESS;
|
||||
|
||||
if ((getLockTypeFlags() & ENTRYLOCKTYPE_UNLOCK) && !file->incrementFileVersion(entryInfo))
|
||||
{
|
||||
LOG(GENERAL, ERR, "Could not bump file version.", file->getEntryID());
|
||||
sessionFiles->releaseSession(sessionFile, entryInfo);
|
||||
clientResult = FhgfsOpsErr_INTERNAL;
|
||||
goto cleanup_session;
|
||||
}
|
||||
|
||||
if (!lockGranted.second.empty() && !isSecondary)
|
||||
LockingNotifier::notifyWaitersRangeLock(file->getReferenceParentID(), file->getEntryID(),
|
||||
file->getIsBuddyMirrored(), std::move(lockGranted.second));
|
||||
|
||||
// cleanup
|
||||
sessionFiles->releaseSession(sessionFile, entryInfo);
|
||||
}
|
||||
|
||||
|
||||
// cleanup
|
||||
cleanup_session:
|
||||
sessions->releaseSession(session);
|
||||
|
||||
LOG_DBG(GENERAL, SPAM, "", clientResult);
|
||||
|
||||
return boost::make_unique<ResponseState>(clientResult);
|
||||
}
|
||||
|
||||
void FLockRangeMsgEx::forwardToSecondary(ResponseContext& ctx)
|
||||
{
|
||||
sendToSecondary(ctx, *this, NETMSGTYPE_FLockRangeResp, clientResult);
|
||||
}
|
||||
36
meta/source/net/message/session/locking/FLockRangeMsgEx.h
Normal file
36
meta/source/net/message/session/locking/FLockRangeMsgEx.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/net/message/session/locking/FLockRangeMsg.h>
|
||||
#include <common/net/message/session/locking/FLockRangeRespMsg.h>
|
||||
#include <common/storage/StorageErrors.h>
|
||||
#include <net/message/MirroredMessage.h>
|
||||
#include <storage/FileInode.h>
|
||||
|
||||
|
||||
class FLockRangeMsgEx : public MirroredMessage<FLockRangeMsg, FileIDLock>
|
||||
{
|
||||
public:
|
||||
typedef ErrorCodeResponseState<FLockRangeRespMsg, NETMSGTYPE_FLockRange> ResponseState;
|
||||
|
||||
virtual bool processIncoming(ResponseContext& ctx) override;
|
||||
|
||||
std::unique_ptr<MirroredMessageResponseState> executeLocally(ResponseContext& ctx,
|
||||
bool isSecondary) override;
|
||||
|
||||
FileIDLock lock(EntryLockStore& store) override;
|
||||
|
||||
bool isMirrored() override { return getEntryInfo()->getIsBuddyMirrored(); }
|
||||
|
||||
private:
|
||||
FhgfsOpsErr clientResult;
|
||||
|
||||
void forwardToSecondary(ResponseContext& ctx) override;
|
||||
|
||||
FhgfsOpsErr processSecondaryResponse(NetMessage& resp) override
|
||||
{
|
||||
return static_cast<FLockRangeRespMsg&>(resp).getResult();
|
||||
}
|
||||
|
||||
const char* mirrorLogContext() const override { return "FLockRangeMsgEx/forward"; }
|
||||
};
|
||||
|
||||
246
meta/source/net/message/session/opening/CloseFileMsgEx.cpp
Normal file
246
meta/source/net/message/session/opening/CloseFileMsgEx.cpp
Normal file
@@ -0,0 +1,246 @@
|
||||
#include <common/components/streamlistenerv2/IncomingPreprocessedMsgWork.h>
|
||||
#include <common/net/message/control/GenericResponseMsg.h>
|
||||
#include <common/net/message/session/opening/CloseFileRespMsg.h>
|
||||
#include <common/toolkit/MessagingTk.h>
|
||||
#include <common/toolkit/SessionTk.h>
|
||||
#include <components/FileEventLogger.h>
|
||||
#include <net/msghelpers/MsgHelperClose.h>
|
||||
#include <net/msghelpers/MsgHelperLocking.h>
|
||||
#include <program/Program.h>
|
||||
#include <session/EntryLock.h>
|
||||
#include <storage/MetaStore.h>
|
||||
#include "CloseFileMsgEx.h"
|
||||
|
||||
FileIDLock CloseFileMsgEx::lock(EntryLockStore& store)
|
||||
{
|
||||
return {&store, getEntryInfo()->getEntryID(), true};
|
||||
}
|
||||
|
||||
bool CloseFileMsgEx::processIncoming(ResponseContext& ctx)
|
||||
{
|
||||
#ifdef BEEGFS_DEBUG
|
||||
const char* logContext = "CloseFileMsg incoming";
|
||||
#endif // BEEGFS_DEBUG
|
||||
|
||||
LOG_DEBUG(logContext, Log_DEBUG,
|
||||
"BuddyMirrored: " + std::string(getEntryInfo()->getIsBuddyMirrored() ? "Yes" : "No") +
|
||||
" Secondary: " +
|
||||
std::string(hasFlag(NetMessageHeader::Flag_BuddyMirrorSecond) ? "Yes" : "No") );
|
||||
|
||||
// update operation counters (here on top because we have an early sock release in this msg)
|
||||
updateNodeOp(ctx, MetaOpCounter_CLOSE);
|
||||
|
||||
return BaseType::processIncoming(ctx);
|
||||
}
|
||||
|
||||
std::unique_ptr<MirroredMessageResponseState> CloseFileMsgEx::executeLocally(ResponseContext& ctx,
|
||||
bool isSecondary)
|
||||
{
|
||||
if (isSecondary)
|
||||
return closeFileSecondary(ctx);
|
||||
else
|
||||
return closeFilePrimary(ctx);
|
||||
}
|
||||
|
||||
std::unique_ptr<CloseFileMsgEx::ResponseState> CloseFileMsgEx::closeFilePrimary(
|
||||
ResponseContext& ctx)
|
||||
{
|
||||
FhgfsOpsErr closeRes;
|
||||
bool unlinkDisposalFile = false;
|
||||
bool outLastWriterClosed = false;
|
||||
EntryInfo* entryInfo = getEntryInfo();
|
||||
unsigned numHardlinks;
|
||||
bool closeSucceeded;
|
||||
|
||||
if(isMsgHeaderFeatureFlagSet(CLOSEFILEMSG_FLAG_CANCELAPPENDLOCKS) )
|
||||
{ // client requests cleanup of granted or pending locks for this handle
|
||||
|
||||
unsigned ownerFD = SessionTk::ownerFDFromHandleID(getFileHandleID() );
|
||||
EntryLockDetails lockDetails(getClientNumID(), 0, 0, "", ENTRYLOCKTYPE_CANCEL);
|
||||
|
||||
MsgHelperLocking::flockAppend(entryInfo, ownerFD, lockDetails);
|
||||
}
|
||||
|
||||
/* two alternatives:
|
||||
1) early response before chunk file close (if client isn't interested in chunks result).
|
||||
2) normal response after chunk file close. */
|
||||
|
||||
// if we are buddy mirrored, *do not* allow early close responses. since the primary will close
|
||||
// the chunk files (and update the inodes dynamic attributes), the secondary cannot do that.
|
||||
// thus we need to close all chunks, get the dynamic attributes, and push them to the secondary
|
||||
if (getEntryInfo()->getIsBuddyMirrored())
|
||||
unsetMsgHeaderFeatureFlag(CLOSEFILEMSG_FLAG_EARLYRESPONSE);
|
||||
|
||||
if(isMsgHeaderFeatureFlagSet(CLOSEFILEMSG_FLAG_EARLYRESPONSE) )
|
||||
{ // alternative 1: client requests an early response
|
||||
|
||||
/* note: linux won't even return the vfs release() result to userspace apps, so there's
|
||||
usually no point in waiting for the chunk file close result before sending the response */
|
||||
|
||||
unsigned accessFlags;
|
||||
MetaFileHandle inode;
|
||||
|
||||
closeRes = MsgHelperClose::closeSessionFile(
|
||||
getClientNumID(), getFileHandleID(), entryInfo, &accessFlags, inode);
|
||||
closeSucceeded = closeRes == FhgfsOpsErr_SUCCESS;
|
||||
|
||||
// send response
|
||||
earlyComplete(ctx, ResponseState(closeRes));
|
||||
|
||||
// if session file close succeeds but chunk file close fails we should not attempt to
|
||||
// dispose. if chunk close failed for any other reason than network outages we might
|
||||
// put the storage server into an even weirder state by unlinking the chunk file:
|
||||
// the file itself is still open (has a session), but is gone on disk, and thus cannot
|
||||
// be reopened from stored sessions when the server is restarted.
|
||||
if(likely(closeRes == FhgfsOpsErr_SUCCESS) )
|
||||
closeRes = closeFileAfterEarlyResponse(std::move(inode), accessFlags, &unlinkDisposalFile,
|
||||
numHardlinks, outLastWriterClosed);
|
||||
}
|
||||
else
|
||||
{ // alternative 2: normal response (after chunk file close)
|
||||
|
||||
closeRes = MsgHelperClose::closeFile(getClientNumID(), getFileHandleID(),
|
||||
entryInfo, getMaxUsedNodeIndex(), getMsgHeaderUserID(), &unlinkDisposalFile,
|
||||
&numHardlinks, outLastWriterClosed, &dynAttribs, &inodeTimestamps);
|
||||
|
||||
closeSucceeded = closeRes == FhgfsOpsErr_SUCCESS;
|
||||
|
||||
if (getEntryInfo()->getIsBuddyMirrored() && getMaxUsedNodeIndex() >= 0)
|
||||
addMsgHeaderFeatureFlag(CLOSEFILEMSG_FLAG_DYNATTRIBS);
|
||||
|
||||
//Avoid sending early response. Let unlink of Disposal file happens.
|
||||
//with Locks held. But make sure before file gets unlink we synchronise
|
||||
//the operation with any on-going buddy mirror resync operation.
|
||||
ResponseState responseState(closeRes);
|
||||
buddyResyncNotify(ctx, responseState.changesObservableState());
|
||||
}
|
||||
|
||||
if (closeSucceeded && Program::getApp()->getFileEventLogger() && getFileEvent())
|
||||
{
|
||||
// Important Note:
|
||||
// - If the last writer, who previously opened this file with write permissions,
|
||||
// is currently closing it,
|
||||
// - And it is not marked for disposal,
|
||||
// - And it is not due to a symlink creation,
|
||||
// Then we update the event type to LAST_WRITER_CLOSED.
|
||||
bool isSymlinkEvent = getFileEvent()->type == FileEventType::SYMLINK;
|
||||
if (!isSymlinkEvent && outLastWriterClosed && !unlinkDisposalFile)
|
||||
{
|
||||
auto fileEvent = const_cast<FileEvent*>(getFileEvent());
|
||||
fileEvent->type = FileEventType::LAST_WRITER_CLOSED;
|
||||
}
|
||||
|
||||
EventContext eventCtx = makeEventContext(
|
||||
entryInfo,
|
||||
entryInfo->getParentEntryID(),
|
||||
getMsgHeaderUserID(),
|
||||
"", // targetParentID
|
||||
numHardlinks,
|
||||
false // This is not the secondary node if closeFilePrimary() was called.
|
||||
);
|
||||
|
||||
logEvent(Program::getApp()->getFileEventLogger(), *getFileEvent(), eventCtx);
|
||||
}
|
||||
|
||||
// unlink if file marked as disposable
|
||||
if( (closeRes == FhgfsOpsErr_SUCCESS) && unlinkDisposalFile)
|
||||
{ // check whether file has been unlinked (and perform the unlink operation on last close)
|
||||
|
||||
/* note: we do this only if also the chunk file close succeeded, because if storage servers
|
||||
are down, unlinkDisposableFile() will keep the file in the disposal store anyways */
|
||||
|
||||
// this only touches timestamps on the disposal dirinode, which is not visible to the user,
|
||||
// so no need to fix up timestamps that have diverged between primary and secondary
|
||||
MsgHelperClose::unlinkDisposableFile(entryInfo->getEntryID(), getMsgHeaderUserID(),
|
||||
entryInfo->getIsBuddyMirrored());
|
||||
}
|
||||
|
||||
//for alternative 2: forward the operation to secondary
|
||||
//after unlinkDisposalFile on primary is complete.
|
||||
if(!isMsgHeaderFeatureFlagSet(CLOSEFILEMSG_FLAG_EARLYRESPONSE))
|
||||
return boost::make_unique<ResponseState>(closeRes);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::unique_ptr<CloseFileMsgEx::ResponseState> CloseFileMsgEx::closeFileSecondary(
|
||||
ResponseContext& ctx)
|
||||
{
|
||||
if (isMsgHeaderFeatureFlagSet(CLOSEFILEMSG_FLAG_CANCELAPPENDLOCKS))
|
||||
{
|
||||
// client requests cleanup of granted or pending locks for this handle
|
||||
unsigned ownerFD = SessionTk::ownerFDFromHandleID(getFileHandleID() );
|
||||
EntryLockDetails lockDetails(getClientNumID(), 0, 0, "", ENTRYLOCKTYPE_CANCEL);
|
||||
|
||||
MsgHelperLocking::flockAppend(getEntryInfo(), ownerFD, lockDetails);
|
||||
}
|
||||
|
||||
// on secondary we only need to close the session and the meta file, because the chunk files
|
||||
// will be closed by primary
|
||||
|
||||
unsigned accessFlags;
|
||||
MetaFileHandle inode;
|
||||
|
||||
FhgfsOpsErr closeRes = MsgHelperClose::closeSessionFile(
|
||||
getClientNumID(), getFileHandleID(), getEntryInfo(), &accessFlags, inode);
|
||||
|
||||
// the file may not be open on the secondary, in which case inode == nullptr
|
||||
if (closeRes != FhgfsOpsErr_SUCCESS)
|
||||
return boost::make_unique<ResponseState>(closeRes);
|
||||
|
||||
// maybe assert?
|
||||
if (isMsgHeaderFeatureFlagSet(CLOSEFILEMSG_FLAG_DYNATTRIBS))
|
||||
inode->setDynAttribs(dynAttribs);
|
||||
|
||||
fixInodeTimestamp(*inode, inodeTimestamps, getEntryInfo());
|
||||
|
||||
unsigned numHardlinks;
|
||||
unsigned numInodeRefs;
|
||||
bool outLastWriterClosed;
|
||||
|
||||
Program::getApp()->getMetaStore()->closeFile(getEntryInfo(), std::move(inode), accessFlags,
|
||||
&numHardlinks, &numInodeRefs, outLastWriterClosed);
|
||||
|
||||
// unlink if file marked as disposable
|
||||
// this only touches timestamps on the disposal dirinode, which is not visible to the user,
|
||||
// so no need to fix up timestamps that have diverged between primary and secondary
|
||||
if( (closeRes == FhgfsOpsErr_SUCCESS) && (!numHardlinks) && (!numInodeRefs))
|
||||
MsgHelperClose::unlinkDisposableFile(getEntryInfo()->getEntryID(), getMsgHeaderUserID(),
|
||||
getEntryInfo()->getIsBuddyMirrored());
|
||||
|
||||
return boost::make_unique<ResponseState>(closeRes);
|
||||
}
|
||||
|
||||
/**
|
||||
* The rest after MsgHelperClose::closeSessionFile(), i.e. MsgHelperClose::closeChunkFile()
|
||||
* and metaStore->closeFile().
|
||||
*
|
||||
* @param inode inode for closed file (as returned by MsgHelperClose::closeSessionFile() )
|
||||
* @param maxUsedNodeIndex zero-based index, -1 means "none"
|
||||
* @param outFileWasUnlinked true if the hardlink count of the file was 0
|
||||
*/
|
||||
FhgfsOpsErr CloseFileMsgEx::closeFileAfterEarlyResponse(MetaFileHandle inode, unsigned accessFlags,
|
||||
bool* outUnlinkDisposalFile, unsigned& outNumHardlinks, bool& outLastWriterClosed)
|
||||
{
|
||||
MetaStore* metaStore = Program::getApp()->getMetaStore();
|
||||
unsigned numInodeRefs;
|
||||
|
||||
*outUnlinkDisposalFile = false;
|
||||
|
||||
FhgfsOpsErr chunksRes = MsgHelperClose::closeChunkFile(
|
||||
getClientNumID(), getFileHandleID(), getMaxUsedNodeIndex(), *inode, getEntryInfo(),
|
||||
getMsgHeaderUserID(), NULL);
|
||||
|
||||
metaStore->closeFile(getEntryInfo(), std::move(inode), accessFlags, &outNumHardlinks,
|
||||
&numInodeRefs, outLastWriterClosed);
|
||||
|
||||
if (!outNumHardlinks && !numInodeRefs)
|
||||
*outUnlinkDisposalFile = true;
|
||||
|
||||
return chunksRes;
|
||||
}
|
||||
|
||||
void CloseFileMsgEx::forwardToSecondary(ResponseContext& ctx)
|
||||
{
|
||||
sendToSecondary(ctx, *this, NETMSGTYPE_CloseFileResp);
|
||||
}
|
||||
38
meta/source/net/message/session/opening/CloseFileMsgEx.h
Normal file
38
meta/source/net/message/session/opening/CloseFileMsgEx.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/storage/StorageErrors.h>
|
||||
#include <common/net/message/session/opening/CloseFileMsg.h>
|
||||
#include <common/net/message/session/opening/CloseFileRespMsg.h>
|
||||
#include <net/message/MirroredMessage.h>
|
||||
#include <session/EntryLock.h>
|
||||
#include <storage/FileInode.h>
|
||||
|
||||
class CloseFileMsgEx : public MirroredMessage<CloseFileMsg, FileIDLock>
|
||||
{
|
||||
public:
|
||||
typedef ErrorCodeResponseState<CloseFileRespMsg, NETMSGTYPE_CloseFile> ResponseState;
|
||||
|
||||
virtual bool processIncoming(ResponseContext& ctx) override;
|
||||
|
||||
std::unique_ptr<MirroredMessageResponseState> executeLocally(ResponseContext& ctx,
|
||||
bool isSecondary) override;
|
||||
|
||||
FileIDLock lock(EntryLockStore& store) override;
|
||||
|
||||
bool isMirrored() override { return getEntryInfo()->getIsBuddyMirrored(); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<ResponseState> closeFilePrimary(ResponseContext& ctx);
|
||||
std::unique_ptr<ResponseState> closeFileSecondary(ResponseContext& ctx);
|
||||
void forwardToSecondary(ResponseContext& ctx) override;
|
||||
FhgfsOpsErr closeFileAfterEarlyResponse(MetaFileHandle inode, unsigned accessFlags,
|
||||
bool* outUnlinkDisposalFile, unsigned& numHardlinks, bool& outLastWriterClosed);
|
||||
|
||||
FhgfsOpsErr processSecondaryResponse(NetMessage& resp) override
|
||||
{
|
||||
return (FhgfsOpsErr) static_cast<CloseFileRespMsg&>(resp).getValue();
|
||||
}
|
||||
|
||||
const char* mirrorLogContext() const override { return "CloseFileMsgEx/forward"; }
|
||||
};
|
||||
|
||||
157
meta/source/net/message/session/opening/OpenFileMsgEx.cpp
Normal file
157
meta/source/net/message/session/opening/OpenFileMsgEx.cpp
Normal file
@@ -0,0 +1,157 @@
|
||||
#include <common/net/message/control/GenericResponseMsg.h>
|
||||
#include <common/net/message/session/opening/OpenFileRespMsg.h>
|
||||
#include <common/toolkit/SessionTk.h>
|
||||
#include <common/storage/striping/Raid0Pattern.h>
|
||||
#include <components/FileEventLogger.h>
|
||||
#include <net/msghelpers/MsgHelperOpen.h>
|
||||
#include <program/Program.h>
|
||||
#include <session/EntryLock.h>
|
||||
#include <session/SessionStore.h>
|
||||
#include "OpenFileMsgEx.h"
|
||||
|
||||
FileIDLock OpenFileMsgEx::lock(EntryLockStore& store)
|
||||
{
|
||||
return {&store, getEntryInfo()->getEntryID(), true};
|
||||
}
|
||||
|
||||
bool OpenFileMsgEx::processIncoming(ResponseContext& ctx)
|
||||
{
|
||||
#ifdef BEEGFS_DEBUG
|
||||
const char* logContext = "OpenFileMsg incoming";
|
||||
|
||||
EntryInfo* entryInfo = getEntryInfo();
|
||||
|
||||
LOG_DEBUG(logContext, Log_SPAM, "ParentInfo: " + entryInfo->getParentEntryID() +
|
||||
" EntryID: " + entryInfo->getEntryID() + " FileName: " + entryInfo->getFileName() );
|
||||
|
||||
LOG_DEBUG(logContext, Log_DEBUG,
|
||||
"BuddyMirrored: " + std::string(entryInfo->getIsBuddyMirrored() ? "Yes" : "No") +
|
||||
" Secondary: " +
|
||||
std::string(hasFlag(NetMessageHeader::Flag_BuddyMirrorSecond) ? "Yes" : "No") );
|
||||
#endif // BEEGFS_DEBUG
|
||||
|
||||
return BaseType::processIncoming(ctx);
|
||||
}
|
||||
|
||||
std::unique_ptr<MirroredMessageResponseState> OpenFileMsgEx::executeLocally(ResponseContext& ctx,
|
||||
bool isSecondary)
|
||||
{
|
||||
App* app = Program::getApp();
|
||||
|
||||
EntryInfo* entryInfo = this->getEntryInfo();
|
||||
bool useQuota = isMsgHeaderFeatureFlagSet(OPENFILEMSG_FLAG_USE_QUOTA);
|
||||
bool bypassAccessCheck = isMsgHeaderFeatureFlagSet(OPENFILEMSG_FLAG_BYPASS_ACCESS_CHECK);
|
||||
|
||||
const bool eventLoggingEnabled = !isSecondary && app->getFileEventLogger() && getFileEvent();
|
||||
MetaFileHandle inode;
|
||||
|
||||
PathInfo pathInfo;
|
||||
StripePattern* pattern;
|
||||
unsigned sessionFileID;
|
||||
SessionStore* sessions = entryInfo->getIsBuddyMirrored()
|
||||
? app->getMirroredSessions()
|
||||
: app->getSessions();
|
||||
|
||||
FhgfsOpsErr openRes = MsgHelperOpen::openFile(
|
||||
entryInfo, getAccessFlags(), useQuota, bypassAccessCheck, getMsgHeaderUserID(),
|
||||
inode, isSecondary);
|
||||
|
||||
if (openRes == FhgfsOpsErr_SUCCESS && shouldFixTimestamps())
|
||||
fixInodeTimestamp(*inode, fileTimestamps, entryInfo);
|
||||
|
||||
// update operation counters
|
||||
updateNodeOp(ctx, MetaOpCounter_OPEN);
|
||||
|
||||
if (openRes != FhgfsOpsErr_SUCCESS)
|
||||
{
|
||||
// If open() fails due to file state restrictions, emit an OPEN_BLOCKED event
|
||||
// (when event logging is enabled). The numHardlinks in event context will be 0
|
||||
// since inode is nullptr after access denial.
|
||||
if ((openRes == FhgfsOpsErr_FILEACCESS_DENIED) && eventLoggingEnabled)
|
||||
{
|
||||
FileEvent* fileEvent = const_cast<FileEvent*>(getFileEvent());
|
||||
fileEvent->type = FileEventType::OPEN_BLOCKED;
|
||||
|
||||
EventContext eventCtx = makeEventContext(
|
||||
entryInfo,
|
||||
entryInfo->getParentEntryID(),
|
||||
getMsgHeaderUserID(),
|
||||
"",
|
||||
inode ? inode->getNumHardlinks() : 0,
|
||||
isSecondary
|
||||
);
|
||||
logEvent(app->getFileEventLogger(), *fileEvent, eventCtx);
|
||||
}
|
||||
|
||||
// error occurred
|
||||
Raid0Pattern dummyPattern(1, UInt16Vector{});
|
||||
|
||||
// generate response
|
||||
if(unlikely(openRes == FhgfsOpsErr_COMMUNICATION))
|
||||
{
|
||||
return boost::make_unique<OpenFileResponseState>();
|
||||
}
|
||||
else
|
||||
{ // normal response
|
||||
return boost::make_unique<OpenFileResponseState>(openRes, std::string(), dummyPattern,
|
||||
pathInfo, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (eventLoggingEnabled)
|
||||
{
|
||||
EventContext eventCtx = makeEventContext(
|
||||
entryInfo,
|
||||
entryInfo->getParentEntryID(),
|
||||
getMsgHeaderUserID(),
|
||||
"",
|
||||
inode->getNumHardlinks(),
|
||||
isSecondary
|
||||
);
|
||||
|
||||
logEvent(app->getFileEventLogger(), *getFileEvent(), eventCtx);
|
||||
}
|
||||
|
||||
// success => insert session
|
||||
SessionFile* sessionFile = new SessionFile(std::move(inode), getAccessFlags(), entryInfo);
|
||||
|
||||
Session* session = sessions->referenceSession(getClientNumID(), true);
|
||||
|
||||
pattern = sessionFile->getInode()->getStripePattern();
|
||||
|
||||
if (!isSecondary)
|
||||
{
|
||||
sessionFileID = session->getFiles()->addSession(sessionFile);
|
||||
fileHandleID = SessionTk::generateFileHandleID(sessionFileID, entryInfo->getEntryID() );
|
||||
|
||||
setSessionFileID(sessionFileID);
|
||||
setFileHandleID(fileHandleID.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
fileHandleID = getFileHandleID();
|
||||
sessionFileID = getSessionFileID();
|
||||
|
||||
bool addRes = session->getFiles()->addSession(sessionFile, sessionFileID);
|
||||
|
||||
if (!addRes)
|
||||
{
|
||||
const char* logContext = "OpenFileMsgEx (executeLocally)";
|
||||
LogContext(logContext).log(Log_NOTICE,
|
||||
"Couldn't add sessionFile on secondary buddy; sessionID: " + getClientNumID().str()
|
||||
+ "; sessionFileID: " + StringTk::uintToStr(sessionFileID));
|
||||
}
|
||||
}
|
||||
|
||||
sessions->releaseSession(session);
|
||||
|
||||
sessionFile->getInode()->getPathInfo(&pathInfo);
|
||||
|
||||
return boost::make_unique<OpenFileResponseState>(openRes, fileHandleID, *pattern, pathInfo,
|
||||
sessionFile->getInode()->getFileVersion());
|
||||
}
|
||||
|
||||
void OpenFileMsgEx::forwardToSecondary(ResponseContext& ctx)
|
||||
{
|
||||
sendToSecondary(ctx, *this, NETMSGTYPE_OpenFileResp);
|
||||
}
|
||||
105
meta/source/net/message/session/opening/OpenFileMsgEx.h
Normal file
105
meta/source/net/message/session/opening/OpenFileMsgEx.h
Normal file
@@ -0,0 +1,105 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/storage/StorageErrors.h>
|
||||
#include <common/net/message/session/opening/OpenFileMsg.h>
|
||||
#include <common/net/message/session/opening/OpenFileRespMsg.h>
|
||||
#include <storage/DirInode.h>
|
||||
#include <storage/FileInode.h>
|
||||
#include <net/message/MirroredMessage.h>
|
||||
#include <session/EntryLock.h>
|
||||
|
||||
class OpenFileResponseState : public MirroredMessageResponseState
|
||||
{
|
||||
public:
|
||||
OpenFileResponseState()
|
||||
: isIndirectCommErr(true)
|
||||
{
|
||||
}
|
||||
|
||||
explicit OpenFileResponseState(Deserializer& des)
|
||||
{
|
||||
serialize(this, des);
|
||||
}
|
||||
|
||||
OpenFileResponseState(FhgfsOpsErr result, const std::string& fileHandleID,
|
||||
const StripePattern& pattern, const PathInfo& pathInfo, uint32_t fileVersion)
|
||||
: isIndirectCommErr(false), result(result), fileHandleID(fileHandleID),
|
||||
pattern(pattern.clone()), pathInfo(pathInfo), fileVersion(fileVersion)
|
||||
{
|
||||
}
|
||||
|
||||
void sendResponse(NetMessage::ResponseContext& ctx) override
|
||||
{
|
||||
if (isIndirectCommErr)
|
||||
ctx.sendResponse(
|
||||
GenericResponseMsg(
|
||||
GenericRespMsgCode_INDIRECTCOMMERR,
|
||||
"Communication with storage targets failed"));
|
||||
else
|
||||
ctx.sendResponse(
|
||||
OpenFileRespMsg(
|
||||
result, fileHandleID, pattern.get(), &pathInfo, fileVersion));
|
||||
}
|
||||
|
||||
bool changesObservableState() const override
|
||||
{
|
||||
return !isIndirectCommErr && result == FhgfsOpsErr_SUCCESS;
|
||||
}
|
||||
|
||||
protected:
|
||||
uint32_t serializerTag() const override { return NETMSGTYPE_OpenFile; }
|
||||
|
||||
template<typename This, typename Ctx>
|
||||
static void serialize(This* obj, Ctx& ctx)
|
||||
{
|
||||
ctx
|
||||
% obj->isIndirectCommErr;
|
||||
|
||||
if (!obj->isIndirectCommErr)
|
||||
ctx
|
||||
% serdes::as<int32_t>(obj->result)
|
||||
% obj->fileHandleID
|
||||
% obj->pattern
|
||||
% obj->pathInfo;
|
||||
}
|
||||
|
||||
void serializeContents(Serializer& ser) const override
|
||||
{
|
||||
serialize(this, ser);
|
||||
}
|
||||
|
||||
private:
|
||||
bool isIndirectCommErr;
|
||||
|
||||
FhgfsOpsErr result;
|
||||
std::string fileHandleID;
|
||||
std::unique_ptr<StripePattern> pattern;
|
||||
PathInfo pathInfo;
|
||||
uint32_t fileVersion;
|
||||
};
|
||||
|
||||
class OpenFileMsgEx : public MirroredMessage<OpenFileMsg, FileIDLock>
|
||||
{
|
||||
public:
|
||||
typedef OpenFileResponseState ResponseState;
|
||||
|
||||
bool processIncoming(ResponseContext& ctx) override;
|
||||
|
||||
FileIDLock lock(EntryLockStore& store) override;
|
||||
std::unique_ptr<MirroredMessageResponseState> executeLocally(ResponseContext& ctx,
|
||||
bool isSecondary) override;
|
||||
void forwardToSecondary(ResponseContext& ctx) override;
|
||||
|
||||
bool isMirrored() override { return getEntryInfo()->getIsBuddyMirrored(); }
|
||||
|
||||
private:
|
||||
FhgfsOpsErr processSecondaryResponse(NetMessage& resp) override
|
||||
{
|
||||
return (FhgfsOpsErr) static_cast<OpenFileRespMsg&>(resp).getResult();
|
||||
}
|
||||
|
||||
const char* mirrorLogContext() const override { return "OpenFileMsgEx/forward"; }
|
||||
|
||||
std::string fileHandleID;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user