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,445 @@
#pragma once
#include <app/App.h>
#include <common/app/log/Logger.h>
#include <common/components/streamlistenerv2/IncomingPreprocessedMsgWork.h>
#include <common/net/message/session/AckNotifyMsg.h>
#include <common/net/message/session/AckNotifyRespMsg.h>
#include <common/net/message/NetMessage.h>
#include <common/storage/StorageErrors.h>
#include <common/toolkit/DebugVariable.h>
#include <common/toolkit/MessagingTk.h>
#include <program/Program.h>
#include <session/MirrorMessageResponseState.h>
#include <toolkit/BuddyCommTk.h>
template<typename BaseT, typename LockStateT>
class MirroredMessage : public BaseT
{
protected:
typedef MirroredMessage BaseType;
BuddyResyncJob* resyncJob;
LockStateT lockState;
MirroredMessage():
resyncJob(nullptr)
{}
virtual FhgfsOpsErr processSecondaryResponse(NetMessage& resp) = 0;
virtual const char* mirrorLogContext() const = 0;
virtual std::unique_ptr<MirroredMessageResponseState> executeLocally(
NetMessage::ResponseContext& ctx, bool isSecondary) = 0;
virtual bool isMirrored() = 0;
// IMPORTANT NOTE ON LOCKING ORDER:
// * always take locks the order
// - HashDirLock
// - DirIDLock
// - ParentNameLock
// - FileIDLock
// * always take locks of each type with the order induced by:
// - HashDirLock: id
// - DirIDLock: (id, forWrite)
// - ParentNameLock: (parentID, name)
// - FileIDLock: id
//
// not doing this may result in deadlocks.
virtual LockStateT lock(EntryLockStore& store) = 0;
virtual void forwardToSecondary(NetMessage::ResponseContext& ctx) = 0;
virtual bool processIncoming(NetMessage::ResponseContext& ctx)
{
Session* session = nullptr;
bool isNewState = true;
if (isMirrored() && !this->hasFlag(NetMessageHeader::Flag_BuddyMirrorSecond))
{
if (Program::getApp()->getInternodeSyncer()->getResyncInProgress())
resyncJob = Program::getApp()->getBuddyResyncer()->getResyncJob();
lockState = lock(*Program::getApp()->getMirroredSessions()->getEntryLockStore());
}
// make sure that the thread change set is *always* cleared when we leave this method.
struct _ClearChangeSet {
~_ClearChangeSet()
{
if (BuddyResyncer::getSyncChangeset())
{
LOG(MIRRORING, WARNING, "Abandoning sync changeset");
BuddyResyncer::abandonSyncChangeset();
}
}
} _clearChangeSet;
(void) _clearChangeSet;
mirrorState.reset();
if (isMirrored())
{
const auto nodeID = this->getRequestorID(ctx).second;
session = Program::getApp()->getMirroredSessions()->referenceSession(nodeID, true);
}
if (isMirrored() && this->hasFlag(NetMessageHeader::Flag_HasSequenceNumber))
{
// special case: client has not been told where to start its sequence. in this case,
// we want to answer with only the new seqNoBase for the client, and do NO processing.
if (this->getSequenceNumber() == 0)
{
GenericResponseMsg response(GenericRespMsgCode_NEWSEQNOBASE, "New seqNoBase");
response.addFlag(NetMessageHeader::Flag_HasSequenceNumber);
response.setSequenceNumber(session->getSeqNoBase());
ctx.sendResponse(response);
goto exit;
}
// a note on locking of mirrorState. since clients process each request in only one
// thread, per client we can have only one request for a given sequence number at any
// given time. retries may reuse the same sequence number, and they may be processed in
// a different thread on the server, but no two threads process the same sequence number
// from the same client at the same time. thus, no locking for the actual structure is
// needed, but extra memory barriers to ensure propagation of results between threads
// are necessary.
__sync_synchronize();
if (this->hasFlag(NetMessageHeader::Flag_IsSelectiveAck))
std::tie(mirrorState, isNewState) = session->acquireMirrorStateSlotSelective(
this->getSequenceNumberDone(),
this->getSequenceNumber());
else
std::tie(mirrorState, isNewState) = session->acquireMirrorStateSlot(
this->getSequenceNumberDone(),
this->getSequenceNumber());
}
if (!isNewState)
{
if (mirrorState->response)
mirrorState->response->sendResponse(ctx);
else
ctx.sendResponse(
GenericResponseMsg(
GenericRespMsgCode_TRYAGAIN,
"Request for same sequence number is currently in progress"));
}
else
{
if (resyncJob && resyncJob->isRunning())
{
BuddyResyncer::registerSyncChangeset();
resyncJob->registerOps();
}
auto responseState = executeLocally(ctx,
isMirrored() && this->hasFlag(NetMessageHeader::Flag_BuddyMirrorSecond));
// responseState may ne null if the message has called earlyComplete(). do not finish
// the operation twice in this case.
if (responseState)
finishOperation(ctx, std::move(responseState));
}
exit:
if (session)
Program::getApp()->getMirroredSessions()->releaseSession(session);
return true;
}
template<typename ResponseT>
void earlyComplete(NetMessage::ResponseContext& ctx, ResponseT&& state)
{
finishOperation(ctx, boost::make_unique<ResponseT>(std::move(state)));
Socket* sock = ctx.getSocket();
IncomingPreprocessedMsgWork::releaseSocket(Program::getApp(), &sock, this);
}
void buddyResyncNotify(NetMessage::ResponseContext& ctx, bool stateChanged)
{
// pairs with the memory barrier before acquireMirrorStateSlot
__sync_synchronize();
if (BuddyResyncer::getSyncChangeset())
{
if (isMirrored() &&
!this->hasFlag(NetMessageHeader::Flag_BuddyMirrorSecond) &&
stateChanged)
BuddyResyncer::commitThreadChangeSet();
else
BuddyResyncer::abandonSyncChangeset();
}
}
void finishOperation(NetMessage::ResponseContext& ctx,
std::unique_ptr<MirroredMessageResponseState> state)
{
auto* responsePtr = state.get();
if (isMirrored() &&
!this->hasFlag(NetMessageHeader::Flag_BuddyMirrorSecond) &&
state)
{
if (state->changesObservableState())
forwardToSecondary(ctx);
else
notifySecondaryOfACK(ctx);
}
if (mirrorState)
mirrorState->response = std::move(state);
// pairs with the memory barrier before acquireMirrorStateSlot
__sync_synchronize();
if (BuddyResyncer::getSyncChangeset())
{
resyncJob = Program::getApp()->getBuddyResyncer()->getResyncJob();
if (isMirrored() &&
!this->hasFlag(NetMessageHeader::Flag_BuddyMirrorSecond) &&
responsePtr &&
responsePtr->changesObservableState())
BuddyResyncer::commitThreadChangeSet();
else
BuddyResyncer::abandonSyncChangeset();
resyncJob->unregisterOps();
}
if (responsePtr)
responsePtr->sendResponse(ctx);
lockState = {};
}
void notifySecondaryOfACK(NetMessage::ResponseContext& ctx)
{
AckNotifiyMsg msg;
// if the secondary does not respond with SUCCESS, it will automatically be set to
// needs-resync. eventually, resync will clear the secondary sessions entirely, which will
// also flush the sequence number store.
sendToSecondary(ctx, msg, NETMSGTYPE_AckNotifyResp);
}
virtual void prepareMirrorRequestArgs(RequestResponseArgs& args)
{
}
template<typename T>
void sendToSecondary(NetMessage::ResponseContext& ctx, MirroredMessageBase<T>& message,
unsigned respType, FhgfsOpsErr expectedResult = FhgfsOpsErr_SUCCESS)
{
App* app = Program::getApp();
NodeStoreServers* metaNodes = app->getMetaNodes();
MirrorBuddyGroupMapper* buddyGroups = app->getMetaBuddyGroupMapper();
DEBUG_ENV_VAR(unsigned, FORWARD_DELAY, 0, "BEEGFS_FORWARD_DELAY_SECS");
if (FORWARD_DELAY)
sleep(FORWARD_DELAY);
// if a resync is currently running, abort right here, immediatly. we do not need to know
// the exact state of the buddy: a resync is running. it's bad.
if (app->getInternodeSyncer()->getResyncInProgress())
return;
// check whether the secondary is viable at all: if it is not online and good,
// communicating will not do any good. even online/needs-resync must be skipped, because
// the resyncer must be the only entitity that changes the secondary as long as it is not
// good yet.
{
CombinedTargetState secondaryState;
NumNodeID secondaryID(buddyGroups->getSecondaryTargetID(
buddyGroups->getLocalGroupID()));
bool getStateRes = app->getMetaStateStore()->getState(secondaryID.val(),
secondaryState);
// if the secondary is anything except online/good, set it to needs-resync immediately.
// whenever we pass this point, the secondary will have missed *something* of
// importance, so anything except online/good must be set to needs-resync right here.
if (!getStateRes
|| secondaryState.reachabilityState != TargetReachabilityState_ONLINE
|| secondaryState.consistencyState != TargetConsistencyState_GOOD)
{
auto* const resyncer = app->getBuddyResyncer();
auto* const job = resyncer->getResyncJob();
// if we have no job or a running job, we must start a resync soon. if we have a
// job that has finished successfully, the management server may not have noticed
// that the secondary is completely resynced, so our buddys state may well not be
// GOOD even though we have resynced completely. we may assume that a successful
// resync implies that the buddy is good, even if the management server thinks it
// isn't.
if (!job ||
(!job->isRunning() && job->getState() != BuddyResyncJobState_SUCCESS))
{
setBuddyNeedsResync();
return;
}
}
}
RequestResponseArgs rrArgs(NULL, &message, respType);
RequestResponseNode rrNode(NumNodeID(buddyGroups->getLocalGroupID()), metaNodes);
rrNode.setMirrorInfo(buddyGroups, true);
rrNode.setTargetStates(app->getMetaStateStore());
prepareMirrorRequestArgs(rrArgs);
// copy sequence numbers and set original requestor info for secondary
message.setSequenceNumber(this->getSequenceNumber());
message.setSequenceNumberDone(this->getSequenceNumberDone());
message.setRequestorID(this->getRequestorID(ctx));
// (almost) all messages do some sort of statistics gathering by user ID
message.setMsgHeaderUserID(this->getMsgHeaderUserID());
// set flag here instead of at the beginning because &message == this is often used
message.addFlag(NetMessageHeader::Flag_BuddyMirrorSecond);
message.addFlag(this->getFlags() & NetMessageHeader::Flag_IsSelectiveAck);
message.addFlag(this->getFlags() & NetMessageHeader::Flag_HasSequenceNumber);
FhgfsOpsErr commRes = MessagingTk::requestResponseNode(&rrNode, &rrArgs);
message.removeFlag(NetMessageHeader::Flag_BuddyMirrorSecond);
if (commRes != FhgfsOpsErr_SUCCESS)
{
// since we have reached this point, the secondary has indubitably not received
// important information from the primary. we now have two choices to keep the system
// in a consistent, safe state:
//
// 1) set the secondary to needs-resync
// 2) rollback the modifications we have made and let the client retry, hoping that
// some future communication with the secondary is successful
//
// 2 is not a viable option: since some operations may move data off of this metadata
// server and onto another one completely; allowing these to be undone requires a
// two-phase commit protocol, which incurs large communication overhead for a
// (hopefully) very rare error case. other operations delete local state (eg unlink,
// or close of an unlinked file), which would have to be held in limbo until either a
// commit or a rollback is issued.
//
// since we assume that communication errors are very rare, option 1 is the most
// efficient in the general case (as it does not have to keep objects alive past their
// intended lifetimes), so we set the secondary to needs-resync on any kind of
// communication error.
// other errors, e.g. out-of-memory conditions or errors caused by streamout hooks, are
// also assumed to be rare. if any of these happens, the secondary must be resynced no
// matter what actually happened. since the operations itself succeeded, we cannot send
// a notification about the communication error either - we'd have to drop the operation
// result to do that.
#ifdef BEEGFS_DEBUG
int buddyNodeID = buddyGroups->getBuddyTargetID(app->getLocalNodeNumID().val());
LOG_CTX(MIRRORING, DEBUG, mirrorLogContext(), "Communication with secondary failed. "
"Resync will be required when secondary comes back", buddyNodeID, commRes);
#endif
setBuddyNeedsResync();
return;
}
FhgfsOpsErr respMsgRes = processSecondaryResponse(*rrArgs.outRespMsg);
if (respMsgRes != expectedResult)
{
// whoops; primary and secondary did different things; if secondary is not resyncing
// AND communication was good this is concerning (result must have been success on
// primary, otherwise no forwarding would have happened).
// usually, this would mean that primary and secondary do not have the same state, or
// that the secondary has some kind of system error. (if the primary had a system error,
// it would be more likely to fail than to succeed).
// in either case, the secondary should be resynced, even if the primary experienced
// a hardware fault or similar errors: at this point, we can no longer differentiate
// between good and bad state on the primary, and the secondary may be arbitrarily out
// of sync.
LOG_CTX(MIRRORING, NOTICE, mirrorLogContext(),
"Different return codes from primary and secondary buddy. "
"Setting secondary to needs-resync.",
("Expected response", expectedResult),
("Received response", respMsgRes));
setBuddyNeedsResync();
}
}
// inodes that are changes during mirrored processing on the secondary (eg file creation or
// deletion, setxattr, etc) may have timestamps changes to a different value than the primary.
// to remedy this, the secondary must explicitly set these timestamps during processing.
bool shouldFixTimestamps()
{
return isMirrored() && Program::getApp()->getConfig()->getTuneMirrorTimestamps();
}
void fixInodeTimestamp(DirInode& inode, MirroredTimestamps& ts)
{
if (!isMirrored())
return;
BEEGFS_BUG_ON_DEBUG(!inode.getIsLoaded(), "inode not loaded");
StatData stat;
inode.getStatData(stat);
if (!this->hasFlag(NetMessageHeader::Flag_BuddyMirrorSecond))
{
ts = stat.getMirroredTimestamps();
}
else
{
stat.setMirroredTimestamps(ts);
inode.setStatData(stat);
}
}
void fixInodeTimestamp(FileInode& inode, MirroredTimestamps& ts,
EntryInfo* const saveEntryInfo)
{
if (!isMirrored())
return;
StatData stat;
inode.getStatData(stat);
if (!this->hasFlag(NetMessageHeader::Flag_BuddyMirrorSecond))
{
ts = stat.getMirroredTimestamps();
}
else
{
stat.setMirroredTimestamps(ts);
inode.setStatData(stat);
if (saveEntryInfo)
inode.updateInodeOnDisk(saveEntryInfo);
}
}
void updateNodeOp(NetMessage::ResponseContext& ctx, MetaOpCounterTypes type)
{
const auto counter = isMirrored() && this->hasFlag(NetMessageHeader::Flag_BuddyMirrorSecond)
? MetaOpCounter_MIRROR
: type;
Program::getApp()->getNodeOpStats()->updateNodeOp(ctx.getSocket()->getPeerIP(),
counter, this->getMsgHeaderUserID());
}
private:
std::shared_ptr<MirrorStateSlot> mirrorState;
void setBuddyNeedsResync()
{
BuddyCommTk::setBuddyNeedsResync(Program::getApp()->getMetaPath(), true);
}
};

View File

