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,38 @@
#pragma once
#include <common/components/worker/Work.h>
#include <common/threading/Atomics.h>
#include <common/threading/Condition.h>
#include <common/app/log/Logger.h>
/**
* Work item intended to stop all worker threads temporarily, detect that all are stopped using a
* barrier, and restarting them using the same barrier.
* Example:
* Barrier workerBarrier(numWorkers + 1);
* <insert instance of BarrierWorkItem(&workerBarrier) into personal queue of numWorkers threads>
* workerBarrier.wait(); // Wait for all workers to stop
* <do something while workers are stopped>
* workerBarrier.wait(); // restart the workers
*/
class BarrierWork : public Work
{
public:
BarrierWork(Barrier* barrier) :
barrier(barrier)
{ }
virtual ~BarrierWork() { }
void process(char*, unsigned, char*, unsigned)
{
LOG_DBG(WORKQUEUES, DEBUG, "Start blocking.");
barrier->wait();
barrier->wait();
LOG_DBG(WORKQUEUES, DEBUG, "Done.");
}
private:
Barrier* barrier;
};

View File

@@ -0,0 +1,114 @@
#include <common/app/log/LogContext.h>
#include <common/app/AbstractApp.h>
#include <common/threading/PThread.h>
#include <common/net/message/session/opening/CloseChunkFileMsg.h>
#include <common/net/message/session/opening/CloseChunkFileRespMsg.h>
#include <common/net/message/NetMessage.h>
#include <program/Program.h>
#include "CloseChunkFileWork.h"
#include <boost/lexical_cast.hpp>
void CloseChunkFileWork::process(char* bufIn, unsigned bufInLen, char* bufOut, unsigned bufOutLen)
{
FhgfsOpsErr commRes = communicate();
*outResult = commRes;
counter->incCount();
}
FhgfsOpsErr CloseChunkFileWork::communicate()
{
const char* logContext = "Close chunk file work";
App* app = Program::getApp();
// prepare request message
CloseChunkFileMsg closeMsg(sessionID, fileHandleID, targetID, pathInfoPtr);
if(pattern->getPatternType() == StripePatternType_BuddyMirror)
{
closeMsg.addMsgHeaderFeatureFlag(CLOSECHUNKFILEMSG_FLAG_BUDDYMIRROR);
if(useBuddyMirrorSecond)
{
closeMsg.addMsgHeaderFeatureFlag(CLOSECHUNKFILEMSG_FLAG_NODYNAMICATTRIBS);
closeMsg.addMsgHeaderFeatureFlag(CLOSECHUNKFILEMSG_FLAG_BUDDYMIRROR_SECOND);
}
}
closeMsg.setMsgHeaderUserID(msgUserID);
// prepare communication
RequestResponseTarget rrTarget(targetID, app->getTargetMapper(), app->getStorageNodes() );
rrTarget.setTargetStates(app->getTargetStateStore() );
if(pattern->getPatternType() == StripePatternType_BuddyMirror)
rrTarget.setMirrorInfo(app->getStorageBuddyGroupMapper(), useBuddyMirrorSecond);
RequestResponseArgs rrArgs(NULL, &closeMsg, NETMSGTYPE_CloseChunkFileResp);
// communicate
FhgfsOpsErr requestRes = MessagingTk::requestResponseTarget(&rrTarget, &rrArgs);
if(unlikely(requestRes != FhgfsOpsErr_SUCCESS) )
{
LogContext(logContext).log(Log_WARNING,
"Communication with storage target failed. " +
std::string(pattern->getPatternType() == StripePatternType_BuddyMirror ? "Mirror " : "") +
"TargetID: " + StringTk::uintToStr(targetID) + "; "
"Session: " + sessionID.str() + "; "
"FileHandle: " + fileHandleID);
return requestRes;
}
// correct response type received
CloseChunkFileRespMsg* closeRespMsg = (CloseChunkFileRespMsg*)rrArgs.outRespMsg.get();
FhgfsOpsErr closeRemoteRes = closeRespMsg->getResult();
// set current dynamic attribs (even if result not success, because then storageVersion==0)
if(outDynAttribs)
{
DynamicFileAttribs currentDynAttribs(closeRespMsg->getStorageVersion(),
closeRespMsg->getFileSize(), closeRespMsg->getAllocedBlocks(),
closeRespMsg->getModificationTimeSecs(), closeRespMsg->getLastAccessTimeSecs() );
*outDynAttribs = currentDynAttribs;
}
if(closeRemoteRes != FhgfsOpsErr_SUCCESS)
{ // error: chunk file not closed
int logLevel = Log_WARNING;
if(closeRemoteRes == FhgfsOpsErr_INUSE)
logLevel = Log_DEBUG; // happens on ctrl+c, so don't irritate user with these log msgs
LogContext(logContext).log(logLevel,
"Closing chunk file on target failed. " +
std::string(pattern->getPatternType() == StripePatternType_BuddyMirror ? "Mirror " : "") +
"TargetID: " + StringTk::uintToStr(targetID) + "; "
"Error: " + boost::lexical_cast<std::string>(closeRemoteRes) + "; "
"Session: " + sessionID.str() + "; "
"FileHandle: " + std::string(fileHandleID) );
return closeRemoteRes;
}
// success: chunk file closed
LOG_DEBUG(logContext, Log_DEBUG,
"Closed chunk file on target. " +
std::string( (pattern->getPatternType() == StripePatternType_BuddyMirror) ? "Mirror " : "") +
"TargetID: " + StringTk::uintToStr(targetID) + "; "
"Session: " + sessionID.str() + "; "
"FileHandle: " + fileHandleID);
return FhgfsOpsErr_SUCCESS;
}

View File

