beegfs/storage/source/components/chunkfetcher/ChunkFetcherSlave.cpp
2025-08-10 01:34:16 +02:00

166 lines
4.0 KiB
C++

#include "ChunkFetcherSlave.h"
#include <program/Program.h>
#include <boost/static_assert.hpp>
#include <libgen.h>
ChunkFetcherSlave::ChunkFetcherSlave(uint16_t targetID):
PThread("ChunkFetcherSlave-" + StringTk::uintToStr(targetID) ),
log("ChunkFetcherSlave-" + StringTk::uintToStr(targetID) ),
isRunning(false),
targetID(targetID)
{
}
ChunkFetcherSlave::~ChunkFetcherSlave()
{
}
void ChunkFetcherSlave::run()
{
setIsRunning(true);
try
{
registerSignalHandler();
walkAllChunks();
log.log(4, "Component stopped.");
}
catch(std::exception& e)
{
PThread::getCurrentThreadApp()->handleComponentException(e);
}
setIsRunning(false);
}
/*
* walk over all chunks in that target
*/
void ChunkFetcherSlave::walkAllChunks()
{
App* app = Program::getApp();
log.log(Log_DEBUG, "Starting chunks walk...");
const auto& target = *app->getStorageTargets()->getTargets().at(targetID);
const auto& targetPath = target.getPath().str();
// walk over "normal" chunks (i.e. no mirrors)
std::string walkPath = targetPath + "/" + CONFIG_CHUNK_SUBDIR_NAME;
if(!walkChunkPath(walkPath, 0, walkPath.size() ) )
return;
// let's find out if this target is part of a buddy mirror group and if it is the primary
// target; if it is, walk over buddy mirror directory
bool isPrimaryTarget;
uint16_t buddyGroupID = app->getMirrorBuddyGroupMapper()->getBuddyGroupID(this->targetID,
&isPrimaryTarget);
if (isPrimaryTarget)
{
walkPath = targetPath + "/" CONFIG_BUDDYMIRROR_SUBDIR_NAME;
if(!walkChunkPath(walkPath, buddyGroupID, walkPath.size() ) )
return;
}
log.log(Log_DEBUG, "End of chunks walk.");
}
bool ChunkFetcherSlave::walkChunkPath(const std::string& path, uint16_t buddyGroupID,
unsigned basePathLen)
{
DIR* dir = ::opendir(path.c_str() );
if(!dir)
{
LOG(GENERAL, WARNING, "Could not open directory.", path, targetID, sysErr);
Program::getApp()->getChunkFetcher()->setBad();
return false;
}
int readRes;
bool result = true;
std::string pathBuf = path;
pathBuf.push_back('/');
while(!getSelfTerminate())
{
::dirent* item;
// we really want struct struct dirent to contain a reasonably sized array for the filename
BOOST_STATIC_ASSERT(sizeof(item->d_name) >= NAME_MAX + 1);
#if USE_READDIR_R
::dirent entry;
readRes = ::readdir_r(dir, &entry, &item);
#else
errno = 0;
item = readdir(dir);
readRes = item ? 0 : errno;
#endif
if(readRes != 0)
{
LOG(GENERAL, WARNING, "readdir failed.", path, targetID, sysErr(readRes));
result = false;
break;
}
if(!item)
break;
if(::strcmp(item->d_name, ".") == 0 || ::strcmp(item->d_name, "..") == 0)
continue;
pathBuf.resize(path.size() + 1);
pathBuf += item->d_name;
struct stat statBuf;
int statRes = ::stat(pathBuf.c_str(), &statBuf);
if(statRes)
{
LOG(GENERAL, WARNING, "Could not stat directory.", ("path", pathBuf), targetID, sysErr);
result = false;
break;
}
if(S_ISDIR(statBuf.st_mode) )
{
result = walkChunkPath(pathBuf, buddyGroupID, basePathLen);
if(!result)
break;
}
else
{
const char* relativeChunkPath = pathBuf.c_str() + basePathLen + 1;
// get only the dirname part of the path
char* tmpPathCopy = strdup(relativeChunkPath);
Path savedPath(dirname(tmpPathCopy) );
free(tmpPathCopy);
FsckChunk fsckChunk(item->d_name, targetID, savedPath, statBuf.st_size, statBuf.st_blocks,
statBuf.st_ctime, statBuf.st_mtime, statBuf.st_atime, statBuf.st_uid, statBuf.st_gid,
buddyGroupID);
Program::getApp()->getChunkFetcher()->addChunk(fsckChunk);
}
}
::closedir(dir);
if (getSelfTerminate())
result = false;
if(!result)
Program::getApp()->getChunkFetcher()->setBad();
return result;
}