New upstream version 8.1.0
This commit is contained in:
38
meta/source/components/worker/BarrierWork.h
Normal file
38
meta/source/components/worker/BarrierWork.h
Normal 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;
|
||||
};
|
||||
|
||||
114
meta/source/components/worker/CloseChunkFileWork.cpp
Normal file
114
meta/source/components/worker/CloseChunkFileWork.cpp
Normal 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;
|
||||
}
|
||||
69
meta/source/components/worker/CloseChunkFileWork.h
Normal file
69
meta/source/components/worker/CloseChunkFileWork.h
Normal 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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
90
meta/source/components/worker/GetChunkFileAttribsWork.cpp
Normal file
90
meta/source/components/worker/GetChunkFileAttribsWork.cpp
Normal 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;
|
||||
}
|
||||
64
meta/source/components/worker/GetChunkFileAttribsWork.h
Normal file
64
meta/source/components/worker/GetChunkFileAttribsWork.h
Normal 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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
218
meta/source/components/worker/LockEntryNotificationWork.cpp
Normal file
218
meta/source/components/worker/LockEntryNotificationWork.cpp
Normal 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, ¬ifier);
|
||||
|
||||
|
||||
// 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(¤tWaitAcks, ¬ifier, 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();
|
||||
}
|
||||
57
meta/source/components/worker/LockEntryNotificationWork.h
Normal file
57
meta/source/components/worker/LockEntryNotificationWork.h
Normal 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);
|
||||
};
|
||||
|
||||
|
||||
185
meta/source/components/worker/LockRangeNotificationWork.cpp
Normal file
185
meta/source/components/worker/LockRangeNotificationWork.cpp
Normal 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, ¬ifier);
|
||||
|
||||
|
||||
// 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(¤tWaitAcks, ¬ifier, 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();
|
||||
}
|
||||
49
meta/source/components/worker/LockRangeNotificationWork.h
Normal file
49
meta/source/components/worker/LockRangeNotificationWork.h
Normal 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);
|
||||
};
|
||||
|
||||
|
||||
97
meta/source/components/worker/SetChunkFileAttribsWork.cpp
Normal file
97
meta/source/components/worker/SetChunkFileAttribsWork.cpp
Normal 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;
|
||||
}
|
||||
|
||||
79
meta/source/components/worker/SetChunkFileAttribsWork.h
Normal file
79
meta/source/components/worker/SetChunkFileAttribsWork.h
Normal 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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
111
meta/source/components/worker/TruncChunkFileWork.cpp
Normal file
111
meta/source/components/worker/TruncChunkFileWork.cpp
Normal 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;
|
||||
}
|
||||
78
meta/source/components/worker/TruncChunkFileWork.h
Normal file
78
meta/source/components/worker/TruncChunkFileWork.h
Normal 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;
|
||||
}
|
||||
};
|
||||
|
||||
87
meta/source/components/worker/UnlinkChunkFileWork.cpp
Normal file
87
meta/source/components/worker/UnlinkChunkFileWork.cpp
Normal 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;
|
||||
}
|
||||
|
||||
62
meta/source/components/worker/UnlinkChunkFileWork.h
Normal file
62
meta/source/components/worker/UnlinkChunkFileWork.h
Normal 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;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user