@@ -0,0 +1,69 @@
#pragma once
#include <common/components/worker/Work.h>
#include <common/net/sock/Socket.h>
#include <common/storage/striping/StripePattern.h>
#include <common/storage/StorageErrors.h>
#include <common/toolkit/SynchronizedCounter.h>
#include <common/storage/striping/ChunkFileInfo.h>
#include <common/Common.h>
class CloseChunkFileWork : public Work
{
public:
/**
* @param outDynAttribs may be NULL if caller is not interested
*/
CloseChunkFileWork(const NumNodeID sessionID, const std::string& fileHandleID,
StripePattern* pattern, uint16_t targetID, PathInfo* pathInfo,
DynamicFileAttribs *outDynAttribs, FhgfsOpsErr* outResult, SynchronizedCounter* counter) :
sessionID(sessionID), fileHandleID(fileHandleID), pattern(pattern), targetID(targetID),
pathInfoPtr(pathInfo), outDynAttribs(outDynAttribs), outResult(outResult),
counter(counter), useBuddyMirrorSecond(false),
msgUserID(NETMSG_DEFAULT_USERID)
{
// all assignments done in initializer list
}
virtual ~CloseChunkFileWork() {}
virtual void process(char* bufIn, unsigned bufInLen, char* bufOut, unsigned bufOutLen);
private:
NumNodeID sessionID;
std::string fileHandleID;
StripePattern* pattern;
uint16_t targetID;
PathInfo* pathInfoPtr; // to find chunk files
DynamicFileAttribs* outDynAttribs;
FhgfsOpsErr* outResult;
SynchronizedCounter* counter;
bool useBuddyMirrorSecond;
unsigned msgUserID;
FhgfsOpsErr communicate();
public:
// getters & setters
void setMsgUserID(unsigned msgUserID)
{
this->msgUserID = msgUserID;
}
void setUseBuddyMirrorSecond()
{
this->useBuddyMirrorSecond = true;
}
};

View File

@@ -0,0 +1,90 @@
#include <common/app/log/LogContext.h>
#include <common/app/AbstractApp.h>
#include <common/threading/PThread.h>
#include <common/net/message/storage/attribs/GetChunkFileAttribsMsg.h>
#include <common/net/message/storage/attribs/GetChunkFileAttribsRespMsg.h>
#include <common/net/message/NetMessage.h>
#include <program/Program.h>
#include "GetChunkFileAttribsWork.h"
void GetChunkFileAttribsWork::process(char* bufIn, unsigned bufInLen, char* bufOut,
unsigned bufOutLen)
{
FhgfsOpsErr commRes = communicate();
*outResult = commRes;
counter->incCount();
}
/**
* @return true if communication successful
*/
FhgfsOpsErr GetChunkFileAttribsWork::communicate()
{
const char* logContext = "Stat chunk file work";
App* app = Program::getApp();
GetChunkFileAttribsMsg getSizeMsg(entryID, targetID, pathInfo);
if(pattern->getPatternType() == StripePatternType_BuddyMirror)
{
getSizeMsg.addMsgHeaderFeatureFlag(GETCHUNKFILEATTRSMSG_FLAG_BUDDYMIRROR);
if(useBuddyMirrorSecond)
getSizeMsg.addMsgHeaderFeatureFlag(GETCHUNKFILEATTRSMSG_FLAG_BUDDYMIRROR_SECOND);
}
getSizeMsg.setMsgHeaderUserID(msgUserID);
// prepare communication
RequestResponseTarget rrTarget(targetID, app->getTargetMapper(), app->getStorageNodes() );
rrTarget.setTargetStates(app->getTargetStateStore() );
if(pattern->getPatternType() == StripePatternType_BuddyMirror)
rrTarget.setMirrorInfo(app->getStorageBuddyGroupMapper(), useBuddyMirrorSecond);
RequestResponseArgs rrArgs(NULL, &getSizeMsg, NETMSGTYPE_GetChunkFileAttribsResp);
// communicate
FhgfsOpsErr requestRes = MessagingTk::requestResponseTarget(&rrTarget, &rrArgs);
if(unlikely(requestRes != FhgfsOpsErr_SUCCESS) )
{ // communication error
LogContext(logContext).log(Log_WARNING,
"Communication with storage target failed. " +
std::string(pattern->getPatternType() == StripePatternType_BuddyMirror ? "Mirror " : "") +
"TargetID: " + StringTk::uintToStr(targetID) + "; "
"EntryID: " + entryID);
return requestRes;
}
// correct response type received
auto* getSizeRespMsg = (GetChunkFileAttribsRespMsg*)rrArgs.outRespMsg.get();
FhgfsOpsErr getSizeResult = getSizeRespMsg->getResult();
if(getSizeResult != FhgfsOpsErr_SUCCESS)
{ // error: chunk file not unlinked
LogContext(logContext).log(Log_WARNING,
"Getting chunk file attributes from target failed. " +
std::string(pattern->getPatternType() == StripePatternType_BuddyMirror ? "Mirror " : "") +
"TargetID: " + StringTk::uintToStr(targetID) + "; "
"EntryID: " + entryID);
return getSizeResult;
}
// success: chunk file dynamic attribs refreshed
DynamicFileAttribs currentDynAttribs(getSizeRespMsg->getStorageVersion(),
getSizeRespMsg->getSize(), getSizeRespMsg->getAllocedBlocks(),
getSizeRespMsg->getModificationTimeSecs(), getSizeRespMsg->getLastAccessTimeSecs() );
*outDynAttribs = currentDynAttribs;
return FhgfsOpsErr_SUCCESS;
}

View File

