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,273 @@
#include "DatabaseTk.h"
#include <common/app/log/LogContext.h>
#include <common/storage/striping/Raid0Pattern.h>
#include <common/toolkit/FsckTk.h>
#include <common/toolkit/StringTk.h>
#include <database/FsckDB.h>
#include <database/FsckDBTable.h>
#include <common/storage/Path.h>
#include <common/toolkit/StorageTk.h>
DatabaseTk::DatabaseTk()
{
}
DatabaseTk::~DatabaseTk()
{
}
FsckDirEntry DatabaseTk::createDummyFsckDirEntry(FsckDirEntryType entryType)
{
FsckDirEntryList list;
createDummyFsckDirEntries(7, 1, &list, entryType);
return list.front();
}
void DatabaseTk::createDummyFsckDirEntries(uint amount, FsckDirEntryList* outList,
FsckDirEntryType entryType)
{
createDummyFsckDirEntries(0,amount, outList, entryType);
}
void DatabaseTk::createDummyFsckDirEntries(uint from, uint amount, FsckDirEntryList* outList,
FsckDirEntryType entryType)
{
for ( uint i = from; i < (from+amount); i++ )
{
std::string index = StringTk::uintToHexStr(i);
std::string id = index + "-1-1";
std::string name = "dentryName" + index;
std::string parentID = index + "-2-1";
NumNodeID entryOwnerNodeID(i + 1000);
NumNodeID inodeOwnerNodeID(i + 2000);
NumNodeID saveNodeID(i + 3000);
int saveDevice = i;
uint64_t saveInode = i;
FsckDirEntry dentry(id, name, parentID, entryOwnerNodeID, inodeOwnerNodeID, entryType, true,
saveNodeID, saveDevice, saveInode, false);
outList->push_back(dentry);
}
}
FsckFileInode DatabaseTk::createDummyFsckFileInode()
{
FsckFileInodeList list;
createDummyFsckFileInodes(7, 1, &list);
return list.front();
}
void DatabaseTk::createDummyFsckFileInodes(uint amount, FsckFileInodeList* outList)
{
createDummyFsckFileInodes(0,amount,outList);
}
void DatabaseTk::createDummyFsckFileInodes(uint from, uint amount, FsckFileInodeList* outList)
{
for ( uint i = from; i < (from + amount); i++ )
{
std::string index = StringTk::uintToHexStr(i);
UInt16Vector targetIDs;
while (targetIDs.size() < i)
targetIDs.push_back(i + 1000 * (targetIDs.size() + 1) );
Raid0Pattern stripePatternIn(1024, targetIDs);
std::string id = index + "-1-1";
std::string parentDirID = index + "-2-1";
NumNodeID parentNodeID(i + 1000);
unsigned userID = 1000;
unsigned groupID = 1000;
uint64_t usedBlocks = 0;
int64_t fileSize = usedBlocks*512;
unsigned numHardLinks = 1;
PathInfo pathInfo(userID, parentDirID, PATHINFO_FEATURE_ORIG);
FsckStripePatternType stripePatternType = FsckTk::stripePatternToFsckStripePattern(
&stripePatternIn);
unsigned chunkSize = 524288;
NumNodeID saveNodeID(i + 2000);
FsckFileInode fileInode(id, parentDirID, parentNodeID, pathInfo, userID, groupID, fileSize,
numHardLinks, usedBlocks, targetIDs, stripePatternType, chunkSize, saveNodeID,
1000 + i, 42, true, false, true, false);
outList->push_back(fileInode);
}
}
FsckDirInode DatabaseTk::createDummyFsckDirInode()
{
FsckDirInodeList list;
createDummyFsckDirInodes(7, 1, &list);
return list.front();
}
void DatabaseTk::createDummyFsckDirInodes(uint amount, FsckDirInodeList* outList)
{
createDummyFsckDirInodes(0, amount, outList);
}
void DatabaseTk::createDummyFsckDirInodes(uint from, uint amount, FsckDirInodeList* outList)
{
for ( uint i = from; i < (from + amount); i++ )
{
std::string index = StringTk::uintToHexStr(i);
UInt16Vector targetIDs;
Raid0Pattern stripePatternIn(1024, targetIDs);
std::string id = index + "-1-1";
std::string parentDirID = index + "-2-1";
NumNodeID parentNodeID(i + 1000);
NumNodeID ownerNodeID(i + 2000);
int64_t size = 10;
unsigned numHardLinks = 12;
FsckStripePatternType stripePatternType = FsckTk::stripePatternToFsckStripePattern(
&stripePatternIn);
NumNodeID saveNodeID(i + 3000);
FsckDirInode dirInode(id, parentDirID, parentNodeID, ownerNodeID, size, numHardLinks,
targetIDs, stripePatternType, saveNodeID, false, true, false);
outList->push_back(dirInode);
}
}
FsckChunk DatabaseTk::createDummyFsckChunk()
{
FsckChunkList list;
createDummyFsckChunks(7, 1, &list);
return list.front();
}
void DatabaseTk::createDummyFsckChunks(uint amount, FsckChunkList* outList)
{
createDummyFsckChunks(amount, 1, outList);
}
void DatabaseTk::createDummyFsckChunks(uint amount, uint numTargets, FsckChunkList* outList)
{
createDummyFsckChunks(0, amount, numTargets, outList);
}
void DatabaseTk::createDummyFsckChunks(uint from, uint amount, uint numTargets,
FsckChunkList* outList)
{
for ( uint i = from; i < (from + amount); i++ )
{
std::string index = StringTk::uintToHexStr(i);
for ( uint j = 0; j < numTargets; j++ )
{
std::string id = index + "-1-1";
uint16_t targetID = j;
PathInfo pathInfo(0, META_ROOTDIR_ID_STR, PATHINFO_FEATURE_ORIG);
Path chunkDirPath; // ignored!
std::string chunkFilePathStr;
StorageTk::getChunkDirChunkFilePath(&pathInfo, id, true, chunkDirPath,
chunkFilePathStr);
Path savedPath(chunkFilePathStr);
uint64_t usedBlocks = 300;
int64_t fileSize = usedBlocks*512;
FsckChunk chunk(id, targetID, savedPath, fileSize, usedBlocks, 0, 0, 0, 0, 0);
outList->push_back(chunk);
}
}
}
FsckContDir DatabaseTk::createDummyFsckContDir()
{
FsckContDirList list;
createDummyFsckContDirs(7, 1, &list);
return list.front();
}
void DatabaseTk::createDummyFsckContDirs(uint amount, FsckContDirList* outList)
{
createDummyFsckContDirs(0, amount, outList);
}
void DatabaseTk::createDummyFsckContDirs(uint from, uint amount, FsckContDirList* outList)
{
for ( uint i = from; i < (from + amount); i++ )
{
std::string index = StringTk::uintToHexStr(i);
std::string id = index + "-1-1";
NumNodeID saveNodeID(i);
FsckContDir contDir(id, saveNodeID, false);
outList->push_back(contDir);
}
}
FsckFsID DatabaseTk::createDummyFsckFsID()
{
FsckFsIDList list;
createDummyFsckFsIDs(7, 1, &list);
return list.front();
}
void DatabaseTk::createDummyFsckFsIDs(uint amount, FsckFsIDList* outList)
{
createDummyFsckFsIDs(0, amount, outList);
}
void DatabaseTk::createDummyFsckFsIDs(uint from, uint amount, FsckFsIDList* outList)
{
for ( uint i = from; i < (from + amount); i++ )
{
std::string index = StringTk::uintToHexStr(i);
std::string id = index + "-1-1";
std::string parentDirID = index + "-2-1";
NumNodeID saveNodeID(i);
int saveDevice = i;
uint64_t saveInode = i;
FsckFsID fsID(id, parentDirID, saveNodeID, saveDevice, saveInode, false);
outList->push_back(fsID);
}
}
std::string DatabaseTk::calculateExpectedChunkPath(std::string entryID, unsigned origParentUID,
std::string origParentEntryID, int pathInfoFlags)
{
std::string resStr;
bool hasOrigFeature;
hasOrigFeature = pathInfoFlags == PATHINFO_FEATURE_ORIG;
PathInfo pathInfo(origParentUID, origParentEntryID, pathInfoFlags);
Path chunkDirPath;
std::string chunkFilePath;
StorageTk::getChunkDirChunkFilePath(&pathInfo, entryID, hasOrigFeature, chunkDirPath,
chunkFilePath);
if (hasOrigFeature) // we can use the Path chunkDirPath
resStr = chunkDirPath.str();
else
{
/* chunk in old format => Path chunkDirPath is not set in getChunkDirChunkFilePath(),
* so it is a bit more tricky */
// we need to strip the filename itself (including the '/')
size_t startPos = 0;
size_t len = chunkFilePath.find_last_of('/');
// generate a substring as result
resStr = chunkFilePath.substr(startPos, len);
}
return resStr;
}

