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,97 @@
#include "AdjustChunkPermissionsWork.h"
#include <common/net/message/fsck/AdjustChunkPermissionsMsg.h>
#include <common/net/message/fsck/AdjustChunkPermissionsRespMsg.h>
#include <common/toolkit/MessagingTk.h>
#include <toolkit/FsckException.h>
#include <program/Program.h>
AdjustChunkPermissionsWork::AdjustChunkPermissionsWork(Node& node, SynchronizedCounter* counter,
AtomicUInt64* fileCount, AtomicUInt64* errorCount)
: log("AdjustChunkPermissionsWork"),
node(node),
counter(counter),
fileCount(fileCount),
errorCount(errorCount)
{
}
AdjustChunkPermissionsWork::~AdjustChunkPermissionsWork()
{
}
void AdjustChunkPermissionsWork::process(char* bufIn, unsigned bufInLen, char* bufOut,
unsigned bufOutLen)
{
log.log(4, "Processing AdjustChunkPermissionsWork");
try
{
doWork(false);
doWork(true);
// work package finished => increment counter
this->counter->incCount();
}
catch (std::exception &e)
{
// exception thrown, but work package is finished => increment counter
this->counter->incCount();
// after incrementing counter, re-throw exception
throw;
}
log.log(4, "Processed AdjustChunkPermissionsWork");
}
void AdjustChunkPermissionsWork::doWork(bool isBuddyMirrored)
{
for ( unsigned firstLevelhashDirNum = 0;
firstLevelhashDirNum <= META_DENTRIES_LEVEL1_SUBDIR_NUM - 1; firstLevelhashDirNum++ )
{
for ( unsigned secondLevelhashDirNum = 0;
secondLevelhashDirNum < META_DENTRIES_LEVEL2_SUBDIR_NUM; secondLevelhashDirNum++ )
{
unsigned hashDirNum = StorageTk::mergeHashDirs(firstLevelhashDirNum,
secondLevelhashDirNum);
int64_t hashDirOffset = 0;
int64_t contDirOffset = 0;
std::string currentContDirID;
unsigned resultCount = 0;
do
{
AdjustChunkPermissionsMsg adjustChunkPermissionsMsg(hashDirNum, currentContDirID,
ADJUST_AT_ONCE, hashDirOffset, contDirOffset, isBuddyMirrored);
const auto respMsg = MessagingTk::requestResponse(node, adjustChunkPermissionsMsg,
NETMSGTYPE_AdjustChunkPermissionsResp);
if (respMsg)
{
auto* adjustChunkPermissionsRespMsg = (AdjustChunkPermissionsRespMsg*) respMsg.get();
// set new parameters
currentContDirID = adjustChunkPermissionsRespMsg->getCurrentContDirID();
hashDirOffset = adjustChunkPermissionsRespMsg->getNewHashDirOffset();
contDirOffset = adjustChunkPermissionsRespMsg->getNewContDirOffset();
resultCount = adjustChunkPermissionsRespMsg->getCount();
this->fileCount->increase(resultCount);
if (adjustChunkPermissionsRespMsg->getErrorCount() > 0)
this->errorCount->increase(adjustChunkPermissionsRespMsg->getErrorCount());
}
else
{
throw FsckException("Communication error occured with node " + node.getAlias());
}
// if any of the worker threads threw an exception, we should stop now!
if ( Program::getApp()->getSelfTerminate() )
return;
} while ( resultCount > 0 );
}
}
}

View File

@@ -0,0 +1,32 @@
#ifndef ADJUSTCHUNKPERMISSIONSWORK_H
#define ADJUSTCHUNKPERMISSIONSWORK_H
#include <common/app/log/LogContext.h>
#include <common/components/worker/Work.h>
#include <common/toolkit/SynchronizedCounter.h>
#include <database/FsckDB.h>
// the size of one packet, i.e. how many files are adjusted at once; basically just
// limited to have some control and give the user feedback
#define ADJUST_AT_ONCE 50
class AdjustChunkPermissionsWork : public Work
{
public:
AdjustChunkPermissionsWork(Node& node, SynchronizedCounter* counter, AtomicUInt64* fileCount,
AtomicUInt64* errorCount);
virtual ~AdjustChunkPermissionsWork();
void process(char* bufIn, unsigned bufInLen, char* bufOut, unsigned bufOutLen);
private:
LogContext log;
Node& node;
SynchronizedCounter* counter;
AtomicUInt64* fileCount;
AtomicUInt64* errorCount;
void doWork(bool isBuddyMirrored);
};
#endif /* ADJUSTCHUNKPERMISSIONSWORK_H */