@@ -0,0 +1,354 @@
// control messages
#include <common/net/message/control/AuthenticateChannelMsgEx.h>
#include <common/net/message/control/GenericResponseMsg.h>
#include <common/net/message/control/PeerInfoMsgEx.h>
#include <net/message/control/AckMsgEx.h>
#include <net/message/control/SetChannelDirectMsgEx.h>
// nodes messages
#include <common/net/message/nodes/ChangeTargetConsistencyStatesRespMsg.h>
#include <common/net/message/nodes/GetNodeCapacityPoolsRespMsg.h>
#include <common/net/message/nodes/GetNodesRespMsg.h>
#include <common/net/message/nodes/GetTargetMappingsRespMsg.h>
#include <common/net/message/nodes/GetMirrorBuddyGroupsRespMsg.h>
#include <common/net/message/nodes/GetStatesAndBuddyGroupsRespMsg.h>
#include <common/net/message/nodes/GetTargetStatesRespMsg.h>
#include <common/net/message/nodes/RegisterNodeRespMsg.h>
#include <common/net/message/nodes/RemoveNodeRespMsg.h>
#include <common/net/message/nodes/SetTargetConsistencyStatesRespMsg.h>
#include <common/net/message/nodes/storagepools/GetStoragePoolsRespMsg.h>
#include <net/message/nodes/GenericDebugMsgEx.h>
#include <net/message/nodes/GetClientStatsMsgEx.h>
#include <net/message/nodes/GetNodeCapacityPoolsMsgEx.h>
#include <net/message/nodes/GetNodesMsgEx.h>
#include <net/message/nodes/GetTargetMappingsMsgEx.h>
#include <net/message/nodes/HeartbeatMsgEx.h>
#include <net/message/nodes/HeartbeatRequestMsgEx.h>
#include <net/message/nodes/MapTargetsMsgEx.h>
#include <net/message/nodes/PublishCapacitiesMsgEx.h>
#include <net/message/nodes/RefreshCapacityPoolsMsgEx.h>
#include <net/message/nodes/RemoveNodeMsgEx.h>
#include <net/message/nodes/RefreshTargetStatesMsgEx.h>
#include <net/message/nodes/SetMirrorBuddyGroupMsgEx.h>
#include <net/message/nodes/SetTargetConsistencyStatesMsgEx.h>
#include <net/message/nodes/storagepools/RefreshStoragePoolsMsgEx.h>
// storage messages
#include <common/net/message/storage/attribs/RefreshEntryInfoRespMsg.h>
#include <common/net/message/storage/attribs/GetChunkFileAttribsRespMsg.h>
#include <common/net/message/storage/listing/ListDirFromOffsetRespMsg.h>
#include <common/net/message/storage/lookup/FindOwnerRespMsg.h>
#include <common/net/message/storage/lookup/LookupIntentRespMsg.h>
#include <common/net/message/storage/creating/MkDirRespMsg.h>
#include <common/net/message/storage/creating/MkFileRespMsg.h>
#include <common/net/message/storage/creating/MkFileWithPatternRespMsg.h>
#include <common/net/message/storage/creating/MkLocalDirRespMsg.h>
#include <common/net/message/storage/creating/RmChunkPathsRespMsg.h>
#include <common/net/message/storage/creating/RmDirRespMsg.h>
#include <common/net/message/storage/creating/RmLocalDirRespMsg.h>
#include <common/net/message/storage/mirroring/MirrorMetadataRespMsg.h>
#include <common/net/message/storage/mirroring/ResyncRawInodesRespMsg.h>
#include <common/net/message/storage/mirroring/ResyncSessionStoreRespMsg.h>
#include <common/net/message/storage/moving/MovingDirInsertRespMsg.h>
#include <common/net/message/storage/moving/MovingFileInsertRespMsg.h>
#include <common/net/message/storage/moving/RenameRespMsg.h>
#include <common/net/message/storage/quota/RequestExceededQuotaRespMsg.h>
#include <common/net/message/storage/attribs/SetAttrRespMsg.h>
#include <common/net/message/storage/attribs/SetFilePatternRespMsg.h>
#include <common/net/message/storage/attribs/SetLocalAttrRespMsg.h>
#include <common/net/message/storage/attribs/StatRespMsg.h>
#include <common/net/message/storage/StatStoragePathRespMsg.h>
#include <common/net/message/storage/TruncFileRespMsg.h>
#include <common/net/message/storage/TruncLocalFileRespMsg.h>
#include <common/net/message/storage/creating/UnlinkFileRespMsg.h>
#include <common/net/message/storage/creating/UnlinkLocalFileRespMsg.h>
#include <common/net/message/storage/creating/MoveFileInodeMsg.h>
#include <common/net/message/storage/creating/MoveFileInodeRespMsg.h>
#include <common/net/message/storage/creating/UnlinkLocalFileInodeRespMsg.h>
#include <common/net/message/storage/attribs/GetEntryInfoRespMsg.h>
#include <common/net/message/storage/attribs/RemoveXAttrRespMsg.h>
#include <common/net/message/storage/attribs/SetXAttrRespMsg.h>
#include <common/net/message/storage/creating/HardlinkRespMsg.h>
#include <common/net/message/storage/attribs/UpdateDirParentRespMsg.h>
#include <common/net/message/storage/SetStorageTargetInfoRespMsg.h>
#include <common/net/message/storage/mirroring/StorageResyncStartedRespMsg.h>
#include <net/message/storage/lookup/FindOwnerMsgEx.h>
#include <net/message/storage/listing/ListDirFromOffsetMsgEx.h>
#include <net/message/storage/creating/MkDirMsgEx.h>
#include <net/message/storage/creating/MkFileMsgEx.h>
#include <net/message/storage/creating/MkFileWithPatternMsgEx.h>
#include <net/message/storage/creating/MkLocalDirMsgEx.h>
#include <net/message/storage/creating/RmDirMsgEx.h>
#include <net/message/storage/creating/RmLocalDirMsgEx.h>
#include <net/message/storage/creating/UnlinkLocalFileInodeMsgEx.h>
#include <net/message/storage/creating/RmDirEntryMsgEx.h>
#include <net/message/storage/mirroring/GetMetaResyncStatsMsgEx.h>
#include <net/message/storage/mirroring/ResyncSessionStoreMsgEx.h>
#include <net/message/storage/mirroring/SetMetadataMirroringMsgEx.h>
#include <net/message/storage/mirroring/StorageResyncStartedMsgEx.h>
#include <net/message/storage/moving/MovingDirInsertMsgEx.h>
#include <net/message/storage/moving/MovingFileInsertMsgEx.h>
#include <net/message/storage/moving/RenameV2MsgEx.h>
#include <net/message/storage/quota/SetExceededQuotaMsgEx.h>
#include <net/message/storage/attribs/GetEntryInfoMsgEx.h>
#include <net/message/storage/lookup/LookupIntentMsgEx.h>
#include <net/message/storage/attribs/GetXAttrMsgEx.h>
#include <net/message/storage/attribs/ListXAttrMsgEx.h>
#include <net/message/storage/attribs/RemoveXAttrMsgEx.h>
#include <net/message/storage/attribs/SetAttrMsgEx.h>
#include <net/message/storage/attribs/SetDirPatternMsgEx.h>
#include <net/message/storage/attribs/SetFilePatternMsgEx.h>
#include <net/message/storage/attribs/SetFileStateMsgEx.h>
#include <net/message/storage/attribs/SetXAttrMsgEx.h>
#include <net/message/storage/attribs/StatMsgEx.h>
#include <net/message/storage/attribs/UpdateDirParentMsgEx.h>
#include <net/message/storage/StatStoragePathMsgEx.h>
#include <net/message/storage/TruncFileMsgEx.h>
#include <net/message/storage/creating/UnlinkFileMsgEx.h>
#include <net/message/storage/GetHighResStatsMsgEx.h>
#include <net/message/storage/attribs/RefreshEntryInfoMsgEx.h>
#include <net/message/storage/lookup/FindLinkOwnerMsgEx.h>
#include <net/message/storage/creating/HardlinkMsgEx.h>
#include <net/message/storage/creating/MoveFileInodeMsgEx.h>
#include <net/message/storage/attribs/UpdateDirParentMsgEx.h>
#include <net/message/storage/mirroring/ResyncRawInodesMsgEx.h>
// session messages
#include <common/net/message/session/AckNotifyRespMsg.h>
#include <common/net/message/session/BumpFileVersionRespMsg.h>
#include <common/net/message/session/FSyncLocalFileRespMsg.h>
#include <common/net/message/session/locking/FLockEntryRespMsg.h>
#include <common/net/message/session/locking/FLockRangeRespMsg.h>
#include <common/net/message/session/opening/CloseChunkFileRespMsg.h>
#include <common/net/message/session/opening/CloseFileRespMsg.h>
#include <common/net/message/session/opening/OpenFileRespMsg.h>
#include <common/net/message/session/rw/WriteLocalFileRespMsg.h>
#include <common/net/message/storage/attribs/SetDirPatternRespMsg.h>
#include <net/message/session/AckNotifyMsgEx.h>
#include <net/message/session/BumpFileVersionMsgEx.h>
#include <net/message/session/GetFileVersionMsgEx.h>
#include <net/message/session/locking/FLockAppendMsgEx.h>
#include <net/message/session/locking/FLockEntryMsgEx.h>
#include <net/message/session/locking/FLockRangeMsgEx.h>
#include <net/message/session/opening/CloseFileMsgEx.h>
#include <net/message/session/opening/OpenFileMsgEx.h>
// mon message
#include <net/message/mon/RequestMetaDataMsgEx.h>
// fsck messages
#include <net/message/fsck/CreateDefDirInodesMsgEx.h>
#include <net/message/fsck/CreateEmptyContDirsMsgEx.h>
#include <net/message/fsck/DeleteDirEntriesMsgEx.h>
#include <net/message/fsck/FixInodeOwnersMsgEx.h>
#include <net/message/fsck/FixInodeOwnersInDentryMsgEx.h>
#include <net/message/fsck/LinkToLostAndFoundMsgEx.h>
#include <net/message/fsck/RecreateFsIDsMsgEx.h>
#include <net/message/fsck/RecreateDentriesMsgEx.h>
#include <net/message/fsck/RemoveInodesMsgEx.h>
#include <net/message/fsck/RetrieveDirEntriesMsgEx.h>
#include <net/message/fsck/RetrieveInodesMsgEx.h>
#include <net/message/fsck/RetrieveFsIDsMsgEx.h>
#include <net/message/fsck/FsckSetEventLoggingMsgEx.h>
#include <net/message/fsck/UpdateDirAttribsMsgEx.h>
#include <net/message/fsck/UpdateFileAttribsMsgEx.h>
#include <net/message/fsck/AdjustChunkPermissionsMsgEx.h>
#include <net/message/fsck/CheckAndRepairDupInodeMsgEx.h>
// chunk balancing
#include <common/net/message/storage/chunkbalancing/CpChunkPathsRespMsg.h>
#include <net/message/storage/chunkbalancing/ChunkBalanceMsgEx.h>
#include <net/message/storage/chunkbalancing/StripePatternUpdateMsgEx.h>
#include <common/net/message/SimpleMsg.h>
#include <net/message/nodes/storagepools/RefreshStoragePoolsMsgEx.h>
#include "NetMessageFactory.h"
/**
* @return NetMessage that must be deleted by the caller
* (msg->msgType is NETMSGTYPE_Invalid on error)
*/
std::unique_ptr<NetMessage> NetMessageFactory::createFromMsgType(unsigned short msgType) const
{
NetMessage* msg;
switch(msgType)
{
// The following lines are grouped by "type of the message" and ordered alphabetically inside
// the groups. There should always be one message per line to keep a clear layout (although
// this might lead to lines that are longer than usual)
// control messages
case NETMSGTYPE_Ack: { msg = new AckMsgEx(); } break;
case NETMSGTYPE_AuthenticateChannel: { msg = new AuthenticateChannelMsgEx(); } break;
case NETMSGTYPE_GenericResponse: { msg = new GenericResponseMsg(); } break;
case NETMSGTYPE_SetChannelDirect: { msg = new SetChannelDirectMsgEx(); } break;
case NETMSGTYPE_PeerInfo: { msg = new PeerInfoMsgEx(); } break;
// nodes messages
case NETMSGTYPE_ChangeTargetConsistencyStatesResp: { msg = new ChangeTargetConsistencyStatesRespMsg(); } break;
case NETMSGTYPE_GenericDebug: { msg = new GenericDebugMsgEx(); } break;
case NETMSGTYPE_GetClientStats: { msg = new GetClientStatsMsgEx(); } break;
case NETMSGTYPE_GetMirrorBuddyGroupsResp: { msg = new GetMirrorBuddyGroupsRespMsg(); } break;
case NETMSGTYPE_GetNodeCapacityPools: { msg = new GetNodeCapacityPoolsMsgEx(); } break;
case NETMSGTYPE_GetNodeCapacityPoolsResp: { msg = new GetNodeCapacityPoolsRespMsg(); } break;
case NETMSGTYPE_GetNodes: { msg = new GetNodesMsgEx(); } break;
case NETMSGTYPE_GetNodesResp: { msg = new GetNodesRespMsg(); } break;
case NETMSGTYPE_GetStatesAndBuddyGroupsResp: { msg = new GetStatesAndBuddyGroupsRespMsg(); } break;
case NETMSGTYPE_GetStoragePoolsResp: { msg = new GetStoragePoolsRespMsg(); } break;
case NETMSGTYPE_GetTargetMappings: { msg = new GetTargetMappingsMsgEx(); } break;
case NETMSGTYPE_GetTargetMappingsResp: { msg = new GetTargetMappingsRespMsg(); } break;
case NETMSGTYPE_GetTargetStatesResp: { msg = new GetTargetStatesRespMsg(); } break;
case NETMSGTYPE_HeartbeatRequest: { msg = new HeartbeatRequestMsgEx(); } break;
case NETMSGTYPE_Heartbeat: { msg = new HeartbeatMsgEx(); } break;
case NETMSGTYPE_MapTargets: { msg = new MapTargetsMsgEx(); } break;
case NETMSGTYPE_PublishCapacities: { msg = new PublishCapacitiesMsgEx(); } break;
case NETMSGTYPE_RefreshStoragePools: { msg = new RefreshStoragePoolsMsgEx(); } break;
case NETMSGTYPE_RegisterNodeResp: { msg = new RegisterNodeRespMsg(); } break;
case NETMSGTYPE_RemoveNode: { msg = new RemoveNodeMsgEx(); } break;
case NETMSGTYPE_RemoveNodeResp: { msg = new RemoveNodeRespMsg(); } break;
case NETMSGTYPE_RefreshCapacityPools: { msg = new RefreshCapacityPoolsMsgEx(); } break;
case NETMSGTYPE_RefreshTargetStates: { msg = new RefreshTargetStatesMsgEx(); } break;
case NETMSGTYPE_SetMirrorBuddyGroup: { msg = new SetMirrorBuddyGroupMsgEx(); } break;
case NETMSGTYPE_SetTargetConsistencyStates: { msg = new SetTargetConsistencyStatesMsgEx(); } break;
case NETMSGTYPE_SetTargetConsistencyStatesResp: { msg = new SetTargetConsistencyStatesRespMsg(); } break;
// storage messages
case NETMSGTYPE_ChunkBalance: { msg = new ChunkBalanceMsgEx(); } break;
case NETMSGTYPE_CpChunkPathsResp: { msg = new CpChunkPathsRespMsg(); } break;
case NETMSGTYPE_FindLinkOwner: { msg = new FindLinkOwnerMsgEx(); } break;
case NETMSGTYPE_FindOwner: { msg = new FindOwnerMsgEx(); } break;
case NETMSGTYPE_FindOwnerResp: { msg = new FindOwnerRespMsg(); } break;
case NETMSGTYPE_GetChunkFileAttribsResp: { msg = new GetChunkFileAttribsRespMsg(); } break;
case NETMSGTYPE_GetEntryInfo: { msg = new GetEntryInfoMsgEx(); } break;
case NETMSGTYPE_GetEntryInfoResp: { msg = new GetEntryInfoRespMsg(); } break;
case NETMSGTYPE_GetHighResStats: { msg = new GetHighResStatsMsgEx(); } break;
case NETMSGTYPE_GetMetaResyncStats: { msg = new GetMetaResyncStatsMsgEx(); } break;
case NETMSGTYPE_RequestExceededQuotaResp: {msg = new RequestExceededQuotaRespMsg(); } break;
case NETMSGTYPE_SetExceededQuota: {msg = new SetExceededQuotaMsgEx(); } break;
case NETMSGTYPE_StorageResyncStarted: { msg = new StorageResyncStartedMsgEx(); } break;
case NETMSGTYPE_StorageResyncStartedResp: { msg = new StorageResyncStartedRespMsg(); } break;
case NETMSGTYPE_GetXAttr: { msg = new GetXAttrMsgEx(); } break;
case NETMSGTYPE_GetXAttrResp: { msg = new GetXAttrRespMsg(); } break;
case NETMSGTYPE_Hardlink: { msg = new HardlinkMsgEx(); } break;
case NETMSGTYPE_HardlinkResp: { msg = new HardlinkRespMsg(); } break;
case NETMSGTYPE_ListDirFromOffset: { msg = new ListDirFromOffsetMsgEx(); } break;
case NETMSGTYPE_ListDirFromOffsetResp: { msg = new ListDirFromOffsetRespMsg(); } break;
case NETMSGTYPE_ListXAttr: { msg = new ListXAttrMsgEx(); } break;
case NETMSGTYPE_ListXAttrResp: { msg = new ListXAttrRespMsg(); } break;
case NETMSGTYPE_LookupIntent: { msg = new LookupIntentMsgEx(); } break;
case NETMSGTYPE_LookupIntentResp: { msg = new LookupIntentRespMsg(); } break;
case NETMSGTYPE_MkDir: { msg = new MkDirMsgEx(); } break;
case NETMSGTYPE_MkDirResp: { msg = new MkDirRespMsg(); } break;
case NETMSGTYPE_MkFile: { msg = new MkFileMsgEx(); } break;
case NETMSGTYPE_MkFileResp: { msg = new MkFileRespMsg(); } break;
case NETMSGTYPE_MkFileWithPattern: { msg = new MkFileWithPatternMsgEx(); } break;
case NETMSGTYPE_MkFileWithPatternResp: { msg = new MkFileWithPatternRespMsg(); } break;
case NETMSGTYPE_MkLocalDir: { msg = new MkLocalDirMsgEx(); } break;
case NETMSGTYPE_MkLocalDirResp: { msg = new MkLocalDirRespMsg(); } break;
case NETMSGTYPE_MovingDirInsert: { msg = new MovingDirInsertMsgEx(); } break;
case NETMSGTYPE_MovingDirInsertResp: { msg = new MovingDirInsertRespMsg(); } break;
case NETMSGTYPE_MovingFileInsert: { msg = new MovingFileInsertMsgEx(); } break;
case NETMSGTYPE_MovingFileInsertResp: { msg = new MovingFileInsertRespMsg(); } break;
case NETMSGTYPE_RefreshEntryInfo: { msg = new RefreshEntryInfoMsgEx(); } break;
case NETMSGTYPE_RefreshEntryInfoResp: { msg = new RefreshEntryInfoRespMsg(); } break;
case NETMSGTYPE_ResyncRawInodes: { msg = new ResyncRawInodesMsgEx(); } break;
case NETMSGTYPE_ResyncRawInodesResp: { msg = new ResyncRawInodesRespMsg(); } break;
case NETMSGTYPE_ResyncSessionStore: { msg = new ResyncSessionStoreMsgEx(); } break;
case NETMSGTYPE_ResyncSessionStoreResp: { msg = new ResyncSessionStoreRespMsg(); } break;
case NETMSGTYPE_RemoveXAttr: { msg = new RemoveXAttrMsgEx(); } break;
case NETMSGTYPE_RemoveXAttrResp: { msg = new RemoveXAttrRespMsg(); } break;
case NETMSGTYPE_Rename: { msg = new RenameV2MsgEx(); } break;
case NETMSGTYPE_RenameResp: { msg = new RenameRespMsg(); } break;
case NETMSGTYPE_RmChunkPathsResp: { msg = new RmChunkPathsRespMsg(); } break;
case NETMSGTYPE_RmDirEntry: { msg = new RmDirEntryMsgEx(); } break;
case NETMSGTYPE_RmDir: { msg = new RmDirMsgEx(); } break;
case NETMSGTYPE_RmDirResp: { msg = new RmDirRespMsg(); } break;
case NETMSGTYPE_RmLocalDir: { msg = new RmLocalDirMsgEx(); } break;
case NETMSGTYPE_RmLocalDirResp: { msg = new RmLocalDirRespMsg(); } break;
case NETMSGTYPE_SetAttr: { msg = new SetAttrMsgEx(); } break;
case NETMSGTYPE_SetAttrResp: { msg = new SetAttrRespMsg(); } break;
case NETMSGTYPE_SetDirPattern: { msg = new SetDirPatternMsgEx(); } break;
case NETMSGTYPE_SetDirPatternResp: { msg = new SetDirPatternRespMsg(); } break;
case NETMSGTYPE_SetLocalAttrResp: { msg = new SetLocalAttrRespMsg(); } break;
case NETMSGTYPE_SetMetadataMirroring: { msg = new SetMetadataMirroringMsgEx(); } break;
case NETMSGTYPE_SetStorageTargetInfoResp: { msg = new SetStorageTargetInfoRespMsg(); } break;
case NETMSGTYPE_SetXAttr: { msg = new SetXAttrMsgEx(); } break;
case NETMSGTYPE_SetXAttrResp: { msg = new SetXAttrRespMsg(); } break;
case NETMSGTYPE_Stat: { msg = new StatMsgEx(); } break;
case NETMSGTYPE_StatResp: { msg = new StatRespMsg(); } break;
case NETMSGTYPE_StatStoragePath: { msg = new StatStoragePathMsgEx(); } break;
case NETMSGTYPE_StatStoragePathResp: { msg = new StatStoragePathRespMsg(); } break;
case NETMSGTYPE_StripePatternUpdate: { msg = new StripePatternUpdateMsgEx(); } break;
case NETMSGTYPE_TruncFile: { msg = new TruncFileMsgEx(); } break;
case NETMSGTYPE_TruncFileResp: { msg = new TruncFileRespMsg(); } break;
case NETMSGTYPE_TruncLocalFileResp: { msg = new TruncLocalFileRespMsg(); } break;
case NETMSGTYPE_UnlinkFile: { msg = new UnlinkFileMsgEx(); } break;
case NETMSGTYPE_UnlinkFileResp: { msg = new UnlinkFileRespMsg(); } break;
case NETMSGTYPE_UnlinkLocalFileResp: { msg = new UnlinkLocalFileRespMsg(); } break;
case NETMSGTYPE_UpdateDirParent: { msg = new UpdateDirParentMsgEx(); } break;
case NETMSGTYPE_UpdateDirParentResp: { msg = new UpdateDirParentRespMsg(); } break;
case NETMSGTYPE_MoveFileInode: { msg = new MoveFileInodeMsgEx(); } break;
case NETMSGTYPE_MoveFileInodeResp: {msg = new MoveFileInodeRespMsg(); } break;
case NETMSGTYPE_UnlinkLocalFileInode: {msg = new UnlinkLocalFileInodeMsgEx(); } break;
case NETMSGTYPE_UnlinkLocalFileInodeResp: {msg = new UnlinkLocalFileInodeRespMsg(); } break;
case NETMSGTYPE_SetFilePattern: { msg = new SetFilePatternMsgEx(); } break;
case NETMSGTYPE_SetFilePatternResp: { msg = new SetFilePatternRespMsg(); } break;
case NETMSGTYPE_SetFileState: { msg = new SetFileStateMsgEx(); } break;
case NETMSGTYPE_SetFileStateResp: { msg = new SetFileStateRespMsg(); } break;
// session messages
case NETMSGTYPE_BumpFileVersion: { msg = new BumpFileVersionMsgEx(); } break;
case NETMSGTYPE_BumpFileVersionResp: { msg = new BumpFileVersionRespMsg(); } break;
case NETMSGTYPE_OpenFile: { msg = new OpenFileMsgEx(); } break;
case NETMSGTYPE_OpenFileResp: { msg = new OpenFileRespMsg(); } break;
case NETMSGTYPE_CloseFile: { msg = new CloseFileMsgEx(); } break;
case NETMSGTYPE_CloseFileResp: { msg = new CloseFileRespMsg(); } break;
case NETMSGTYPE_CloseChunkFileResp: { msg = new CloseChunkFileRespMsg(); } break;
case NETMSGTYPE_WriteLocalFileResp: { msg = new WriteLocalFileRespMsg(); } break;
case NETMSGTYPE_FSyncLocalFileResp: { msg = new FSyncLocalFileRespMsg(); } break;
case NETMSGTYPE_FLockAppend: { msg = new FLockAppendMsgEx(); } break;
case NETMSGTYPE_FLockAppendResp: { msg = new FLockAppendRespMsg(); } break;
case NETMSGTYPE_FLockEntry: { msg = new FLockEntryMsgEx(); } break;
case NETMSGTYPE_FLockEntryResp: { msg = new FLockEntryRespMsg(); } break;
case NETMSGTYPE_FLockRange: { msg = new FLockRangeMsgEx(); } break;
case NETMSGTYPE_FLockRangeResp: { msg = new FLockRangeRespMsg(); } break;
case NETMSGTYPE_GetFileVersion: { msg = new GetFileVersionMsgEx(); } break;
case NETMSGTYPE_GetFileVersionResp: { msg = new GetFileVersionRespMsg(); } break;
case NETMSGTYPE_AckNotify: { msg = new AckNotifiyMsgEx(); } break;
case NETMSGTYPE_AckNotifyResp: { msg = new AckNotifiyRespMsg(); } break;
// mon message
case NETMSGTYPE_RequestMetaData: { msg = new RequestMetaDataMsgEx(); } break;
// fsck messages
case NETMSGTYPE_RetrieveDirEntries: { msg = new RetrieveDirEntriesMsgEx(); } break;
case NETMSGTYPE_RetrieveInodes: { msg = new RetrieveInodesMsgEx(); } break;
case NETMSGTYPE_RetrieveFsIDs: { msg = new RetrieveFsIDsMsgEx(); } break;
case NETMSGTYPE_DeleteDirEntries: { msg = new DeleteDirEntriesMsgEx(); } break;
case NETMSGTYPE_CreateDefDirInodes: { msg = new CreateDefDirInodesMsgEx(); } break;
case NETMSGTYPE_FixInodeOwners: { msg = new FixInodeOwnersMsgEx(); } break;
case NETMSGTYPE_FixInodeOwnersInDentry: { msg = new FixInodeOwnersInDentryMsgEx(); } break;
case NETMSGTYPE_LinkToLostAndFound: { msg = new LinkToLostAndFoundMsgEx(); } break;
case NETMSGTYPE_CreateEmptyContDirs: { msg = new CreateEmptyContDirsMsgEx(); } break;
case NETMSGTYPE_UpdateFileAttribs: { msg = new UpdateFileAttribsMsgEx(); } break;
case NETMSGTYPE_UpdateDirAttribs: { msg = new UpdateDirAttribsMsgEx(); } break;
case NETMSGTYPE_RemoveInodes: { msg = new RemoveInodesMsgEx(); } break;
case NETMSGTYPE_RecreateFsIDs: { msg = new RecreateFsIDsMsgEx(); } break;
case NETMSGTYPE_RecreateDentries: { msg = new RecreateDentriesMsgEx(); } break;
case NETMSGTYPE_FsckSetEventLogging: { msg = new FsckSetEventLoggingMsgEx(); } break;
case NETMSGTYPE_AdjustChunkPermissions: { msg = new AdjustChunkPermissionsMsgEx(); } break;
case NETMSGTYPE_CheckAndRepairDupInode: { msg = new CheckAndRepairDupInodeMsgEx(); } break;
default:
{
msg = new SimpleMsg(NETMSGTYPE_Invalid);
} break;
}
return std::unique_ptr<NetMessage>(msg);
}

View File

@@ -0,0 +1,14 @@
#pragma once
#include <common/Common.h>
#include <common/net/message/AbstractNetMessageFactory.h>
class NetMessageFactory : public AbstractNetMessageFactory
{
public:
NetMessageFactory() {}
protected:
virtual std::unique_ptr<NetMessage> createFromMsgType(unsigned short msgType) const override;
} ;

View File