View File

@@ -0,0 +1,62 @@
#ifndef DATABASETK_H_
#define DATABASETK_H_
#include <common/fsck/FsckChunk.h>
#include <common/fsck/FsckContDir.h>
#include <common/fsck/FsckDirEntry.h>
#include <common/fsck/FsckDirInode.h>
#include <common/fsck/FsckFileInode.h>
#include <common/fsck/FsckFsID.h>
#include <common/fsck/FsckModificationEvent.h>
#include <common/fsck/FsckTargetID.h>
#include <database/Chunk.h>
#include <database/ContDir.h>
#include <database/DirEntry.h>
#include <database/DirInode.h>
#include <database/FileInode.h>
#include <database/FsID.h>
class FsckDB;
class DatabaseTk
{
public:
DatabaseTk();
virtual ~DatabaseTk();
static FsckDirEntry createDummyFsckDirEntry(
FsckDirEntryType entryType = FsckDirEntryType_REGULARFILE);
static void createDummyFsckDirEntries(uint amount, FsckDirEntryList* outList,
FsckDirEntryType entryType = FsckDirEntryType_REGULARFILE);
static void createDummyFsckDirEntries(uint from, uint amount, FsckDirEntryList* outList,
FsckDirEntryType entryType = FsckDirEntryType_REGULARFILE);
static FsckFileInode createDummyFsckFileInode();
static void createDummyFsckFileInodes(uint amount, FsckFileInodeList* outList);
static void createDummyFsckFileInodes(uint from, uint amount, FsckFileInodeList* outList);
static FsckDirInode createDummyFsckDirInode();
static void createDummyFsckDirInodes(uint amount, FsckDirInodeList* outList);
static void createDummyFsckDirInodes(uint from, uint amount, FsckDirInodeList* outList);
static FsckChunk createDummyFsckChunk();
static void createDummyFsckChunks(uint amount, FsckChunkList* outList);
static void createDummyFsckChunks(uint amount, uint numTargets, FsckChunkList* outList);
static void createDummyFsckChunks(uint from, uint amount, uint numTargets,
FsckChunkList* outList);
static FsckContDir createDummyFsckContDir();
static void createDummyFsckContDirs(uint amount, FsckContDirList* outList);
static void createDummyFsckContDirs(uint from, uint amount, FsckContDirList* outList);
static FsckFsID createDummyFsckFsID();
static void createDummyFsckFsIDs(uint amount, FsckFsIDList* outList);
static void createDummyFsckFsIDs(uint from, uint amount, FsckFsIDList* outList);
static std::string calculateExpectedChunkPath(std::string entryID, unsigned origParentUID,
std::string origParentEntryID, int pathInfoFlags);
};
#endif /* DATABASETK_H_ */