View File

@@ -0,0 +1,152 @@
#include "RetrieveChunksWork.h"
#include <common/net/message/fsck/FetchFsckChunkListMsg.h>
#include <common/net/message/fsck/FetchFsckChunkListRespMsg.h>
#include <common/storage/Storagedata.h>
#include <common/toolkit/FsckTk.h>
#include <common/toolkit/MessagingTk.h>
#include <common/toolkit/StorageTk.h>
#include <database/FsckDBException.h>
#include <toolkit/FsckException.h>
#include <program/Program.h>
RetrieveChunksWork::RetrieveChunksWork(FsckDB* db, NodeHandle node, SynchronizedCounter* counter,
AtomicUInt64* numChunksFound, bool forceRestart) :
log("RetrieveChunksWork"), node(std::move(node)), counter(counter),
numChunksFound(numChunksFound),
chunks(db->getChunksTable()), chunksHandle(chunks->newBulkHandle()),
malformedChunks(db->getMalformedChunksList()),
forceRestart(forceRestart),
started(false), startedBarrier(2)
{
}
RetrieveChunksWork::~RetrieveChunksWork()
{
}
void RetrieveChunksWork::process(char* bufIn, unsigned bufInLen, char* bufOut, unsigned bufOutLen)
{
log.log(Log_DEBUG, "Processing RetrieveChunksWork");
try
{
doWork();
// flush buffers before signaling completion
chunks->flush(chunksHandle);
// work package finished => increment counter
this->counter->incCount();
}
catch (std::exception& e)
{
// exception thrown, but work package is finished => increment counter
this->counter->incCount();
// after incrementing counter, re-throw exception
throw;
}
log.log(Log_DEBUG, "Processed RetrieveChunksWork");
}
void RetrieveChunksWork::doWork()
{
// take the node associated with the current target and send a RetrieveChunksMsg to
// that node; the chunks are retrieved incrementally
if ( node )
{
std::string nodeID = node->getAlias();
FetchFsckChunkListStatus status = FetchFsckChunkListStatus_NOTSTARTED;
unsigned resultCount = 0;
do
{
FetchFsckChunkListMsg fetchFsckChunkListMsg(RETRIEVE_CHUNKS_PACKET_SIZE, status,
forceRestart);
const auto respMsg = MessagingTk::requestResponse(*node, fetchFsckChunkListMsg,
NETMSGTYPE_FetchFsckChunkListResp);
if (respMsg)
{
auto* fetchFsckChunkListRespMsg = (FetchFsckChunkListRespMsg*) respMsg.get();
FsckChunkList& chunks = fetchFsckChunkListRespMsg->getChunkList();
resultCount = chunks.size();
status = fetchFsckChunkListRespMsg->getStatus();
// check entry IDs
for (auto it = chunks.begin(); it != chunks.end(); )
{
if (db::EntryID::tryFromStr(it->getID()).first
&& it->getSavedPath()->str().size() <= db::Chunk::SAVED_PATH_SIZE)
{
++it;
continue;
}
++it;
malformedChunks->append(*std::prev(it));
chunks.erase(std::prev(it));
}
if (status == FetchFsckChunkListStatus_NOTSTARTED)
{
// Another fsck run is still in progress or was aborted, and --forceRestart was not
// set - this means we can't start a new chunk fetcher.
started = false;
startedBarrier.wait();
startedBarrier.wait();
return;
}
else if (status == FetchFsckChunkListStatus_READERROR)
{
throw FsckException("Read error occured while fetching chunks from node; nodeID: "
+ nodeID);
}
if (!started)
{
started = true;
startedBarrier.wait();
startedBarrier.wait();
}
this->chunks->insert(chunks, this->chunksHandle);
numChunksFound->increase(resultCount);
}
else
{
throw FsckException("Communication error occured with node; nodeID: " + nodeID);
}
if ( Program::getApp()->getShallAbort() )
break;
} while ( (resultCount > 0) || (status == FetchFsckChunkListStatus_RUNNING) );
}
else
{
// basically this should never ever happen
log.logErr("Requested node does not exist");
throw FsckException("Requested node does not exist");
}
}
/**
* Waits until started conditin is is signalled and returns the value of stared
* @param isStarted ptr to boolean which is set to whether the server replied it actually started
* the process. Note: this is a ptr and not a return to ensure the member variable
* started is no longer accessed after doWork is finished and the object possibly
* already deleted.
*/
void RetrieveChunksWork::waitForStarted(bool* isStarted)
{
startedBarrier.wait();
*isStarted = started;
startedBarrier.wait();
}