@@ -0,0 +1,64 @@
#pragma once
#include <common/components/worker/Work.h>
#include <common/net/sock/Socket.h>
#include <common/storage/striping/StripePattern.h>
#include <common/storage/PathInfo.h>
#include <common/storage/StorageErrors.h>
#include <common/toolkit/SynchronizedCounter.h>
#include <common/storage/striping/ChunkFileInfo.h>
#include <common/Common.h>
class GetChunkFileAttribsWork : public Work
{
public:
/**
* @param pathInfo: Only as reference pointer, not owned by this object
*/
GetChunkFileAttribsWork(const std::string& entryID, StripePattern* pattern, uint16_t targetID,
PathInfo* pathInfo, DynamicFileAttribs *outDynAttribs, FhgfsOpsErr* outResult,
SynchronizedCounter* counter) : entryID(entryID), pattern(pattern), targetID(targetID),
pathInfo(pathInfo), outDynAttribs(outDynAttribs), outResult(outResult), counter(counter),
useBuddyMirrorSecond(false), msgUserID(NETMSG_DEFAULT_USERID)
{
// all assignments done in initializer list
}
virtual ~GetChunkFileAttribsWork()
{
}
virtual void process(char* bufIn, unsigned bufInLen, char* bufOut, unsigned bufOutLen);
private:
std::string entryID;
StripePattern* pattern;
uint16_t targetID;
PathInfo *pathInfo; // only as reference ptr, not owned by this object!
DynamicFileAttribs* outDynAttribs;
FhgfsOpsErr* outResult;
SynchronizedCounter* counter;
bool useBuddyMirrorSecond;
unsigned msgUserID; // only used for msg header info
FhgfsOpsErr communicate();
public:
void setMsgUserID(unsigned msgUserID)
{
this->msgUserID = msgUserID;
}
void setUseBuddyMirrorSecond()
{
this->useBuddyMirrorSecond = true;
}
};

View File

@@ -0,0 +1,218 @@
#include <common/app/log/LogContext.h>
#include <common/app/AbstractApp.h>
#include <common/net/message/control/AckMsg.h>
#include <common/net/message/session/locking/LockGrantedMsg.h>
#include <common/net/message/NetMessage.h>
#include <program/Program.h>
#include "LockEntryNotificationWork.h"
#include <mutex>
Mutex LockEntryNotificationWork::ackCounterMutex;
unsigned LockEntryNotificationWork::ackCounter = 0;
void LockEntryNotificationWork::process(char* bufIn, unsigned bufInLen, char* bufOut,
unsigned bufOutLen)
{
/* note: this code is very similar to LockRangeNotificationWork, so if you change something here,
you probably want to change it there, too. */
const char* logContext = "LockEntryNotificationWork::process";
App* app = Program::getApp();
Logger* logger = Logger::getLogger();
Config* cfg = app->getConfig();
AcknowledgmentStore* ackStore = app->getAckStore();
DatagramListener* dgramLis = app->getDatagramListener();
MetaStore* metaStore = app->getMetaStore();
NodeStoreClients* clients = app->getClientNodes();
NumNodeID localNodeID = app->getLocalNode().getNumID();
// max total time is ackWaitMS * numRetries, defaults to 333ms * 15 => 5s
int ackWaitSleepMS = cfg->getTuneLockGrantWaitMS();
int numRetriesLeft = cfg->getTuneLockGrantNumRetries();
WaitAckMap waitAcks;
WaitAckMap receivedAcks;
WaitAckNotification notifier;
bool allAcksReceived = false;
// note: we use uint for tv_sec (not uint64) because 32 bits are enough here
// gives string like this: "time-counter-elck-"
std::string ackIDPrefix =
StringTk::uintToHexStr(TimeAbs().getTimeval()->tv_sec) + "-" +
StringTk::uintToHexStr(incAckCounter() ) + "-" "elck" "-";
if (notifyList.empty())
return; // nothing to be done
// create and register waitAcks
/* note: waitAcks store pointers to notifyList items, so make sure to not remove anything from
the list while we're still using the waitAcks pointers */
for (LockEntryNotifyListIter iter = notifyList.begin(); iter != notifyList.end(); iter++)
{
std::string ackID = ackIDPrefix + iter->lockAckID; // (we assume lockAckID is globally unique)
WaitAck waitAck(ackID, &(*iter) );
waitAcks.insert(WaitAckMapVal(ackID, waitAck) );
}
ackStore->registerWaitAcks(&waitAcks, &receivedAcks, &notifier);
// loop: send requests -> waitforcompletion -> resend
while(numRetriesLeft && !app->getSelfTerminate() )
{
// create waitAcks copy
WaitAckMap currentWaitAcks;
{
const std::lock_guard<Mutex> lock (notifier.waitAcksMutex);
currentWaitAcks = waitAcks;
}
// send messages
for(WaitAckMapIter iter = currentWaitAcks.begin(); iter != currentWaitAcks.end(); iter++)
{
EntryLockDetails* lockDetails = (EntryLockDetails*)iter->second.privateData;
LockGrantedMsg msg(lockDetails->lockAckID, iter->first, localNodeID);
std::pair<bool, unsigned> serializeRes = msg.serializeMessage(bufOut, bufOutLen);
if(unlikely(!serializeRes.first) )
{ // buffer too small - should never happen
logger->log(Log_CRITICAL, logContext, "BUG(?): Buffer too small for message "
"serialization: " + StringTk::intToStr(bufOutLen) + "/" +
StringTk::intToStr(serializeRes.second) );
continue;
}
auto node = clients->referenceNode(lockDetails->clientNumID);
if(unlikely(!node) )
{ // node not exists
logger->log(Log_DEBUG, logContext, "Cannot grant lock to unknown client: " +
lockDetails->clientNumID.str());
continue;
}
dgramLis->sendBufToNode(*node, bufOut, serializeRes.second);
}
// wait for acks
allAcksReceived = ackStore->waitForAckCompletion(&currentWaitAcks, &notifier, ackWaitSleepMS);
if(allAcksReceived)
break; // all acks received
// some waitAcks left => prepare next loop
numRetriesLeft--;
}
// waiting for acks is over
ackStore->unregisterWaitAcks(&waitAcks);
// check and handle results (waitAcks now contains all unreceived acks)
if (waitAcks.empty())
{
LOG_DBG(GENERAL, DEBUG, "Stats: received all acks.", receivedAcks.size(), notifyList.size());
return; // perfect, all acks received
}
// some acks were missing...
logger->log(Log_DEBUG, logContext, "Some replies to lock grants missing. Received: " +
StringTk::intToStr(receivedAcks.size() ) + "/" +
StringTk::intToStr(receivedAcks.size() + waitAcks.size() ) );
// the inode is supposed to be be referenced already
MetaFileHandle inode = metaStore->referenceLoadedFile(this->parentEntryID, this->isBuddyMirrored,
this->entryID);
if(unlikely(!inode) )
{ // locked inode cannot be referenced
logger->log(Log_DEBUG, logContext, "FileID cannot be referenced (file unlinked?): " +
this->entryID);
return;
}
// unlock all locks for which we didn't receive an ack
for(WaitAckMapIter iter = waitAcks.begin(); iter != waitAcks.end(); iter++)
{
EntryLockDetails* lockDetails = (EntryLockDetails*)iter->second.privateData;
unlockWaiter(*inode, lockDetails);
LOG_DEBUG(logContext, Log_DEBUG, "Reply was missing from: " + lockDetails->clientNumID.str());
}
// cancel all remaining lock waiters if too many acks were missing
// (this is very important to avoid long timeouts if multiple clients are gone/disconnected)
if(waitAcks.size() > 1)
{ // cancel all waiters
cancelAllWaiters(*inode);
}
// cleanup
metaStore->releaseFile(this->parentEntryID, inode);
}
/**
* Remove lock of a waiter from which we didn't receive an ack.
*/
void LockEntryNotificationWork::unlockWaiter(FileInode& inode, EntryLockDetails* lockDetails)
{
lockDetails->setUnlock();
if(lockType == LockEntryNotifyType_APPEND)
inode.flockAppend(*lockDetails);
else
if(lockType == LockEntryNotifyType_FLOCK)
inode.flockEntry(*lockDetails);
else
LOG(GENERAL, ERR, "Invalid lockType given.", lockType);
}
/**
* Cancel all remaining lock waiters.
*
* Usually called because too many acks were not received and we want to avoid repeated long
* timeout stalls.
*/
void LockEntryNotificationWork::cancelAllWaiters(FileInode& inode)
{
if(lockType == LockEntryNotifyType_APPEND)
inode.flockAppendCancelAllWaiters();
else
if(lockType == LockEntryNotifyType_FLOCK)
inode.flockEntryCancelAllWaiters();
else
LOG(GENERAL, ERR, "Invalid lockType given.", lockType);
}
unsigned LockEntryNotificationWork::incAckCounter()
{
const std::lock_guard<Mutex> lock(ackCounterMutex);
return ackCounter++;
}
Mutex* LockEntryNotificationWork::getDGramLisMutex(AbstractDatagramListener* dgramLis)
{
return dgramLis->getSendMutex();
}