View File

@@ -0,0 +1,2 @@
#include "FsckDefinitions.h"

View File

@@ -0,0 +1,75 @@
#ifndef FSCKDBTYPES_H_
#define FSCKDBTYPES_H_
#include <common/Common.h>
#include <common/storage/striping/StripePattern.h>
#include <common/storage/StorageDefinitions.h>
#define TABLE_NAME_DIR_ENTRIES "dirEntries"
#define TABLE_NAME_FILE_INODES "fileInodes"
#define TABLE_NAME_DIR_INODES "dirInodes"
#define TABLE_NAME_CHUNKS "chunks"
#define TABLE_NAME_STRIPE_PATTERNS "stripePatterns"
#define TABLE_NAME_CONT_DIRS "contDirs"
#define TABLE_NAME_FSIDS "fsIDs"
#define TABLE_NAME_USED_TARGETS "usedTargets"
#define TABLE_NAME_MODIFICATION_EVENTS "modificationEvents"
enum FsckRepairAction
{
FsckRepairAction_DELETEDENTRY = 0,
FsckRepairAction_DELETEFILE = 1,
FsckRepairAction_CREATEDEFAULTDIRINODE = 2,
FsckRepairAction_CORRECTOWNER = 3,
FsckRepairAction_LOSTANDFOUND = 4,
FsckRepairAction_CREATECONTDIR = 5,
FsckRepairAction_DELETEINODE = 7,
FsckRepairAction_DELETECHUNK = 8,
FsckRepairAction_DELETECONTDIR = 9,
FsckRepairAction_UPDATEATTRIBS = 10,
FsckRepairAction_CHANGETARGET = 11,
FsckRepairAction_RECREATEFSID = 12,
FsckRepairAction_RECREATEDENTRY = 13,
FsckRepairAction_FIXPERMISSIONS = 14,
FsckRepairAction_MOVECHUNK = 15,
FsckRepairAction_REPAIRDUPLICATEINODE = 16,
FsckRepairAction_UPDATEOLDTYLEDHARDLINKS = 17,
FsckRepairAction_NOTHING = 18,
FsckRepairAction_UNDEFINED = 19
};
struct FsckRepairActionElem
{
const char* actionShortDesc;
const char* actionDesc;
enum FsckRepairAction action;
};
// Note: Keep in sync with enum FsckErrorCode
FsckRepairActionElem const __FsckRepairActions[] =
{
{"DeleteDentry", "Delete directory entry", FsckRepairAction_DELETEDENTRY},
{"DeleteFile", "Delete file", FsckRepairAction_DELETEFILE},
{"CreateDefDirInode", "Create a directory inode with default values",
FsckRepairAction_CREATEDEFAULTDIRINODE},
{"CorrectOwner", "Correct owner node", FsckRepairAction_CORRECTOWNER},
{"LostAndFound", "Link to lost+found", FsckRepairAction_LOSTANDFOUND},
{"CreateContDir", "Create an empty content directory", FsckRepairAction_CREATECONTDIR},
{"DeleteInode", "Delete inodes", FsckRepairAction_DELETEINODE},
{"DeleteChunk", "Delete chunk", FsckRepairAction_DELETECHUNK},
{"DeleteContDir", "Delete content directory", FsckRepairAction_DELETECONTDIR},
{"UpdateAttribs", "Update attributes", FsckRepairAction_UPDATEATTRIBS},
{"ChangeTarget", "Change target ID in stripe patterns", FsckRepairAction_CHANGETARGET},
{"RecreateFsID", "Recreate dentry-by-id file", FsckRepairAction_RECREATEFSID},
{"RecreateDentry", "Recreate directory entry file", FsckRepairAction_RECREATEDENTRY},
{"FixPermissions", "Fix permissions", FsckRepairAction_FIXPERMISSIONS},
{"MoveChunk", "Move chunk", FsckRepairAction_MOVECHUNK},
{"RepairDuplicateInode", "Repair duplicate inode", FsckRepairAction_REPAIRDUPLICATEINODE},
{"UpdateOldStyledHardlinks", "Update metadata of old styled hardlinks to new format",
FsckRepairAction_UPDATEOLDTYLEDHARDLINKS},
{"Nothing", "Do nothing", FsckRepairAction_NOTHING},
{0, 0, FsckRepairAction_UNDEFINED}
};
#endif /* FSCKDBTYPES_H_ */

