//------------------------------------------------------------------------------ //! @file FmdHandler.hh //! @author Abhishek Lekshmanan - CERN //------------------------------------------------------------------------------ /************************************************************************ * EOS - the CERN Disk Storage System * * Copyright (C) 2021 CERN/Switzerland * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* ************************************************************************/ #include "common/Path.hh" #include "namespace/interface/IFileMD.hh" #include "namespace/ns_quarkdb/FileMD.hh" #include "namespace/ns_quarkdb/persistency/FileMDSvc.hh" #include "namespace/ns_quarkdb/persistency/MetadataFetcher.hh" #include "namespace/ns_quarkdb/persistency/RequestBuilder.hh" #include "namespace/ns_quarkdb/QdbContactDetails.hh" #include "qclient/structures/QSet.hh" #include "fst/utils/FTSWalkTree.hh" #include "fst/checksum/ChecksumPlugins.hh" #include "fst/XrdFstOfs.hh" #include "fst/io/local/LocalIo.hh" #include "fst/io/FileIoPluginCommon.hh" #include "fst/filemd/FmdMgm.hh" #include "fst/filemd/FmdAttr.hh" #include "fst/filemd/FmdHandler.hh" EOSFSTNAMESPACE_BEGIN //------------------------------------------------------------------------------ // Check if entry has a file checksum error //------------------------------------------------------------------------------ bool FmdHandler::FileHasXsError(const std::string& lpath, eos::common::FileSystem::fsid_t fsid) { bool has_xs_err = false; // First check the local db for any filecxerror flags auto fid = eos::common::FileId::PathToFid(lpath.c_str()); auto fmd = LocalGetFmd(fid, fsid, true); if (fmd && fmd->mProtoFmd.filecxerror()) { has_xs_err = true; } // If no error found then also check the xattr on the physical file if (!has_xs_err) { std::unique_ptr io(FileIoPluginHelper::GetIoObject(lpath.c_str())); std::string xattr_xs_err = "0"; if (io->attrGet("user.eos.filecxerror", xattr_xs_err) == 0) { has_xs_err = (xattr_xs_err == "1"); } } return has_xs_err; } //------------------------------------------------------------------------------ // Update file metadata object with new fid information //------------------------------------------------------------------------------ bool FmdHandler::UpdateFmd(const std::string& path, eos::common::FileId::fileid_t fid) { // We rely on the path to retrieve the Fmd object auto [status, fmd] = LocalRetrieveFmd(0ull, 0ul, path); if (!status) { return false; } fmd.mProtoFmd.set_fid(fid); return LocalPutFmd(fmd, 0ull, 0ul, path); } //------------------------------------------------------------------------------ // Update fmd with disk info i.e. physical file extended attributes //------------------------------------------------------------------------------ bool FmdHandler::UpdateWithDiskInfo(eos::common::FileSystem::fsid_t fsid, eos::common::FileId::fileid_t fid, unsigned long long disk_size, const std::string& disk_xs, unsigned long check_ts_sec, bool filexs_err, bool blockxs_err, bool layout_err) { if (!fid) { eos_err("%s", "msg=\"skipping insert of file with fid=0\""); return false; } eos_debug("fsid=%lu fxid=%08llx disksize=%llu diskchecksum=%s checktime=%llu " "fcxerror=%d bcxerror=%d flaglayouterror=%d", fsid, fid, disk_size, disk_xs.c_str(), check_ts_sec, filexs_err, blockxs_err, layout_err); auto [status, valfmd] = LocalRetrieveFmd(fid, fsid); valfmd.mProtoFmd.set_fid(fid); valfmd.mProtoFmd.set_fsid(fsid); valfmd.mProtoFmd.set_disksize(disk_size); valfmd.mProtoFmd.set_checktime(check_ts_sec); valfmd.mProtoFmd.set_filecxerror(filexs_err ? 1 : 0); valfmd.mProtoFmd.set_blockcxerror(blockxs_err ? 1 : 0); // Update reference size only if undefined if (valfmd.mProtoFmd.size() == eos::common::FmdHelper::UNDEF) { // This is done only for non-rain layouts if (!eos::common::LayoutId::IsRain(valfmd.mProtoFmd.lid())) { valfmd.mProtoFmd.set_size(disk_size); } } if (disk_xs.empty() && disk_size == 0) { valfmd.mProtoFmd.set_diskchecksum(common::LayoutId::GetEmptyFileChecksum( valfmd.mProtoFmd.lid())); } else { valfmd.mProtoFmd.set_diskchecksum(disk_xs); } // Update the reference checksum only if empty if (valfmd.mProtoFmd.checksum().empty()) { valfmd.mProtoFmd.set_checksum(disk_xs); } if (layout_err) { // If the mgm sync is run afterwards, every disk file is by construction an // orphan, until it is synced from the mgm valfmd.mProtoFmd.set_layouterror(LayoutId::kOrphan); } return LocalPutFmd(valfmd, fid, fsid); } //------------------------------------------------------------------------------ // Update fmd from MGM metadata //------------------------------------------------------------------------------ bool FmdHandler::UpdateWithMgmInfo(eos::common::FileSystem::fsid_t fsid, eos::common::FileId::fileid_t fid, eos::common::FileId::fileid_t cid, eos::common::LayoutId::layoutid_t lid, unsigned long long mgmsize, std::string mgmchecksum, uid_t uid, gid_t gid, unsigned long long ctime, unsigned long long ctime_ns, unsigned long long mtime, unsigned long long mtime_ns, int layouterror, std::string locations) { if (!fid) { eos_err("msg=\"skip inserting file with fid=0\""); return false; } eos_debug("fxid=%08llx fsid=%lu cid=%llu lid=%lx mgmsize=%llu mgmchecksum=%s", fid, fsid, cid, lid, mgmsize, mgmchecksum.c_str()); auto [status, valfmd] = LocalRetrieveFmd(fid, fsid); if (!status) { eos_err("msg=\"failed to retrieve filemd to update mgm info\" fxid=%08llx fsid=%lu", fid, fsid); return false; } valfmd.mProtoFmd.set_mgmsize(mgmsize); valfmd.mProtoFmd.set_mgmchecksum(mgmchecksum); valfmd.mProtoFmd.set_cid(cid); valfmd.mProtoFmd.set_lid(lid); valfmd.mProtoFmd.set_uid(uid); valfmd.mProtoFmd.set_gid(gid); valfmd.mProtoFmd.set_ctime(ctime); valfmd.mProtoFmd.set_ctime_ns(ctime_ns); valfmd.mProtoFmd.set_mtime(mtime); valfmd.mProtoFmd.set_mtime_ns(mtime_ns); valfmd.mProtoFmd.set_layouterror(layouterror); valfmd.mProtoFmd.set_locations(locations); // Truncate the checksum to the right length size_t cslen = LayoutId::GetChecksumLen(lid) * 2; valfmd.mProtoFmd.set_mgmchecksum(std::string( valfmd.mProtoFmd.mgmchecksum()).erase (std::min(valfmd.mProtoFmd.mgmchecksum().length(), cslen))); // Update reference size only if undefined if (valfmd.mProtoFmd.size() == eos::common::FmdHelper::UNDEF) { valfmd.mProtoFmd.set_size(mgmsize); } else { // For RAIN layouts the logical size (should) matche the MGM size // even if it is already set if (eos::common::LayoutId::IsRain(lid)) { valfmd.mProtoFmd.set_size(mgmsize); } } // Update the reference checksum only if empty if (valfmd.mProtoFmd.checksum().empty()) { valfmd.mProtoFmd.set_checksum(valfmd.mProtoFmd.mgmchecksum()); } return LocalPutFmd(valfmd, fid, fsid); } //------------------------------------------------------------------------------ // Update local fmd with info from the rain stripes scanner //----------------------------------------------------------------------------- void FmdHandler::UpdateWithStripeCheckInfo( eos::common::FileId::fileid_t fid, eos::common::FileSystem::fsid_t fsid, const std::set& invalid_stripes) { auto fmd = LocalGetFmd(fid, fsid, true); if (fmd) { fmd->mProtoFmd.clear_stripeerror(); for (auto invalid_fsid : invalid_stripes) { fmd->mProtoFmd.add_stripeerror(invalid_fsid); } Commit(fmd.get()); } } //------------------------------------------------------------------------------ // Update local fmd with info from the scanner //------------------------------------------------------------------------------ void FmdHandler::UpdateWithScanInfo(eos::common::FileId::fileid_t fid, eos::common::FileSystem::fsid_t fsid, const std::string& fpath, uint64_t scan_sz, const std::string& scan_xs_hex, std::shared_ptr qcl) { eos_debug("msg=\"resyncing qdb and disk info\" fxid=%08llx fsid=%lu", fid, fsid); if (ResyncFileFromQdb(fid, fsid, fpath, qcl)) { return; } int rd_rc = ResyncDisk(fpath.c_str(), fsid, false, scan_sz, scan_xs_hex); if (rd_rc) { if (rd_rc == ENOENT) { // File no longer on disk - mark it as missing unless it's a 0-size file auto fmd = LocalGetFmd(fid, fsid, true); if (fmd && fmd->mProtoFmd.mgmsize()) { fmd->mProtoFmd.set_layouterror(fmd->mProtoFmd.layouterror() | LayoutId::kMissing); Commit(fmd.get()); } } } } //------------------------------------------------------------------------------ // Clear errors on local fmd //------------------------------------------------------------------------------ void FmdHandler::ClearErrors(eos::common::FileId::fileid_t fid, eos::common::FileSystem::fsid_t fsid) { auto fmd = LocalGetFmd(fid, fsid, true); if (fmd) { fmd->mProtoFmd.set_layouterror(LayoutId::kNone); fmd->mProtoFmd.set_blockcxerror(0); fmd->mProtoFmd.set_filecxerror(0); fmd->mProtoFmd.clear_stripeerror(); Commit(fmd.get()); } } //------------------------------------------------------------------------------ // Resync a single entry from disk //------------------------------------------------------------------------------ int FmdHandler::ResyncDisk(const char* path, eos::common::FileSystem::fsid_t fsid, bool flaglayouterror, uint64_t scan_sz, const std::string& scan_xs_hex) { eos::common::Path cPath(path); eos::common::FileId::fileid_t fid = eos::common::FileId::Hex2Fid(cPath.GetName()); if (fid == 0) { eos_err("%s", "msg=\"unable to sync fid=0\""); return EINVAL; } std::unique_ptr io(eos::fst::FileIoPluginHelper::GetIoObject(path)); if (io == nullptr) { eos_crit("msg=\"failed to get IO object\" path=%s", path); return ENOMEM; } struct stat buf; if ((!io->fileStat(&buf)) && S_ISREG(buf.st_mode)) { std::string sxs_type, scheck_stamp, filexs_err, blockxs_err; char xs_val[SHA256_DIGEST_LENGTH]; size_t xs_len = SHA256_DIGEST_LENGTH; memset(xs_val, 0, sizeof(xs_val)); io->attrGet("user.eos.checksumtype", sxs_type); io->attrGet("user.eos.filecxerror", filexs_err); io->attrGet("user.eos.blockcxerror", blockxs_err); io->attrGet("user.eos.timestamp", scheck_stamp); // Handle the old format in microseconds, truncate to seconds if (scheck_stamp.length() > 10) { scheck_stamp.erase(10); } unsigned long check_ts_sec {0ul}; try { check_ts_sec = std::stoul(scheck_stamp); } catch (...) { // ignore } std::string disk_xs_hex; off_t disk_size {0ull}; if (scan_sz && !scan_xs_hex.empty()) { disk_size = scan_sz; disk_xs_hex = scan_xs_hex; } else { disk_size = buf.st_size; if (io->attrGet("user.eos.checksum", xs_val, xs_len) == 0) { std::unique_ptr xs_obj {ChecksumPlugins::GetXsObj(sxs_type)}; if (xs_obj) { if (xs_obj->SetBinChecksum(xs_val, xs_len)) { disk_xs_hex = xs_obj->GetHexChecksum(); } } } } // Update the DB if (!UpdateWithDiskInfo(fsid, fid, disk_size, disk_xs_hex, check_ts_sec, (filexs_err == "1"), (blockxs_err == "1"), flaglayouterror)) { // eos_err("msg=\"failed to update DB\" dbpath=%s fxid=%08llx fsid=%lu", // eos::common::DbMap::getDbType().c_str(), fid, fsid); return false; } } else { eos_err("msg=\"failed stat or entry is not a file\" path=%s", path); return ENOENT; } return 0; } //------------------------------------------------------------------------------ // Resync files under path into DB //------------------------------------------------------------------------------ bool FmdHandler::ResyncAllDisk(const char* path, eos::common::FileSystem::fsid_t fsid, bool flaglayouterror) { if (flaglayouterror) { SetSyncStatus(fsid, true); } if (!ResetDiskInformation(fsid)) { eos_err("failed to reset the disk information before resyncing fsid=%lu", fsid); return false; } uint64_t scan_sz = 0; std::string scan_xs_hex; std::error_code ec; WalkFSTree(path, [&](const char* path) { this->ResyncDisk(path, fsid, flaglayouterror, scan_sz, scan_xs_hex); }, ec); if (ec) { eos_err("msg=\"Walk FST tree failed\" error=%s", ec.message().c_str()); return false; } return true; } //------------------------------------------------------------------------------ // Resync file meta data from MGM into local database //------------------------------------------------------------------------------ bool FmdHandler::ResyncMgm(eos::common::FileSystem::fsid_t fsid, eos::common::FileId::fileid_t fid, const char* manager) { eos::common::FmdHelper fMd; int rc = FmdMgmHandler::GetMgmFmd((manager ? manager : ""), fid, fMd); if ((rc == 0) || (rc == ENODATA)) { if (rc == ENODATA) { eos_warning("msg=\"file not found on MGM\" fxid=%08llx", fid); fMd.mProtoFmd.set_fid(fid); if (fid == 0) { eos_warning("msg=\"removing fxid=0 entry\""); LocalDeleteFmd(fMd.mProtoFmd.fid(), fsid, false); return true; } } // Define layouterrors fMd.mProtoFmd.set_layouterror(fMd.LayoutError(fsid)); // Get an existing record without creating the record !!! std::unique_ptr fmd { LocalGetFmd(fMd.mProtoFmd.fid(), fsid, true, false, fMd.mProtoFmd.uid(), fMd.mProtoFmd.gid(), fMd.mProtoFmd.lid())}; if (fmd) { // Check if exists on disk if (fmd->mProtoFmd.disksize() == eos::common::FmdHelper::UNDEF) { if (fMd.mProtoFmd.layouterror() & LayoutId::kUnregistered) { // There is no replica supposed to be here and there is nothing on // disk, so remove it from the database eos_warning("msg=\"removing ghost fmd from db\" fsid=%u fxid=%08llx", fsid, fid); LocalDeleteFmd(fMd.mProtoFmd.fid(), fsid, false); return true; } } } else { // No file locally and also not registered with the MGM if ((fMd.mProtoFmd.layouterror() & LayoutId::kUnregistered) || (fMd.mProtoFmd.layouterror() & LayoutId::kOrphan)) { return true; } } // Get/create a record fmd = LocalGetFmd(fMd.mProtoFmd.fid(), fsid, true, true, fMd.mProtoFmd.uid(), fMd.mProtoFmd.gid(), fMd.mProtoFmd.lid()); if (fmd) { // Check if it exists on disk if ((fmd->mProtoFmd.disksize() == eos::common::FmdHelper::UNDEF) && (fMd.mProtoFmd.mgmsize())) { fMd.mProtoFmd.set_layouterror(fMd.mProtoFmd.layouterror() | LayoutId::kMissing); eos_warning("msg=\"mark missing replica\" fxid=%08llx on fsid=%u", fid, fsid); } if (!UpdateWithMgmInfo(fsid, fMd.mProtoFmd.fid(), fMd.mProtoFmd.cid(), fMd.mProtoFmd.lid(), fMd.mProtoFmd.mgmsize(), fMd.mProtoFmd.mgmchecksum(), fMd.mProtoFmd.uid(), fMd.mProtoFmd.gid(), fMd.mProtoFmd.ctime(), fMd.mProtoFmd.ctime_ns(), fMd.mProtoFmd.mtime(), fMd.mProtoFmd.mtime_ns(), fMd.mProtoFmd.layouterror(), fMd.mProtoFmd.locations())) { eos_err("msg=\"failed to update fmd with mgm info\" fxid=%08llx", fid); return false; } // Check if it exists on disk and at the mgm if ((fmd->mProtoFmd.disksize() == eos::common::FmdHelper::UNDEF) && (fMd.mProtoFmd.mgmsize() == eos::common::FmdHelper::UNDEF)) { // There is no replica supposed to be here and there is nothing on // disk, so remove it from the database eos_warning("removing entry for fxid=%08llx on fsid=%u", fid, (unsigned long) fsid); LocalDeleteFmd(fMd.mProtoFmd.fid(), fsid, false); return true; } } else { eos_err("failed to create fmd for fxid=%08llx", fid); return false; } } else { eos_err("failed to retrieve MGM fmd for fxid=%08llx", fid); return false; } return true; } //------------------------------------------------------------------------------ // Resync all meta data from MGM into local database //------------------------------------------------------------------------------ bool FmdHandler::ResyncAllMgm(eos::common::FileSystem::fsid_t fsid, const char* manager) { if (!ResetMgmInformation(fsid)) { eos_err("%s", "msg=\"failed to reset the mgm information before resyncing\""); SetSyncStatus(fsid, false); return false; } std::string tmpfile; if (!FmdMgmHandler::ExecuteDumpmd(manager, fsid, tmpfile)) { SetSyncStatus(fsid, false); return false; } // Parse the result and unlink temporary file std::ifstream inFile(tmpfile); std::string dumpentry; unlink(tmpfile.c_str()); unsigned long long cnt = 0; while (std::getline(inFile, dumpentry)) { cnt++; eos_debug("line=%s", dumpentry.c_str()); std::unique_ptr env(new XrdOucEnv(dumpentry.c_str())); if (env) { eos::common::FmdHelper fMd; if (FmdMgmHandler::EnvMgmToFmd(*env, fMd)) { // get/create one auto fmd = LocalGetFmd(fMd.mProtoFmd.fid(), fsid, true, true, fMd.mProtoFmd.uid(), fMd.mProtoFmd.gid(), fMd.mProtoFmd.lid()); fMd.mProtoFmd.set_layouterror(fMd.LayoutError(fsid)); if (fmd) { // Check if it exists on disk if ((fmd->mProtoFmd.disksize() == eos::common::FmdHelper::UNDEF) && (fmd->mProtoFmd.mgmsize())) { fMd.mProtoFmd.set_layouterror(fMd.mProtoFmd.layouterror() | LayoutId::kMissing); eos_warning("found missing replica for fxid=%08llx on fsid=%u", fMd.mProtoFmd.fid(), (unsigned long) fsid); } if (!UpdateWithMgmInfo(fsid, fMd.mProtoFmd.fid(), fMd.mProtoFmd.cid(), fMd.mProtoFmd.lid(), fMd.mProtoFmd.mgmsize(), fMd.mProtoFmd.mgmchecksum(), fMd.mProtoFmd.uid(), fMd.mProtoFmd.gid(), fMd.mProtoFmd.ctime(), fMd.mProtoFmd.ctime_ns(), fMd.mProtoFmd.mtime(), fMd.mProtoFmd.mtime_ns(), fMd.mProtoFmd.layouterror(), fMd.mProtoFmd.locations())) { eos_err("msg=\"failed to update fmd\" entry=\"%s\"", dumpentry.c_str()); } } else { eos_err("msg=\"failed to get/create fmd\" enrty=\"%s\"", dumpentry.c_str()); } } else { eos_err("msg=\"failed to convert\" entry=\"%s\"", dumpentry.c_str()); } } if (!(cnt % 10000)) { eos_info("msg=\"synced files so far\" nfiles=%llu fsid=%u", cnt, (unsigned long) fsid); } } SetSyncStatus(fsid, false); return true; } //------------------------------------------------------------------------------ // Move given file to orphans directory and also set its extended attribute // to reflect the original path to the file. //------------------------------------------------------------------------------ void FmdHandler::MoveToOrphans(const std::string& fpath) { eos::common::Path cpath(fpath.c_str()); size_t cpath_sz = cpath.GetSubPathSize(); if (cpath_sz <= 2) { eos_static_err("msg=\"failed to extract FST mount/fid hex\" path=%s", fpath.c_str()); return; } std::string fid_hex = cpath.GetName(); std::ostringstream oss; oss << cpath.GetSubPath(cpath_sz - 2) << ".eosorphans/" << fid_hex; std::string forphan = oss.str(); // Store the original path name as an extended attribute in case ... std::unique_ptr io(FileIoPluginHelper::GetIoObject(fpath)); io->attrSet("user.eos.orphaned", fpath.c_str()); // If orphan move it into the orphaned directory if (!rename(fpath.c_str(), forphan.c_str())) { eos_static_warning("msg=\"orphaned/unregistered quarantined\" " "fst-path=%s orphan-path=%s", fpath.c_str(), forphan.c_str()); } else { eos_static_err("msg=\"failed to quarantine orphaned/unregistered\" " "fst-path=%s orphan-path=%s", fpath.c_str(), forphan.c_str()); } } //------------------------------------------------------------------------------ // Resync file meta data from QuarkDB into local database //------------------------------------------------------------------------------ int FmdHandler::ResyncFileFromQdb(eos::common::FileId::fileid_t fid, eos::common::FileSystem::fsid_t fsid, const std::string& fpath, std::shared_ptr qcl) { using eos::common::FileId; if (qcl == nullptr) { eos_notice("msg=\"no qclient present, skipping file resync\" fxid=%08llx" " fid=%lu", fid, fsid); return EINVAL; } eos::common::FmdHelper ns_fmd; auto file_fut = eos::MetadataFetcher::getFileFromId(*qcl.get(), eos::FileIdentifier(fid)); try { FmdMgmHandler::NsFileProtoToFmd(std::move(file_fut).get(), ns_fmd); } catch (const eos::MDException& e) { eos_err("msg=\"failed to get metadata from QDB: %s\" fxid=%08llx", e.what(), fid); // If there is any transient error with QDB then we skip this file, // otherwise it might be wronly marked as orphan below. if (e.getErrno() != ENOENT) { eos_err("msg=\"skip file update due to QDB error\" msg_err=\"%s\" " "fxid=%08llx", e.what(), fid); return e.getErrno(); } } // Mark any possible layout error, if fid not found in QDB then this is // marked as orphan ns_fmd.mProtoFmd.set_layouterror(ns_fmd.LayoutError(fsid)); // Get an existing local record without creating the record!!! std::unique_ptr local_fmd { LocalGetFmd(fid, fsid, true, false)}; if (!local_fmd) { // Create the local record if (!(local_fmd = LocalGetFmd(fid, fsid, true, true))) { eos_err("msg=\"failed to create local fmd entry\" fxid=%08llx fsid=%u", fid, fsid); return EINVAL; } } // Orphan files get moved to a special directory .eosorphans if (ns_fmd.mProtoFmd.layouterror() & eos::common::LayoutId::kOrphan) { local_fmd->mProtoFmd.set_layouterror(LayoutId::kOrphan); if (!Commit(local_fmd.get())) { eos_err("msg=\"failed to mark orphan entry\" fxid=%08llx fsid=%u", fid, fsid); } FmdHandler::MoveToOrphans(fpath); #ifndef _NOOFS gOFS.Storage->PublishFsckError(fid, fsid, eos::common::FsckErr::Orphans); #endif return ENOENT; } // Never mark an ns 0-size file without replicas on disk as missing if (ns_fmd.mProtoFmd.mgmsize() == 0) { ns_fmd.mProtoFmd.set_layouterror(ns_fmd.mProtoFmd.layouterror() & ~LayoutId::kMissing); } else { // If file is not on disk or already marked as missing then keep the // missing flag if ((local_fmd->mProtoFmd.disksize() == eos::common::FmdHelper::UNDEF) || (local_fmd->mProtoFmd.layouterror() & LayoutId::kMissing)) { eos_warning("msg=\"mark missing replica\" fxid=%08llx fsid=%u", fid, fsid); ns_fmd.mProtoFmd.set_layouterror(ns_fmd.mProtoFmd.layouterror() | LayoutId::kMissing); } } if (!UpdateWithMgmInfo(fsid, fid, ns_fmd.mProtoFmd.cid(), ns_fmd.mProtoFmd.lid(), ns_fmd.mProtoFmd.mgmsize(), ns_fmd.mProtoFmd.mgmchecksum(), ns_fmd.mProtoFmd.uid(), ns_fmd.mProtoFmd.gid(), ns_fmd.mProtoFmd.ctime(), ns_fmd.mProtoFmd.ctime_ns(), ns_fmd.mProtoFmd.mtime(), ns_fmd.mProtoFmd.mtime_ns(), ns_fmd.mProtoFmd.layouterror(), ns_fmd.mProtoFmd.locations())) { eos_err("msg=\"failed to update fmd with qdb info\" fxid=%08llx", fid); return EINVAL; } return 0; } //------------------------------------------------------------------------------ // Resync all meta data from QuarkdDB //------------------------------------------------------------------------------ bool FmdHandler::ResyncAllFromQdb(const QdbContactDetails& contact_details, eos::common::FileSystem::fsid_t fsid) { using namespace std::chrono; if (!ResetMgmInformation(fsid)) { eos_err("%s", "msg=\"failed to reset the mgm info before resyncing\""); SetSyncStatus(fsid, false); return false; } // Collect all file ids on the desired file system auto start = steady_clock::now(); qclient::QClient qcl(contact_details.members, contact_details.constructOptions()); std::unordered_set file_ids; qclient::QSet qset(qcl, eos::RequestBuilder::keyFilesystemFiles(fsid)); try { for (qclient::QSet::Iterator its = qset.getIterator(); its.valid(); its.next()) { try { file_ids.insert(std::stoull(its.getElement())); } catch (...) { eos_err("msg=\"failed to convert fid entry\" data=\"%s\"", its.getElement().c_str()); } } } catch (const std::runtime_error& e) { // There are no files on current filesystem } uint64_t total = file_ids.size(); eos_info("msg=\"resyncing %llu files for file_system %u\"", total, fsid); uint64_t num_files = 0; auto it = file_ids.begin(); std::list>> files; // Pre-fetch the first 1000 files while ((it != file_ids.end()) && (num_files < 1000)) { ++num_files; files.emplace_back(*it, MetadataFetcher::getFileFromId(qcl, FileIdentifier(*it))); ++it; } while (!files.empty()) { eos::common::FmdHelper ns_fmd; eos::common::FileId::fileid_t fid = files.front().first; try { FmdMgmHandler::NsFileProtoToFmd(std::move(files.front().second).get(), ns_fmd); } catch (const eos::MDException& e) { eos_err("msg=\"failed to get metadata from QDB: %s\"", e.what()); } files.pop_front(); // Mark any possible layout error, if fid not found in QDB then this is // marked as orphan ns_fmd.mProtoFmd.set_layouterror(ns_fmd.LayoutError(fsid)); // Get an existing local record without creating the record!!! std::unique_ptr local_fmd { LocalGetFmd(fid, fsid, true, false)}; if (!local_fmd) { // Create the local record if (!(local_fmd = LocalGetFmd(fid, fsid, true, true))) { eos_err("msg=\"failed to create local fmd entry\" fxid=%08llx", fid); continue; } } // If file does not exist on disk and is not 0-size then mark as missing if ((local_fmd->mProtoFmd.disksize() == eos::common::FmdHelper::UNDEF) && (ns_fmd.mProtoFmd.mgmsize())) { ns_fmd.mProtoFmd.set_layouterror(ns_fmd.mProtoFmd.layouterror() | LayoutId::kMissing); eos_warning("msg=\"mark missing replica\" fxid=%08llx fsid=%u", fid, fsid); } if (!UpdateWithMgmInfo(fsid, fid, ns_fmd.mProtoFmd.cid(), ns_fmd.mProtoFmd.lid(), ns_fmd.mProtoFmd.mgmsize(), ns_fmd.mProtoFmd.mgmchecksum(), ns_fmd.mProtoFmd.uid(), ns_fmd.mProtoFmd.gid(), ns_fmd.mProtoFmd.ctime(), ns_fmd.mProtoFmd.ctime_ns(), ns_fmd.mProtoFmd.mtime(), ns_fmd.mProtoFmd.mtime_ns(), ns_fmd.mProtoFmd.layouterror(), ns_fmd.mProtoFmd.locations())) { eos_err("msg=\"failed to update fmd with qdb info\" fxid=%08llx", fid); continue; } if (it != file_ids.end()) { files.emplace_back(*it, MetadataFetcher::getFileFromId(qcl, FileIdentifier(*it))); ++num_files; ++it; } if (num_files % 10000 == 0) { double rate = 0; auto duration = steady_clock::now() - start; auto ms = duration_cast(duration); if (ms.count()) { rate = (num_files * 1000.0) / (double)ms.count(); } eos_info("fsid=%u resynced %llu/%llu files at a rate of %.2f Hz", fsid, num_files, total, rate); } } double rate = 0; auto duration = steady_clock::now() - start; auto ms = duration_cast(duration); if (ms.count()) { rate = (num_files * 1000.0) / (double)ms.count(); } SetSyncStatus(fsid, false); eos_info("msg=\"fsid=%u resynced %llu/%llu files at a rate of %.2f Hz\"", fsid, num_files, total, rate); return true; } //------------------------------------------------------------------------------ // Reset the disk info related to the encoded Fmd object //------------------------------------------------------------------------------ std::string FmdHandler::ResetFmdDiskInfo(const std::string& input) { eos::common::FmdHelper f; if (!f.mProtoFmd.ParseFromString(input)) return {}; f.mProtoFmd.set_disksize(eos::common::FmdHelper::UNDEF); f.mProtoFmd.set_diskchecksum(""); f.mProtoFmd.set_checktime(0); f.mProtoFmd.set_filecxerror(0); f.mProtoFmd.set_blockcxerror(0); f.mProtoFmd.clear_stripeerror(); std::string out; f.mProtoFmd.SerializeToString(&out); return out; } //------------------------------------------------------------------------------ // Reset the MGM info related to the encoded Fmd object //------------------------------------------------------------------------------ std::string FmdHandler::ResetFmdMgmInfo(const std::string& input) { eos::common::FmdHelper f; if (!f.mProtoFmd.ParseFromString(input)) return {}; f.mProtoFmd.set_mgmsize(eos::common::FmdHelper::UNDEF); f.mProtoFmd.set_mgmchecksum(""); f.mProtoFmd.set_locations(""); std::string out; f.mProtoFmd.SerializeToString(&out); return out; } EOSFSTNAMESPACE_END