View File

@@ -0,0 +1,57 @@
#pragma once
#include <common/Common.h>
#include <common/components/worker/Work.h>
#include <common/components/AbstractDatagramListener.h>
#include <common/storage/StorageErrors.h>
#include <storage/Locking.h>
class FileInode; // forward declaration
typedef std::list<EntryLockDetails> LockEntryNotifyList;
typedef LockEntryNotifyList::iterator LockEntryNotifyListIter;
typedef LockEntryNotifyList::const_iterator LockEntryNotifyListCIter;
class LockEntryNotificationWork : public Work
{
public:
/**
* @param notifyList will be owned and freed by this object, so do not use or free it after
* calling this.
*/
LockEntryNotificationWork(LockEntryNotifyType lockType, const std::string& parentEntryID,
const std::string& entryID, bool isBuddyMirrored, LockEntryNotifyList notifyList) :
lockType(lockType), parentEntryID(parentEntryID), entryID(entryID),
isBuddyMirrored(isBuddyMirrored), notifyList(std::move(notifyList))
{
}
virtual void process(char* bufIn, unsigned bufInLen, char* bufOut, unsigned bufOutLen);
private:
// static attributes & methods
static Mutex ackCounterMutex;
static unsigned ackCounter;
static unsigned incAckCounter();
// instance attributes & methods
LockEntryNotifyType lockType;
std::string parentEntryID;
std::string entryID;
bool isBuddyMirrored;
LockEntryNotifyList notifyList;
void unlockWaiter(FileInode& inode, EntryLockDetails* lockDetails);
void cancelAllWaiters(FileInode& inode);
Mutex* getDGramLisMutex(AbstractDatagramListener* dgramLis);
};

View File