View File

@@ -0,0 +1,16 @@
/*
* FsckException.h
*
* This exception is intended for things that can happen in fsck, that prevents it from running
* further, e.g. if a server goes down fsck should abort
*
*/
#ifndef FSCKEXCEPTION_H
#define FSCKEXCEPTION_H
#include <common/toolkit/NamedException.h>
DECLARE_NAMEDEXCEPTION(FsckException, "FsckException")
#endif /* FSCKEXCEPTION_H */

View File

@@ -0,0 +1,604 @@
#include "FsckTkEx.h"
#include <common/net/message/fsck/FsckSetEventLoggingMsg.h>
#include <common/net/message/fsck/FsckSetEventLoggingRespMsg.h>
#include <common/net/message/storage/StatStoragePathMsg.h>
#include <common/net/message/storage/StatStoragePathRespMsg.h>
#include <common/toolkit/ListTk.h>
#include <common/toolkit/FsckTk.h>
#include <common/toolkit/UnitTk.h>
#include <program/Program.h>
#include <mutex>
char FsckTkEx::progressChar = '-';
Mutex FsckTkEx::outputMutex;
/*
* check the reachability of all nodes in the system
*/
bool FsckTkEx::checkReachability()
{
NodeStore* metaNodes = Program::getApp()->getMetaNodes();
NodeStore* storageNodes = Program::getApp()->getStorageNodes();
StringList errors;
bool commSuccess = true;
FsckTkEx::fsckOutput("Step 1: Check reachability of nodes: ", OutputOptions_FLUSH);
if ( metaNodes->getSize() == 0 )
{
errors.push_back("No metadata nodes found");
commSuccess = false;
}
if ( storageNodes->getSize() == 0 )
{
errors.push_back("No storage nodes found");
commSuccess = false;
}
for (const auto& node : metaNodes->referenceAllNodes())
{
if ( !FsckTkEx::checkReachability(*node, NODETYPE_Meta) )
{
errors.push_back("Communication with metadata node failed: " + node->getAlias());
commSuccess = false;
}
}
for (const auto& node : storageNodes->referenceAllNodes())
{
if ( !FsckTkEx::checkReachability(*node, NODETYPE_Storage) )
{
errors.push_back("Communication with storage node failed: " + node->getAlias());
commSuccess = false;
}
}
if ( commSuccess )
FsckTkEx::fsckOutput("Finished", OutputOptions_LINEBREAK);
else
{
for ( StringListIter iter = errors.begin(); iter != errors.end(); iter++ )
{
FsckTkEx::fsckOutput(*iter,
OutputOptions_NONE | OutputOptions_LINEBREAK | OutputOptions_STDERR);
}
}
return commSuccess;
}
/*
* check reachability of a single node
*/
bool FsckTkEx::checkReachability(Node& node, NodeType nodetype)
{
bool retVal = false;
HeartbeatRequestMsg heartbeatRequestMsg;
std::string realNodeID = node.getAlias();
const auto respMsg = MessagingTk::requestResponse(node, heartbeatRequestMsg,
NETMSGTYPE_Heartbeat);
if (respMsg)
{
HeartbeatMsg *heartbeatMsg = (HeartbeatMsg *) respMsg.get();
std::string receivedNodeID = heartbeatMsg->getNodeID();
retVal = receivedNodeID.compare(realNodeID) == 0;
}
return retVal;
}
void FsckTkEx::fsckOutput(std::string text, int optionFlags)
{
const std::lock_guard<Mutex> lock(outputMutex);
static bool fileErrLogged = false; // to make sure we print logfile open err only once
Config* cfg = Program::getApp()->getConfig(); // might be NULL on app init failure
bool toLog = cfg && (!(OutputOptions_NOLOG & optionFlags)); // true if write to log file
FILE *logFile = NULL;
if (likely(toLog))
{
std::string logFilePath = cfg->getLogOutFile();
logFile = fopen(logFilePath.c_str(),"a+");
if (logFile == NULL)
{
toLog = false;
if(!fileErrLogged)
{
std::cerr << "Cannot open output file for writing: '" << logFilePath << "'"
<< std::endl;
fileErrLogged = true;
}
}
}
const char* colorNormal = OutputColor_NORMAL;
const char* color = OutputColor_NORMAL;
FILE *outFile = stdout;
if (OutputOptions_STDERR & optionFlags)
{
outFile = stderr;
}
else if (OutputOptions_NOSTDOUT & optionFlags)
{
outFile = NULL;
}
bool outFileIsTty;
if (outFile)
outFileIsTty = isatty(fileno(outFile));
else
outFileIsTty = false;
if (OutputOptions_COLORGREEN & optionFlags)
{
color = OutputColor_GREEN;
}
else if (OutputOptions_COLORRED & optionFlags)
{
color = OutputColor_RED;
}
else
{
color = OutputColor_NORMAL;
}
if (OutputOptions_LINEDELETE & optionFlags)
{
optionFlags = optionFlags | OutputOptions_FLUSH;
SAFE_FPRINTF(outFile, "\r");
SAFE_FPRINTF(outFile, " ");
SAFE_FPRINTF(outFile, "\r");
}
if (OutputOptions_ADDLINEBREAKBEFORE & optionFlags)
{
SAFE_FPRINTF(outFile, "\n");
if (likely(toLog)) SAFE_FPRINTF(logFile,"\n");
}
if (OutputOptions_HEADLINE & optionFlags)
{
SAFE_FPRINTF(outFile, "\n--------------------------------------------------------------------\n");
if (likely(toLog))
SAFE_FPRINTF(logFile,"\n--------------------------------------------------------------------\n");
if (likely(outFileIsTty))
SAFE_FPRINTF(outFile, "%s%s%s",color,text.c_str(),colorNormal);
else
SAFE_FPRINTF(outFile, "%s",text.c_str());
if (likely(toLog))
SAFE_FPRINTF(logFile,"%s",text.c_str());
SAFE_FPRINTF(outFile, "\n--------------------------------------------------------------------\n") ;
if (likely(toLog))
SAFE_FPRINTF(logFile,"\n--------------------------------------------------------------------\n");
}
else
{
if (likely(outFileIsTty))
SAFE_FPRINTF(outFile, "%s%s%s",color,text.c_str(),colorNormal);
else
SAFE_FPRINTF(outFile, "%s",text.c_str());
if (likely(toLog)) SAFE_FPRINTF(logFile,"%s",text.c_str());
}
if (OutputOptions_LINEBREAK & optionFlags)
{
SAFE_FPRINTF(outFile, "\n");
if (likely(toLog))
SAFE_FPRINTF(logFile,"\n");
}
if (OutputOptions_DOUBLELINEBREAK & optionFlags)
{
SAFE_FPRINTF(outFile, "\n\n");
if (likely(toLog))
SAFE_FPRINTF(logFile,"\n\n");
}
if (OutputOptions_FLUSH & optionFlags)
{
fflush(outFile);
if (likely(toLog))
fflush(logFile);
}
if (logFile != NULL)
{
fclose(logFile);
}
}
void FsckTkEx::printVersionHeader(bool toStdErr, bool noLogFile)
{
int optionFlags = OutputOptions_LINEBREAK;
if (toStdErr)
{
optionFlags = OutputOptions_LINEBREAK | OutputOptions_STDERR;
}
if (noLogFile)
{
optionFlags = optionFlags | OutputOptions_NOLOG;
}
FsckTkEx::fsckOutput("\n", optionFlags);
FsckTkEx::fsckOutput("BeeGFS File System Check Version : " + std::string(BEEGFS_VERSION),
optionFlags);
FsckTkEx::fsckOutput("----", optionFlags);
}
void FsckTkEx::progressMeter()
{
const std::lock_guard<Mutex> lock(outputMutex);
printf("\b%c",progressChar);
fflush(stdout);
switch(progressChar)
{
case '-' :
{
progressChar = '\\';
break;
}
case '\\' :
{
progressChar = '|';
break;
}
case '|' :
{
progressChar = '/';
break;
}
case '/' :
{
progressChar = '-';
break;
}
default:
{
progressChar = '-';
break;
}
}
}
/*
* this is only a rough approximation
*/
int64_t FsckTkEx::calcNeededSpace()
{
const char* logContext = "FsckTkEx (calcNeededSpace)";
int64_t neededSpace = 0;
// get used inodes from all meta data servers and sum them up
NodeStore* metaNodes = Program::getApp()->getMetaNodes();
for (const auto& metaNode : metaNodes->referenceAllNodes())
{
NumNodeID nodeID = metaNode->getNumID();
StatStoragePathMsg statStoragePathMsg(0);
const auto respMsg = MessagingTk::requestResponse(*metaNode, statStoragePathMsg,
NETMSGTYPE_StatStoragePathResp);
if (respMsg)
{
StatStoragePathRespMsg* statStoragePathRespMsg = (StatStoragePathRespMsg *) respMsg.get();
int64_t usedInodes = statStoragePathRespMsg->getInodesTotal()
- statStoragePathRespMsg->getInodesFree();
neededSpace += usedInodes * NEEDED_DISKSPACE_META_INODE;
}
else
{
LogContext(logContext).logErr(
"Unable to calculate needed disk space; Communication error with node: "
+ nodeID.str());
return 0;
}
}
// get used inodes from all storage servers and sum them up
NodeStore* storageNodes = Program::getApp()->getStorageNodes();
TargetMapper* targetMapper = Program::getApp()->getTargetMapper();
for (const auto& storageNode : storageNodes->referenceAllNodes())
{
NumNodeID nodeID = storageNode->getNumID();
UInt16List targetIDs;
targetMapper->getTargetsByNode(nodeID, targetIDs);
for ( UInt16ListIter targetIDIter = targetIDs.begin(); targetIDIter != targetIDs.end();
targetIDIter++ )
{
uint16_t targetID = *targetIDIter;
StatStoragePathMsg statStoragePathMsg(targetID);
const auto respMsg = MessagingTk::requestResponse(*storageNode, statStoragePathMsg,
NETMSGTYPE_StatStoragePathResp);
if (respMsg)
{
auto* statStoragePathRespMsg = (StatStoragePathRespMsg *) respMsg.get();
int64_t usedInodes = statStoragePathRespMsg->getInodesTotal()
- statStoragePathRespMsg->getInodesFree();
neededSpace += usedInodes * NEEDED_DISKSPACE_STORAGE_INODE;
}
else
{
LogContext(logContext).logErr(
"Unable to calculate needed disk space; Communication error with node: "
+ nodeID.str());
return -1;
}
}
}
// now we take the calculated approximation and double it to have a lot of space for errors
return neededSpace*2;
}
bool FsckTkEx::checkDiskSpace(Path& dbPath)
{
int64_t neededDiskSpace = FsckTkEx::calcNeededSpace();
if ( unlikely(neededDiskSpace < 0) )
{
FsckTkEx::fsckOutput("Could not determine needed disk space. Aborting now.",
OutputOptions_LINEBREAK | OutputOptions_ADDLINEBREAKBEFORE);
return false;
}
int64_t sizeTotal;
int64_t sizeFree;
int64_t inodesTotal;
int64_t inodesFree;
bool statRes = StorageTk::statStoragePath(dbPath, true, &sizeTotal, &sizeFree,
&inodesTotal, &inodesFree);
if (!statRes)
{
FsckTkEx::fsckOutput(
"Could not stat database file path to determine free space; database file: "
+ dbPath.str());
return false;
}
if ( neededDiskSpace >= sizeFree )
{
std::string neededDiskSpaceUnit;
double neededDiskSpaceValue = UnitTk::byteToXbyte(neededDiskSpace, &neededDiskSpaceUnit);
std::string sizeFreeUnit;
double sizeFreeValue = UnitTk::byteToXbyte(sizeFree, &sizeFreeUnit);
FsckTkEx::fsckOutput(
"Not enough disk space to create database file: " + dbPath.str()
+ "; Recommended free space: " + StringTk::doubleToStr(neededDiskSpaceValue)
+ neededDiskSpaceUnit + "; Free space: " + StringTk::doubleToStr(sizeFreeValue)
+ sizeFreeUnit, OutputOptions_LINEBREAK | OutputOptions_ADDLINEBREAKBEFORE);
bool ignoreDBDiskSpace = Program::getApp()->getConfig()->getIgnoreDBDiskSpace();
if(!ignoreDBDiskSpace)
return false;
}
return true;
}
std::string FsckTkEx::getRepairActionDesc(FsckRepairAction repairAction, bool shortDesc)
{
for (size_t i = 0; __FsckRepairActions[i].actionDesc != nullptr; i++)
{
if( repairAction == __FsckRepairActions[i].action )
{ // we have a match
if (shortDesc)
return __FsckRepairActions[i].actionShortDesc;
else
return __FsckRepairActions[i].actionDesc;
}
}
return "";
}
FhgfsOpsErr FsckTkEx::startModificationLogging(NodeStore* metaNodes, Node& localNode,
bool forceRestart)
{
const char* logContext = "FsckTkEx (startModificationLogging)";
FhgfsOpsErr retVal = FhgfsOpsErr_SUCCESS;
NicAddressList localNicList = localNode.getNicList();
unsigned localPortUDP = localNode.getPortUDP();
FsckTkEx::fsckOutput("-----",
OutputOptions_ADDLINEBREAKBEFORE | OutputOptions_FLUSH | OutputOptions_LINEBREAK);
FsckTkEx::fsckOutput(
"Waiting for metadata servers to start modification logging. This might take some time.",
OutputOptions_FLUSH | OutputOptions_LINEBREAK);
FsckTkEx::fsckOutput("-----", OutputOptions_FLUSH | OutputOptions_DOUBLELINEBREAK);
NumNodeIDList nodeIDs;
auto metaNodeList = metaNodes->referenceAllNodes();
for (auto iter = metaNodeList.begin(); iter != metaNodeList.end(); iter++)
{
auto node = metaNodes->referenceNode((*iter)->getNumID());
NicAddressList nicList;
FsckSetEventLoggingMsg fsckSetEventLoggingMsg(true, localPortUDP,
&localNicList, forceRestart);
const auto respMsg = MessagingTk::requestResponse(*node, fsckSetEventLoggingMsg,
NETMSGTYPE_FsckSetEventLoggingResp);
if (respMsg)
{
auto* fsckSetEventLoggingRespMsg = (FsckSetEventLoggingRespMsg*) respMsg.get();
bool started = fsckSetEventLoggingRespMsg->getLoggingEnabled();
if (!started) // EventFlusher was already running on this node!
{
LogContext(logContext).logErr("Modification logging already running on node: "
+ node->getAlias());
retVal = FhgfsOpsErr_INUSE;
break;
}
}
else
{
LogContext(logContext).logErr("Communication error occured with node: " + node->getAlias());
retVal = FhgfsOpsErr_COMMUNICATION;
}
}
return retVal;
}
bool FsckTkEx::stopModificationLogging(NodeStore* metaNodes)
{
const char* logContext = "FsckTkEx (stopModificationLogging)";
bool retVal = true;
FsckTkEx::fsckOutput("-----",
OutputOptions_ADDLINEBREAKBEFORE | OutputOptions_FLUSH | OutputOptions_LINEBREAK);
FsckTkEx::fsckOutput(
"Waiting for metadata servers to stop modification logging. This might take some time.",
OutputOptions_FLUSH | OutputOptions_LINEBREAK);
FsckTkEx::fsckOutput("-----", OutputOptions_FLUSH | OutputOptions_DOUBLELINEBREAK);
NumNodeIDList nodeIDs;
auto metaNodeList = metaNodes->referenceAllNodes();
for (auto iter = metaNodeList.begin(); iter != metaNodeList.end(); iter++)
nodeIDs.push_back((*iter)->getNumID());
NumNodeIDListIter nodeIdIter = nodeIDs.begin();
while (! nodeIDs.empty())
{
NumNodeID nodeID = *nodeIdIter;
auto node = metaNodes->referenceNode(nodeID);
NicAddressList nicList;
FsckSetEventLoggingMsg fsckSetEventLoggingMsg(false, 0, &nicList, false);
const auto respMsg = MessagingTk::requestResponse(*node, fsckSetEventLoggingMsg,
NETMSGTYPE_FsckSetEventLoggingResp);
if (respMsg)
{
auto* fsckSetEventLoggingRespMsg = (FsckSetEventLoggingRespMsg*) respMsg.get();
bool result = fsckSetEventLoggingRespMsg->getResult();
bool missedEvents = fsckSetEventLoggingRespMsg->getMissedEvents();
if ( result )
{
nodeIdIter = nodeIDs.erase(nodeIdIter);
if ( missedEvents )
{
retVal = false;
}
}
else
nodeIdIter++; // keep in list and try again later
}
else
{
LogContext(logContext).logErr("Communication error occurred with node: " + node->getAlias());
retVal = false;
}
if (nodeIdIter == nodeIDs.end())
{
nodeIdIter = nodeIDs.begin();
sleep(5);
}
}
return retVal;
}
bool FsckTkEx::checkConsistencyStates()
{
auto mgmtdNode = Program::getApp()->getMgmtNodes()->referenceFirstNode();
if (!mgmtdNode)
throw std::runtime_error("Management node not found");
std::list<uint8_t> storageReachabilityStates;
std::list<uint8_t> storageConsistencyStates;
std::list<uint16_t> storageTargetIDs;
std::list<uint8_t> metaReachabilityStates;
std::list<uint8_t> metaConsistencyStates;
std::list<uint16_t> metaTargetIDs;
if (!NodesTk::downloadTargetStates(*mgmtdNode, NODETYPE_Storage, &storageTargetIDs,
&storageReachabilityStates, &storageConsistencyStates, false)
|| !NodesTk::downloadTargetStates(*mgmtdNode, NODETYPE_Meta, &metaTargetIDs,
&metaReachabilityStates, &metaConsistencyStates, false))
{
throw std::runtime_error("Could not download target states from management.");
}
bool result = true;
{
auto idIt = storageTargetIDs.begin();
auto stateIt = storageConsistencyStates.begin();
for (; idIt != storageTargetIDs.end() && stateIt != storageConsistencyStates.end();
idIt++, stateIt++)
{
if (*stateIt == TargetConsistencyState_NEEDS_RESYNC)
{
FsckTkEx::fsckOutput("Storage target " + StringTk::uintToStr(*idIt) + " is set to "
"NEEDS_RESYNC.", OutputOptions_LINEBREAK);
result = false;
}
}
}
{
auto idIt = metaTargetIDs.begin();
auto stateIt = metaConsistencyStates.begin();
for (; idIt != metaTargetIDs.end() && stateIt != metaConsistencyStates.end();
idIt++, stateIt++)
{
if (*stateIt == TargetConsistencyState_NEEDS_RESYNC)
{
FsckTkEx::fsckOutput("Meta node " + StringTk::uintToStr(*idIt) + " is set to "
"NEEDS_RESYNC.", OutputOptions_LINEBREAK);
result = false;
}
}
}
return result;
}