@@ -0,0 +1,24 @@
#include <program/Program.h>
#include "AckMsgEx.h"
bool AckMsgEx::processIncoming(ResponseContext& ctx)
{
#ifdef BEEGFS_DEBUG
const char* logContext = "Ack incoming";
#endif //BEEGFS_DEBUG
LOG_DEBUG(logContext, 5, std::string("Value: ") + getValue() );
AcknowledgmentStore* ackStore = Program::getApp()->getAckStore();
ackStore->receivedAck(getValue() );
App* app = Program::getApp();
app->getNodeOpStats()->updateNodeOp(ctx.getSocket()->getPeerIP(), MetaOpCounter_ACK,
getMsgHeaderUserID() );
// note: this message does not require a response
return true;
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include <common/net/message/control/AckMsg.h>
// see class AcknowledgeableMsg (fhgfs_common) for a short description
class AckMsgEx : public AckMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,21 @@
#include <program/Program.h>
#include "SetChannelDirectMsgEx.h"
bool SetChannelDirectMsgEx::processIncoming(ResponseContext& ctx)
{
#ifdef BEEGFS_DEBUG
const char* logContext = "SetChannelDirect incoming";
LOG_DEBUG(logContext, 5, std::string("Value: ") + StringTk::intToStr(getValue() ) );
#endif // BEEGFS_DEBUG
ctx.getSocket()->setIsDirect(getValue() );
App* app = Program::getApp();
app->getNodeOpStats()->updateNodeOp(ctx.getSocket()->getPeerIP(), MetaOpCounter_SETCHANNELDIRECT,
getMsgHeaderUserID() );
return true;
}

View File

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

View File

@@ -0,0 +1,213 @@
#include "AdjustChunkPermissionsMsgEx.h"
#include <program/Program.h>
#include <common/net/message/storage/attribs/SetLocalAttrMsg.h>
#include <common/net/message/storage/attribs/SetLocalAttrRespMsg.h>
#include <common/storage/striping/Raid0Pattern.h>
#include <components/worker/SetChunkFileAttribsWork.h>
bool AdjustChunkPermissionsMsgEx::processIncoming(ResponseContext& ctx)
{
LogContext log("Incoming AdjustChunkPermissionsMsg");
MetaStore *metaStore = Program::getApp()->getMetaStore();
unsigned hashDirNum = this->getHashDirNum();
unsigned maxEntries = this->getMaxEntries();
int64_t lastHashDirOffset = this->getLastHashDirOffset();
int64_t lastContDirOffset = this->getLastContDirOffset();
std::string currentContDirID = this->getCurrentContDirID();
int64_t newHashDirOffset = 0;
int64_t newContDirOffset = 0;
unsigned errorCount = 0;
unsigned readOutEntries = 0;
bool hasNext;
if ( currentContDirID.empty() )
{
hasNext = StorageTkEx::getNextContDirID(hashDirNum, getIsBuddyMirrored(), lastHashDirOffset,
&currentContDirID, &newHashDirOffset);
if ( hasNext )
{
lastHashDirOffset = newHashDirOffset;
}
}
else
hasNext = true;
while ( hasNext )
{
std::string parentID = currentContDirID;
unsigned remainingEntries = maxEntries - readOutEntries;
StringList entryNames;
bool parentDirInodeIsTemp = false;
FileIDLock dirLock;
if (getIsBuddyMirrored())
dirLock = {Program::getApp()->getMirroredSessions()->getEntryLockStore(), parentID, false};
DirInode* parentDirInode = metaStore->referenceDir(parentID, getIsBuddyMirrored(), true);
// it could be, that parentDirInode does not exist
// in fsck we create a temporary inode for this case
if ( unlikely(!parentDirInode) )
{
log.log(
Log_NOTICE,
"Could not reference directory. EntryID: " + parentID
+ " => using temporary directory inode ");
// create temporary inode
int mode = S_IFDIR | S_IRWXU;
UInt16Vector stripeTargets;
Raid0Pattern stripePattern(0, stripeTargets, 0);
parentDirInode = new DirInode(parentID, mode, 0, 0,
Program::getApp()->getLocalNode().getNumID(), stripePattern, getIsBuddyMirrored());
parentDirInodeIsTemp = true;
}
if ( parentDirInode->listIncremental(lastContDirOffset, remainingEntries, &entryNames,
&newContDirOffset) == FhgfsOpsErr_SUCCESS )
{
lastContDirOffset = newContDirOffset;
readOutEntries += entryNames.size();
}
else
{
log.log(Log_WARNING, "Could not list contents of directory. EntryID: " + parentID);
}
// actually process the entries; for the dentry part we only need to know if it is a file
// with inlined inode data
for ( StringListIter namesIter = entryNames.begin(); namesIter != entryNames.end();
namesIter++ )
{
std::string filename = MetaStorageTk::getMetaDirEntryPath(
getIsBuddyMirrored()
? Program::getApp()->getBuddyMirrorDentriesPath()->str()
: Program::getApp()->getDentriesPath()->str(), parentID) + "/" + *namesIter;
EntryInfo entryInfo;
FileInodeStoreData inodeDiskData;
auto [getEntryRes, isFileOpen] = metaStore->getEntryData(parentDirInode, *namesIter, &entryInfo,
&inodeDiskData);
inodeDiskData.setDynamicOrigParentEntryID(parentID);
if (getEntryRes == FhgfsOpsErr_SUCCESS ||
getEntryRes == FhgfsOpsErr_DYNAMICATTRIBSOUTDATED )
{
DirEntryType entryType = entryInfo.getEntryType();
// we only care if inode data is present
if ( (DirEntryType_ISFILE(entryType)) && (entryInfo.getIsInlined() ) )
{
const std::string& inodeID = inodeDiskData.getEntryID();
unsigned userID = inodeDiskData.getInodeStatData()->getUserID();
unsigned groupID = inodeDiskData.getInodeStatData()->getGroupID();
StripePattern* pattern = inodeDiskData.getStripePattern();
PathInfo pathInfo;
inodeDiskData.getPathInfo(&pathInfo);
if ( !this->sendSetAttrMsg(inodeID, userID, groupID, &pathInfo, pattern) )
errorCount++;
}
}
else
{
log.log(Log_WARNING, "Unable to create dir entry from entry with name " + *namesIter
+ " in directory with ID " + parentID);
}
}
if ( parentDirInodeIsTemp )
SAFE_DELETE(parentDirInode);
else
metaStore->releaseDir(parentID);
if ( entryNames.size() < remainingEntries )
{
// directory is at the end => proceed with next
hasNext = StorageTkEx::getNextContDirID(hashDirNum, getIsBuddyMirrored(),
lastHashDirOffset, &currentContDirID, &newHashDirOffset);
if ( hasNext )
{
lastHashDirOffset = newHashDirOffset;
lastContDirOffset = 0;
}
}
else
{
// there are more to come, but we need to exit the loop now, because maxCount is reached
hasNext = false;
}
}
ctx.sendResponse(
AdjustChunkPermissionsRespMsg(readOutEntries, currentContDirID, lastHashDirOffset,
lastContDirOffset, errorCount) );
return true;
}
bool AdjustChunkPermissionsMsgEx::sendSetAttrMsg(const std::string& entryID, unsigned userID,
unsigned groupID, PathInfo* pathInfo, StripePattern* pattern)
{
const char* logContext = "AdjustChunkPermissionsMsgEx::sendSetAttrMsg";
MultiWorkQueue* slaveQueue = Program::getApp()->getCommSlaveQueue();
int validAttribs = SETATTR_CHANGE_USERID | SETATTR_CHANGE_GROUPID; // only interested in these
SettableFileAttribs attribs;
attribs.userID = userID;
attribs.groupID = groupID;
const UInt16Vector* stripeTargets = pattern->getStripeTargetIDs();
size_t numTargetWorks = stripeTargets->size();
FhgfsOpsErrVec nodeResults(numTargetWorks);
SynchronizedCounter counter;
// generate work for storage targets...
for(size_t i=0; i < numTargetWorks; i++)
{
SetChunkFileAttribsWork* work = new SetChunkFileAttribsWork(
entryID, validAttribs, &attribs, false, pattern, (*stripeTargets)[i], pathInfo,
NULL, &(nodeResults[i]), &counter);
work->setQuotaChown(true);
work->setMsgUserID(getMsgHeaderUserID() );
slaveQueue->addDirectWork(work);
}
// wait for work completion...
counter.waitForCount(numTargetWorks);
// check target results...
for(size_t i=0; i < numTargetWorks; i++)
{
if(unlikely(nodeResults[i] != FhgfsOpsErr_SUCCESS) )
{
LogContext(logContext).log(Log_WARNING,
"Problems occurred during setting of chunk file attribs. "
"fileID: " + entryID );
return false;
}
}
return true;
}

View File

@@ -0,0 +1,17 @@
#pragma once
#include <common/net/message/fsck/AdjustChunkPermissionsMsg.h>
#include <common/net/message/fsck/AdjustChunkPermissionsRespMsg.h>
#include <common/storage/PathInfo.h>
#include <common/storage/striping/StripePattern.h>
class AdjustChunkPermissionsMsgEx : public AdjustChunkPermissionsMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
private:
bool sendSetAttrMsg(const std::string& entryID, unsigned userID, unsigned groupID,
PathInfo* pathInfo, StripePattern* pattern);
};

View File