View File

@@ -0,0 +1,57 @@
#ifndef RETRIEVECHUNKSWORK_H
#define RETRIEVECHUNKSWORK_H
/*
* retrieve all chunks from one storage server and save them to DB
*/
#include <common/app/log/LogContext.h>
#include <common/components/worker/Work.h>
#include <common/threading/Barrier.h>
#include <common/toolkit/SynchronizedCounter.h>
#include <database/FsckDB.h>
#include <database/FsckDBTable.h>
// the size of one response packet, i.e. how many chunks are asked for at once
#define RETRIEVE_CHUNKS_PACKET_SIZE 400
class RetrieveChunksWork : public Work
{
public:
/*
* @param db database instance
* @param node pointer to the node to retrieve data from
* @param counter a pointer to a Synchronized counter; this is incremented by one at the end
* and the calling thread can wait for the counter
* @param numChunksFound
* @param forceRestart In case the storage servers' chunk fetchers still have data from a
* previous run, force a restart instead of aborting with an error
*/
RetrieveChunksWork(FsckDB* db, NodeHandle node, SynchronizedCounter* counter,
AtomicUInt64* numChunksFound, bool forceRestart);
virtual ~RetrieveChunksWork();
void process(char* bufIn, unsigned bufInLen, char* bufOut, unsigned bufOutLen);
void waitForStarted(bool* isStarted);
private:
LogContext log;
NodeHandle node;
SynchronizedCounter* counter;
AtomicUInt64* numChunksFound;
FsckDBChunksTable* chunks;
FsckDBChunksTable::BulkHandle chunksHandle;
DiskList<FsckChunk>* malformedChunks;
bool forceRestart;
void doWork();
bool started;
Barrier startedBarrier;
};
#endif /* RETRIEVECHUNKSWORK_H */

View File