@@ -0,0 +1,185 @@
#include <common/app/log/LogContext.h>
#include <common/app/AbstractApp.h>
#include <common/net/message/control/AckMsg.h>
#include <common/net/message/session/locking/LockGrantedMsg.h>
#include <common/net/message/NetMessage.h>
#include <program/Program.h>
#include "LockRangeNotificationWork.h"
#include <mutex>
Mutex LockRangeNotificationWork::ackCounterMutex;
unsigned LockRangeNotificationWork::ackCounter = 0;
void LockRangeNotificationWork::process(char* bufIn, unsigned bufInLen, char* bufOut,
unsigned bufOutLen)
{
/* note: this code is very similar to LockEntryNotificationWork, so if you change something here,
you probably want to change it there, too. */
const char* logContext = __func__;
App* app = Program::getApp();
Logger* logger = Logger::getLogger();
Config* cfg = app->getConfig();
AcknowledgmentStore* ackStore = app->getAckStore();
DatagramListener* dgramLis = app->getDatagramListener();
MetaStore* metaStore = app->getMetaStore();
NodeStoreClients* clients = app->getClientNodes();
NumNodeID localNodeID = app->getLocalNode().getNumID();
// max total time is ackWaitMS * numRetries, defaults to 333ms * 15 => 5s
int ackWaitSleepMS = cfg->getTuneLockGrantWaitMS();
int numRetriesLeft = cfg->getTuneLockGrantNumRetries();
WaitAckMap waitAcks;
WaitAckMap receivedAcks;
WaitAckNotification notifier;
bool allAcksReceived = false;
// note: we use uint for tv_sec (not uint64) because 32 bits are enough here
std::string ackIDPrefix =
StringTk::uintToHexStr(TimeAbs().getTimeval()->tv_sec) + "-" +
StringTk::uintToHexStr(incAckCounter() ) + "-"
"rlck" "-";
if (notifyList.empty())
return; // nothing to be done
// create and register waitAcks
/* note: waitAcks store pointers to notifyList items, so make sure to not remove anything from
the list while we're still using the waitAcks pointers */
for (LockRangeNotifyListIter iter = notifyList.begin(); iter != notifyList.end(); iter++)
{
std::string ackID = ackIDPrefix + iter->lockAckID; // (we assume lockAckID is globally unique)
WaitAck waitAck(ackID, &(*iter) );
waitAcks.insert(WaitAckMapVal(ackID, waitAck) );
}
ackStore->registerWaitAcks(&waitAcks, &receivedAcks, &notifier);
// loop: send requests -> waitforcompletion -> resend
while(numRetriesLeft && !app->getSelfTerminate() )
{
// create waitAcks copy
WaitAckMap currentWaitAcks;
{
const std::lock_guard<Mutex> lock(notifier.waitAcksMutex);
currentWaitAcks = waitAcks;
}
// send messages
for(WaitAckMapIter iter = currentWaitAcks.begin(); iter != currentWaitAcks.end(); iter++)
{
RangeLockDetails* lockDetails = (RangeLockDetails*)iter->second.privateData;
LockGrantedMsg msg(lockDetails->lockAckID, iter->first, localNodeID);
std::pair<bool, unsigned> serializeRes = msg.serializeMessage(bufOut, bufOutLen);
if(unlikely(!serializeRes.first) )
{ // buffer too small - should never happen
logger->log(Log_CRITICAL, logContext, "BUG(?): Buffer too small for message "
"serialization: " + StringTk::intToStr(bufOutLen) + "/" +
StringTk::intToStr(serializeRes.second) );
continue;
}
auto node = clients->referenceNode(lockDetails->clientNumID);
if(unlikely(!node) )
{ // node not exists
logger->log(Log_DEBUG, logContext, "Cannot grant lock to unknown client: " +
lockDetails->clientNumID.str());
continue;
}
dgramLis->sendBufToNode(*node, bufOut, serializeRes.second);
}
// wait for acks
allAcksReceived = ackStore->waitForAckCompletion(&currentWaitAcks, &notifier, ackWaitSleepMS);
if(allAcksReceived)
break; // all acks received
// some waitAcks left => prepare next loop
numRetriesLeft--;
}
// waiting for acks is over
ackStore->unregisterWaitAcks(&waitAcks);
// check and handle results (waitAcks now contains all unreceived acks)
if (waitAcks.empty())
{
LOG_DBG(GENERAL, DEBUG, "Stats: received all acks.", receivedAcks.size(), notifyList.size());
return; // perfect, all acks received
}
// some acks were missing...
logger->log(Log_DEBUG, logContext, "Some replies to lock grants missing. Received: " +
StringTk::intToStr(receivedAcks.size() ) + "/" +
StringTk::intToStr(receivedAcks.size() + waitAcks.size() ) );
// the inode is supposed to be be referenced already
MetaFileHandle inode = metaStore->referenceLoadedFile(this->parentEntryID, this->isBuddyMirrored,
this->entryID);
if(unlikely(!inode) )
{ // locked inode cannot be referenced
logger->log(Log_DEBUG, logContext, "FileID cannot be referenced (file unlinked?): "
+ this->entryID);
return;
}
// unlock all locks for which we didn't receive an ack
for(WaitAckMapIter iter = waitAcks.begin(); iter != waitAcks.end(); iter++)
{
RangeLockDetails* lockDetails = (RangeLockDetails*)iter->second.privateData;
lockDetails->setUnlock();
inode->flockRange(*lockDetails);
LOG_DEBUG(logContext, Log_DEBUG, "Reply was missing from: " + lockDetails->clientNumID.str());
}
// cancel all remaining lock waiters if too many acks were missing
// (this is very important to avoid long timeouts it multiple clients are gone/disconnected)
if(waitAcks.size() > 1)
{ // cancel all waiters
inode->flockRangeCancelAllWaiters();
}
// cleanup
metaStore->releaseFile(this->parentEntryID, inode);
}
unsigned LockRangeNotificationWork::incAckCounter()
{
const std::lock_guard<Mutex> lock(ackCounterMutex);
return ackCounter++;
}
Mutex* LockRangeNotificationWork::getDGramLisMutex(AbstractDatagramListener* dgramLis)
{
return dgramLis->getSendMutex();
}

View File

@@ -0,0 +1,49 @@
#pragma once
#include <common/components/worker/Work.h>
#include <common/components/AbstractDatagramListener.h>
#include <common/Common.h>
typedef std::list<RangeLockDetails> LockRangeNotifyList;
typedef LockRangeNotifyList::iterator LockRangeNotifyListIter;
typedef LockRangeNotifyList::const_iterator LockRangeNotifyListCIter;
class LockRangeNotificationWork : public Work
{
public:
/**
* @param notifyList will be owned and freed by this object, so do not use or free it after
* calling this.
*/
LockRangeNotificationWork(const std::string& parentEntryID, const std::string& entryID,
bool isBuddyMirrored, LockRangeNotifyList notifyList):
parentEntryID(parentEntryID), entryID(entryID), isBuddyMirrored(isBuddyMirrored),
notifyList(std::move(notifyList))
{
/* all assignments done in initializer list */
}
virtual void process(char* bufIn, unsigned bufInLen, char* bufOut, unsigned bufOutLen);
private:
// static attributes & methods
static Mutex ackCounterMutex;
static unsigned ackCounter;
static unsigned incAckCounter();
// instance attributes & methods
std::string parentEntryID;
std::string entryID;
bool isBuddyMirrored;
LockRangeNotifyList notifyList;
Mutex* getDGramLisMutex(AbstractDatagramListener* dgramLis);
};

View File