@@ -0,0 +1,38 @@
#include <program/Program.h>
#include <common/net/message/fsck/CheckAndRepairDupInodeRespMsg.h>
#include "CheckAndRepairDupInodeMsgEx.h"
bool CheckAndRepairDupInodeMsgEx::processIncoming(ResponseContext& ctx)
{
MetaStore* metaStore = Program::getApp()->getMetaStore();
EntryLockStore* entryLockStore = Program::getApp()->getMirroredSessions()->getEntryLockStore();
StringList failedIDList;
for (const auto& inode : getDuplicateInodes())
{
const std::string& entryID = inode.getID();
const std::string& parentEntryID = inode.getParentDirID();
const bool isBuddyMirrored = inode.getIsBuddyMirrored();
FileIDLock dirLock = {entryLockStore, parentEntryID, true};
FileIDLock fileLock = {entryLockStore, entryID, true};
EntryInfo fileInfo(NumNodeID(0), parentEntryID, entryID, std::string(""), DirEntryType_REGULARFILE, 0);
fileInfo.setBuddyMirroredFlag(isBuddyMirrored);
DirInode* parentDir = metaStore->referenceDir(parentEntryID, isBuddyMirrored, true);
FhgfsOpsErr repairRes = metaStore->checkAndRepairDupFileInode(*parentDir, &fileInfo);
if (repairRes != FhgfsOpsErr_SUCCESS)
{
failedIDList.push_back(entryID);
}
metaStore->releaseDir(parentDir->getID());
}
ctx.sendResponse(CheckAndRepairDupInodeRespMsg(std::move(failedIDList)));
return true;
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include <common/net/message/fsck/CheckAndRepairDupInodeMsg.h>
class CheckAndRepairDupInodeMsgEx : public CheckAndRepairDupInodeMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,60 @@
#include "CreateDefDirInodesMsgEx.h"
#include <program/Program.h>
#include <toolkit/BuddyCommTk.h>
bool CreateDefDirInodesMsgEx::processIncoming(ResponseContext& ctx)
{
LogContext log("CreateDefDirInodesMsg incoming");
App* app = Program::getApp();
Config* cfg = app->getConfig();
StringList failedInodeIDs;
FsckDirInodeList createdInodes;
for (auto it = items.begin(); it != items.end(); ++it)
{
const std::string& inodeID = std::get<0>(*it);
const bool isBuddyMirrored = std::get<1>(*it);
int mode = S_IFDIR | S_IRWXU;
unsigned userID = 0; // root
unsigned groupID = 0; // root
const NumNodeID ownerNodeID = isBuddyMirrored
? NumNodeID(app->getMetaBuddyGroupMapper()->getLocalGroupID())
: app->getLocalNode().getNumID();
UInt16Vector stripeTargets;
unsigned defaultChunkSize = cfg->getTuneDefaultChunkSize();
unsigned defaultNumStripeTargets = cfg->getTuneDefaultNumStripeTargets();
Raid0Pattern stripePattern(defaultChunkSize, stripeTargets, defaultNumStripeTargets);
// we try to create a new directory inode, with default values
FileIDLock dirLock;
if (isBuddyMirrored)
dirLock = {Program::getApp()->getMirroredSessions()->getEntryLockStore(), inodeID, true};
DirInode dirInode(inodeID, mode, userID, groupID, ownerNodeID, stripePattern,
isBuddyMirrored);
if ( dirInode.storeAsReplacementFile(inodeID) == FhgfsOpsErr_SUCCESS )
{
// try to refresh the metainfo (maybe a .cont directory was already present)
dirInode.refreshMetaInfo();
StatData statData;
dirInode.getStatData(statData);
FsckDirInode fsckDirInode(inodeID, "", NumNodeID(), ownerNodeID, statData.getFileSize(),
statData.getNumHardlinks(), stripeTargets, FsckStripePatternType_RAID0,
ownerNodeID, isBuddyMirrored, true, false);
createdInodes.push_back(fsckDirInode);
}
else
failedInodeIDs.push_back(inodeID);
}
ctx.sendResponse(CreateDefDirInodesRespMsg(&failedInodeIDs, &createdInodes) );
return true;
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include <common/storage/striping/Raid0Pattern.h>
#include <common/net/message/fsck/CreateDefDirInodesMsg.h>
#include <common/net/message/fsck/CreateDefDirInodesRespMsg.h>
class CreateDefDirInodesMsgEx : public CreateDefDirInodesMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,77 @@
#include "CreateEmptyContDirsMsgEx.h"
#include <program/Program.h>
#include <toolkit/BuddyCommTk.h>
bool CreateEmptyContDirsMsgEx::processIncoming(ResponseContext& ctx)
{
const char* logContext = "CreateEmptyContDirsMsg incoming";
App* app = Program::getApp();
MetaStore* metaStore = app->getMetaStore();
StringList failedIDs;
for (auto iter = items.begin(); iter != items.end(); iter++)
{
const std::string& dirID = std::get<0>(*iter);
const bool isBuddyMirrored = std::get<1>(*iter);
std::string contentsDirStr = MetaStorageTk::getMetaDirEntryPath(
isBuddyMirrored
? app->getBuddyMirrorDentriesPath()->str()
: app->getDentriesPath()->str(), dirID);
// create contents directory
int mkRes = mkdir(contentsDirStr.c_str(), 0755);
if ( mkRes != 0 )
{ // error
LOG(GENERAL, ERR, "Unable to create contents directory.", contentsDirStr, sysErr);
failedIDs.push_back(dirID);
continue;
}
// create the dirEntryID directory, which allows access to inlined inodes via dirID access
std::string contentsDirIDStr = MetaStorageTk::getMetaDirEntryIDPath(contentsDirStr);
int mkDirIDRes = mkdir(contentsDirIDStr.c_str(), 0755);
if ( mkDirIDRes != 0 )
{ // error
LOG(GENERAL, ERR, "Unable to create dirEntryID directory.", contentsDirIDStr, sysErr);
failedIDs.push_back(dirID);
continue;
}
FileIDLock lock;
if (isBuddyMirrored)
lock = {Program::getApp()->getMirroredSessions()->getEntryLockStore(), dirID, true};
// update the dir attribs
DirInode* dirInode = metaStore->referenceDir(dirID, isBuddyMirrored, true);
if (!dirInode)
{
LOG(GENERAL, ERR, "Unable to reference directory.", dirID);
failedIDs.push_back(dirID);
continue;
}
FhgfsOpsErr refreshRes = dirInode->refreshMetaInfo();
if (refreshRes != FhgfsOpsErr_SUCCESS)
{
LogContext(logContext).log(Log_NOTICE, "Unable to refresh contents directory metadata: "
+ contentsDirStr + ". " + "SysErr: " + System::getErrString());
}
metaStore->releaseDir(dirID);
}
ctx.sendResponse(CreateEmptyContDirsRespMsg(&failedIDs) );
return true;
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include <common/storage/striping/Raid0Pattern.h>
#include <common/net/message/fsck/CreateEmptyContDirsMsg.h>
#include <common/net/message/fsck/CreateEmptyContDirsRespMsg.h>
class CreateEmptyContDirsMsgEx : public CreateEmptyContDirsMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,66 @@
#include "DeleteDirEntriesMsgEx.h"
#include <program/Program.h>
#include <common/fsck/FsckDirEntry.h>
#include <toolkit/BuddyCommTk.h>
#include <boost/lexical_cast.hpp>
bool DeleteDirEntriesMsgEx::processIncoming(ResponseContext& ctx)
{
LogContext log("DeleteDirEntriesMsgEx");
MetaStore* metaStore = Program::getApp()->getMetaStore();
EntryLockStore* entryLockStore = Program::getApp()->getMirroredSessions()->getEntryLockStore();
FsckDirEntryList& entries = getEntries();
FsckDirEntryList failedEntries;
for ( FsckDirEntryListIter iter = entries.begin(); iter != entries.end(); iter++ )
{
const std::string& parentID = iter->getParentDirID();
const std::string& entryName = iter->getName();
FsckDirEntryType dirEntryType = iter->getEntryType();
FileIDLock dirLock;
ParentNameLock dentryLock;
if (iter->getIsBuddyMirrored())
{
dirLock = {entryLockStore, parentID, true};
dentryLock = {entryLockStore, parentID, entryName};
}
DirInode* parentDirInode = metaStore->referenceDir(parentID, iter->getIsBuddyMirrored(),
true);
if (!parentDirInode)
{
log.log(3,"Failed to delete directory entry; ParentID: " + parentID + "; EntryName: " +
entryName + " - ParentID does not exist");
failedEntries.push_back(*iter);
continue;
}
FhgfsOpsErr unlinkRes;
if (FsckDirEntryType_ISDIR(dirEntryType))
unlinkRes = parentDirInode->removeDir(entryName, NULL);
else
unlinkRes = parentDirInode->unlinkDirEntry(entryName, NULL,
DirEntry_UNLINK_ID_AND_FILENAME);
metaStore->releaseDir(parentID);
if (unlinkRes != FhgfsOpsErr_SUCCESS )
{
log.logErr("Failed to delete directory entry; ParentID: " + parentID + "; EntryName: " +
entryName + "; Err: " + boost::lexical_cast<std::string>(unlinkRes));
failedEntries.push_back(*iter);
}
}
ctx.sendResponse(DeleteDirEntriesRespMsg(&failedEntries) );
return true;
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include <common/net/message/NetMessage.h>
#include <common/net/message/fsck/DeleteDirEntriesMsg.h>
#include <common/net/message/fsck/DeleteDirEntriesRespMsg.h>
class DeleteDirEntriesMsgEx : public DeleteDirEntriesMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,77 @@
#include "FixInodeOwnersInDentryMsgEx.h"
#include <common/storage/striping/Raid0Pattern.h>
#include <common/fsck/FsckDirEntry.h>
#include <program/Program.h>
#include <toolkit/BuddyCommTk.h>
bool FixInodeOwnersInDentryMsgEx::processIncoming(ResponseContext& ctx)
{
LogContext log("FixInodeOwnersInDentryMsgEx");
MetaStore* metaStore = Program::getApp()->getMetaStore();
EntryLockStore* entryLockStore = Program::getApp()->getMirroredSessions()->getEntryLockStore();
FsckDirEntryList& dentries = getDentries();
FsckDirEntryList failedEntries;
FsckDirEntryListIter dentryIter = dentries.begin();
NumNodeIDListIter ownerIter = getOwners().begin();
while (dentryIter != dentries.end() )
{
const std::string& parentID = dentryIter->getParentDirID();
const std::string& entryName = dentryIter->getName();
ParentNameLock lock;
if (dentryIter->getIsBuddyMirrored())
lock = {entryLockStore, parentID, entryName};
bool parentDirInodeIsTemp = false;
DirInode* parentDirInode = metaStore->referenceDir(parentID,
dentryIter->getIsBuddyMirrored(), true);
// it could be, that parentDirInode does not exist
// in fsck we create a temporary inode for this case, so that we can modify the dentry
// hopefully, the inode itself will get fixed later
if (unlikely(!parentDirInode))
{
log.log(Log_NOTICE,
"Failed to update directory entry. Parent directory could not be "
"referenced. parentID: " + parentID + " entryName: " + entryName
+ " => Using temporary inode");
// create temporary inode
int mode = S_IFDIR | S_IRWXU;
UInt16Vector stripeTargets;
Raid0Pattern stripePattern(0, stripeTargets, 0);
parentDirInode = new DirInode(parentID, mode, 0, 0,
Program::getApp()->getLocalNode().getNumID(), stripePattern,
dentryIter->getIsBuddyMirrored());
parentDirInodeIsTemp = true;
}
FhgfsOpsErr updateRes = parentDirInode->setOwnerNodeID(entryName, *ownerIter);
if (updateRes != FhgfsOpsErr_SUCCESS )
{
log.log(Log_WARNING, "Failed to update directory entry. parentID: " + parentID +
" entryName: " + entryName);
failedEntries.push_back(*dentryIter);
}
if (parentDirInodeIsTemp)
SAFE_DELETE(parentDirInode);
else
metaStore->releaseDir(parentID);
dentryIter++;
ownerIter++;
}
ctx.sendResponse(FixInodeOwnersInDentryRespMsg(&failedEntries) );
return true;
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include <common/net/message/NetMessage.h>
#include <common/net/message/fsck/FixInodeOwnersInDentryMsg.h>
#include <common/net/message/fsck/FixInodeOwnersInDentryRespMsg.h>
class FixInodeOwnersInDentryMsgEx : public FixInodeOwnersInDentryMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,51 @@
#include "FixInodeOwnersMsgEx.h"
#include <common/fsck/FsckDirEntry.h>
#include <program/Program.h>
#include <toolkit/BuddyCommTk.h>
bool FixInodeOwnersMsgEx::processIncoming(ResponseContext& ctx)
{
const char* logContext = "FixInodeOwnersMsgEx incoming";
MetaStore* metaStore = Program::getApp()->getMetaStore();
EntryLockStore* entryLockStore = Program::getApp()->getMirroredSessions()->getEntryLockStore();
FsckDirInodeList& inodes = getInodes();
FsckDirInodeList failedInodes;
for ( FsckDirInodeListIter iter = inodes.begin(); iter != inodes.end(); iter++ )
{
const std::string& entryID = iter->getID();
NumNodeID ownerNodeID = iter->getOwnerNodeID();
FileIDLock lock;
if (iter->getIsBuddyMirrored())
lock = {entryLockStore, entryID, true};
DirInode* dirInode = metaStore->referenceDir(entryID, iter->getIsBuddyMirrored(), true);
if (unlikely(!dirInode))
{
LogContext(logContext).log(Log_WARNING, "Failed to update directory inode. Inode could"
" not be referenced. entryID: " + entryID);
continue; // continue to next entry
}
bool updateRes = dirInode->setOwnerNodeID(ownerNodeID);
metaStore->releaseDir(entryID);
if (!updateRes)
{
LogContext(logContext).log(Log_WARNING, "Failed to update directory inode. entryID: "
+ entryID);
failedInodes.push_back(*iter);
}
}
ctx.sendResponse(FixInodeOwnersRespMsg(&failedInodes) );
return true;
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include <common/net/message/NetMessage.h>
#include <common/net/message/fsck/FixInodeOwnersMsg.h>
#include <common/net/message/fsck/FixInodeOwnersRespMsg.h>
class FixInodeOwnersMsgEx : public FixInodeOwnersMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,34 @@
#include <components/ModificationEventFlusher.h>
#include <program/Program.h>
#include "FsckSetEventLoggingMsgEx.h"
bool FsckSetEventLoggingMsgEx::processIncoming(ResponseContext& ctx)
{
LogContext log("FsckSetEventLoggingMsg incoming");
App* app = Program::getApp();
ModificationEventFlusher* flusher = app->getModificationEventFlusher();
bool result;
bool loggingEnabled;
bool missedEvents;
bool enableLogging = this->getEnableLogging();
if (enableLogging)
{
loggingEnabled = flusher->enableLogging(getPortUDP(), getNicList(), getForceRestart());
result = true; // (always true when logging is enabled)
missedEvents = true; // (value ignored when logging is enabled)
}
else
{ // disable logging
result = flusher->disableLogging();
loggingEnabled = false; // (value ignored when logging is disabled)
missedEvents = flusher->getFsckMissedEvent();
}
ctx.sendResponse(FsckSetEventLoggingRespMsg(result, loggingEnabled, missedEvents));
return true;
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include <common/net/message/fsck/FsckSetEventLoggingMsg.h>
#include <common/net/message/fsck/FsckSetEventLoggingRespMsg.h>
class FsckSetEventLoggingMsgEx : public FsckSetEventLoggingMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,108 @@
#include "LinkToLostAndFoundMsgEx.h"
#include <common/net/message/fsck/RemoveInodesMsg.h>
#include <common/net/message/fsck/RemoveInodesRespMsg.h>
#include <program/Program.h>
#include <toolkit/BuddyCommTk.h>
bool LinkToLostAndFoundMsgEx::processIncoming(ResponseContext& ctx)
{
if (FsckDirEntryType_ISDIR(this->getEntryType()))
{
FsckDirEntryList createdDirEntries;
FsckDirInodeList failedInodes;
linkDirInodes(&failedInodes, &createdDirEntries);
ctx.sendResponse(LinkToLostAndFoundRespMsg(&failedInodes, &createdDirEntries) );
}
else
{
LOG(COMMUNICATION, ERR, "LinkToLostAndFoundMsg received for non-inlined file inode.",
("from", ctx.peerName()));
return false;
}
return true;
}
void LinkToLostAndFoundMsgEx::linkDirInodes(FsckDirInodeList* outFailedInodes,
FsckDirEntryList* outCreatedDirEntries)
{
const char* logContext = "LinkToLostAndFoundMsgEx (linkDirInodes)";
NumNodeID localNodeNumID = Program::getApp()->getLocalNode().getNumID();
FsckDirInodeList& dirInodes = getDirInodes();
MetaStore* metaStore = Program::getApp()->getMetaStore();
EntryLockStore* entryLockStore = Program::getApp()->getMirroredSessions()->getEntryLockStore();
EntryInfo* lostAndFoundInfo = this->getLostAndFoundInfo();
DirInode* lostAndFoundDir = metaStore->referenceDir(lostAndFoundInfo->getEntryID(),
lostAndFoundInfo->getIsBuddyMirrored(), true);
if ( !lostAndFoundDir )
{
*outFailedInodes = dirInodes;
return;
}
else
{
for ( FsckDirInodeListIter iter = dirInodes.begin(); iter != dirInodes.end(); iter++ )
{
const std::string& entryID = iter->getID();
NumNodeID ownerNodeID = iter->getOwnerNodeID();
DirEntryType entryType = DirEntryType_DIRECTORY;
DirEntry newDirEntry(entryType, entryID, entryID, ownerNodeID);
FileIDLock lock;
if (iter->getIsBuddyMirrored())
{
lock = {entryLockStore, entryID, true};
newDirEntry.setBuddyMirrorFeatureFlag();
}
bool makeRes = lostAndFoundDir->makeDirEntry(newDirEntry);
// stat the new file to get device and inode information
std::string filename = MetaStorageTk::getMetaDirEntryPath(
lostAndFoundInfo->getIsBuddyMirrored()
? Program::getApp()->getBuddyMirrorDentriesPath()->str()
: Program::getApp()->getDentriesPath()->str(),
lostAndFoundInfo->getEntryID()) + "/" + entryID;
struct stat statBuf;
int statRes = stat(filename.c_str(), &statBuf);
int saveDevice;
uint64_t saveInode;
if ( likely(!statRes) )
{
saveDevice = statBuf.st_dev;
saveInode = statBuf.st_ino;
}
else
{
saveDevice = 0;
saveInode = 0;
LogContext(logContext).log(Log_CRITICAL,
"Could not stat dir entry file; entryID: " + entryID + ";filename: " + filename);
}
if ( makeRes != FhgfsOpsErr_SUCCESS )
outFailedInodes->push_back(*iter);
else
{
std::string parentID = lostAndFoundInfo->getEntryID();
FsckDirEntry newFsckDirEntry(entryID, entryID, parentID, localNodeNumID,
ownerNodeID, FsckDirEntryType_DIRECTORY, false, localNodeNumID,
saveDevice, saveInode, lostAndFoundInfo->getIsBuddyMirrored());
outCreatedDirEntries->push_back(newFsckDirEntry);
}
}
lostAndFoundDir->refreshMetaInfo();
metaStore->releaseDir(lostAndFoundInfo->getEntryID() );
}
}

View File

@@ -0,0 +1,24 @@
#pragma once
#include <common/net/message/NetMessage.h>
#include <common/net/message/fsck/LinkToLostAndFoundMsg.h>
#include <common/net/message/fsck/LinkToLostAndFoundRespMsg.h>
#include <common/net/message/storage/creating/MkDirMsg.h>
#include <common/net/message/storage/creating/MkDirRespMsg.h>
#include <common/storage/StorageErrors.h>
#include <dirent.h>
class LinkToLostAndFoundMsgEx : public LinkToLostAndFoundMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
private:
void linkDirInodes(FsckDirInodeList* outFailedInodes, FsckDirEntryList* outCreatedDirEntries);
void linkFileInodes(FsckFileInodeList* outFailedInodes,
FsckDirEntryList* outCreatedDirEntries);
FhgfsOpsErr deleteInode(std::string& entryID, uint16_t ownerNodeID);
};

View File

@@ -0,0 +1,141 @@
#include "RecreateDentriesMsgEx.h"
#include <common/fsck/FsckDirEntry.h>
#include <common/fsck/FsckFsID.h>
#include <program/Program.h>
#include <toolkit/BuddyCommTk.h>
bool RecreateDentriesMsgEx::processIncoming(ResponseContext& ctx)
{
LogContext log("RecreateDentriesMsgEx");
App* app = Program::getApp();
MetaStore* metaStore = app->getMetaStore();
EntryLockStore* entryLockStore = app->getMirroredSessions()->getEntryLockStore();
FsckFsIDList& fsIDs = getFsIDs();
FsckFsIDList failedCreates;
FsckDirEntryList createdDentries;
FsckFileInodeList createdInodes;
for ( FsckFsIDListIter iter = fsIDs.begin(); iter != fsIDs.end(); iter++ )
{
NumNodeID localNodeID = iter->getIsBuddyMirrored()
? NumNodeID(app->getMetaBuddyGroupMapper()->getLocalGroupID())
: app->getLocalNodeNumID();
std::string parentPath = MetaStorageTk::getMetaDirEntryPath(
iter->getIsBuddyMirrored()
? app->getBuddyMirrorDentriesPath()->str()
: app->getDentriesPath()->str(), iter->getParentDirID());
std::string dirEntryIDFilePath = MetaStorageTk::getMetaDirEntryIDPath(parentPath) + "/"
+ iter->getID();
// the name is lost, so we take the ID as new name
std::string dirEntryNameFilePath = parentPath + "/" + iter->getID();
// before we link, let's see if we can open the parent dir, otherwise we should not mess
// around here
const std::string& dirID = iter->getParentDirID();
FileIDLock dirLock;
ParentNameLock dentryLock;
if (iter->getIsBuddyMirrored())
{
dirLock = {entryLockStore, dirID, true};
dentryLock = {entryLockStore, dirID, iter->getID()};
}
DirInode* parentDirInode = metaStore->referenceDir(dirID, iter->getIsBuddyMirrored(), false);
if (!parentDirInode)
{
log.logErr("Unable to reference parent directory; ID: " + iter->getParentDirID());
failedCreates.push_back(*iter);
continue;
}
// link the dentry-by-name file
int linkRes = link(dirEntryIDFilePath.c_str(), dirEntryNameFilePath.c_str());
if ( linkRes )
{
// error occured while linking
log.logErr(
"Failed to link dentry file; ParentID: " + iter->getParentDirID() + "; ID: "
+ iter->getID());
failedCreates.push_back(*iter);
metaStore->releaseDir(dirID);
continue;
}
// linking was OK => gather dentry (and inode) data, so fsck can add it
DirEntry dirEntry(iter->getID());
bool getRes = parentDirInode->getDentry(iter->getID(), dirEntry);
if (!getRes)
{
log.logErr(
"Could not read the created dentry file; ParentID: " + iter->getParentDirID() + "; ID: "
+ iter->getID());
failedCreates.push_back(*iter);
metaStore->releaseDir(dirID);
continue;
}
// create the FsckDirEntry
FsckDirEntry fsckDirEntry(dirEntry.getID(), dirEntry.getName(), iter->getParentDirID(),
localNodeID, localNodeID,
FsckTk::DirEntryTypeToFsckDirEntryType(dirEntry.getEntryType()), true, localNodeID,
iter->getSaveDevice(), iter->getSaveInode(), iter->getIsBuddyMirrored());
createdDentries.push_back(fsckDirEntry);
// inlined inode data should be present, because otherwise dentry-by-id file would not
// exist, and we could not get this far
FileInodeStoreData* inodeData = dirEntry.getInodeStoreData();
if ( inodeData )
{
int pathInfoFlags;
if (inodeData->getOrigFeature() == FileInodeOrigFeature_TRUE)
pathInfoFlags = PATHINFO_FEATURE_ORIG;
else
pathInfoFlags = PATHINFO_FEATURE_ORIG_UNKNOWN;
PathInfo pathInfo(inodeData->getOrigUID(), inodeData->getOrigParentEntryID(),
pathInfoFlags);
UInt16Vector targetIDs;
unsigned chunkSize;
FsckStripePatternType fsckStripePatternType = FsckTk::stripePatternToFsckStripePattern(
inodeData->getPattern(), &chunkSize, &targetIDs);
FsckFileInode fsckFileInode(inodeData->getEntryID(), iter->getParentDirID(),
localNodeID, pathInfo, inodeData->getInodeStatData(),
inodeData->getInodeStatData()->getNumBlocks(), targetIDs, fsckStripePatternType,
chunkSize, localNodeID, iter->getSaveInode(), iter->getSaveDevice(), true,
iter->getIsBuddyMirrored(), true, false);
createdInodes.push_back(fsckFileInode);
}
else
{
log.logErr(
"No inlined inode data found; parentID: " + iter->getParentDirID() + "; ID: "
+ iter->getID());
}
metaStore->releaseDir(dirID);
}
ctx.sendResponse(RecreateDentriesRespMsg(&failedCreates, &createdDentries, &createdInodes) );
return true;
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include <common/net/message/NetMessage.h>
#include <common/net/message/fsck/RecreateDentriesMsg.h>
#include <common/net/message/fsck/RecreateDentriesRespMsg.h>
class RecreateDentriesMsgEx : public RecreateDentriesMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,65 @@
#include "RecreateFsIDsMsgEx.h"
#include <common/fsck/FsckDirEntry.h>
#include <program/Program.h>
#include <toolkit/BuddyCommTk.h>
bool RecreateFsIDsMsgEx::processIncoming(ResponseContext& ctx)
{
EntryLockStore* entryLockStore = Program::getApp()->getMirroredSessions()->getEntryLockStore();
LogContext log("RecreateFsIDsMsgEx");
FsckDirEntryList& entries = getEntries();
FsckDirEntryList failedEntries;
for ( FsckDirEntryListIter iter = entries.begin(); iter != entries.end(); iter++ )
{
const std::string& parentID = iter->getParentDirID();
const std::string& entryName = iter->getName();
const std::string& entryID = iter->getID();
std::string dirEntryPath = MetaStorageTk::getMetaDirEntryPath(
iter->getIsBuddyMirrored()
? Program::getApp()->getBuddyMirrorDentriesPath()->str()
: Program::getApp()->getDentriesPath()->str(), parentID);
std::string dirEntryIDFilePath = MetaStorageTk::getMetaDirEntryIDPath(dirEntryPath) +
"/" + entryID;
std::string dirEntryNameFilePath = dirEntryPath + "/" + entryName;
FileIDLock dirLock(entryLockStore, parentID, true);
ParentNameLock dentryLock(entryLockStore, parentID, entryName);
FileIDLock fileLock(entryLockStore, entryID, true);
// delete the old dentry-by-id file link (if one existed)
int removeRes = unlink(dirEntryIDFilePath.c_str());
if ( (removeRes) && (errno != ENOENT) )
{
log.logErr(
"Failed to recreate dentry-by-id file for directory entry; ParentID: " + parentID
+ "; EntryName: " + entryName
+ " - Could not delete old, faulty dentry-by-id file link");
failedEntries.push_back(*iter);
continue;
}
// link a new one
int linkRes = link(dirEntryNameFilePath.c_str(), dirEntryIDFilePath.c_str());
if ( linkRes )
{
log.logErr(
"Failed to recreate dentry-by-id file for directory entry; ParentID: " + parentID
+ "; EntryName: " + entryName + " - File could not be linked");
failedEntries.push_back(*iter);
continue;
}
}
ctx.sendResponse(RecreateFsIDsRespMsg(&failedEntries) );
return true;
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include <common/net/message/NetMessage.h>
#include <common/net/message/fsck/RecreateFsIDsMsg.h>
#include <common/net/message/fsck/RecreateFsIDsRespMsg.h>
class RecreateFsIDsMsgEx : public RecreateFsIDsMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,44 @@
#include <program/Program.h>
#include <common/net/message/fsck/RemoveInodesRespMsg.h>
#include <common/toolkit/ZipIterator.h>
#include <toolkit/BuddyCommTk.h>
#include "RemoveInodesMsgEx.h"
bool RemoveInodesMsgEx::processIncoming(ResponseContext& ctx)
{
MetaStore* metaStore = Program::getApp()->getMetaStore();
EntryLockStore* entryLockStore = Program::getApp()->getMirroredSessions()->getEntryLockStore();
StringList failedIDList;
for (auto it = items.begin(); it != items.end(); ++it)
{
const std::string& entryID = std::get<0>(*it);
const DirEntryType entryType = std::get<1>(*it);
const bool isBuddyMirrored = std::get<2>(*it);
FhgfsOpsErr rmRes;
FileIDLock dirLock;
FileIDLock fileLock;
if (entryType == DirEntryType_DIRECTORY)
{
dirLock = {entryLockStore, entryID, true};
rmRes = metaStore->removeDirInode(entryID, isBuddyMirrored);
}
else
{
fileLock = {entryLockStore, entryID, true};
rmRes = metaStore->fsckUnlinkFileInode(entryID, isBuddyMirrored);
}
if (rmRes != FhgfsOpsErr_SUCCESS)
failedIDList.push_back(entryID);
}
ctx.sendResponse(RemoveInodesRespMsg(std::move(failedIDList)));
return true;
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include <common/net/message/fsck/RemoveInodesMsg.h>
class RemoveInodesMsgEx : public RemoveInodesMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,269 @@
#include "RetrieveDirEntriesMsgEx.h"
#include <common/storage/striping/Raid0Pattern.h>
#include <net/msghelpers/MsgHelperStat.h>
#include <program/Program.h>
bool RetrieveDirEntriesMsgEx::processIncoming(ResponseContext& ctx)
{
LogContext log("Incoming RetrieveDirEntriesMsg");
unsigned hashDirNum = getHashDirNum();
std::string currentContDirID = getCurrentContDirID();
unsigned maxOutEntries = getMaxOutEntries();
int64_t lastContDirOffset = getLastContDirOffset();
int64_t lastHashDirOffset = getLastHashDirOffset();
int64_t newHashDirOffset;
int64_t newContDirOffset;
FsckContDirList contDirsOutgoing;
FsckDirEntryList dirEntriesOutgoing;
FsckFileInodeList inlinedFileInodesOutgoing;
unsigned readOutEntries = 0;
NumNodeID localNodeNumID = getIsBuddyMirrored()
? NumNodeID(Program::getApp()->getMetaBuddyGroupMapper()->getLocalGroupID())
: Program::getApp()->getLocalNode().getNumID();
MetaStore* metaStore = Program::getApp()->getMetaStore();
MirrorBuddyGroupMapper* bgm = Program::getApp()->getMetaBuddyGroupMapper();
if (getIsBuddyMirrored() &&
(bgm->getLocalBuddyGroup().secondTargetID
== Program::getApp()->getLocalNode().getNumID().val()
|| bgm->getLocalGroupID() == 0))
{
ctx.sendResponse(
RetrieveDirEntriesRespMsg(&contDirsOutgoing, &dirEntriesOutgoing,
&inlinedFileInodesOutgoing, currentContDirID, lastHashDirOffset, lastContDirOffset));
return true;
}
bool hasNext;
if ( currentContDirID.empty() )
{
hasNext = StorageTkEx::getNextContDirID(hashDirNum, getIsBuddyMirrored(), lastHashDirOffset,
&currentContDirID, &newHashDirOffset);
if ( hasNext )
{
lastHashDirOffset = newHashDirOffset;
// we found a new .cont directory => send it to fsck
FsckContDir contDir(currentContDirID, localNodeNumID, getIsBuddyMirrored());
contDirsOutgoing.push_back(contDir);
}
}
else
hasNext = true;
while ( hasNext )
{
std::string parentID = currentContDirID;
unsigned remainingOutNames = maxOutEntries - readOutEntries;
StringList entryNames;
bool parentDirInodeIsTemp = false;
DirInode* parentDirInode = metaStore->referenceDir(parentID, getIsBuddyMirrored(), true);
// it could be, that parentDirInode does not exist
// in fsck we create a temporary inode for this case, so that we can modify the dentry
// hopefully, the inode itself will get fixed later
if ( unlikely(!parentDirInode) )
{
log.log(
Log_NOTICE,
"Could not reference directory. EntryID: " + parentID
+ " => using temporary directory inode ");
// create temporary inode
int mode = S_IFDIR | S_IRWXU;
UInt16Vector stripeTargets;
Raid0Pattern stripePattern(0, stripeTargets, 0);
parentDirInode = new DirInode(parentID, mode, 0, 0,
Program::getApp()->getLocalNode().getNumID(), stripePattern, getIsBuddyMirrored());
parentDirInodeIsTemp = true;
}
if ( parentDirInode->listIncremental(lastContDirOffset, remainingOutNames, &entryNames,
&newContDirOffset) == FhgfsOpsErr_SUCCESS )
{
lastContDirOffset = newContDirOffset;
}
else
{
log.log(Log_WARNING, "Could not list contents of directory. EntryID: " + parentID);
}
// actually process the entries
for ( StringListIter namesIter = entryNames.begin(); namesIter != entryNames.end();
namesIter++ )
{
std::string filename = MetaStorageTk::getMetaDirEntryPath(
getIsBuddyMirrored()
? Program::getApp()->getBuddyMirrorDentriesPath()->str()
: Program::getApp()->getDentriesPath()->str(), parentID) + "/" + *namesIter;
// create a EntryInfo and put the information into an FsckDirEntry object
EntryInfo entryInfo;
FileInodeStoreData inodeDiskData;
bool hasInlinedInode = false;
int32_t saveDevice = 0;
uint64_t saveInode = 0;
auto [getEntryRes, isFileOpen] = metaStore->getEntryData(parentDirInode, *namesIter, &entryInfo,
&inodeDiskData);
if (getEntryRes == FhgfsOpsErr_SUCCESS ||
getEntryRes == FhgfsOpsErr_DYNAMICATTRIBSOUTDATED )
{
DirEntryType entryType = entryInfo.getEntryType();
const std::string& dentryID = entryInfo.getEntryID();
const std::string& dentryName = *namesIter;
NumNodeID dentryOwnerID = entryInfo.getOwnerNodeID();
FsckDirEntryType fsckEntryType = FsckTk::DirEntryTypeToFsckDirEntryType(entryType);
// stat the file to get device and inode information
struct stat statBuf;
int statRes = stat(filename.c_str(), &statBuf);
if (likely(!statRes))
{
saveDevice = statBuf.st_dev;
saveInode = statBuf.st_ino;
}
else
{
log.log(Log_CRITICAL, "Could not stat dir entry file; entryID: " + dentryID
+ ";filename: " + filename);
}
if ( (DirEntryType_ISFILE(entryType)) && (entryInfo.getIsInlined() ) )
{
hasInlinedInode = true;
}
FsckDirEntry fsckDirEntry(dentryID, dentryName, parentID, localNodeNumID,
dentryOwnerID, fsckEntryType, hasInlinedInode, localNodeNumID,
saveDevice, saveInode, entryInfo.getIsBuddyMirrored());
dirEntriesOutgoing.push_back(fsckDirEntry);
}
else
{
log.log(Log_WARNING, "Unable to create dir entry from entry with name " + *namesIter
+ " in directory with ID " + parentID);
}
// now, if the inode data is inlined we create an fsck inode object here
if ( hasInlinedInode )
{
std::string inodeID = inodeDiskData.getEntryID();
int pathInfoFlag;
if (inodeDiskData.getOrigFeature() == FileInodeOrigFeature_TRUE)
pathInfoFlag = PATHINFO_FEATURE_ORIG;
else
pathInfoFlag = PATHINFO_FEATURE_ORIG_UNKNOWN;
unsigned origUID = inodeDiskData.getOrigUID();
std::string origParentEntryID = inodeDiskData.getOrigParentEntryID();
PathInfo pathInfo(origUID, origParentEntryID, pathInfoFlag);
unsigned userID;
unsigned groupID;
int64_t fileSize;
unsigned numHardLinks;
uint64_t numBlocks;
StatData* statData;
StatData updatedStatData;
if (getEntryRes == FhgfsOpsErr_SUCCESS)
statData = inodeDiskData.getInodeStatData();
else
{
FhgfsOpsErr statRes = MsgHelperStat::stat(&entryInfo, true, getMsgHeaderUserID(),
updatedStatData);
if (statRes == FhgfsOpsErr_SUCCESS)
statData = &updatedStatData;
else
statData = NULL;
}
if ( statData )
{
userID = statData->getUserID();
groupID = statData->getGroupID();
fileSize = statData->getFileSize();
numHardLinks = statData->getNumHardlinks();
numBlocks = statData->getNumBlocks();
}
else
{
log.logErr(std::string("Unable to get stat data of inlined file inode: ") + inodeID
+ ". SysErr: " + System::getErrString());
userID = 0;
groupID = 0;
fileSize = 0;
numHardLinks = 0;
numBlocks = 0;
}
UInt16Vector stripeTargets;
unsigned chunkSize;
FsckStripePatternType stripePatternType = FsckTk::stripePatternToFsckStripePattern(
inodeDiskData.getPattern(), &chunkSize, &stripeTargets);
FsckFileInode fileInode(inodeID, parentID, localNodeNumID, pathInfo, userID, groupID,
fileSize, numHardLinks, numBlocks, stripeTargets, stripePatternType, chunkSize,
localNodeNumID, saveInode, saveDevice, true, entryInfo.getIsBuddyMirrored(),
true, inodeDiskData.getIsBuddyMirrored() != getIsBuddyMirrored());
inlinedFileInodesOutgoing.push_back(fileInode);
}
}
if ( parentDirInodeIsTemp )
SAFE_DELETE(parentDirInode);
else
metaStore->releaseDir(parentID);
if ( entryNames.size() < remainingOutNames )
{
// directory is at the end => proceed with next
hasNext = StorageTkEx::getNextContDirID(hashDirNum, getIsBuddyMirrored(),
lastHashDirOffset, &currentContDirID, &newHashDirOffset);
if ( hasNext )
{
lastHashDirOffset = newHashDirOffset;
lastContDirOffset = 0;
readOutEntries += entryNames.size();
// we found a new .cont directory => send it to fsck
FsckContDir contDir(currentContDirID, localNodeNumID, getIsBuddyMirrored());
contDirsOutgoing.push_back(contDir);
}
}
else
{
// there are more to come, but we need to exit the loop now, because maxCount is reached
hasNext = false;
}
}
ctx.sendResponse(
RetrieveDirEntriesRespMsg(&contDirsOutgoing, &dirEntriesOutgoing,
&inlinedFileInodesOutgoing, currentContDirID, lastHashDirOffset, lastContDirOffset) );
return true;
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include <common/net/message/fsck/RetrieveDirEntriesMsg.h>
#include <common/net/message/fsck/RetrieveDirEntriesRespMsg.h>
class RetrieveDirEntriesMsgEx : public RetrieveDirEntriesMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,166 @@
#include "RetrieveFsIDsMsgEx.h"
#include <common/storage/striping/Raid0Pattern.h>
#include <common/threading/SafeRWLock.h>
#include <program/Program.h>
bool RetrieveFsIDsMsgEx::processIncoming(ResponseContext& ctx)
{
LogContext log("Incoming RetrieveFsIDsMsg");
App* app = Program::getApp();
MetaStore* metaStore = app->getMetaStore();
unsigned hashDirNum = getHashDirNum();
bool buddyMirrored = getBuddyMirrored();
std::string currentContDirID = getCurrentContDirID();
unsigned maxOutIDs = getMaxOutIDs();
int64_t lastContDirOffset = getLastContDirOffset();
int64_t lastHashDirOffset = getLastHashDirOffset();
int64_t newHashDirOffset;
FsckFsIDList fsIDsOutgoing;
unsigned readOutIDs = 0;
NumNodeID localNodeNumID = buddyMirrored
? NumNodeID(Program::getApp()->getMetaBuddyGroupMapper()->getLocalGroupID())
: Program::getApp()->getLocalNode().getNumID();
MirrorBuddyGroupMapper* bgm = Program::getApp()->getMetaBuddyGroupMapper();
if (buddyMirrored &&
(bgm->getLocalBuddyGroup().secondTargetID == app->getLocalNode().getNumID().val()
|| bgm->getLocalGroupID() == 0))
{
ctx.sendResponse(
RetrieveFsIDsRespMsg(&fsIDsOutgoing, currentContDirID, lastHashDirOffset,
lastContDirOffset));
return true;
}
bool hasNext;
if ( currentContDirID.empty() )
{
hasNext = StorageTkEx::getNextContDirID(hashDirNum, buddyMirrored, lastHashDirOffset,
&currentContDirID, &newHashDirOffset);
if ( hasNext )
lastHashDirOffset = newHashDirOffset;
}
else
hasNext = true;
while ( hasNext )
{
std::string parentID = currentContDirID;
std::string idPath = MetaStorageTk::getMetaDirEntryIDPath(
MetaStorageTk::getMetaDirEntryPath(
buddyMirrored
? app->getBuddyMirrorDentriesPath()->str()
: app->getDentriesPath()->str(),
parentID));
bool parentDirInodeIsTemp = false;
StringList outNames;
int64_t outNewServerOffset;
ListIncExOutArgs outArgs(&outNames, NULL, NULL, NULL, &outNewServerOffset);
FhgfsOpsErr listRes;
unsigned remainingOutIDs = maxOutIDs - readOutIDs;
DirInode* parentDirInode = metaStore->referenceDir(parentID, buddyMirrored, true);
// it could be, that parentDirInode does not exist
// in fsck we create a temporary inode for this case, so that we can modify the dentry
// hopefully, the inode itself will get fixed later
if ( unlikely(!parentDirInode) )
{
log.log(
Log_NOTICE,
"Could not reference directory. EntryID: " + parentID
+ " => using temporary directory inode ");
// create temporary inode
int mode = S_IFDIR | S_IRWXU;
UInt16Vector stripeTargets;
Raid0Pattern stripePattern(0, stripeTargets, 0);
parentDirInode = new DirInode(parentID, mode, 0, 0,
Program::getApp()->getLocalNode().getNumID(), stripePattern, buddyMirrored);
parentDirInodeIsTemp = true;
}
listRes = parentDirInode->listIDFilesIncremental(lastContDirOffset, 0, remainingOutIDs,
outArgs);
lastContDirOffset = outNewServerOffset;
if ( parentDirInodeIsTemp )
SAFE_DELETE(parentDirInode);
else
metaStore->releaseDir(parentID);
if (listRes != FhgfsOpsErr_SUCCESS)
{
log.logErr("Could not read dentry-by-ID files; parentID: " + parentID);
}
// process entries
readOutIDs += outNames.size();
for ( StringListIter iter = outNames.begin(); iter != outNames.end(); iter++ )
{
std::string id = *iter;
std::string filename = idPath + "/" + id;
// stat the file to get device and inode information
struct stat statBuf;
int statRes = stat(filename.c_str(), &statBuf);
int saveDevice;
uint64_t saveInode;
if ( likely(!statRes) )
{
saveDevice = statBuf.st_dev;
saveInode = statBuf.st_ino;
}
else
{
saveDevice = 0;
saveInode = 0;
log.log(Log_CRITICAL,
"Could not stat ID file; ID: " + id + ";filename: " + filename);
}
FsckFsID fsID(id, parentID, localNodeNumID, saveDevice, saveInode, buddyMirrored);
fsIDsOutgoing.push_back(fsID);
}
if ( readOutIDs < maxOutIDs )
{
// directory is at the end => proceed with next
hasNext = StorageTkEx::getNextContDirID(hashDirNum, buddyMirrored, lastHashDirOffset,
&currentContDirID, &newHashDirOffset);
if ( hasNext )
{
lastHashDirOffset = newHashDirOffset;
lastContDirOffset = 0;
}
}
else
{
// there are more to come, but we need to exit the loop now, because maxCount is reached
hasNext = false;
}
}
ctx.sendResponse(
RetrieveFsIDsRespMsg(&fsIDsOutgoing, currentContDirID, lastHashDirOffset,
lastContDirOffset) );
return true;
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include <common/net/message/fsck/RetrieveFsIDsMsg.h>
#include <common/net/message/fsck/RetrieveFsIDsRespMsg.h>
class RetrieveFsIDsMsgEx : public RetrieveFsIDsMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,25 @@
#include "RetrieveInodesMsgEx.h"
#include <program/Program.h>
bool RetrieveInodesMsgEx::processIncoming(ResponseContext& ctx)
{
LogContext log("Incoming RetrieveInodesMsg");
MetaStore *metaStore = Program::getApp()->getMetaStore();
unsigned hashDirNum = getHashDirNum();
unsigned maxOutInodes = getMaxOutInodes();
int64_t lastOffset = getLastOffset();
int64_t newOffset;
FsckFileInodeList fileInodesOutgoing;
FsckDirInodeList dirInodesOutgoing;
metaStore->getAllInodesIncremental(hashDirNum, lastOffset, maxOutInodes, &dirInodesOutgoing,
&fileInodesOutgoing, &newOffset, getIsBuddyMirrored());
ctx.sendResponse(RetrieveInodesRespMsg(&fileInodesOutgoing, &dirInodesOutgoing, newOffset) );
return true;
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include <common/net/message/fsck/RetrieveInodesMsg.h>
#include <common/net/message/fsck/RetrieveInodesRespMsg.h>
class RetrieveInodesMsgEx : public RetrieveInodesMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,51 @@
#include "UpdateDirAttribsMsgEx.h"
#include <storage/MetaStore.h>
#include <program/Program.h>
#include <toolkit/BuddyCommTk.h>
bool UpdateDirAttribsMsgEx::processIncoming(ResponseContext& ctx)
{
const char* logContext = "UpdateDirAttribsMsg incoming";
MetaStore* metaStore = Program::getApp()->getMetaStore();
EntryLockStore* entryLockStore = Program::getApp()->getMirroredSessions()->getEntryLockStore();
FsckDirInodeList& inodes = getInodes();
FsckDirInodeList failedInodes;
for (FsckDirInodeListIter iter = inodes.begin(); iter != inodes.end(); iter++)
{
// call the updating method
const std::string& dirID = iter->getID();
FileIDLock lock;
if (iter->getIsBuddyMirrored())
lock = {entryLockStore, dirID, true};
DirInode* dirInode = metaStore->referenceDir(dirID, iter->getIsBuddyMirrored(), true);
if (!dirInode)
{
LogContext(logContext).logErr("Unable to reference directory; ID: " + dirID);
failedInodes.push_back(*iter);
continue;
}
FhgfsOpsErr refreshRes = dirInode->refreshMetaInfo();
metaStore->releaseDir(dirID);
if (refreshRes != FhgfsOpsErr_SUCCESS)
{
LogContext(logContext).log(Log_WARNING, "Failed to update attributes of directory. "
"entryID: " + dirID);
failedInodes.push_back(*iter);
}
}
ctx.sendResponse(UpdateDirAttribsRespMsg(&failedInodes) );
return true;
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include <common/net/message/NetMessage.h>
#include <common/net/message/fsck/UpdateDirAttribsMsg.h>
#include <common/net/message/fsck/UpdateDirAttribsRespMsg.h>
class UpdateDirAttribsMsgEx : public UpdateDirAttribsMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,62 @@
#include "UpdateFileAttribsMsgEx.h"
#include <net/msghelpers/MsgHelperStat.h>
#include <program/Program.h>
#include <toolkit/BuddyCommTk.h>
bool UpdateFileAttribsMsgEx::processIncoming(ResponseContext& ctx)
{
const char* logContext = "UpdateFileAttribsMsg incoming";
MetaStore* metaStore = Program::getApp()->getMetaStore();
EntryLockStore* entryLockStore = Program::getApp()->getMirroredSessions()->getEntryLockStore();
FsckFileInodeList& inodes = getInodes();
FsckFileInodeList failedInodes;
for (FsckFileInodeListIter iter = inodes.begin(); iter != inodes.end(); iter++)
{
// create an EntryInfo object (NOTE: dummy fileName)
EntryInfo entryInfo(iter->getSaveNodeID(), iter->getParentDirID(), iter->getID(), "",
DirEntryType_REGULARFILE,
(iter->getIsBuddyMirrored() ? ENTRYINFO_FEATURE_BUDDYMIRRORED : 0) |
(iter->getIsInlined() ? ENTRYINFO_FEATURE_INLINED : 0));
FileIDLock lock;
if (iter->getIsBuddyMirrored())
lock = {entryLockStore, entryInfo.getEntryID(), true};
auto [inode, referenceRes] = metaStore->referenceFile(&entryInfo);
if (inode)
{
inode->setNumHardlinksUnpersistent(iter->getNumHardLinks());
inode->updateInodeOnDisk(&entryInfo);
// call the dynamic attribs refresh method
FhgfsOpsErr refreshRes = MsgHelperStat::refreshDynAttribs(&entryInfo, true,
getMsgHeaderUserID() );
if (refreshRes != FhgfsOpsErr_SUCCESS)
{
LogContext(logContext).log(Log_WARNING, "Failed to update dynamic attributes of file. "
"entryID: " + iter->getID());
failedInodes.push_back(*iter);
}
/* only release it here, as refreshDynAttribs() also takes an inode reference and can
* do the reference from in-memory data then */
metaStore->releaseFile(entryInfo.getParentEntryID(), inode);
}
else
{
LogContext(logContext).log(Log_WARNING, "Could not reference inode to update attributes. "
"entryID: " + iter->getID());
failedInodes.push_back(*iter);
}
}
ctx.sendResponse(UpdateFileAttribsRespMsg(&failedInodes) );
return true;
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include <common/net/message/NetMessage.h>
#include <common/net/message/fsck/UpdateFileAttribsMsg.h>
#include <common/net/message/fsck/UpdateFileAttribsRespMsg.h>
class UpdateFileAttribsMsgEx : public UpdateFileAttribsMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,39 @@
#include <common/components/worker/queue/MultiWorkQueue.h>
#include <program/Program.h>
#include <session/SessionStore.h>
#include "RequestMetaDataMsgEx.h"
bool RequestMetaDataMsgEx::processIncoming(ResponseContext& ctx)
{
LogContext log("RequestMetaDataMsg incoming");
App *app = Program::getApp();
Node& node = app->getLocalNode();
MultiWorkQueue *workQueue = app->getWorkQueue();
unsigned sessionCount = app->getSessions()->getSize() + app->getMirroredSessions()->getSize();
NicAddressList nicList(node.getNicList());
std::string hostnameid = System::getHostname();
// highresStats
HighResStatsList statsHistory;
uint64_t lastStatsMS = getValue();
// get stats history
StatsCollector* statsCollector = app->getStatsCollector();
statsCollector->getStatsSince(lastStatsMS, statsHistory);
RequestMetaDataRespMsg requestMetaDataRespMsg(node.getAlias(), hostnameid, node.getNumID(), &nicList,
app->getMetaRoot().getID() == node.getNumID(), workQueue->getIndirectWorkListSize(),
workQueue->getDirectWorkListSize(), sessionCount, &statsHistory);
ctx.sendResponse(requestMetaDataRespMsg);
LOG_DEBUG_CONTEXT(log, 5, std::string("Sent a message with type: " ) +
StringTk::uintToStr(requestMetaDataRespMsg.getMsgType() ) + std::string(" to mon") );
app->getNodeOpStats()->updateNodeOp(ctx.getSocket()->getPeerIP(), MetaOpCounter_REQUESTMETADATA,
getMsgHeaderUserID() );
return true;
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include <app/App.h>
#include <common/app/log/LogContext.h>
#include <common/net/message/mon/RequestMetaDataMsg.h>
#include <common/net/message/mon/RequestMetaDataRespMsg.h>
class RequestMetaDataMsgEx : public RequestMetaDataMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,900 @@
#include <common/net/message/nodes/GenericDebugRespMsg.h>
#include <common/net/msghelpers/MsgHelperGenericDebug.h>
#include <common/storage/quota/Quota.h>
#include <common/toolkit/MessagingTk.h>
#include <program/Program.h>
#include <session/SessionStore.h>
#include "GenericDebugMsgEx.h"
#define GENDBGMSG_OP_LISTFILEAPPENDLOCKS "listfileappendlocks"
#define GENDBGMSG_OP_LISTFILEENTRYLOCKS "listfileentrylocks"
#define GENDBGMSG_OP_LISTFILERANGELOCKS "listfilerangelocks"
#define GENDBGMSG_OP_LISTOPENFILES "listopenfiles"
#define GENDBGMSG_OP_REFERENCESTATISTICS "refstats"
#define GENDBGMSG_OP_CACHESTATISTICS "cachestats"
#define GENDBGMSG_OP_VERSION "version"
#define GENDBGMSG_OP_MSGQUEUESTATS "msgqueuestats"
#define GENDBGMSG_OP_LISTPOOLS "listpools"
#define GENDBGMSG_OP_DUMPDENTRY "dumpdentry"
#define GENDBGMSG_OP_DUMPINODE "dumpinode"
#define GENDBGMSG_OP_DUMPINLINEDINODE "dumpinlinedinode"
#ifdef BEEGFS_DEBUG
#define GENDBGMSG_OP_WRITEDIRDENTRY "writedirdentry"
#define GENDBGMSG_OP_WRITEDIRINODE "writedirinode"
#define GENDBGMSG_OP_WRITEFILEINODE "writefileinode"
#endif // BEEGFS_DEBUG
bool GenericDebugMsgEx::processIncoming(ResponseContext& ctx)
{
LogContext log("GenericDebugMsg incoming");
LOG_DEBUG_CONTEXT(log, 5, std::string("Command string: ") + getCommandStr() );
std::string cmdRespStr = processCommand();
ctx.sendResponse(GenericDebugRespMsg(cmdRespStr.c_str() ) );
return true;
}
/**
* @return command response string
*/
std::string GenericDebugMsgEx::processCommand()
{
App* app = Program::getApp();
Config* cfg = app->getConfig();
std::string responseStr;
std::string operation;
// load command string into a stream to allow us to use getline
std::istringstream commandStream(getCommandStr() );
// get operation type from command string
std::getline(commandStream, operation, ' ');
if(operation == GENDBGMSG_OP_LISTFILEAPPENDLOCKS)
responseStr = processOpListFileAppendLocks(commandStream);
else
if(operation == GENDBGMSG_OP_LISTFILEENTRYLOCKS)
responseStr = processOpListFileEntryLocks(commandStream);
else
if(operation == GENDBGMSG_OP_LISTFILERANGELOCKS)
responseStr = processOpListFileRangeLocks(commandStream);
else
if(operation == GENDBGMSG_OP_LISTOPENFILES)
responseStr = processOpListOpenFiles(commandStream);
else
if(operation == GENDBGMSG_OP_REFERENCESTATISTICS)
responseStr = processOpReferenceStatistics(commandStream);
else
if(operation == GENDBGMSG_OP_CACHESTATISTICS)
responseStr = processOpCacheStatistics(commandStream);
else
if(operation == GENDBGMSG_OP_VERSION)
responseStr = processOpVersion(commandStream);
else
if(operation == GENDBGMSG_OP_MSGQUEUESTATS)
responseStr = processOpMsgQueueStats(commandStream);
else
if(operation == GENDBGMSG_OP_VARLOGMESSAGES)
responseStr = MsgHelperGenericDebug::processOpVarLogMessages(commandStream);
else
if(operation == GENDBGMSG_OP_VARLOGKERNLOG)
responseStr = MsgHelperGenericDebug::processOpVarLogKernLog(commandStream);
else
if(operation == GENDBGMSG_OP_FHGFSLOG)
responseStr = MsgHelperGenericDebug::processOpFhgfsLog(commandStream);
else
if(operation == GENDBGMSG_OP_LOADAVG)
responseStr = MsgHelperGenericDebug::processOpLoadAvg(commandStream);
else
if(operation == GENDBGMSG_OP_DROPCACHES)
responseStr = MsgHelperGenericDebug::processOpDropCaches(commandStream);
else
if(operation == GENDBGMSG_OP_GETCFG)
responseStr = MsgHelperGenericDebug::processOpCfgFile(commandStream, cfg->getCfgFile() );
else
if(operation == GENDBGMSG_OP_GETLOGLEVEL)
responseStr = MsgHelperGenericDebug::processOpGetLogLevel(commandStream);
else
if(operation == GENDBGMSG_OP_SETLOGLEVEL)
responseStr = MsgHelperGenericDebug::processOpSetLogLevel(commandStream);
else
if(operation == GENDBGMSG_OP_NETOUT)
responseStr = MsgHelperGenericDebug::processOpNetOut(commandStream,
app->getMgmtNodes(), app->getMetaNodes(), app->getStorageNodes() );
else
if(operation == GENDBGMSG_OP_LISTMETASTATES)
responseStr = MsgHelperGenericDebug::processOpListTargetStates(commandStream,
app->getMetaStateStore() );
else
if(operation == GENDBGMSG_OP_LISTSTORAGESTATES)
responseStr = MsgHelperGenericDebug::processOpListTargetStates(commandStream,
app->getTargetStateStore() );
else
if(operation == GENDBGMSG_OP_LISTPOOLS)
responseStr = processOpListPools(commandStream);
else
if(operation == GENDBGMSG_OP_DUMPDENTRY)
responseStr = processOpDumpDentry(commandStream);
else
if(operation == GENDBGMSG_OP_DUMPINODE)
responseStr = processOpDumpInode(commandStream);
else
if(operation == GENDBGMSG_OP_DUMPINLINEDINODE)
responseStr = processOpDumpInlinedInode(commandStream);
else
if(operation == GENDBGMSG_OP_QUOTAEXCEEDED)
responseStr = processOpQuotaExceeded(commandStream);
else if(operation == GENDBGMSG_OP_LISTSTORAGEPOOLS)
responseStr = MsgHelperGenericDebug::processOpListStoragePools(commandStream,
app->getStoragePoolStore());
#ifdef BEEGFS_DEBUG
else
if(operation == GENDBGMSG_OP_WRITEDIRDENTRY)
responseStr = processOpWriteDirDentry(commandStream);
else
if(operation == GENDBGMSG_OP_WRITEDIRINODE)
responseStr = processOpWriteDirInode(commandStream);
else
if(operation == GENDBGMSG_OP_WRITEFILEINODE)
responseStr = processOpWriteInlinedFileInode(commandStream);
#endif // BEEGFS_DEBUG
else
responseStr = "Unknown/invalid operation";
return responseStr;
}
/**
* Retrieve append lock stats for a certain file.
*/
std::string GenericDebugMsgEx::processOpListFileAppendLocks(std::istringstream& commandStream)
{
// procotol: entryID as only argument
std::string parentEntryID;
std::string entryID;
std::string responseStr;
std::string isBuddyMirroredStr;
bool isBuddyMirrored;
// get entryID from command string
std::getline(commandStream, parentEntryID, ' ');
std::getline(commandStream, entryID, ' ');
std::getline(commandStream, isBuddyMirroredStr, ' ');
if (parentEntryID.empty() )
return "Invalid or missing parentEntryID";
if(entryID.empty() )
return "Invalid or missing entryID";
if(isBuddyMirroredStr.empty())
isBuddyMirrored = false;
else
isBuddyMirrored = StringTk::strToBool(isBuddyMirroredStr);
MetaStore* metaStore = Program::getApp()->getMetaStore();
MetaFileHandle inode = metaStore->referenceLoadedFile(parentEntryID, isBuddyMirrored, entryID);
if(!inode)
return "FileID not exists: " + entryID;
responseStr = inode->flockAppendGetAllAsStr();
metaStore->releaseFile(parentEntryID, inode);
return responseStr;
}
std::string GenericDebugMsgEx::processOpListFileEntryLocks(std::istringstream& commandStream)
{
// procotol: entryID as only argument
std::string parentEntryID;
std::string entryID;
std::string responseStr;
std::string isBuddyMirroredStr;
bool isBuddyMirrored;
// get entryID from command string
std::getline(commandStream, parentEntryID, ' ');
std::getline(commandStream, entryID, ' ');
std::getline(commandStream, isBuddyMirroredStr, ' ');
if (parentEntryID.empty() )
return "Invalid or missing parentEntryID";
if(entryID.empty() )
return "Invalid or missing entryID";
if(isBuddyMirroredStr.empty())
isBuddyMirrored = false;
else
isBuddyMirrored = StringTk::strToBool(isBuddyMirroredStr);
MetaStore* metaStore = Program::getApp()->getMetaStore();
MetaFileHandle inode = metaStore->referenceLoadedFile(parentEntryID, isBuddyMirrored, entryID);
if(!inode)
return "FileID not exists: " + entryID;
responseStr = inode->flockEntryGetAllAsStr();
metaStore->releaseFile(parentEntryID, inode);
return responseStr;
}
std::string GenericDebugMsgEx::processOpListFileRangeLocks(std::istringstream& commandStream)
{
// procotol: entryID as only argument
std::string parentEntryID;
std::string entryID;
std::string isBuddyMirroredStr;
bool isBuddyMirrored;
// get parentEntryID from command string
std::getline(commandStream, parentEntryID, ' ');
if(parentEntryID.empty() )
return "Invalid or missing parentEntryID";
// get entryID from command string
std::getline(commandStream, entryID, ' ');
if(entryID.empty() )
return "Invalid or missing entryID";
// get isBuddyMirrored from command string
std::getline(commandStream, isBuddyMirroredStr, ' ');
if(isBuddyMirroredStr.empty())
isBuddyMirrored = false;
else
isBuddyMirrored = StringTk::strToBool(isBuddyMirroredStr);
MetaStore* metaStore = Program::getApp()->getMetaStore();
MetaFileHandle file = metaStore->referenceLoadedFile(parentEntryID, isBuddyMirrored, entryID);
if(!file)
return "FileID not found: " + entryID;
std::string responseStr = file->flockRangeGetAllAsStr();
metaStore->releaseFile(parentEntryID, file);
return responseStr;
}
std::string GenericDebugMsgEx::processOpListOpenFiles(std::istringstream& commandStream)
{
// protocol: no arguments
App* app = Program::getApp();
SessionStore* sessions = app->getSessions();
SessionStore* mirroredSessions = app->getMirroredSessions();
std::ostringstream responseStream;
size_t numFilesTotal = 0;
size_t numCheckedSessions = 0; // may defer from number of initially queried sessions
NumNodeIDList sessionIDs = sessions->getAllSessionIDs();
NumNodeIDList mirroredSessionIDs = mirroredSessions->getAllSessionIDs();
responseStream << "Found " << sessionIDs.size() << " non-mirrored sessions and "
<< mirroredSessionIDs.size() << " mirrored sessions." << std::endl;
responseStream << std::endl;
responseStream << "Non-mirrored sessions:" << std::endl;
// walk over all sessions
for(NumNodeIDListCIter iter = sessionIDs.begin(); iter != sessionIDs.end(); iter++)
{
Session* session = sessions->referenceSession(*iter, false);
// note: sessionID might have been removed since we queried it, e.g. because client is gone
if(!session)
continue;
numCheckedSessions++;
SessionFileStore* sessionFiles = session->getFiles();
size_t numFiles = sessionFiles->getSize();
sessions->releaseSession(session);
if(!numFiles)
continue; // only print sessions with open files
numFilesTotal += numFiles;
responseStream << *iter << ": " << numFiles << std::endl;
}
responseStream << "Mirrored sessions:" << std::endl;
// ...and the mirrored sessions
for(NumNodeIDListCIter iter = mirroredSessionIDs.begin(); iter != mirroredSessionIDs.end();
++iter)
{
Session* session = mirroredSessions->referenceSession(*iter, false);
if (!session)
continue;
numCheckedSessions++;
SessionFileStore* sessionFiles = session->getFiles();
size_t numFiles = sessionFiles->getSize();
mirroredSessions->releaseSession(session);
if (!numFiles)
continue;
numFilesTotal += numFiles;
responseStream << *iter << ": " << numFiles << std::endl;
}
responseStream << std::endl;
responseStream << "Final results: " << numFilesTotal << " open files in " <<
numCheckedSessions << " checked sessions";
return responseStream.str();
}
std::string GenericDebugMsgEx::processOpReferenceStatistics(std::istringstream& commandStream)
{
// protocol: no arguments
App* app = Program::getApp();
MetaStore* metaStore = app->getMetaStore();
std::ostringstream responseStream;
size_t numDirs;
size_t numFiles;
metaStore->getReferenceStats(&numDirs, &numFiles);
responseStream << "Dirs: " << numDirs << std::endl;
responseStream << "Files: " << numFiles;
return responseStream.str();
}
std::string GenericDebugMsgEx::processOpCacheStatistics(std::istringstream& commandStream)
{
// protocol: no arguments
App* app = Program::getApp();
MetaStore* metaStore = app->getMetaStore();
std::ostringstream responseStream;
size_t numDirs;
metaStore->getCacheStats(&numDirs);
responseStream << "Dirs: " << numDirs;
return responseStream.str();
}
std::string GenericDebugMsgEx::processOpVersion(std::istringstream& commandStream)
{
return BEEGFS_VERSION;
}
std::string GenericDebugMsgEx::processOpMsgQueueStats(std::istringstream& commandStream)
{
// protocol: no arguments
App* app = Program::getApp();
MultiWorkQueue* workQ = app->getWorkQueue();
std::ostringstream responseStream;
std::string indirectQueueStats;
std::string directQueueStats;
std::string busyStats;
workQ->getStatsAsStr(indirectQueueStats, directQueueStats, busyStats);
responseStream << "general queue stats: " << std::endl <<
indirectQueueStats << std::endl;
responseStream << "direct queue stats: " << std::endl <<
directQueueStats << std::endl;
responseStream << "busy worker stats: " << std::endl <<
busyStats << std::endl;
return responseStream.str();
}
/**
* List internal state of meta and storage capacity pools.
*/
std::string GenericDebugMsgEx::processOpListPools(std::istringstream& commandStream)
{
// protocol: no arguments
const App* app = Program::getApp();
const NodeCapacityPools* metaPools = app->getMetaCapacityPools();
std::ostringstream responseStream;
responseStream << "META POOLS STATE: " << std::endl << metaPools->getStateAsStr() << std::endl;
const StoragePoolPtrVec storagePools = app->getStoragePoolStore()->getPoolsAsVec();
for (auto iter = storagePools.begin(); iter != storagePools.end(); iter++)
{
const TargetCapacityPools* capPool = (*iter)->getTargetCapacityPools();
responseStream << "STORAGE CAPACITY POOLS STATE (STORAGE POOL ID: " << (*iter)->getId()
<< "): " << std::endl << capPool->getStateAsStr() << std::endl;
}
for (auto iter = storagePools.begin(); iter != storagePools.end(); iter++)
{
const NodeCapacityPools* capPool = (*iter)->getBuddyCapacityPools();
responseStream << "STORAGE BUDDY CAPACITY POOLS STATE (STORAGE POOL ID: "
<< (*iter)->getId() << "): " << std::endl << capPool->getStateAsStr()
<< std::endl;
}
return responseStream.str();
}
std::string GenericDebugMsgEx::processOpDumpDentry(std::istringstream& commandStream)
{
MetaStore* metaStore = Program::getApp()->getMetaStore();
std::ostringstream responseStream;
StringList parameterList;
StringTk::explode(commandStream.str(), ' ', &parameterList);
if ( parameterList.size() < 3 || parameterList.size() > 4 )
return "Invalid or missing parameters; Parameter format: parentDirID entryName "
"[isBuddyMirrored]";
StringListIter iter = parameterList.begin();
iter++;
std::string parentDirID = *iter;
iter++;
std::string entryName = *iter;
iter++;
bool isBuddyMirrored = false;
if (iter != parameterList.end())
{
isBuddyMirrored = StringTk::strToBool(*iter);
}
DirInode* parentDirInode = metaStore->referenceDir(parentDirID, isBuddyMirrored, false);
if (!parentDirInode)
return "Unable to reference parent directory.";
DirEntry dentry(entryName);
bool getDentryRes = parentDirInode->getDentry(entryName, dentry);
metaStore->releaseDir(parentDirID);
if (!getDentryRes)
return "Unable to get dentry from parent directory.";
responseStream << "entryType: " << dentry.getEntryType() << std::endl;
responseStream << "ID: " << dentry.getID() << std::endl;
responseStream << "ownerNodeID: " << dentry.getOwnerNodeID() << std::endl;
responseStream << "featureFlags: " << dentry.getDentryFeatureFlags() << std::endl;
return responseStream.str();
}
#ifdef BEEGFS_DEBUG
std::string GenericDebugMsgEx::processOpWriteDirDentry(std::istringstream& commandStream)
{
MetaStore* metaStore = Program::getApp()->getMetaStore();
std::string dentriesPath = Program::getApp()->getDentriesPath()->str();
std::ostringstream responseStream;
StringList parameterList;
StringTk::explode(commandStream.str(), ' ', &parameterList);
if ( parameterList.size() < 4 || parameterList.size() > 5 )
return "Invalid or missing parameters; Parameter format: parentDirID entryName ownerNodeID "
"[isBuddyMirrored]";
StringListIter iter = parameterList.begin();
iter++;
std::string parentDirID = *iter;
iter++;
std::string entryName = *iter;
iter++;
NumNodeID ownerNodeID(StringTk::strToUInt(*iter) );
iter++;
bool isBuddyMirrored = false;
if (iter!=parameterList.end())
{
isBuddyMirrored = StringTk::strToBool(*iter);
}
DirInode* parentDirInode = metaStore->referenceDir(parentDirID, isBuddyMirrored, true);
if (!parentDirInode)
return "Unable to reference parent directory.";
DirEntry dentry(entryName);
bool getDentryRes = parentDirInode->getDentry(entryName, dentry);
metaStore->releaseDir(parentDirID);
if (!getDentryRes)
return "Unable to get dentry from parent directory.";
bool setOwnerRes = dentry.setOwnerNodeID(
MetaStorageTk::getMetaDirEntryPath(dentriesPath, parentDirID), ownerNodeID);
if (!setOwnerRes)
return "Unable to set new owner node ID in dentry.";
return "OK";
}
#endif // BEEGFS_DEBUG
std::string GenericDebugMsgEx::processOpDumpInode(std::istringstream& commandStream)
{
// commandStream: ID of inode
MetaStore* metaStore = Program::getApp()->getMetaStore();
std::ostringstream responseStream;
std::string inodeID;
std::string isBuddyMirroredStr;
bool isBuddyMirrored;
// get inodeID from command string
std::getline(commandStream, inodeID, ' ');
if(inodeID.empty() )
return "Invalid or missing inode ID";
// get isBuddyMirrored from command string
std::getline(commandStream, isBuddyMirroredStr, ' ');
if(isBuddyMirroredStr.empty())
isBuddyMirrored = false;
else
isBuddyMirrored = StringTk::strToBool(isBuddyMirroredStr);
MetaFileHandle fileInode;
DirInode* dirInode = NULL;
metaStore->referenceInode(inodeID, isBuddyMirrored, fileInode, dirInode);
if (fileInode)
{
StatData statData;
if (fileInode->getStatData(statData) != FhgfsOpsErr_SUCCESS)
{ // stat data retrieval failed
metaStore->releaseFile("", fileInode);
return "Could not get stat data for requested file inode";
}
DirEntryType dirEntryType = MetadataTk::posixFileTypeToDirEntryType(fileInode->getMode() );
std::string parentDirID = "cannotBeUsed";
uint16_t parentNodeID = 0;
responseStream << "entryType: " << dirEntryType << std::endl;
responseStream << "parentEntryID: " << parentDirID << std::endl;
responseStream << "parentNodeID: " << StringTk::uintToStr(parentNodeID) << std::endl;
responseStream << "mode: " << StringTk::intToStr(statData.getMode()) << std::endl;
responseStream << "uid: " << StringTk::uintToStr(statData.getUserID()) << std::endl;
responseStream << "gid: " << StringTk::uintToStr(statData.getGroupID()) << std::endl;
responseStream << "filesize: " << StringTk::int64ToStr(statData.getFileSize()) << std::endl;
responseStream << "ctime: " << StringTk::int64ToStr(statData.getCreationTimeSecs()) << std::endl;
responseStream << "atime: " << StringTk::int64ToStr(statData.getLastAccessTimeSecs()) << std::endl;
responseStream << "mtime: " << StringTk::int64ToStr(statData.getModificationTimeSecs()) << std::endl;
responseStream << "hardlinks: " << StringTk::intToStr(statData.getNumHardlinks()) << std::endl;
responseStream << "stripeTargets: "
<< StringTk::uint16VecToStr(fileInode->getStripePattern()->getStripeTargetIDs())
<< std::endl;
responseStream << "chunkSize: "
<< StringTk::uintToStr(fileInode->getStripePattern()->getChunkSize()) << std::endl;
responseStream << "featureFlags: " << fileInode->getFeatureFlags() << std::endl;
metaStore->releaseFile("", fileInode);
}
else
if (dirInode)
{
StatData statData;
if (dirInode->getStatData(statData) != FhgfsOpsErr_SUCCESS)
{ // stat data retrieval failed
metaStore->releaseDir(inodeID);
return "Could not get stat data for requested dir inode";
}
DirEntryType dirEntryType = MetadataTk::posixFileTypeToDirEntryType(dirInode->getMode() );
std::string parentDirID;
NumNodeID parentNodeID;
dirInode->getParentInfo(&parentDirID, &parentNodeID);
responseStream << "entryType: " << dirEntryType << std::endl;
responseStream << "parentEntryID: " << parentDirID << std::endl;
responseStream << "parentNodeID: " << parentNodeID.str() << std::endl;
responseStream << "ownerNodeID: " << dirInode->getOwnerNodeID().str() << std::endl;
responseStream << "mode: " << StringTk::intToStr(statData.getMode()) << std::endl;
responseStream << "uid: " << StringTk::uintToStr(statData.getUserID()) << std::endl;
responseStream << "gid: " << StringTk::uintToStr(statData.getGroupID()) << std::endl;
responseStream << "size: " << StringTk::int64ToStr(statData.getFileSize()) << std::endl;
responseStream << "numLinks: " << StringTk::int64ToStr(statData.getNumHardlinks())
<< std::endl;
responseStream << "ctime: " << StringTk::int64ToStr(statData.getCreationTimeSecs())
<< std::endl;
responseStream << "atime: " << StringTk::int64ToStr(statData.getLastAccessTimeSecs())
<< std::endl;
responseStream << "mtime: " << StringTk::int64ToStr(statData.getModificationTimeSecs())
<< std::endl;
responseStream << "featureFlags: " << dirInode->getFeatureFlags() << std::endl;
metaStore->releaseDir(inodeID);
}
else
{
return "Could not read requested inode";
}
return responseStream.str();
}
std::string GenericDebugMsgEx::processOpDumpInlinedInode(std::istringstream& commandStream)
{
// commandStream: parentID, name
MetaStore* metaStore = Program::getApp()->getMetaStore();
NumNodeID localNodeID = Program::getApp()->getLocalNode().getNumID();
std::ostringstream responseStream;
StringList parameterList;
StringTk::explode(commandStream.str(), ' ', &parameterList);
if ( parameterList.size() < 3 || parameterList.size() > 4 )
return "Invalid or missing parameters; Parameter format: parentDirID entryName "
"[isBuddyMirrored]";
StringListIter iter = parameterList.begin();
iter++;
std::string parentEntryID = *iter;
iter++;
std::string entryName = *iter;
iter++;
bool isBuddyMirrored = false;
if (iter != parameterList.end())
{
isBuddyMirrored = StringTk::strToBool(*iter);
}
EntryInfo entryInfo(localNodeID, parentEntryID, "unknown", entryName, DirEntryType_REGULARFILE,
0);
DirInode* parentInode = metaStore->referenceDir(parentEntryID, isBuddyMirrored, false);
if ( !parentInode )
return "Could not open parent directory";
DirEntry dirEntry(entryName);
bool getDentryRes = parentInode->getDentry(entryName, dirEntry);
if ( !getDentryRes )
{
metaStore->releaseDir(parentEntryID);
return "Could not open dir entry";
}
FileInodeStoreData* inodeData = dirEntry.getInodeStoreData();
if ( !inodeData )
{
metaStore->releaseDir(parentEntryID);
return "Could not get inlined inode data";
}
StatData* statData = inodeData->getInodeStatData();
if ( !statData )
{
metaStore->releaseDir(parentEntryID);
return "Could not get stat data for requested file inode";
}
responseStream << "entryID: " << inodeData->getEntryID() << std::endl;
responseStream << "mode: " << StringTk::intToStr(statData->getMode()) << std::endl;
responseStream << "uid: " << StringTk::uintToStr(statData->getUserID()) << std::endl;
responseStream << "gid: " << StringTk::uintToStr(statData->getGroupID()) << std::endl;
responseStream << "filesize: " << StringTk::int64ToStr(statData->getFileSize()) << std::endl;
responseStream << "ctime: " << StringTk::int64ToStr(statData->getCreationTimeSecs()) << std::endl;
responseStream << "atime: " << StringTk::int64ToStr(statData->getLastAccessTimeSecs())
<< std::endl;
responseStream << "mtime: " << StringTk::int64ToStr(statData->getModificationTimeSecs())
<< std::endl;
responseStream << "hardlinks: " << StringTk::intToStr(statData->getNumHardlinks()) << std::endl;
responseStream << "stripeTargets: "
<< StringTk::uint16VecToStr(inodeData->getPattern()->getStripeTargetIDs()) << std::endl;
responseStream << "chunkSize: "
<< StringTk::uintToStr(inodeData->getPattern()->getChunkSize()) << std::endl;
responseStream << "featureFlags: " << inodeData->getInodeFeatureFlags() << std::endl;
metaStore->releaseDir(parentEntryID);
return responseStream.str();
}
std::string GenericDebugMsgEx::processOpQuotaExceeded(std::istringstream& commandStream)
{
App* app = Program::getApp();
std::string targetIdStr;
std::getline(commandStream, targetIdStr, ' ');
uint16_t targetId = StringTk::strToUInt(targetIdStr);
std::string returnString;
if(!app->getConfig()->getQuotaEnableEnforcement() )
return "No quota exceeded IDs on this storage daemon because quota enforcement is"
"disabled.";
ExceededQuotaStorePtr exQuotaStore = app->getExceededQuotaStores()->get(targetId);
// exQuotaStore may be null;needs to be checked in MsgHelperGenericDebug::processOpQuotaExceeded
return MsgHelperGenericDebug::processOpQuotaExceeded(commandStream, exQuotaStore.get());
}
#ifdef BEEGFS_DEBUG
std::string GenericDebugMsgEx::processOpWriteDirInode(std::istringstream& commandStream)
{
MetaStore* metaStore = Program::getApp()->getMetaStore();
// get parameters from command string
StringVector paramVec;
StringTk::explode(commandStream.str(), ' ', &paramVec);
std::string entryID;
std::string parentDirID;
NumNodeID parentNodeID;
NumNodeID ownerNodeID;
int mode;
uint uid;
uint gid;
int64_t size;
unsigned numLinks;
bool isBuddyMirrored;
try
{
unsigned i = 1;
entryID = paramVec.at(i++);
parentDirID = paramVec.at(i++);
parentNodeID = NumNodeID(StringTk::strToUInt(paramVec.at(i++)));
ownerNodeID = NumNodeID(StringTk::strToUInt(paramVec.at(i++)));
mode = StringTk::strToInt(paramVec.at(i++));
uid = StringTk::strToUInt(paramVec.at(i++));
gid = StringTk::strToUInt(paramVec.at(i++));
size = StringTk::strToInt64(paramVec.at(i++));
numLinks = StringTk::strToUInt(paramVec.at(i++));
if (i<paramVec.size())
isBuddyMirrored = StringTk::strToBool(paramVec.at(i));
else
isBuddyMirrored = false;
}
catch (std::out_of_range& e)
{
std::string paramFormatStr =
"entryID parentDirID parentNodeID ownerNodeID mode uid gid size numLinks "
"[isBuddyMirrored]";
return "Invalid or missing parameters; Parameter format: " + paramFormatStr;
}
DirInode* dirInode = metaStore->referenceDir(entryID, isBuddyMirrored, true);
if ( !dirInode )
return "Could not find directory with ID: " + entryID;
StatData statData;
if ( dirInode->getStatData(statData) != FhgfsOpsErr_SUCCESS )
{
metaStore->releaseDir(entryID);
return "Could not get stat data for requested dir inode";
}
dirInode->setParentInfoInitial(parentDirID, parentNodeID);
dirInode->setOwnerNodeID(ownerNodeID);
statData.setMode(mode);
statData.setUserID(uid);
statData.setGroupID(gid);
statData.setFileSize(size);
statData.setNumHardLinks(numLinks);
dirInode->setStatData(statData);
metaStore->releaseDir(entryID);
return "OK";
}
std::string GenericDebugMsgEx::processOpWriteInlinedFileInode(std::istringstream& commandStream)
{
MetaStore* metaStore = Program::getApp()->getMetaStore();
std::string retStr = "OK";
// get parameters from command string
StringVector paramVec;
StringTk::explode(commandStream.str(), ' ', &paramVec);
std::string parentDirID;
std::string name;
std::string entryID;
int mode;
uint uid;
uint gid;
int64_t filesize;
unsigned numLinks;
UInt16Vector stripeTargets;
// UInt16Vector* origStripeTargets;
try
{
unsigned i = 1;
parentDirID = paramVec.at(i++);
name = paramVec.at(i++);
entryID = paramVec.at(i++);
mode = StringTk::strToInt(paramVec.at(i++));
uid = StringTk::strToUInt(paramVec.at(i++));
gid = StringTk::strToUInt(paramVec.at(i++));
filesize = StringTk::strToInt64(paramVec.at(i++));
numLinks = StringTk::strToUInt(paramVec.at(i++));
StringTk::strToUint16Vec(paramVec.at(i++), &stripeTargets);
}
catch (std::out_of_range& e)
{
std::string paramFormatStr =
"parentDirID entryName entryID mode uid gid filesize numLinks stripeTargets";
return "Invalid or missing parameters; Parameter format: " + paramFormatStr;
}
EntryInfo entryInfo(Program::getApp()->getLocalNodeNumID(), parentDirID, entryID, name,
DirEntryType_REGULARFILE, 0);
auto [fileInode, referenceRes] = metaStore->referenceFile(&entryInfo);
if (!fileInode)
return "Could not reference inode";
StatData statData;
fileInode->getStatData(statData);
statData.setMode(mode);
statData.setUserID(uid);
statData.setGroupID(gid);
statData.setFileSize(filesize);
statData.setNumHardLinks(numLinks);
fileInode->setStatData(statData);
StripePattern* pattern = fileInode->getStripePattern();
UInt16Vector* origTargets = pattern->getStripeTargetIDsModifyable();
*origTargets = stripeTargets;
fileInode->updateInodeOnDisk(&entryInfo, pattern);
metaStore->releaseFile(parentDirID, fileInode);
return retStr;
}
#endif // BEEGFS_DEBUG

View File

@@ -0,0 +1,36 @@
#pragma once
#include <common/net/message/nodes/GenericDebugMsg.h>
#include <common/Common.h>
class GenericDebugMsgEx : public GenericDebugMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
private:
std::string processCommand();
std::string processOpListFileAppendLocks(std::istringstream& commandStream);
std::string processOpListFileEntryLocks(std::istringstream& commandStream);
std::string processOpListFileRangeLocks(std::istringstream& commandStream);
std::string processOpListOpenFiles(std::istringstream& commandStream);
std::string processOpReferenceStatistics(std::istringstream& commandStream);
std::string processOpCacheStatistics(std::istringstream& commandStream);
std::string processOpVersion(std::istringstream& commandStream);
std::string processOpMsgQueueStats(std::istringstream& commandStream);
std::string processOpListPools(std::istringstream& commandStream);
std::string processOpDumpDentry(std::istringstream& commandStream);
std::string processOpDumpInode(std::istringstream& commandStream);
std::string processOpDumpInlinedInode(std::istringstream& commandStream);
std::string processOpQuotaExceeded(std::istringstream& commandStream);
#ifdef BEEGFS_DEBUG
std::string processOpWriteDirDentry(std::istringstream& commandStream);
std::string processOpWriteDirInode(std::istringstream& commandStream);
std::string processOpWriteInlinedFileInode(std::istringstream& commandStream);
#endif // BEEGFS_DEBUG
};

View File

@@ -0,0 +1,32 @@
#include <program/Program.h>
#include <common/net/message/storage/GetHighResStatsRespMsg.h>
#include <common/toolkit/MessagingTk.h>
#include <common/nodes/OpCounter.h>
#include "GetClientStatsMsgEx.h"
#include <nodes/MetaNodeOpStats.h>
#include <common/net/message/nodes/GetClientStatsRespMsg.h>
/**
* Server side gets a GetClientStatsMsgEx request
*/
bool GetClientStatsMsgEx::processIncoming(ResponseContext& ctx)
{
LogContext log("GetClientStatsMsgEx incoming");
uint64_t cookieIP = getCookieIP(); // requested is cookie+1
// get stats
MetaNodeOpStats* opStats = Program::getApp()->getNodeOpStats();
bool wantPerUserStats = isMsgHeaderFeatureFlagSet(GETCLIENTSTATSMSG_FLAG_PERUSERSTATS);
UInt64Vector opStatsVec;
opStats->mapToUInt64Vec(
cookieIP, GETCLIENTSTATSRESP_MAX_PAYLOAD_LEN, wantPerUserStats, &opStatsVec);
ctx.sendResponse(GetClientStatsRespMsg(&opStatsVec) );
return true;
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include <common/storage/StorageErrors.h>
#include <common/net/message/nodes/GetClientStatsMsg.h>
class GetClientStatsMsgEx : public GetClientStatsMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,65 @@
#include <common/net/message/nodes/GetNodeCapacityPoolsRespMsg.h>
#include <common/storage/StoragePool.h>
#include <program/Program.h>
#include "GetNodeCapacityPoolsMsgEx.h"
bool GetNodeCapacityPoolsMsgEx::processIncoming(ResponseContext& ctx)
{
const char* logContext = "GetNodeCapacityPools incoming";
CapacityPoolQueryType poolType = getCapacityPoolQueryType();
LOG_DEBUG(logContext, Log_SPAM, "PoolType: " + StringTk::intToStr(poolType) );
const App* app = Program::getApp();
GetNodeCapacityPoolsRespMsg::PoolsMap capacityPoolsMap;
switch(poolType)
{
case CapacityPoolQuery_META:
{
const NodeCapacityPools* capPools = app->getMetaCapacityPools();
capacityPoolsMap[StoragePoolId(StoragePoolStore::INVALID_POOL_ID)] =
capPools->getPoolsAsLists();
} break;
case CapacityPoolQuery_STORAGE:
{
const StoragePoolPtrVec storagePools = app->getStoragePoolStore()->getPoolsAsVec();
for (auto iter = storagePools.begin(); iter != storagePools.end(); iter++)
{
const TargetCapacityPools* capPools = (*iter)->getTargetCapacityPools();
capacityPoolsMap[(*iter)->getId()] = capPools->getPoolsAsLists();
}
} break;
case CapacityPoolQuery_STORAGEBUDDIES:
{
const StoragePoolPtrVec storagePools = app->getStoragePoolStore()->getPoolsAsVec();
for (auto iter = storagePools.begin(); iter != storagePools.end(); iter++)
{
const NodeCapacityPools* capPools = (*iter)->getBuddyCapacityPools();
capacityPoolsMap[(*iter)->getId()] = capPools->getPoolsAsLists();
}
} break;
default:
{
LogContext(logContext).logErr("Invalid pool type: " + StringTk::intToStr(poolType) );
return false;
} break;
}
ctx.sendResponse(GetNodeCapacityPoolsRespMsg(&capacityPoolsMap));
return true;
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include <common/net/message/nodes/GetNodeCapacityPoolsMsg.h>
class GetNodeCapacityPoolsMsgEx : public GetNodeCapacityPoolsMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,37 @@
#include <common/net/message/nodes/GetNodesRespMsg.h>
#include <program/Program.h>
#include "GetNodesMsgEx.h"
#include <boost/lexical_cast.hpp>
bool GetNodesMsgEx::processIncoming(ResponseContext& ctx)
{
LogContext log("GetNodes incoming");
NodeType nodeType = (NodeType)getValue();
LOG_DEBUG_CONTEXT(log, 5, "NodeType: " + boost::lexical_cast<std::string>(nodeType));
App* app = Program::getApp();
NodeStore* nodes = app->getServerStoreFromType(nodeType);
if(unlikely(!nodes) )
{
LOG(GENERAL, ERR, "Invalid node type.",
("Node Type", getNodeType()),
("Sender", ctx.peerName())
);
return true;
}
auto nodeList = nodes->referenceAllNodes();
NumNodeID rootID = app->getMetaRoot().getID();
bool rootIsBuddyMirrored = app->getMetaRoot().getIsMirrored();
ctx.sendResponse(GetNodesRespMsg(rootID, rootIsBuddyMirrored, nodeList) );
return true;
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include <common/net/message/nodes/GetNodesMsg.h>
class GetNodesMsgEx : public GetNodesMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,16 @@
#include <common/net/message/nodes/GetTargetMappingsRespMsg.h>
#include <common/toolkit/MessagingTk.h>
#include <program/Program.h>
#include "GetTargetMappingsMsgEx.h"
bool GetTargetMappingsMsgEx::processIncoming(ResponseContext& ctx)
{
App* app = Program::getApp();
TargetMapper* targetMapper = app->getTargetMapper();
ctx.sendResponse(GetTargetMappingsRespMsg(targetMapper->getMapping()));
return true;
}

View File

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

View File

@@ -0,0 +1,90 @@
#include <common/net/sock/NetworkInterfaceCard.h>
#include <program/Program.h>
#include "HeartbeatMsgEx.h"
#include <boost/lexical_cast.hpp>
bool HeartbeatMsgEx::processIncoming(ResponseContext& ctx)
{
LogContext log("Heartbeat incoming");
App* app = Program::getApp();
bool isNodeNew;
// construct node
NicAddressList& nicList = getNicList();
auto node = std::make_shared<Node>(getNodeType(), getNodeID(), getNodeNumID(), getPortUDP(),
getPortTCP(), nicList);
// set local nic capabilities
NicAddressList localNicList(app->getLocalNicList() );
NicListCapabilities localNicCaps;
NetworkInterfaceCard::supportedCapabilities(&localNicList, &localNicCaps);
node->getConnPool()->setLocalNicList(localNicList, localNicCaps);
std::string nodeIDWithTypeStr = node->getNodeIDWithTypeStr();
log.log(Log_DEBUG, std::string("Heartbeat node: ") + nodeIDWithTypeStr);
// add/update node in store
AbstractNodeStore* nodes = app->getAbstractNodeStoreFromType(getNodeType() );
if(!nodes)
{
log.logErr("Invalid node type: " + StringTk::intToStr(getNodeType() ) +
"(" + boost::lexical_cast<std::string>(getNodeType()) + ")");
goto ack_resp;
}
isNodeNew = (nodes->addOrUpdateNode(std::move(node)) == NodeStoreResult::Added);
if( (isNodeNew) && (getNodeType() != NODETYPE_Client) )
{ // log info about new server
bool supportsRDMA = NetworkInterfaceCard::supportsRDMA(&nicList);
std::string supports;
if (supportsRDMA)
supports = "; RDMA.";
log.log(Log_WARNING, std::string("New node: ") + nodeIDWithTypeStr + supports);
log.log(Log_DEBUG, "Number of nodes: "
"Meta: " + StringTk::intToStr(app->getMetaNodes()->getSize() ) + "; "
"Storage: " + StringTk::intToStr(app->getStorageNodes()->getSize() ) );
}
processIncomingRoot();
ack_resp:
acknowledge(ctx);
return true;
}
/**
* Handles the contained root information.
*/
void HeartbeatMsgEx::processIncomingRoot()
{
LogContext log("Heartbeat incoming");
// check whether root info is defined
if( (getNodeType() != NODETYPE_Meta) || !getRootNumID() )
return;
// try to apply the contained root info
if(Program::getApp()->getMetaRoot().setIfDefault(getRootNumID(), getRootIsBuddyMirrored()))
{
log.log(Log_CRITICAL, "Root (by Heartbeat): " + getRootNumID().str() );
Program::getApp()->getRootDir()->setOwnerNodeID(getRootNumID() );
if (getRootIsBuddyMirrored())
Program::getApp()->getRootDir()->setIsBuddyMirroredFlag(true);
}
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include <common/net/message/nodes/HeartbeatMsg.h>
class HeartbeatMsgEx : public HeartbeatMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
private:
void processIncomingRoot();
};

View File

@@ -0,0 +1,24 @@
#include <common/net/message/nodes/HeartbeatMsg.h>
#include <common/toolkit/MessagingTk.h>
#include <program/Program.h>
#include "HeartbeatRequestMsgEx.h"
bool HeartbeatRequestMsgEx::processIncoming(ResponseContext& ctx)
{
App* app = Program::getApp();
Config* cfg = app->getConfig();
Node& localNode = app->getLocalNode();
NumNodeID localNodeNumID = localNode.getNumID();
NumNodeID rootNodeID = app->getMetaRoot().getID();
NicAddressList nicList(localNode.getNicList());
HeartbeatMsg hbMsg(localNode.getAlias(), localNodeNumID, NODETYPE_Meta, &nicList);
hbMsg.setRootNumID(rootNodeID);
hbMsg.setPorts(cfg->getConnMetaPort(), cfg->getConnMetaPort() );
ctx.sendResponse(hbMsg);
return true;
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include <common/net/message/nodes/HeartbeatRequestMsg.h>
class HeartbeatRequestMsgEx : public HeartbeatRequestMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,45 @@
#include <common/net/message/nodes/MapTargetsRespMsg.h>
#include <common/toolkit/MessagingTk.h>
#include <common/toolkit/ZipIterator.h>
#include <program/Program.h>
#include "MapTargetsMsgEx.h"
bool MapTargetsMsgEx::processIncoming(ResponseContext& ctx)
{
LogContext log("MapTargetsMsg incoming");
const App* app = Program::getApp();
const NodeStoreServers* storageNodes = app->getStorageNodes();
TargetMapper* targetMapper = app->getTargetMapper();
const NumNodeID nodeID = getNodeID();
std::map<uint16_t, FhgfsOpsErr> results;
for (const auto mapping : getTargets())
{
const auto targetId = mapping.first;
const auto poolId = mapping.second;
const auto mapRes = targetMapper->mapTarget(targetId, nodeID, poolId);
results[targetId] = mapRes.first;
if ( (mapRes.first != FhgfsOpsErr_SUCCESS) && (mapRes.second) )
{ // target could be mapped and is new
LOG_DEBUG_CONTEXT(log, Log_WARNING, "Mapping "
"target " + StringTk::uintToStr(targetId) +
" => " +
storageNodes->getNodeIDWithTypeStr(nodeID) );
IGNORE_UNUSED_VARIABLE(storageNodes);
}
}
if(!acknowledge(ctx) )
ctx.sendResponse(MapTargetsRespMsg(results));
return true;
}

View File

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

View File

@@ -0,0 +1,23 @@
#include <common/toolkit/MessagingTk.h>
#include <program/Program.h>
#include "PublishCapacitiesMsgEx.h"
bool PublishCapacitiesMsgEx::processIncoming(ResponseContext& ctx)
{
LogContext log("PublishCapacitiesMsg incoming");
App* app = Program::getApp();
InternodeSyncer* syncer = app->getInternodeSyncer();
// force upload of capacity information
syncer->setForcePublishCapacities();
// send response
acknowledge(ctx);
return true;
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include <common/net/message/nodes/PublishCapacitiesMsg.h>
class PublishCapacitiesMsgEx : public PublishCapacitiesMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,23 @@
#include <common/toolkit/MessagingTk.h>
#include <program/Program.h>
#include "RefreshCapacityPoolsMsgEx.h"
bool RefreshCapacityPoolsMsgEx::processIncoming(ResponseContext& ctx)
{
LogContext log("RefreshCapacityPoolsMsg incoming");
App* app = Program::getApp();
InternodeSyncer* syncer = app->getInternodeSyncer();
// force update of capacity pools
syncer->setForcePoolsUpdate();
// send response
acknowledge(ctx);
return true;
}

View File

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

View File

@@ -0,0 +1,22 @@
#include <common/toolkit/MessagingTk.h>
#include <program/Program.h>
#include "RefreshTargetStatesMsgEx.h"
bool RefreshTargetStatesMsgEx::processIncoming(ResponseContext& ctx)
{
LogContext log("RefreshTargetStatesMsg incoming");
App* app = Program::getApp();
InternodeSyncer* syncer = app->getInternodeSyncer();
// force update of target states
syncer->setForceTargetStatesUpdate();
// send response
acknowledge(ctx);
return true;
}

View File

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

View File

@@ -0,0 +1,34 @@
#include <common/net/message/nodes/RemoveNodeRespMsg.h>
#include <common/toolkit/MessagingTk.h>
#include <program/Program.h>
#include "RemoveNodeMsgEx.h"
bool RemoveNodeMsgEx::processIncoming(ResponseContext& ctx)
{
App* app = Program::getApp();
LOG_DBG(GENERAL, SPAM, "Removing node.", getNodeNumID());
if (getNodeType() == NODETYPE_Meta || getNodeType() == NODETYPE_Storage)
{
NodeStoreServers* nodes = app->getServerStoreFromType(getNodeType());
auto node = nodes->referenceNode(getNodeNumID());
bool delRes = nodes->deleteNode(getNodeNumID());
// log
if (delRes)
{
LOG(GENERAL, WARNING, "Node removed.", ("node", node->getNodeIDWithTypeStr()));
LOG(GENERAL, WARNING, "Number of nodes in the system:",
("meta", app->getMetaNodes()->getSize()),
("storage", app->getStorageNodes()->getSize()));
}
}
if (!acknowledge(ctx))
ctx.sendResponse(RemoveNodeRespMsg(0));
return true;
}

View File

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

View File

@@ -0,0 +1,48 @@
#include <common/net/message/nodes/SetMirrorBuddyGroupRespMsg.h>
#include <common/nodes/MirrorBuddyGroupMapper.h>
#include <common/toolkit/MessagingTk.h>
#include <program/Program.h>
#include "SetMirrorBuddyGroupMsgEx.h"
bool SetMirrorBuddyGroupMsgEx::processIncoming(ResponseContext& ctx)
{
LogContext log("SetMirrorBuddyGroupMsg incoming");
App* app = Program::getApp();
MirrorBuddyGroupMapper* buddyGroupMapper;
NodeType nodeType = getNodeType();
switch (nodeType)
{
case NODETYPE_Storage:
buddyGroupMapper = app->getStorageBuddyGroupMapper();
break;
case NODETYPE_Meta:
buddyGroupMapper = app->getMetaBuddyGroupMapper();
break;
default:
log.logErr("Node type mismatch");
return false;
}
uint16_t buddyGroupID = this->getBuddyGroupID();
uint16_t primaryTargetID = this->getPrimaryTargetID();
uint16_t secondaryTargetID = this->getSecondaryTargetID();
bool allowUpdate = this->getAllowUpdate();
uint16_t newBuddyGroupID = 0;
FhgfsOpsErr mapResult = buddyGroupMapper->mapMirrorBuddyGroup(buddyGroupID, primaryTargetID,
secondaryTargetID, app->getLocalNode().getNumID(), allowUpdate, &newBuddyGroupID);
if(!acknowledge(ctx) )
ctx.sendResponse(SetMirrorBuddyGroupRespMsg(mapResult, newBuddyGroupID) );
return true;
}

View File

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

View File

@@ -0,0 +1,37 @@
#include <common/net/message/nodes/SetTargetConsistencyStatesRespMsg.h>
#include <common/nodes/TargetStateStore.h>
#include <common/toolkit/ZipIterator.h>
#include <program/Program.h>
#include "SetTargetConsistencyStatesMsgEx.h"
bool SetTargetConsistencyStatesMsgEx::processIncoming(ResponseContext& ctx)
{
const char* logContext = "Set target states incoming";
App* app = Program::getApp();
InternodeSyncer* internodeSyncer = app->getInternodeSyncer();
FhgfsOpsErr result = FhgfsOpsErr_SUCCESS;
if (getTargetIDs().size() != 1 || getStates().size() != 1)
{
LogContext(logContext).logErr("Invalid list size of target ID or state List (must be 1).");
result = FhgfsOpsErr_INTERNAL;
goto send_response;
}
if (getTargetIDs().front() != app->getLocalNodeNumID().val() )
{
LogContext(logContext).logErr("ID in message does not match local node ID.");
result = FhgfsOpsErr_INTERNAL;
goto send_response;
}
internodeSyncer->setNodeConsistencyState(
static_cast<TargetConsistencyState>(getStates().front() ) );
send_response:
ctx.sendResponse(SetTargetConsistencyStatesRespMsg(result) );
return true;
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include <common/net/message/nodes/SetTargetConsistencyStatesMsg.h>
class SetTargetConsistencyStatesMsgEx : public SetTargetConsistencyStatesMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,14 @@
#include "RefreshStoragePoolsMsgEx.h"
#include <program/Program.h>
bool RefreshStoragePoolsMsgEx::processIncoming(ResponseContext& ctx)
{
Program::getApp()->getInternodeSyncer()->setForceStoragePoolsUpdate();
// can only come as an AcknowledgableMsg from mgmtd
acknowledge(ctx);
return true;
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include <common/net/message/nodes/storagepools/RefreshStoragePoolsMsg.h>
class RefreshStoragePoolsMsgEx : public RefreshStoragePoolsMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View 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"; }
};

View 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);
}

View 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"; }
};

View 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));
}

View 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"; }
};

View 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);
}

View 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"; }
};

View 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);
}

View 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"; }
};

View 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);
}

View 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"; }
};

View 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);
}

View 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"; }
};

View 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);
}