@@ -0,0 +1,222 @@
#include "RetrieveDirEntriesWork.h"
#include <common/net/message/fsck/RetrieveDirEntriesMsg.h>
#include <common/net/message/fsck/RetrieveDirEntriesRespMsg.h>
#include <common/toolkit/MessagingTk.h>
#include <common/toolkit/MetaStorageTk.h>
#include <database/FsckDBException.h>
#include <toolkit/FsckException.h>
#include <program/Program.h>
#include <set>
RetrieveDirEntriesWork::RetrieveDirEntriesWork(FsckDB* db, Node& node, SynchronizedCounter* counter,
AtomicUInt64& errors, unsigned hashDirStart, unsigned hashDirEnd,
AtomicUInt64* numDentriesFound, AtomicUInt64* numFileInodesFound,
std::set<FsckTargetID>& usedTargets) :
log("RetrieveDirEntriesWork"), node(node), counter(counter), errors(&errors),
numDentriesFound(numDentriesFound), numFileInodesFound(numFileInodesFound),
usedTargets(&usedTargets), hashDirStart(hashDirStart), hashDirEnd(hashDirEnd),
dentries(db->getDentryTable()), dentriesHandle(dentries->newBulkHandle()),
files(db->getFileInodesTable()), filesHandle(files->newBulkHandle()),
contDirs(db->getContDirsTable()), contDirsHandle(contDirs->newBulkHandle())
{
}
void RetrieveDirEntriesWork::process(char* bufIn, unsigned bufInLen, char* bufOut,
unsigned bufOutLen)
{
log.log(4, "Processing RetrieveDirEntriesWork");
try
{
doWork(false);
doWork(true);
// flush buffers before signaling completion
dentries->flush(dentriesHandle);
files->flush(filesHandle);
contDirs->flush(contDirsHandle);
// work package finished => increment counter
this->counter->incCount();
}
catch (std::exception &e)
{
// exception thrown, but work package is finished => increment counter
this->counter->incCount();
// after incrementing counter, re-throw exception
throw;
}
log.log(4, "Processed RetrieveDirEntriesWork");
}
void RetrieveDirEntriesWork::doWork(bool isBuddyMirrored)
{
for ( unsigned firstLevelhashDirNum = hashDirStart; firstLevelhashDirNum <= hashDirEnd;
firstLevelhashDirNum++ )
{
for ( unsigned secondLevelhashDirNum = 0;
secondLevelhashDirNum < META_DENTRIES_LEVEL2_SUBDIR_NUM; secondLevelhashDirNum++ )
{
unsigned hashDirNum = StorageTk::mergeHashDirs(firstLevelhashDirNum,
secondLevelhashDirNum);
int64_t hashDirOffset = 0;
int64_t contDirOffset = 0;
std::string currentContDirID;
int resultCount = 0;
do
{
RetrieveDirEntriesMsg retrieveDirEntriesMsg(hashDirNum, currentContDirID,
RETRIEVE_DIR_ENTRIES_PACKET_SIZE, hashDirOffset, contDirOffset, isBuddyMirrored);
const auto respMsg = MessagingTk::requestResponse(node, retrieveDirEntriesMsg,
NETMSGTYPE_RetrieveDirEntriesResp);
if (respMsg)
{
auto* retrieveDirEntriesRespMsg = (RetrieveDirEntriesRespMsg*) respMsg.get();
// set new parameters
currentContDirID = retrieveDirEntriesRespMsg->getCurrentContDirID();
hashDirOffset = retrieveDirEntriesRespMsg->getNewHashDirOffset();
contDirOffset = retrieveDirEntriesRespMsg->getNewContDirOffset();
// parse directory entries
FsckDirEntryList& dirEntries = retrieveDirEntriesRespMsg->getDirEntries();
// this is the actual result count we are interested in, because if no dirEntries
// were read, there is nothing left on the server
resultCount = dirEntries.size();
// check dentry entry IDs
for (auto it = dirEntries.begin(); it != dirEntries.end(); )
{
if (db::EntryID::tryFromStr(it->getID()).first
&& db::EntryID::tryFromStr(it->getParentDirID()).first)
{
++it;
continue;
}
LOG(GENERAL, ERR, "Found dentry with invalid entry IDs.",
("node", it->getSaveNodeID()),
("isBuddyMirrored", it->getIsBuddyMirrored()),
("entryID", it->getID()),
("parentEntryID", it->getParentDirID()));
++it;
errors->increase();
dirEntries.erase(std::prev(it));
}
this->dentries->insert(dirEntries, this->dentriesHandle);
numDentriesFound->increase(resultCount);
// parse inlined file inodes
FsckFileInodeList& inlinedFileInodes =
retrieveDirEntriesRespMsg->getInlinedFileInodes();
// check inode entry IDs
for (auto it = inlinedFileInodes.begin(); it != inlinedFileInodes.end(); )
{
if (db::EntryID::tryFromStr(it->getID()).first
&& db::EntryID::tryFromStr(it->getParentDirID()).first
&& (!it->getPathInfo()->hasOrigFeature()
|| db::EntryID::tryFromStr(
it->getPathInfo()->getOrigParentEntryID()).first))
{
++it;
continue;
}
LOG(GENERAL, ERR, "Found inode with invalid entry IDs.",
("node", it->getSaveNodeID()),
("isBuddyMirrored", it->getIsBuddyMirrored()),
("entryID", it->getID()),
("parentEntryID", it->getParentDirID()),
("origParent", it->getPathInfo()->getOrigParentEntryID()));
++it;
errors->increase();
inlinedFileInodes.erase(std::prev(it));
}
struct ops
{
static bool dentryCmp(const FsckDirEntry& a, const FsckDirEntry& b)
{
return a.getID() < b.getID();
}
static bool inodeCmp(const FsckFileInode& a, const FsckFileInode& b)
{
return a.getID() < b.getID();
}
};
dirEntries.sort(ops::dentryCmp);
inlinedFileInodes.sort(ops::inodeCmp);
this->files->insert(inlinedFileInodes, this->filesHandle);
numFileInodesFound->increase(inlinedFileInodes.size());
// add used targetIDs
for ( FsckFileInodeListIter iter = inlinedFileInodes.begin();
iter != inlinedFileInodes.end(); iter++ )
{
FsckTargetIDType fsckTargetIDType;
if (iter->getStripePatternType() == FsckStripePatternType_BUDDYMIRROR)
fsckTargetIDType = FsckTargetIDType_BUDDYGROUP;
else
fsckTargetIDType = FsckTargetIDType_TARGET;
for (auto targetsIter = iter->getStripeTargets().begin();
targetsIter != iter->getStripeTargets().end(); targetsIter++)
{
this->usedTargets->insert(FsckTargetID(*targetsIter, fsckTargetIDType) );
}
}
// parse all new cont. directories
FsckContDirList& contDirs = retrieveDirEntriesRespMsg->getContDirs();
// check entry IDs
for (auto it = contDirs.begin(); it != contDirs.end(); )
{
if (db::EntryID::tryFromStr(it->getID()).first)
{
++it;
continue;
}
LOG(GENERAL, ERR, "Found content directory with invalid entry ID.",
("node", it->getSaveNodeID()),
("isBuddyMirrored", it->getIsBuddyMirrored()),
("entryID", it->getID()));
++it;
errors->increase();
contDirs.erase(std::prev(it));
}
this->contDirs->insert(contDirs, this->contDirsHandle);
}
else
{
throw FsckException("Communication error occured with node " + node.getAlias());
}
// if any of the worker threads threw an exception, we should stop now!
if ( Program::getApp()->getShallAbort() )
return;
} while ( resultCount > 0 );
}
}
}