@@ -0,0 +1,97 @@
#include <common/app/log/LogContext.h>
#include <common/app/AbstractApp.h>
#include <common/threading/PThread.h>
#include <common/net/message/storage/attribs/SetLocalAttrMsg.h>
#include <common/net/message/storage/attribs/SetLocalAttrRespMsg.h>
#include <common/net/message/NetMessage.h>
#include <components/worker/SetChunkFileAttribsWork.h>
#include <program/Program.h>
void SetChunkFileAttribsWork::process(char* bufIn, unsigned bufInLen, char* bufOut,
unsigned bufOutLen)
{
FhgfsOpsErr commRes = communicate();
*outResult = commRes;
counter->incCount();
}
FhgfsOpsErr SetChunkFileAttribsWork::communicate()
{
const char* logContext = "Set chunk file attribs work";
App* app = Program::getApp();
SetLocalAttrMsg setAttrMsg(entryID, targetID, pathInfo, validAttribs, attribs, enableCreation);
if(pattern->getPatternType() == StripePatternType_BuddyMirror)
{
setAttrMsg.addMsgHeaderFeatureFlag(SETLOCALATTRMSG_FLAG_BUDDYMIRROR);
if(useBuddyMirrorSecond)
setAttrMsg.addMsgHeaderFeatureFlag(SETLOCALATTRMSG_FLAG_BUDDYMIRROR_SECOND);
}
if(quotaChown)
setAttrMsg.addMsgHeaderFeatureFlag(SETLOCALATTRMSG_FLAG_USE_QUOTA);
setAttrMsg.setMsgHeaderUserID(msgUserID);
// prepare communication
RequestResponseTarget rrTarget(targetID, app->getTargetMapper(), app->getStorageNodes() );
rrTarget.setTargetStates(app->getTargetStateStore() );
if(pattern->getPatternType() == StripePatternType_BuddyMirror)
rrTarget.setMirrorInfo(app->getStorageBuddyGroupMapper(), useBuddyMirrorSecond);
RequestResponseArgs rrArgs(NULL, &setAttrMsg, NETMSGTYPE_SetLocalAttrResp);
// communicate
FhgfsOpsErr requestRes = MessagingTk::requestResponseTarget(&rrTarget, &rrArgs);
if(unlikely(requestRes != FhgfsOpsErr_SUCCESS) )
{ // communication error
LogContext(logContext).log(Log_WARNING,
"Communication with storage target failed. " +
std::string(pattern->getPatternType() == StripePatternType_BuddyMirror ? "Mirror " : "") +
"TargetID: " + StringTk::uintToStr(targetID) + "; "
"entryID: " + entryID);
return requestRes;
}
// correct response type received
const auto setRespMsg = (const SetLocalAttrRespMsg*)rrArgs.outRespMsg.get();
FhgfsOpsErr setRespVal = setRespMsg->getResult();
if(setRespVal != FhgfsOpsErr_SUCCESS)
{ // error occurred
LogContext(logContext).log(Log_WARNING,
"Setting chunk file attributes on target failed. " +
std::string(pattern->getPatternType() == StripePatternType_BuddyMirror ? "Mirror " : "") +
"TargetID: " + StringTk::uintToStr(targetID) + "; "
"EntryID: " + entryID);
return setRespVal;
}
// success
LOG_DEBUG(logContext, Log_DEBUG,
"Set attribs of chunk file on target. " +
std::string( (pattern->getPatternType() == StripePatternType_BuddyMirror) ? "Mirror " : "") +
"TargetID: " + StringTk::uintToStr(targetID) + "; "
"EntryID: " + entryID);
if ((outDynamicAttribs)
&& (setRespMsg->isMsgHeaderFeatureFlagSet(SETLOCALATTRRESPMSG_FLAG_HAS_ATTRS)))
{
setRespMsg->getDynamicAttribs(outDynamicAttribs);
}
return FhgfsOpsErr_SUCCESS;
}

View File

@@ -0,0 +1,79 @@
#pragma once
#include <common/components/worker/Work.h>
#include <common/net/sock/Socket.h>
#include <common/storage/StorageDefinitions.h>
#include <common/storage/StorageErrors.h>
#include <common/storage/striping/ChunkFileInfo.h>
#include <common/storage/striping/StripePattern.h>
#include <common/toolkit/SynchronizedCounter.h>
#include <common/Common.h>
class SetChunkFileAttribsWork : public Work
{
public:
/**
* @param pathInfo just a reference, so do not free it as long as you use this object!
*/
SetChunkFileAttribsWork(const std::string& entryID, int validAttribs,
SettableFileAttribs* attribs, bool enableCreation, StripePattern* pattern,
uint16_t targetID, PathInfo* pathInfo, DynamicFileAttribs* outDynamicAttribs,
FhgfsOpsErr* outResult, SynchronizedCounter* counter) :
entryID(entryID), validAttribs(validAttribs), attribs(attribs),
enableCreation(enableCreation), pattern(pattern), targetID(targetID),
pathInfo(pathInfo), outDynamicAttribs(outDynamicAttribs),
outResult(outResult), counter(counter), quotaChown(false),
useBuddyMirrorSecond(false), msgUserID(NETMSG_DEFAULT_USERID)
{
// all assignments done in initializer list
}
virtual ~SetChunkFileAttribsWork() {}
virtual void process(char* bufIn, unsigned bufInLen, char* bufOut, unsigned bufOutLen);
private:
std::string entryID;
int validAttribs;
SettableFileAttribs* attribs;
bool enableCreation;
StripePattern* pattern;
uint16_t targetID;
PathInfo* pathInfo;
DynamicFileAttribs* outDynamicAttribs; // will hold the chunks dynamic attribs as stat'ed on
// the storage server
FhgfsOpsErr* outResult;
SynchronizedCounter* counter;
bool quotaChown;
bool useBuddyMirrorSecond;
unsigned msgUserID; // only used for msg header info
FhgfsOpsErr communicate();
public:
// getters & setters
void setQuotaChown(bool quotaChown)
{
this->quotaChown = quotaChown;
}
void setMsgUserID(unsigned msgUserID)
{
this->msgUserID = msgUserID;
}
void setUseBuddyMirrorSecond()
{
this->useBuddyMirrorSecond = true;
}
};