View 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;
};

View File

@@ -0,0 +1,20 @@
#include <program/Program.h>
#include <common/net/message/storage/GetHighResStatsRespMsg.h>
#include <common/toolkit/MessagingTk.h>
#include "GetHighResStatsMsgEx.h"
bool GetHighResStatsMsgEx::processIncoming(ResponseContext& ctx)
{
HighResStatsList statsHistory;
uint64_t lastStatsMS = getValue();
// get stats history
StatsCollector* statsCollector = Program::getApp()->getStatsCollector();
statsCollector->getStatsSince(lastStatsMS, statsHistory);
ctx.sendResponse(GetHighResStatsRespMsg(&statsHistory) );
return true;
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include <common/storage/StorageErrors.h>
#include <common/net/message/storage/GetHighResStatsMsg.h>
class GetHighResStatsMsgEx : public GetHighResStatsMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
};

View File

@@ -0,0 +1,49 @@
#include <program/Program.h>
#include <common/net/message/storage/StatStoragePathRespMsg.h>
#include <common/toolkit/MessagingTk.h>
#include "StatStoragePathMsgEx.h"
bool StatStoragePathMsgEx::processIncoming(ResponseContext& ctx)
{
int64_t sizeTotal = 0;
int64_t sizeFree = 0;
int64_t inodesTotal = 0;
int64_t inodesFree = 0;
FhgfsOpsErr statRes = statStoragePath(&sizeTotal, &sizeFree, &inodesTotal, &inodesFree);
ctx.sendResponse(StatStoragePathRespMsg(statRes, sizeTotal, sizeFree, inodesTotal, inodesFree) );
App* app = Program::getApp();
app->getNodeOpStats()->updateNodeOp(ctx.getSocket()->getPeerIP(), MetaOpCounter_STATFS,
getMsgHeaderUserID() );
return true;
}
FhgfsOpsErr StatStoragePathMsgEx::statStoragePath(int64_t* outSizeTotal, int64_t* outSizeFree,
int64_t* outInodesTotal, int64_t* outInodesFree)
{
const char* logContext = "StatStoragePathMsg (stat path)";
std::string pathStr = Program::getApp()->getMetaPath();
bool statSuccess = StorageTk::statStoragePath(
pathStr, outSizeTotal, outSizeFree, outInodesTotal, outInodesFree);
if(unlikely(!statSuccess) )
{ // error
LogContext(logContext).logErr("Unable to statfs() storage path: " + pathStr +
" (SysErr: " + System::getErrString() );
return FhgfsOpsErr_INTERNAL;
}
StorageTk::statStoragePathOverride(pathStr, outSizeFree, outInodesFree);
return FhgfsOpsErr_SUCCESS;
}