View File

@@ -0,0 +1,62 @@
#ifndef RETRIEVEDIRENTRIESWORK_H
#define RETRIEVEDIRENTRIESWORK_H
/*
* retrieve all dir entries from one node, inside a specified range of hashDirs and save them to DB
*/
#include <common/app/log/LogContext.h>
#include <common/components/worker/Work.h>
#include <common/toolkit/SynchronizedCounter.h>
#include <database/FsckDB.h>
#include <database/FsckDBTable.h>
// the size of one response packet, i.e. how many dentries are asked for at once
#define RETRIEVE_DIR_ENTRIES_PACKET_SIZE 500
class RetrieveDirEntriesWork : public Work
{
public:
/*
* @param db database instance
* @param node the node to retrieve data from
* @param counter a pointer to a Synchronized counter; this is incremented by one at the end
* and the calling thread can wait for the counter
* @param hashDirStart the first top-level hashDir to open
* @param hashDirEnd the last top-level hashDir to open
* @param numDentriesFound
* @param numFileInodesFound
*/
RetrieveDirEntriesWork(FsckDB* db, Node& node, SynchronizedCounter* counter,
AtomicUInt64& errors, unsigned hashDirStart, unsigned hashDirEnd,
AtomicUInt64* numDentriesFound, AtomicUInt64* numFileInodesFound,
std::set<FsckTargetID>& usedTargets);
void process(char* bufIn, unsigned bufInLen, char* bufOut, unsigned bufOutLen);
private:
LogContext log;
Node& node;
SynchronizedCounter* counter;
AtomicUInt64* errors;
AtomicUInt64* numDentriesFound;
AtomicUInt64* numFileInodesFound;
std::set<FsckTargetID>* usedTargets;
unsigned hashDirStart;
unsigned hashDirEnd;
FsckDBDentryTable* dentries;
FsckDBDentryTable::BulkHandle dentriesHandle;
FsckDBFileInodesTable* files;
FsckDBFileInodesTable::BulkHandle filesHandle;
FsckDBContDirsTable* contDirs;
FsckDBContDirsTable::BulkHandle contDirsHandle;
void doWork(bool isBuddyMirrored);
};
#endif /* RETRIEVEDIRENTRIESWORK_H */

View File