View File

@@ -0,0 +1,111 @@
#include <common/app/log/LogContext.h>
#include <common/app/AbstractApp.h>
#include <common/threading/PThread.h>
#include <common/net/message/storage/TruncLocalFileMsg.h>
#include <common/net/message/storage/TruncLocalFileRespMsg.h>
#include <common/net/message/NetMessage.h>
#include <components/worker/TruncChunkFileWork.h>
#include <program/Program.h>
#include <boost/lexical_cast.hpp>
void TruncChunkFileWork::process(char* bufIn, unsigned bufInLen, char* bufOut, unsigned bufOutLen)
{
FhgfsOpsErr commRes = communicate();
*outResult = commRes;
counter->incCount();
}
FhgfsOpsErr TruncChunkFileWork::communicate()
{
const char* logContext = "Trunc chunk file work";
App* app = Program::getApp();
TruncLocalFileMsg truncMsg(filesize, entryID, targetID, pathInfo);
if(pattern->getPatternType() == StripePatternType_BuddyMirror)
{
truncMsg.addMsgHeaderFeatureFlag(TRUNCLOCALFILEMSG_FLAG_BUDDYMIRROR);
if(useBuddyMirrorSecond)
{
truncMsg.addMsgHeaderFeatureFlag(TRUNCLOCALFILEMSG_FLAG_NODYNAMICATTRIBS);
truncMsg.addMsgHeaderFeatureFlag(TRUNCLOCALFILEMSG_FLAG_BUDDYMIRROR_SECOND);
}
}
if(useQuota)
truncMsg.setUserdataForQuota(userID, groupID);
truncMsg.setMsgHeaderUserID(msgUserID);
// prepare communication
RequestResponseTarget rrTarget(targetID, app->getTargetMapper(), app->getStorageNodes() );
rrTarget.setTargetStates(app->getTargetStateStore() );
if(pattern->getPatternType() == StripePatternType_BuddyMirror)
rrTarget.setMirrorInfo(app->getStorageBuddyGroupMapper(), useBuddyMirrorSecond);
RequestResponseArgs rrArgs(NULL, &truncMsg, NETMSGTYPE_TruncLocalFileResp);
// communicate
FhgfsOpsErr requestRes = MessagingTk::requestResponseTarget(&rrTarget, &rrArgs);
if(unlikely(requestRes != FhgfsOpsErr_SUCCESS) )
{ // communication error
LogContext(logContext).log(Log_WARNING,
"Communication with storage target failed. " +
std::string(pattern->getPatternType() == StripePatternType_BuddyMirror ? "Mirror " : "") +
"TargetID: " + StringTk::uintToStr(targetID) + "; "
"EntryID: " + entryID);
return requestRes;
}
// correct response type received
TruncLocalFileRespMsg* truncRespMsg = (TruncLocalFileRespMsg*)rrArgs.outRespMsg.get();
FhgfsOpsErr truncRespVal = truncRespMsg->getResult();
// set current dynamic attribs (even if result not success, because then storageVersion==0)
if(outDynAttribs)
{
DynamicFileAttribs currentDynAttribs(truncRespMsg->getStorageVersion(),
truncRespMsg->getFileSize(), truncRespMsg->getAllocedBlocks(),
truncRespMsg->getModificationTimeSecs(), truncRespMsg->getLastAccessTimeSecs() );
*outDynAttribs = currentDynAttribs;
}
if(unlikely(truncRespVal != FhgfsOpsErr_SUCCESS) )
{ // error: chunk file not truncated
if(truncRespVal == FhgfsOpsErr_TOOBIG)
return truncRespVal; // will be passed through to user app on client, so don't log here
LogContext(logContext).log(Log_WARNING,
"Truncation of chunk file on target failed. " +
std::string(pattern->getPatternType() == StripePatternType_BuddyMirror ? "Mirror " : "") +
"TargetID: " + StringTk::uintToStr(targetID) + "; "
"EntryID: " + entryID + "; "
"Error: " + boost::lexical_cast<std::string>(truncRespVal) );
return truncRespVal;
}
// success: chunk file truncated
LOG_DEBUG(logContext, Log_DEBUG,
"Chunk file truncated on target. " +
std::string( (pattern->getPatternType() == StripePatternType_BuddyMirror) ? "Mirror " : "") +
"TargetID: " + StringTk::uintToStr(targetID) + "; "
"EntryID: " + entryID);
return FhgfsOpsErr_SUCCESS;
}

View File

@@ -0,0 +1,78 @@
#pragma once
#include <common/components/worker/Work.h>
#include <common/net/sock/Socket.h>
#include <common/storage/striping/StripePattern.h>
#include <common/storage/StorageErrors.h>
#include <common/toolkit/SynchronizedCounter.h>
#include <common/storage/striping/ChunkFileInfo.h>
#include <common/Common.h>
/**
* Truncate file on storage servers
*/
class TruncChunkFileWork : public Work
{
public:
/**
* @param outDynAttribs may be NULL if caller is not interested
*/
TruncChunkFileWork(const std::string& entryID, int64_t filesize, StripePattern* pattern,
uint16_t targetID, PathInfo* pathInfo, DynamicFileAttribs *outDynAttribs,
FhgfsOpsErr* outResult, SynchronizedCounter* counter) :
entryID(entryID), filesize(filesize), pattern(pattern), targetID(targetID),
pathInfo(pathInfo), outDynAttribs(outDynAttribs), outResult(outResult), counter(counter),
useQuota(false), useBuddyMirrorSecond(false), msgUserID(NETMSG_DEFAULT_USERID)
{
// all assignments done in initializer list
}
virtual ~TruncChunkFileWork() {}
virtual void process(char* bufIn, unsigned bufInLen, char* bufOut, unsigned bufOutLen);
private:
std::string entryID;
int64_t filesize; // already converted to storage node's local file size
StripePattern* pattern;
uint16_t targetID;
PathInfo* pathInfo; // note: not owned by this object
DynamicFileAttribs* outDynAttribs;
FhgfsOpsErr* outResult;
SynchronizedCounter* counter;
unsigned userID;
unsigned groupID;
bool useQuota;
bool useBuddyMirrorSecond;
unsigned msgUserID; // only used for msg header info
FhgfsOpsErr communicate();
public:
// getters & setters
void setUserdataForQuota(unsigned userID, unsigned groupID)
{
this->useQuota = true;
this->userID = userID;
this->groupID = groupID;
}
void setMsgUserID(unsigned msgUserID)
{
this->msgUserID = msgUserID;
}
void setUseBuddyMirrorSecond()
{
this->useBuddyMirrorSecond = true;
}
};