View File

@@ -0,0 +1,18 @@
#pragma once
#include <common/storage/StorageErrors.h>
#include <common/net/message/storage/StatStoragePathMsg.h>
// derives from config option "StoragePath" and actually is similar to statfs()
class StatStoragePathMsgEx : public StatStoragePathMsg
{
public:
virtual bool processIncoming(ResponseContext& ctx);
private:
FhgfsOpsErr statStoragePath(int64_t* outSizeTotal, int64_t* outSizeFree,
int64_t* outInodesTotal, int64_t* outInodesFree);
};

View File

@@ -0,0 +1,81 @@
#include <common/net/message/control/GenericResponseMsg.h>
#include <common/net/message/storage/TruncFileRespMsg.h>
#include <common/toolkit/MessagingTk.h>
#include <components/FileEventLogger.h>
#include <net/msghelpers/MsgHelperTrunc.h>
#include "TruncFileMsgEx.h"
#include <program/Program.h>
FileIDLock TruncFileMsgEx::lock(EntryLockStore& store)
{
return {&store, getEntryInfo()->getEntryID(), true};
}
bool TruncFileMsgEx::processIncoming(ResponseContext& ctx)
{
return BaseType::processIncoming(ctx);
}
std::unique_ptr<MirroredMessageResponseState> TruncFileMsgEx::executeLocally(ResponseContext& ctx,
bool isSecondary)
{
App* app = Program::getApp();
// update operation counters
updateNodeOp(ctx, MetaOpCounter_TRUNCATE);
MetaStore* metaStore = Program::getApp()->getMetaStore();
if (!isSecondary)
{
FhgfsOpsErr truncRes = MsgHelperTrunc::truncFile(getEntryInfo(), getFilesize(),
isMsgHeaderFeatureFlagSet(TRUNCFILEMSG_FLAG_USE_QUOTA), getMsgHeaderUserID(),
dynAttribs);
if (truncRes == FhgfsOpsErr_SUCCESS && (shouldFixTimestamps() || getFileEvent()))
{
auto [inode, referenceRes] = metaStore->referenceFile(getEntryInfo());
unsigned numHardlinks = 0;
if (likely(inode))
{
if (shouldFixTimestamps())
fixInodeTimestamp(*inode, mirroredTimestamps, nullptr);
numHardlinks = inode->getNumHardlinks();
metaStore->releaseFile(getEntryInfo()->getParentEntryID(), inode);
}
if (app->getFileEventLogger() && getFileEvent())
{
EventContext eventCtx = makeEventContext(
getEntryInfo(),
getEntryInfo()->getParentEntryID(),
getMsgHeaderUserID(),
"",
numHardlinks,
isSecondary
);
logEvent(app->getFileEventLogger(), *getFileEvent(), eventCtx);
}
}
return boost::make_unique<ResponseState>(truncRes);
}
auto [inode, referenceRes] = metaStore->referenceFile(getEntryInfo());
if(!inode)
return boost::make_unique<ResponseState>(referenceRes);
inode->setDynAttribs(dynAttribs);
if (shouldFixTimestamps())
fixInodeTimestamp(*inode, mirroredTimestamps, nullptr);
inode->updateInodeOnDisk(getEntryInfo());
metaStore->releaseFile(getEntryInfo()->getParentEntryID(), inode);
return boost::make_unique<ResponseState>(FhgfsOpsErr_SUCCESS);
}
void TruncFileMsgEx::forwardToSecondary(ResponseContext& ctx)
{
sendToSecondary(ctx, *this, NETMSGTYPE_TruncFileResp);
}