View File

@@ -0,0 +1,103 @@
#ifndef FSCKTKEX_H_
#define FSCKTKEX_H_
#include <common/app/log/LogContext.h>
#include <common/fsck/FsckDirEntry.h>
#include <common/fsck/FsckChunk.h>
#include <common/fsck/FsckContDir.h>
#include <common/fsck/FsckDirEntry.h>
#include <common/fsck/FsckDirInode.h>
#include <common/fsck/FsckFileInode.h>
#include <common/fsck/FsckFsID.h>
#include <common/net/message/nodes/HeartbeatRequestMsg.h>
#include <common/net/message/nodes/HeartbeatMsg.h>
#include <common/nodes/NodeStore.h>
#include <common/threading/PThread.h>
#include <common/toolkit/NodesTk.h>
#include <common/toolkit/MessagingTk.h>
#include <toolkit/FsckDefinitions.h>
/* OutputOption Flags for fsckOutput */
#define OutputOptions_NONE 0
#define OutputOptions_LINEBREAK 1
#define OutputOptions_DOUBLELINEBREAK 1 << 1
#define OutputOptions_HEADLINE 1 << 2
#define OutputOptions_FLUSH 1 << 3
#define OutputOptions_ADDLINEBREAKBEFORE 1 << 4
#define OutputOptions_COLORGREEN 1 << 5
#define OutputOptions_COLORRED 1 << 6
#define OutputOptions_LINEDELETE 1 << 7
#define OutputOptions_NOSTDOUT 1 << 8
#define OutputOptions_NOLOG 1 << 9
#define OutputOptions_STDERR 1 << 10
#define OutputColor_NORMAL "\033[0m";
#define OutputColor_GREEN "\033[32m";
#define OutputColor_RED "\033[31m";
#define SAFE_FPRINTF(stream, fmt, args...) \
do{ if(stream) {fprintf(stream, fmt, ##args);} } while(0)
/*
* calculating with:
* DirEntry 76+256+28 Byte (space for dentry + longest name + one index)
* FileInode 96 Byte |
* DirInode 56 Byte # only the larger of these two counts, even though files are inlined
* ContDir 16 Byte
* FsID 40 Byte
* chunk 88 Byte
*
*/
#define NEEDED_DISKSPACE_META_INODE 512
#define NEEDED_DISKSPACE_STORAGE_INODE 88
class FsckTkEx
{
public:
// check the reachability of all nodes
static bool checkReachability();
// check the reachability of a given node by sending a heartbeat message
static bool checkReachability(Node& node, NodeType nodetype);
/*
* a formatted output for fsck
*
* @param text The text to be printed
* @param optionFlags OutputOptions_... flags (mainly for formatiing)
*/
static void fsckOutput(std::string text, int optionFlags);
// just print a formatted header with the version to the console
static void printVersionHeader(bool toStdErr = false, bool noLogFile = false);
// print the progress meter which goes round and round (-\|/-)
static void progressMeter();
static int64_t calcNeededSpace();
static bool checkDiskSpace(Path& dbPath);
static std::string getRepairActionDesc(FsckRepairAction repairAction, bool shortDesc = false);
static FhgfsOpsErr startModificationLogging(NodeStore* metaNodes, Node& localNode,
bool forceRestart);
static bool stopModificationLogging(NodeStore* metaNodes);
static bool checkConsistencyStates();
private:
FsckTkEx() {}
// saves the last char output by the progress meter
static char progressChar;
// a mutex that is locked by output functions to make sure the output does not get messed up
// by two threads doing output at the same time
static Mutex outputMutex;
public:
// inliners
static void fsckOutput(std::string text)
{
fsckOutput(text, OutputOptions_LINEBREAK);
}
};
#endif /* FSCKTKEX_H_ */