@@ -0,0 +1,125 @@
#include "RetrieveFsIDsWork.h"
#include <common/net/message/fsck/RetrieveFsIDsMsg.h>
#include <common/net/message/fsck/RetrieveFsIDsRespMsg.h>
#include <common/toolkit/MessagingTk.h>
#include <common/toolkit/MetaStorageTk.h>
#include <database/FsckDBException.h>
#include <toolkit/FsckException.h>
#include <program/Program.h>
RetrieveFsIDsWork::RetrieveFsIDsWork(FsckDB* db, Node& node, SynchronizedCounter* counter,
AtomicUInt64& errors, unsigned hashDirStart, unsigned hashDirEnd) :
log("RetrieveFsIDsWork"), node(node), counter(counter), errors(&errors),
hashDirStart(hashDirStart), hashDirEnd(hashDirEnd),
table(db->getFsIDsTable()), bulkHandle(table->newBulkHandle())
{
}
RetrieveFsIDsWork::~RetrieveFsIDsWork()
{
}
void RetrieveFsIDsWork::process(char* bufIn, unsigned bufInLen, char* bufOut,
unsigned bufOutLen)
{
log.log(4, "Processing RetrieveFsIDsWork");
try
{
doWork(false);
doWork(true);
table->flush(bulkHandle);
// work package finished => increment counter
this->counter->incCount();
}
catch (std::exception &e)
{
// exception thrown, but work package is finished => increment counter
this->counter->incCount();
// after incrementing counter, re-throw exception
throw;
}
log.log(4, "Processed RetrieveFsIDsWork");
}
void RetrieveFsIDsWork::doWork(bool isBuddyMirrored)
{
for ( unsigned firstLevelhashDirNum = hashDirStart; firstLevelhashDirNum <= hashDirEnd;
firstLevelhashDirNum++ )
{
for ( unsigned secondLevelhashDirNum = 0;
secondLevelhashDirNum < META_DENTRIES_LEVEL2_SUBDIR_NUM; secondLevelhashDirNum++ )
{
unsigned hashDirNum = StorageTk::mergeHashDirs(firstLevelhashDirNum,
secondLevelhashDirNum);
int64_t hashDirOffset = 0;
int64_t contDirOffset = 0;
std::string currentContDirID;
int resultCount = 0;
do
{
RetrieveFsIDsMsg retrieveFsIDsMsg(hashDirNum, isBuddyMirrored, currentContDirID,
RETRIEVE_FSIDS_PACKET_SIZE, hashDirOffset, contDirOffset);
const auto respMsg = MessagingTk::requestResponse(node, retrieveFsIDsMsg,
NETMSGTYPE_RetrieveFsIDsResp);
if (respMsg)
{
auto* retrieveFsIDsRespMsg = (RetrieveFsIDsRespMsg*) respMsg.get();
// set new parameters
currentContDirID = retrieveFsIDsRespMsg->getCurrentContDirID();
hashDirOffset = retrieveFsIDsRespMsg->getNewHashDirOffset();
contDirOffset = retrieveFsIDsRespMsg->getNewContDirOffset();
// parse FS-IDs
FsckFsIDList& fsIDs = retrieveFsIDsRespMsg->getFsIDs();
// this is the actual result count we are interested in, because if no fsIDs
// were read, there is nothing left on the server
resultCount = fsIDs.size();
// check entry IDs
for (auto it = fsIDs.begin(); it != fsIDs.end(); )
{
if (db::EntryID::tryFromStr(it->getID()).first
&& db::EntryID::tryFromStr(it->getParentDirID()).first)
{
++it;
continue;
}
LOG(GENERAL, ERR, "Found fsid file with invalid entry IDs.",
("node", it->getSaveNodeID()),
("isBuddyMirrored", it->getIsBuddyMirrored()),
("entryID", it->getID()),
("parentEntryID", it->getParentDirID()));
++it;
errors->increase();
fsIDs.erase(std::prev(it));
}
this->table->insert(fsIDs, this->bulkHandle);
}
else
{
throw FsckException("Communication error occured with node " + node.getAlias());
}
// if any of the worker threads threw an exception, we should stop now!
if ( Program::getApp()->getShallAbort() )
return;
} while ( resultCount > 0 );
}
}
}

View File

@@ -0,0 +1,49 @@
#ifndef RETRIEVEFSIDSWORK_H
#define RETRIEVEFSIDSWORK_H
/*
* retrieve all FS-IDs from one node, inside a specified range of hashDirs and save them to DB
*/
#include <common/app/log/LogContext.h>
#include <common/components/worker/Work.h>
#include <common/toolkit/SynchronizedCounter.h>
#include <database/FsckDB.h>
#include <database/FsckDBTable.h>
// the size of one response packet, i.e. how many fsids are asked for at once
#define RETRIEVE_FSIDS_PACKET_SIZE 1000
class RetrieveFsIDsWork : public Work
{
public:
/*
* @param db database instance
* @param node the node to retrieve data from
* @param counter a pointer to a Synchronized counter; this is incremented by one at the end
* and the calling thread can wait for the counter
* @param hashDirStart the first top-level hashDir to open
* @param hashDirEnd the last top-level hashDir to open
*/
RetrieveFsIDsWork(FsckDB* db, Node& node, SynchronizedCounter* counter, AtomicUInt64& errors,
unsigned hashDirStart, unsigned hashDirEnd);
virtual ~RetrieveFsIDsWork();
void process(char* bufIn, unsigned bufInLen, char* bufOut, unsigned bufOutLen);
private:
LogContext log;
Node& node;
SynchronizedCounter* counter;
AtomicUInt64* errors;
unsigned hashDirStart;
unsigned hashDirEnd;
FsckDBFsIDsTable* table;
FsckDBFsIDsTable::BulkHandle bulkHandle;
void doWork(bool isBuddyMirrored);
};
#endif /* RETRIEVEFSIDSWORK_H */