View File

@@ -0,0 +1,34 @@
#pragma once
#include <common/net/message/storage/TruncFileMsg.h>
#include <common/net/message/storage/TruncFileRespMsg.h>
#include <net/message/MirroredMessage.h>
#include <storage/MetaStore.h>
class TruncFileMsgEx : public MirroredMessage<TruncFileMsg, FileIDLock>
{
public:
typedef ErrorCodeResponseState<TruncFileRespMsg, NETMSGTYPE_TruncFile> 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<TruncFileRespMsg&>(resp).getValue();
}
const char* mirrorLogContext() const override { return "TruncFileMsgEx/forward"; }
};

View File

@@ -0,0 +1,143 @@
#include <common/net/message/storage/attribs/GetEntryInfoRespMsg.h>
#include <common/storage/striping/Raid0Pattern.h>
#include <common/toolkit/MessagingTk.h>
#include <program/Program.h>
#include <storage/MetaStore.h>
#include "GetEntryInfoMsgEx.h"
bool GetEntryInfoMsgEx::processIncoming(ResponseContext& ctx)
{
#ifdef BEEGFS_DEBUG
const char* logContext = "GetEntryInfoMsg incoming";
#endif // BEEGFS_DEBUG
LOG_DEBUG(logContext, Log_SPAM,
"ParentEntryID: " + this->getEntryInfo()->getParentEntryID() + "; "
"entryID: " + this->getEntryInfo()->getParentEntryID() );
return BaseType::processIncoming(ctx);
}
FileIDLock GetEntryInfoMsgEx::lock(EntryLockStore& store)
{
return {&store, getEntryInfo()->getEntryID(), false};
}
std::unique_ptr<MirroredMessageResponseState> GetEntryInfoMsgEx::executeLocally(ResponseContext& ctx,
bool isSecondary)
{
GetEntryInfoMsgResponseState resp;
EntryInfo* entryInfo = this->getEntryInfo();
StripePattern* pattern = NULL;
FhgfsOpsErr getInfoRes;
PathInfo pathInfo;
RemoteStorageTarget rstInfo;
uint32_t numSessionsRead = 0;
uint32_t numSessionsWrite = 0;
uint8_t dataState = 0;
if (entryInfo->getParentEntryID().empty())
{
// special case: get info for root directory
// no pathInfo here, as this is currently only used for fileInodes
getInfoRes = getRootInfo(&pattern, &rstInfo);
}
else
{
getInfoRes = getInfo(entryInfo, &pattern, &pathInfo, &rstInfo, numSessionsRead,
numSessionsWrite, dataState);
}
if (getInfoRes != FhgfsOpsErr_SUCCESS)
{ // error occurred => create a dummy pattern
UInt16Vector dummyStripeNodes;
pattern = new Raid0Pattern(1, dummyStripeNodes);
}
resp.setGetEntryInfoResult(getInfoRes);
resp.setStripePattern(pattern);
resp.setPathInfo(pathInfo);
resp.setRemoteStorageTarget(rstInfo);
resp.setNumSessionsRead(numSessionsRead);
resp.setNumSessionsWrite(numSessionsWrite);
resp.setFileDataState(dataState);
App* app = Program::getApp();
app->getNodeOpStats()->updateNodeOp(ctx.getSocket()->getPeerIP(), MetaOpCounter_GETENTRYINFO,
getMsgHeaderUserID() );
return boost::make_unique<ResponseState>(std::move(resp));
}
/**
* @param outPattern StripePattern clone (in case of success), that must be deleted by the caller
*/
FhgfsOpsErr GetEntryInfoMsgEx::getInfo(EntryInfo* entryInfo, StripePattern** outPattern,
PathInfo* outPathInfo, RemoteStorageTarget* outRstInfo, uint32_t& outNumReadSessions,
uint32_t& outNumWriteSessions, uint8_t& outDataState)
{
MetaStore* metaStore = Program::getApp()->getMetaStore();
if (entryInfo->getEntryType() == DirEntryType_DIRECTORY)
{ // entry is a directory
DirInode* dir = metaStore->referenceDir(entryInfo->getEntryID(),
entryInfo->getIsBuddyMirrored(), true);
if(dir)
{
*outPattern = dir->getStripePatternClone();
outRstInfo->set(dir->getRemoteStorageTargetInfo());
metaStore->releaseDir(entryInfo->getEntryID() );
return FhgfsOpsErr_SUCCESS;
}
}
else
{ // entry is a file
auto [fileInode, referenceRes] = metaStore->referenceFile(entryInfo);
if(fileInode)
{
*outPattern = fileInode->getStripePattern()->clone();
outRstInfo->set(fileInode->getRemoteStorageTargetInfo());
fileInode->getPathInfo(outPathInfo);
outNumReadSessions = fileInode->getNumSessionsRead();
outNumWriteSessions = fileInode->getNumSessionsWrite();
outDataState = fileInode->getFileState().getRawValue();
metaStore->releaseFile(entryInfo->getParentEntryID(), fileInode);
return referenceRes;
}
}
return FhgfsOpsErr_PATHNOTEXISTS;
}
/**
* @param outPattern StripePattern clone (in case of success), that must be deleted by the caller
*/
FhgfsOpsErr GetEntryInfoMsgEx::getRootInfo(StripePattern** outPattern, RemoteStorageTarget* outRstInfo)
{
App* app = Program::getApp();
MirrorBuddyGroupMapper* metaBuddyGroupMapper = app->getMetaBuddyGroupMapper();
DirInode* rootDir = app->getRootDir();
NumNodeID localNodeID = app->getLocalNodeNumID();
if (rootDir->getIsBuddyMirrored())
{
uint16_t buddyGroupID = metaBuddyGroupMapper->getBuddyGroupID(localNodeID.val());
if (buddyGroupID != rootDir->getOwnerNodeID().val() )
return FhgfsOpsErr_NOTOWNER;
}
else
if (localNodeID != rootDir->getOwnerNodeID() )
return FhgfsOpsErr_NOTOWNER;
*outPattern = rootDir->getStripePatternClone();
outRstInfo->set(rootDir->getRemoteStorageTargetInfo());
return FhgfsOpsErr_SUCCESS;
}

