beegfs/fsck/source/database/FsckDBTable.cpp
2025-08-10 01:34:16 +02:00

510 lines
13 KiB
C++

#include "FsckDBTable.h"
#include <database/FsckDBException.h>
#include <toolkit/FsckTkEx.h>
#include <boost/make_shared.hpp>
static db::DirEntry fsckDirEntryToDbDirEntry(const FsckDirEntry& dentry)
{
db::DirEntry result = {
db::EntryID::fromStr(dentry.getID() ),
db::EntryID::fromStr(dentry.getParentDirID() ),
dentry.getEntryOwnerNodeID().val(),
dentry.getInodeOwnerNodeID().val(),
dentry.getSaveNodeID().val(), dentry.getSaveDevice(), dentry.getSaveInode(),
{},
dentry.getInternalID(),
dentry.getEntryType(),
dentry.getName().size() < sizeof(result.name.inlined.text),
dentry.getHasInlinedInode(),
dentry.getIsBuddyMirrored(),
};
if(result.fileNameInlined) {
::memset(result.name.inlined.text, '\0', sizeof(result.name.inlined.text));
::strncpy(result.name.inlined.text, dentry.getName().c_str(),
sizeof(result.name.inlined.text) - 1);
}
return result;
}
void FsckDBDentryTable::insert(FsckDirEntryList& dentries, const BulkHandle* handle)
{
NameBuffer& names = handle ? *handle->nameBuffer : getNameBuffer(0);
for(FsckDirEntryListIter it = dentries.begin(), end = dentries.end(); it != end; ++it)
{
db::DirEntry dentry = fsckDirEntryToDbDirEntry(*it);
ByParent link = { dentry.parentDirID, dentry.id, dentry.entryType };
if(!dentry.fileNameInlined)
{
dentry.name.extended.fileID = names.id();
dentry.name.extended.fileOffset = names.put(it->getName() );
}
if(handle)
{
handle->dentries->append(dentry);
handle->byParent->append(link);
}
else
{
this->table.insert(dentry);
this->byParent.insert(link);
}
}
}
void FsckDBDentryTable::updateFieldsExceptParent(FsckDirEntryList& dentries)
{
for(FsckDirEntryListIter it = dentries.begin(), end = dentries.end(); it != end; ++it)
{
db::DirEntry dentry = fsckDirEntryToDbDirEntry(*it);
this->table.remove(dentry.pkey() );
this->table.insert(dentry);
}
}
void FsckDBDentryTable::remove(FsckDirEntryList& dentries)
{
for(FsckDirEntryListIter it = dentries.begin(), end = dentries.end(); it != end; ++it)
this->table.remove(fsckDirEntryToDbDirEntry(*it).pkey() );
}
Table<db::DirEntry>::QueryType FsckDBDentryTable::get()
{
this->table.commitChanges();
return this->table.cursor();
}
Table<FsckDBDentryTable::ByParent>::QueryType FsckDBDentryTable::getByParent()
{
this->byParent.commitChanges();
return this->byParent.cursor();
}
std::pair<bool, db::DirEntry> FsckDBDentryTable::getAnyFor(db::EntryID id)
{
this->table.commitChanges();
struct ops
{
static db::EntryID onlyID(const db::DirEntry::KeyType& key) { return boost::get<0>(key); }
};
return this->table.getByKeyProjection(id, ops::onlyID);
}
std::string FsckDBDentryTable::getNameOf(const db::DirEntry& dentry)
{
if(dentry.fileNameInlined)
return dentry.name.inlined.text;
return getNameBuffer(dentry.name.extended.fileID).get(dentry.name.extended.fileOffset);
}
std::string FsckDBDentryTable::getPathOf(const db::DirEntry& dentry)
{
std::string result = getNameOf(dentry);
db::EntryID parent = dentry.parentDirID;
unsigned depth = 0;
while(!parent.isSpecial() )
{
depth++;
if(depth > 255)
return "[<unresolved>]/" + result;
const NameCacheEntry* cacheEntry = getFromCache(parent);
if(cacheEntry)
{
result = cacheEntry->name + "/" + result;
parent = cacheEntry->parent;
continue;
}
std::pair<bool, db::DirEntry> item = getAnyFor(parent);
if(!item.first)
return "[<unresolved>]/" + result;
std::string parentName = getNameOf(item.second);
result = parentName + "/" + result;
parent = item.second.parentDirID;
addToCache(item.second, parentName);
}
return getNameOf(parent) + "/" + result;
}
void FsckDBFileInodesTable::insert(FsckFileInodeList& fileInodes, const BulkHandle* handle)
{
for(FsckFileInodeListIter it = fileInodes.begin(), end = fileInodes.end(); it != end; ++it)
{
const std::vector<uint16_t>& stripes = it->getStripeTargets();
db::FileInode inode = {
db::EntryID::fromStr(it->getID() ),
db::EntryID::fromStr(it->getParentDirID() ),
db::EntryID::fromStr(it->getPathInfo()->getOrigParentEntryID() ),
it->getParentNodeID().val(),
it->getSaveNodeID().val(),
it->getPathInfo()->getOrigUID(),
it->getUserID(), it->getGroupID(),
(uint64_t) it->getFileSize(), it->getUsedBlocks(),
it->getNumHardLinks(),
it->getSaveInode(),
it->getSaveDevice(),
it->getChunkSize(),
{},
it->getIsInlined(),
uint32_t(it->getPathInfo()->getFlags() ),
it->getStripePatternType(),
uint32_t(stripes.size() ),
it->getReadable(),
it->getIsBuddyMirrored(),
it->getIsMismirrored(),
};
db::StripeTargets extraTargets = { inode.id, {}, 0 };
for(size_t i = 0; i < stripes.size(); i++)
{
if(i < inode.NTARGETS)
inode.targets[i] = stripes[i];
else
{
size_t offsetInPattern = (i - inode.NTARGETS) % extraTargets.NTARGETS;
if(offsetInPattern == 0)
extraTargets.firstTargetIndex = i;
extraTargets.targets[offsetInPattern] = stripes[i];
if(offsetInPattern == extraTargets.NTARGETS - 1)
{
if(handle)
std::get<1>(*handle)->append(extraTargets);
else
this->targets.insert(extraTargets);
extraTargets.firstTargetIndex = 0;
}
}
}
if(handle)
{
std::get<0>(*handle)->append(inode);
if(extraTargets.firstTargetIndex != 0)
std::get<1>(*handle)->append(extraTargets);
}
else
{
this->inodes.insert(inode);
if(extraTargets.firstTargetIndex != 0)
this->targets.insert(extraTargets);
}
}
}
void FsckDBFileInodesTable::update(FsckFileInodeList& inodes)
{
for(FsckFileInodeListIter it = inodes.begin(), end = inodes.end(); it != end; ++it)
{
FsckFileInodeList list(1, *it);
remove(list);
insert(list);
}
}
void FsckDBFileInodesTable::remove(FsckFileInodeList& fileInodes)
{
for(FsckFileInodeListIter it = fileInodes.begin(), end = fileInodes.end(); it != end; ++it)
{
this->inodes.remove(db::EntryID::fromStr(it->getID() ) );
this->targets.remove(db::EntryID::fromStr(it->getID() ) );
}
}
FsckDBFileInodesTable::InodesQueryType FsckDBFileInodesTable::getInodes()
{
this->inodes.commitChanges();
return
this->inodes.cursor()
| db::groupBy(UniqueInlinedInode() )
| db::select(SelectFirst() );
}
Table<db::StripeTargets, true>::QueryType FsckDBFileInodesTable::getTargets()
{
this->targets.commitChanges();
return this->targets.cursor();
}
UInt16Vector FsckDBFileInodesTable::getStripeTargetsByKey(const db::EntryID& id)
{
UInt16Vector allStripeTargets;
std::pair<bool, db::FileInode> result = this->get(id.str());
if (!result.first)
return allStripeTargets;
// firstly copy stripeTargets from FileInode object
auto inode = result.second;
uint32_t targetArrSize = inode.NTARGETS;
uint32_t numTargets = (inode.stripePatternSize > targetArrSize) ? targetArrSize
: inode.stripePatternSize;
std::copy(inode.targets, inode.targets + numTargets, std::back_inserter(allStripeTargets));
// if extraTargets are present then get them from targets table
uint32_t numExtraTargets = inode.stripePatternSize - numTargets;
if (numExtraTargets)
{
this->targets.commitChanges();
auto dbRes = this->targets.getAllByKey(id);
while (dbRes.step())
{
auto elem = dbRes.get();
for (int i=0; i<elem->NTARGETS; i++)
{
allStripeTargets.push_back(elem->targets[i]);
numExtraTargets -= 1;
if (numExtraTargets == 0) break;
}
if (numExtraTargets == 0) break;
}
}
return allStripeTargets;
}
std::pair<bool, db::FileInode> FsckDBFileInodesTable::get(std::string id)
{
this->inodes.commitChanges();
return this->inodes.getByKey(db::EntryID::fromStr(id) );
}
void FsckDBDirInodesTable::insert(FsckDirInodeList& dirInodes, const BulkHandle* handle)
{
for(FsckDirInodeListIter it = dirInodes.begin(), end = dirInodes.end(); it != end; ++it)
{
db::DirInode inode = {
db::EntryID::fromStr(it->getID() ),
db::EntryID::fromStr(it->getParentDirID() ),
it->getParentNodeID().val(),
it->getOwnerNodeID().val(),
it->getSaveNodeID().val(),
it->getStripePatternType(),
it->getReadable(),
it->getIsBuddyMirrored(),
it->getIsMismirrored(),
(uint64_t) it->getSize(),
it->getNumHardLinks(),
};
if(handle)
(*handle)->append(inode);
else
this->table.insert(inode);
}
}
void FsckDBDirInodesTable::update(FsckDirInodeList& inodes)
{
for(FsckDirInodeListIter it = inodes.begin(), end = inodes.end(); it != end; ++it)
{
FsckDirInodeList list(1, *it);
remove(list);
insert(list);
}
}
void FsckDBDirInodesTable::remove(FsckDirInodeList& dirInodes)
{
for(FsckDirInodeListIter it = dirInodes.begin(), end = dirInodes.end(); it != end; ++it)
this->table.remove(db::EntryID::fromStr(it->getID() ) );
}
Table<db::DirInode>::QueryType FsckDBDirInodesTable::get()
{
this->table.commitChanges();
return this->table.cursor();
}
std::pair<bool, FsckDirInode> FsckDBDirInodesTable::get(std::string id)
{
this->table.commitChanges();
return this->table.getByKey(db::EntryID::fromStr(id) );
}
static db::Chunk fsckChunkToDbChunk(FsckChunk& chunk)
{
db::Chunk result = {
db::EntryID::fromStr(chunk.getID() ),
chunk.getTargetID(), chunk.getBuddyGroupID(),
{},
chunk.getFileSize(), chunk.getUsedBlocks(),
chunk.getUserID(), chunk.getGroupID(),
};
strncpy(result.savedPath, chunk.getSavedPath()->str().c_str(),
sizeof(result.savedPath) - 1);
return result;
}
void FsckDBChunksTable::insert(FsckChunkList& chunks, const BulkHandle* handle)
{
for(FsckChunkListIter it = chunks.begin(), end = chunks.end(); it != end; ++it)
{
if(handle)
(*handle)->append(fsckChunkToDbChunk(*it) );
else
this->table.insert(fsckChunkToDbChunk(*it) );
}
}
void FsckDBChunksTable::update(FsckChunkList& chunks)
{
for(FsckChunkListIter it = chunks.begin(), end = chunks.end(); it != end; ++it)
{
db::Chunk chunk = fsckChunkToDbChunk(*it);
this->table.remove(chunk.pkey() );
this->table.insert(chunk);
}
}
void FsckDBChunksTable::remove(const db::Chunk::KeyType& id)
{
this->table.remove(id);
}
Table<db::Chunk>::QueryType FsckDBChunksTable::get()
{
this->table.commitChanges();
return this->table.cursor();
}
static db::ContDir fsckContDirToDbContDir(FsckContDir& contDir)
{
return {
db::EntryID::fromStr(contDir.getID()),
contDir.getSaveNodeID().val(),
contDir.getIsBuddyMirrored(),
};
}
void FsckDBContDirsTable::insert(FsckContDirList& contDirs, const BulkHandle* handle)
{
for(FsckContDirListIter it = contDirs.begin(), end = contDirs.end(); it != end; ++it)
{
if(handle)
(*handle)->append(fsckContDirToDbContDir(*it) );
else
this->table.insert(fsckContDirToDbContDir(*it) );
}
}
Table<db::ContDir>::QueryType FsckDBContDirsTable::get()
{
this->table.commitChanges();
return this->table.cursor();
}
static db::FsID fsckFsIDToDbFsID(FsckFsID& id)
{
return {
db::EntryID::fromStr(id.getID() ),
db::EntryID::fromStr(id.getParentDirID() ),
id.getSaveNodeID().val(), id.getSaveDevice(), id.getSaveInode(),
id.getIsBuddyMirrored(),
};
}
void FsckDBFsIDsTable::insert(FsckFsIDList& fsIDs, const BulkHandle* handle)
{
for(FsckFsIDListIter it = fsIDs.begin(), end = fsIDs.end(); it != end; ++it)
{
if(handle)
(*handle)->append(fsckFsIDToDbFsID(*it) );
else
this->table.insert(fsckFsIDToDbFsID(*it) );
}
}
void FsckDBFsIDsTable::remove(FsckFsIDList& fsIDs)
{
for(FsckFsIDListIter it = fsIDs.begin(), end = fsIDs.end(); it != end; ++it)
this->table.remove(fsckFsIDToDbFsID(*it).pkey() );
}
Table<db::FsID>::QueryType FsckDBFsIDsTable::get()
{
this->table.commitChanges();
return this->table.cursor();
}
void FsckDBUsedTargetIDsTable::insert(FsckTargetIDList& targetIDs, const BulkHandle& handle)
{
for(FsckTargetIDListIter it = targetIDs.begin(), end = targetIDs.end(); it != end; ++it)
{
db::UsedTarget target = { it->getID(), it->getTargetIDType() };
handle->append(target);
}
}
void FsckDBModificationEventsTable::insert(const FsckModificationEventList& events,
const BulkHandle& handle)
{
for(std::list<FsckModificationEvent>::const_iterator it = events.begin(), end = events.end();
it != end; ++it)
{
db::ModificationEvent event = { db::EntryID::fromStr(it->getEntryID() ) };
handle->append(event);
}
}