View File

@@ -0,0 +1,187 @@
#include "RetrieveInodesWork.h"
#include <common/net/message/fsck/RetrieveInodesMsg.h>
#include <common/net/message/fsck/RetrieveInodesRespMsg.h>
#include <common/toolkit/MetaStorageTk.h>
#include <common/toolkit/MessagingTk.h>
#include <database/FsckDBException.h>
#include <toolkit/FsckException.h>
#include <program/Program.h>
#include <set>
RetrieveInodesWork::RetrieveInodesWork(FsckDB* db, Node& node, SynchronizedCounter* counter,
AtomicUInt64& errors, unsigned hashDirStart, unsigned hashDirEnd,
AtomicUInt64* numFileInodesFound, AtomicUInt64* numDirInodesFound,
std::set<FsckTargetID>& usedTargets) :
log("RetrieveInodesWork"), node(node), counter(counter), errors(&errors),
usedTargets(&usedTargets), hashDirStart(hashDirStart), hashDirEnd(hashDirEnd),
numFileInodesFound(numFileInodesFound), numDirInodesFound(numDirInodesFound),
files(db->getFileInodesTable()), filesHandle(files->newBulkHandle()),
dirs(db->getDirInodesTable()), dirsHandle(dirs->newBulkHandle())
{
}
void RetrieveInodesWork::process(char* bufIn, unsigned bufInLen, char* bufOut,
unsigned bufOutLen)
{
log.log(4, "Processing RetrieveInodesWork");
try
{
doWork(false);
doWork(true);
// flush buffers before signaling completion
files->flush(filesHandle);
dirs->flush(dirsHandle);
// work package finished => increment counter
this->counter->incCount();
}
catch (std::exception &e)
{
// exception thrown, but work package is finished => increment counter
this->counter->incCount();
// after incrementing counter, re-throw exception
throw;
}
log.log(4, "Processed RetrieveInodesWork");
}
void RetrieveInodesWork::doWork(bool isBuddyMirrored)
{
const NumNodeID& metaRootID = Program::getApp()->getMetaRoot().getID();
const NumNodeID& nodeID = node.getNumID();
const NumNodeID nodeBuddyGroupID = NumNodeID(Program::getApp()->getMetaMirrorBuddyGroupMapper()
->getBuddyGroupID(node.getNumID().val()));
for ( unsigned firstLevelhashDirNum = hashDirStart; firstLevelhashDirNum <= hashDirEnd;
firstLevelhashDirNum++ )
{
for ( unsigned secondLevelhashDirNum = 0;
secondLevelhashDirNum < META_DENTRIES_LEVEL2_SUBDIR_NUM; secondLevelhashDirNum++ )
{
unsigned hashDirNum = StorageTk::mergeHashDirs(firstLevelhashDirNum,
secondLevelhashDirNum);
int64_t lastOffset = 0;
size_t fileInodeCount;
size_t dirInodeCount;
do
{
RetrieveInodesMsg retrieveInodesMsg(hashDirNum, lastOffset,
RETRIEVE_INODES_PACKET_SIZE, isBuddyMirrored);
const auto respMsg = MessagingTk::requestResponse(node, retrieveInodesMsg,
NETMSGTYPE_RetrieveInodesResp);
if (respMsg)
{
auto* retrieveInodesRespMsg = (RetrieveInodesRespMsg*) respMsg.get();
// set new parameters
lastOffset = retrieveInodesRespMsg->getLastOffset();
// parse all file inodes
FsckFileInodeList& fileInodes = retrieveInodesRespMsg->getFileInodes();
// check inode entry IDs
for (auto it = fileInodes.begin(); it != fileInodes.end(); )
{
if (db::EntryID::tryFromStr(it->getID()).first
&& db::EntryID::tryFromStr(it->getParentDirID()).first
&& (!it->getPathInfo()->hasOrigFeature()
|| db::EntryID::tryFromStr(
it->getPathInfo()->getOrigParentEntryID()).first))
{
++it;
continue;
}
LOG(GENERAL, ERR, "Found inode with invalid entry IDs.",
("node", it->getSaveNodeID()),
("isBuddyMirrored", it->getIsBuddyMirrored()),
("entryID", it->getID()),
("parentEntryID", it->getParentDirID()),
("origParent", it->getPathInfo()->getOrigParentEntryID()));
++it;
errors->increase();
fileInodes.erase(std::prev(it));
}
// add targetIDs
for (auto iter = fileInodes.begin(); iter != fileInodes.end(); iter++)
{
FsckTargetIDType fsckTargetIDType;
if (iter->getStripePatternType() == FsckStripePatternType_BUDDYMIRROR)
fsckTargetIDType = FsckTargetIDType_BUDDYGROUP;
else
fsckTargetIDType = FsckTargetIDType_TARGET;
for (auto targetsIter = iter->getStripeTargets().begin();
targetsIter != iter->getStripeTargets().end(); targetsIter++)
{
this->usedTargets->insert(FsckTargetID(*targetsIter, fsckTargetIDType) );
}
}
// parse all directory inodes
FsckDirInodeList& dirInodes = retrieveInodesRespMsg->getDirInodes();
// check inode entry IDs
for (auto it = dirInodes.begin(); it != dirInodes.end(); )
{
auto entryIDPair = db::EntryID::tryFromStr(it->getID());
if (!entryIDPair.first ||
!db::EntryID::tryFromStr(it->getParentDirID()).first)
{
LOG(GENERAL, ERR, "Found inode with invalid entry IDs.",
("node", it->getSaveNodeID()),
("isBuddyMirrored", it->getIsBuddyMirrored()),
("entryID", it->getID()),
("parentEntryID", it->getParentDirID()));
++it;
errors->increase();
dirInodes.erase(std::prev(it));
continue;
}
// remove root inodes from non root metas
if (entryIDPair.second.isRootDir() &&
((it->getIsBuddyMirrored() && nodeBuddyGroupID != metaRootID)
|| (!it->getIsBuddyMirrored() && nodeID != metaRootID)))
{
++it;
dirInodes.erase(std::prev(it));
continue;
}
++it;
}
fileInodeCount = fileInodes.size();
dirInodeCount = dirInodes.size();
this->files->insert(fileInodes, this->filesHandle);
this->dirs->insert(dirInodes, this->dirsHandle);
numFileInodesFound->increase(fileInodeCount);
numDirInodesFound->increase(dirInodeCount);
}
else
{
throw FsckException("Communication error occured with node " + node.getAlias());
}
// if any of the worker threads threw an exception, we should stop now!
if ( Program::getApp()->getShallAbort() )
return;
} while ( (fileInodeCount + dirInodeCount) > 0 );
}
}
}