View File

@@ -0,0 +1,98 @@
#pragma once
#include <storage/DirInode.h>
#include <common/storage/StorageErrors.h>
#include <common/net/message/storage/attribs/GetEntryInfoMsg.h>
#include <common/net/message/storage/attribs/GetEntryInfoRespMsg.h>
#include <net/message/MirroredMessage.h>
class GetEntryInfoMsgResponseState : public MirroredMessageResponseState
{
public:
GetEntryInfoMsgResponseState() : result(FhgfsOpsErr_INTERNAL), mirrorNodeID(0)
{
}
GetEntryInfoMsgResponseState(GetEntryInfoMsgResponseState&& other) :
result(other.result),
mirrorNodeID(other.mirrorNodeID),
pattern(std::move(other.pattern)),
pathInfo(std::move(other.pathInfo)),
rst(std::move(other.rst)),
numSessionsRead(other.numSessionsRead),
numSessionsWrite(other.numSessionsWrite),
fileDataState(other.fileDataState)
{
}
void sendResponse(NetMessage::ResponseContext& ctx) override
{
GetEntryInfoRespMsg resp(result, pattern.get(), mirrorNodeID, &pathInfo, &rst,
numSessionsRead, numSessionsWrite, fileDataState);
ctx.sendResponse(resp);
}
// GetEntryInfoMsgEx is transformed into a mirrored message to utilize
// MirroredMessage::lock(), thereby 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 never gets forwarded to seconadary.
bool changesObservableState() const override
{
return false;
}
void setGetEntryInfoResult(FhgfsOpsErr result) { this->result = result; }
void setMirrorNodeID(uint16_t nodeId) { this->mirrorNodeID = nodeId; }
void setStripePattern(StripePattern* pattern) { this->pattern.reset(pattern); }
void setPathInfo(PathInfo const& pathInfo) { this->pathInfo = pathInfo; }
void setRemoteStorageTarget(RemoteStorageTarget const& rstInfo) { rst = rstInfo; }
void setNumSessionsRead(uint32_t numReaders) { numSessionsRead = numReaders; }
void setNumSessionsWrite(uint32_t numWriters) { numSessionsWrite = numWriters; }
void setFileDataState(uint8_t dataState) { fileDataState = dataState; }
protected:
uint32_t serializerTag() const override { return NETMSGTYPE_GetEntryInfo; }
void serializeContents(Serializer& ser) const override {}
private:
FhgfsOpsErr result;
uint16_t mirrorNodeID; // metadata mirror node (0 means "none")
std::unique_ptr<StripePattern> pattern;
PathInfo pathInfo;
RemoteStorageTarget rst;
uint32_t numSessionsRead;
uint32_t numSessionsWrite;
uint8_t fileDataState;
};
class GetEntryInfoMsgEx : public MirroredMessage<GetEntryInfoMsg, FileIDLock>
{
public:
typedef GetEntryInfoMsgResponseState ResponseState;
virtual bool processIncoming(ResponseContext& ctx) override;
FileIDLock lock(EntryLockStore& store) override;
bool isMirrored() override
{
return getEntryInfo()->getIsBuddyMirrored();
}
private:
std::unique_ptr<MirroredMessageResponseState> executeLocally(ResponseContext& ctx,
bool isSecondary) override;
void forwardToSecondary(ResponseContext& ctx) override {}
FhgfsOpsErr processSecondaryResponse(NetMessage& resp) override
{
return FhgfsOpsErr_SUCCESS;
}
FhgfsOpsErr getInfo(EntryInfo* entryInfo, StripePattern** outPattern, PathInfo* outPathInfo,
RemoteStorageTarget* outRstInfo, uint32_t& outNumReadSessions, uint32_t& outNumWriteSessions,
uint8_t& outDataState);
FhgfsOpsErr getRootInfo(StripePattern** outPattern, RemoteStorageTarget* outRstInfo);
const char* mirrorLogContext() const override { return "GetEntryInfoMsgEx/forward"; }
};

View File

@@ -0,0 +1,66 @@
#include <program/Program.h>
#include <common/net/message/storage/attribs/GetXAttrRespMsg.h>
#include <net/msghelpers/MsgHelperXAttr.h>
#include "GetXAttrMsgEx.h"
bool GetXAttrMsgEx::processIncoming(ResponseContext& ctx)
{
const char* logContext = "GetXAttrMsg incoming";
LogContext(logContext).log(Log_DEBUG , "name: " + this->getName() + "; size: " +
StringTk::intToStr(this->getSize()) + ";");
return BaseType::processIncoming(ctx);
}
FileIDLock GetXAttrMsgEx::lock(EntryLockStore& store)
{
return {&store, getEntryInfo()->getEntryID(), false};
}
std::unique_ptr<MirroredMessageResponseState> GetXAttrMsgEx::executeLocally(ResponseContext& ctx,
bool isSecondary)
{
const char* logContext = "Get XAttr Msg";
GetXAttrMsgResponseState resp;
EntryInfo* entryInfo = this->getEntryInfo();
CharVector xAttrValue;
FhgfsOpsErr getXAttrRes;
ssize_t size = this->getSize();
const std::string& name = this->getName();
App* app = Program::getApp();
Config* config = app->getConfig();
if (!config->getStoreClientXAttrs())
{
LogContext(logContext).log(Log_ERR,
"Received a GetXAttrMsg, but client-side extended attributes are disabled in config.");
getXAttrRes = FhgfsOpsErr_NOTSUPP;
goto resp;
}
// Clamp buffer size to the maximum the NetMsg can handle, plus one byte in the (unlikely) case
// the on-disk metadata is larger than that.
if (size > MsgHelperXAttr::MAX_VALUE_SIZE)
size = MsgHelperXAttr::MAX_VALUE_SIZE + 1;
std::tie(getXAttrRes, xAttrValue, size) = MsgHelperXAttr::getxattr(entryInfo, name, size);
if (size >= MsgHelperXAttr::MAX_VALUE_SIZE + 1 && getXAttrRes == FhgfsOpsErr_SUCCESS)
{
// The xattr on disk is at least one byte too large. In this case, we have to return
// an internal error because it won't fit the net message.
xAttrValue.clear();
getXAttrRes = FhgfsOpsErr_INTERNAL;
}
resp:
resp.setGetXAttrValue(xAttrValue);
resp.setSize(size);
resp.setGetXAttrResult(getXAttrRes);
app->getNodeOpStats()->updateNodeOp(ctx.getSocket()->getPeerIP(), MetaOpCounter_GETXATTR,
getMsgHeaderUserID() );
return boost::make_unique<ResponseState>(std::move(resp));
}

View File

@@ -0,0 +1,74 @@
#pragma once
#include <common/net/message/storage/attribs/GetXAttrMsg.h>
#include <common/net/message/storage/attribs/GetXAttrRespMsg.h>
#include <net/message/MirroredMessage.h>
class GetXAttrMsgResponseState : public MirroredMessageResponseState
{
public:
GetXAttrMsgResponseState() : size(0), returnCode(FhgfsOpsErr_INTERNAL)
{
}
GetXAttrMsgResponseState(GetXAttrMsgResponseState&& other) :
value(std::move(other.value)),
size(other.size),
returnCode(other.returnCode)
{
}
void sendResponse(NetMessage::ResponseContext& ctx) override
{
GetXAttrRespMsg resp(value, size, returnCode);
ctx.sendResponse(resp);
}
// GetXAttrMsgEx is converted into a mirrored message to utilize MirroredMessage::lock(),
// thereby preventing races with operations like unlink. However, forwarding this message
// to the secondary is unnecessary. Overriding the changesObservableState() function to
// always return false ensures that this message is never forwarded unnecessarily.
bool changesObservableState() const override
{
return false;
}
void setGetXAttrValue(const CharVector& value) { this->value = value; }
void setSize(size_t size) { this->size = size; }
void setGetXAttrResult(FhgfsOpsErr result) { this->returnCode = result; }
protected:
uint32_t serializerTag() const override { return NETMSGTYPE_GetXAttr; }
void serializeContents(Serializer& ser) const override {}
private:
CharVector value;
size_t size;
FhgfsOpsErr returnCode;
};
class GetXAttrMsgEx : public MirroredMessage<GetXAttrMsg, FileIDLock>
{
public:
typedef GetXAttrMsgResponseState ResponseState;
virtual bool processIncoming(ResponseContext& ctx);
FileIDLock lock(EntryLockStore& store) override;
bool isMirrored() override
{
return getEntryInfo()->getIsBuddyMirrored();
}
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 "GetXAttrMsgEx/forward"; }
};

View File

@@ -0,0 +1,72 @@
#include <program/Program.h>
#include <common/net/message/storage/attribs/ListXAttrRespMsg.h>
#include <net/msghelpers/MsgHelperXAttr.h>
#include "ListXAttrMsgEx.h"
bool ListXAttrMsgEx::processIncoming(ResponseContext& ctx)
{
#ifdef BEEGFS_DEBUG
const char* logContext = "ListXAttrMsg incoming";
#endif // BEEGFS_DEBUG
LOG_DEBUG(logContext, Log_DEBUG, "size: " + StringTk::intToStr(this->getSize()) + ";");
return BaseType::processIncoming(ctx);
}
FileIDLock ListXAttrMsgEx::lock(EntryLockStore& store)
{
return {&store, getEntryInfo()->getEntryID(), false};
}
std::unique_ptr<MirroredMessageResponseState> ListXAttrMsgEx::executeLocally(ResponseContext& ctx,
bool isSecondary)
{
const char* logContext = "List XAttr Msg";
ListXAttrMsgResponseState resp;
App* app = Program::getApp();
Config* config = app->getConfig();
EntryInfo* entryInfo = this->getEntryInfo();
size_t listSize = 0;
StringVector xAttrVec;
FhgfsOpsErr listXAttrRes;
if (!config->getStoreClientXAttrs() )
{
LogContext(logContext).log(Log_ERR,
"Received a ListXAttrMsg, but client-side extended attributes are disabled in config.");
listXAttrRes = FhgfsOpsErr_NOTSUPP;
goto resp;
}
std::tie(listXAttrRes, xAttrVec) = MsgHelperXAttr::listxattr(entryInfo);
for (StringVectorConstIter it = xAttrVec.begin(); it != xAttrVec.end(); ++it)
{
// Plus one byte to account for the '\0's separating the list elements in the buffer.
listSize += it->size() + 1;
}
// note: MsgHelperXAttr::MAX_SIZE is a ssize_t, which is always positive, so it will always fit
// into a size_t
if ((listSize >= (size_t)MsgHelperXAttr::MAX_VALUE_SIZE + 1)
&& (listXAttrRes == FhgfsOpsErr_SUCCESS))
{
// The xattr list on disk is at least one byte too large. In this case, we have to return
// an internal error because it won't fit the net message.
xAttrVec.clear();
listXAttrRes = FhgfsOpsErr_TOOBIG;
}
resp:
resp.setListXAttrValue(xAttrVec);
resp.setSize(listSize);
resp.setListXAttrResult(listXAttrRes);
app->getNodeOpStats()->updateNodeOp(ctx.getSocket()->getPeerIP(), MetaOpCounter_LISTXATTR,
getMsgHeaderUserID() );
return boost::make_unique<ResponseState>(std::move(resp));
}

View File

@@ -0,0 +1,74 @@
#pragma once
#include <common/net/message/storage/attribs/ListXAttrMsg.h>
#include <common/net/message/storage/attribs/ListXAttrRespMsg.h>
#include <net/message/MirroredMessage.h>
class ListXAttrMsgResponseState : public MirroredMessageResponseState
{
public:
ListXAttrMsgResponseState() : size(0), returnCode(FhgfsOpsErr_INTERNAL)
{
}
ListXAttrMsgResponseState(ListXAttrMsgResponseState&& other) :
value(std::move(other.value)),
size(other.size),
returnCode(other.returnCode)
{
}
void sendResponse(NetMessage::ResponseContext& ctx) override
{
ListXAttrRespMsg resp(value, size, returnCode);
ctx.sendResponse(resp);
}
// ListXAttrMsgEx 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 changesObservableState() function to always
// return false ensures that this message is never forwarded unnecessarily.
bool changesObservableState() const override
{
return false;
}
void setListXAttrValue(const StringVector& value) { this->value = value; }
void setSize(size_t size) { this->size = size; }
void setListXAttrResult(FhgfsOpsErr result) { this->returnCode = result; }
protected:
uint32_t serializerTag() const override { return NETMSGTYPE_ListXAttr; }
void serializeContents(Serializer& ser) const override {}
private:
StringVector value;
size_t size;
FhgfsOpsErr returnCode;
};
class ListXAttrMsgEx : public MirroredMessage<ListXAttrMsg, FileIDLock>
{
public:
typedef ListXAttrMsgResponseState ResponseState;
virtual bool processIncoming(ResponseContext& ctx) override;
FileIDLock lock(EntryLockStore& store) override;
bool isMirrored() override
{
return getEntryInfo()->getIsBuddyMirrored();
}
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 "ListXAttrMsgEx/forward"; }
};

Some files were not shown because too many files have changed in this diff Show More