View File

@@ -0,0 +1,87 @@
#include <common/app/log/LogContext.h>
#include <common/app/AbstractApp.h>
#include <common/threading/PThread.h>
#include <common/net/message/storage/creating/UnlinkLocalFileMsg.h>
#include <common/net/message/storage/creating/UnlinkLocalFileRespMsg.h>
#include <common/net/message/NetMessage.h>
#include <components/worker/UnlinkChunkFileWork.h>
#include <program/Program.h>
void UnlinkChunkFileWork::process(char* bufIn, unsigned bufInLen, char* bufOut, unsigned bufOutLen)
{
FhgfsOpsErr commRes = communicate();
*outResult = commRes;
counter->incCount();
}
FhgfsOpsErr UnlinkChunkFileWork::communicate()
{
const char* logContext = "Unlink chunk file work";
App* app = Program::getApp();
UnlinkLocalFileMsg unlinkMsg(entryID, targetID, pathInfo);
if(pattern->getPatternType() == StripePatternType_BuddyMirror)
{
unlinkMsg.addMsgHeaderFeatureFlag(UNLINKLOCALFILEMSG_FLAG_BUDDYMIRROR);
if(useBuddyMirrorSecond)
unlinkMsg.addMsgHeaderFeatureFlag(UNLINKLOCALFILEMSG_FLAG_BUDDYMIRROR_SECOND);
}
unlinkMsg.setMsgHeaderUserID(msgUserID);
// prepare communication
RequestResponseTarget rrTarget(targetID, app->getTargetMapper(), app->getStorageNodes() );
rrTarget.setTargetStates(app->getTargetStateStore() );
if(pattern->getPatternType() == StripePatternType_BuddyMirror)
rrTarget.setMirrorInfo(app->getStorageBuddyGroupMapper(), useBuddyMirrorSecond);
RequestResponseArgs rrArgs(NULL, &unlinkMsg, NETMSGTYPE_UnlinkLocalFileResp);
// communicate
FhgfsOpsErr requestRes = MessagingTk::requestResponseTarget(&rrTarget, &rrArgs);
if(unlikely(requestRes != FhgfsOpsErr_SUCCESS) )
{ // communication error
LogContext(logContext).log(Log_WARNING,
"Communication with storage target failed. " +
std::string( (pattern->getPatternType() == StripePatternType_BuddyMirror) ? "Mirror " : "") +
"TargetID: " + StringTk::uintToStr(targetID) + "; "
"EntryID: " + entryID);
return requestRes;
}
// correct response type received
UnlinkLocalFileRespMsg* unlinkRespMsg = (UnlinkLocalFileRespMsg*)rrArgs.outRespMsg.get();
FhgfsOpsErr unlinkResult = unlinkRespMsg->getResult();
if(unlinkResult != FhgfsOpsErr_SUCCESS)
{ // error: local file not unlinked
LogContext(logContext).log(Log_WARNING,
"Unlinking of chunk file from target failed. " +
std::string(pattern->getPatternType() == StripePatternType_BuddyMirror ? "Mirror " : "") +
"TargetID: " + StringTk::uintToStr(targetID) + "; "
"EntryID: " + entryID);
return unlinkResult;
}
// success: chunk file unlinked
LOG_DEBUG(logContext, Log_DEBUG,
"Chunk file unlinked from target. " +
std::string( (pattern->getPatternType() == StripePatternType_BuddyMirror) ? "Mirror " : "") +
"TargetID: " + StringTk::uintToStr(targetID) + "; "
"EntryID: " + entryID);
return FhgfsOpsErr_SUCCESS;
}

View File

@@ -0,0 +1,62 @@
#pragma once
#include <common/components/worker/Work.h>
#include <common/net/sock/Socket.h>
#include <common/storage/striping/StripePattern.h>
#include <common/storage/PathInfo.h>
#include <common/storage/StorageErrors.h>
#include <common/toolkit/SynchronizedCounter.h>
#include <common/storage/striping/ChunkFileInfo.h>
#include <common/Common.h>
class UnlinkChunkFileWork : public Work
{
public:
/**
* @param pathInfo just a reference, so do not free it as long as you use this object!
*/
UnlinkChunkFileWork(const std::string& entryID, StripePattern* pattern, uint16_t targetID,
PathInfo* pathInfo, FhgfsOpsErr* outResult, SynchronizedCounter* counter) :
entryID(entryID), pattern(pattern), targetID(targetID), pathInfo(pathInfo),
outResult(outResult), counter(counter), useBuddyMirrorSecond(false),
msgUserID(NETMSG_DEFAULT_USERID)
{
// all assignments done in initializer list
}
virtual ~UnlinkChunkFileWork() {}
virtual void process(char* bufIn, unsigned bufInLen, char* bufOut, unsigned bufOutLen);
private:
std::string entryID;
StripePattern* pattern;
uint16_t targetID;
PathInfo* pathInfo;
FhgfsOpsErr* outResult;
SynchronizedCounter* counter;
bool useBuddyMirrorSecond;
unsigned msgUserID;
FhgfsOpsErr communicate();
public:
// getters & setters
void setMsgUserID(unsigned msgUserID)
{
this->msgUserID = msgUserID;
}
void setUseBuddyMirrorSecond()
{
this->useBuddyMirrorSecond = true;
}
};