View File

@@ -0,0 +1,58 @@
#ifndef RETRIEVEINODESWORK_H
#define RETRIEVEINODESWORK_H
/*
* retrieve all inodes from one node, inside a specified range of hashDirs and save them to DB
*/
#include <common/app/log/LogContext.h>
#include <common/components/worker/Work.h>
#include <common/toolkit/SynchronizedCounter.h>
#include <database/FsckDB.h>
#include <database/FsckDBTable.h>
// the size of one response packet, i.e. how many inodes are asked for at once
#define RETRIEVE_INODES_PACKET_SIZE 500
class RetrieveInodesWork : public Work
{
public:
/*
* @param db database instance
* @param node the node to retrieve data from
* @param counter a pointer to a Synchronized counter; this is incremented by one at the end
* and the calling thread can wait for the counter
* @param hashDirStart the first top-level hashDir to open
* @param hashDirEnd the last top-level hashDir to open
*/
RetrieveInodesWork(FsckDB* db, Node& node, SynchronizedCounter* counter,
AtomicUInt64& errors, unsigned hashDirStart, unsigned hashDirEnd,
AtomicUInt64* numFileInodesFound, AtomicUInt64* numDirInodesFound,
std::set<FsckTargetID>& usedTargets);
void process(char* bufIn, unsigned bufInLen, char* bufOut, unsigned bufOutLen);
private:
LogContext log;
Node& node;
SynchronizedCounter* counter;
AtomicUInt64* errors;
std::set<FsckTargetID>* usedTargets;
unsigned hashDirStart;
unsigned hashDirEnd;
AtomicUInt64* numFileInodesFound;
AtomicUInt64* numDirInodesFound;
FsckDBFileInodesTable* files;
FsckDBFileInodesTable::BulkHandle filesHandle;
FsckDBDirInodesTable* dirs;
FsckDBDirInodesTable::BulkHandle dirsHandle;
void doWork(bool isBuddyMirrored);
};
#endif /* RETRIEVEINODESWORK_H */