// ----------------------------------------------------------------------
// File: FileInspector.cc
// Author: Andreas-Joachim Peters - CERN
// ----------------------------------------------------------------------
/************************************************************************
* EOS - the CERN Disk Storage System *
* Copyright (C) 2019 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 "common/FileId.hh"
#include "common/IntervalStopwatch.hh"
#include "common/LayoutId.hh"
#include "common/Timing.hh"
#include "common/ParseUtils.hh"
#include "mgm/FsView.hh"
#include "mgm/inspector/FileInspector.hh"
#include "mgm/proc/ProcCommand.hh"
#include "mgm/XrdMgmOfs.hh"
#include "mgm/XrdMgmOfsDirectory.hh"
#include "namespace/interface/IView.hh"
#include "namespace/ns_quarkdb/inspector/FileScanner.hh"
#include "namespace/ns_quarkdb/FileMD.hh"
#include "namespace/utils/Stat.hh"
#include "namespace/Resolver.hh"
#include "namespace/Prefetcher.hh"
#include
EOSMGMNAMESPACE_BEGIN
//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
FileInspector::FileInspector(std::string_view space_name) :
timeCurrentScan(0), timeLastScan(0), nfiles(0), ndirs(0),
mSpaceName(space_name)
{
mVid = eos::common::VirtualIdentity::Root();
mThread.reset(&FileInspector::backgroundThread, this);
scanned_percent.store(0, std::memory_order_seq_cst);
PriceTbPerYearDisk = 20;
PriceTbPerYearTape = 10;
currency = currencies[0];
}
//------------------------------------------------------------------------------
// Destructor
//------------------------------------------------------------------------------
FileInspector::~FileInspector()
{
mThread.join();
}
//------------------------------------------------------------------------------
// Retrieve current file inspector configuration options
//------------------------------------------------------------------------------
FileInspector::Options FileInspector::getOptions(const LockFsView lockfsview)
{
FileInspector::Options opts;
// Default options
opts.enabled = false;
opts.interval = std::chrono::minutes(4 * 60);
eos::common::RWMutexReadLock lock;
if (lockfsview == LockFsView::On)
lock.Grab(FsView::gFsView.ViewMutex);
if (FsView::gFsView.mSpaceView.count(mSpaceName)) {
if (FsView::gFsView.mSpaceView[mSpaceName]->GetConfigMember("inspector") ==
"on") {
opts.enabled = true;
}
int64_t intv = 0;
std::string interval =
FsView::gFsView.mSpaceView[mSpaceName]->GetConfigMember("inspector.interval");
if (!interval.empty()) {
common::ParseInt64(interval, intv);
if (intv) {
opts.interval = std::chrono::seconds(intv);
}
}
std::string tbprice =
FsView::gFsView.mSpaceView[mSpaceName]->GetConfigMember("inspector.price.disk.tbyear");
double price=0;
if (!tbprice.empty()) {
price = common::ParseDouble(tbprice);
if (price) {
PriceTbPerYearDisk = price;
}
}
tbprice =
FsView::gFsView.mSpaceView[mSpaceName]->GetConfigMember("inspector.price.tape.tbyear");
price=0;
if (!tbprice.empty()) {
price = common::ParseDouble(tbprice);
if (price) {
PriceTbPerYearTape = price;
}
}
std::string scurrency =
FsView::gFsView.mSpaceView[mSpaceName]->GetConfigMember("inspector.price.currency");
if (!scurrency.empty()) {
int64_t index=0;
common::ParseInt64(scurrency, index);
if (index < 6) {
currency = currencies[index];
}
}
}
if (opts.enabled) {
enable();
eos_static_debug("file inspector is enabled - interval = %ld seconds",
opts.interval.count());
} else {
disable();
}
return opts;
}
//------------------------------------------------------------------------------
// Background Thread cleaning up left-over atomic uploads
//------------------------------------------------------------------------------
void
FileInspector::backgroundThread(ThreadAssistant& assistant) noexcept
{
gOFS->WaitUntilNamespaceIsBooted(assistant);
// set the initial state after boot
Options opts = getOptions(LockFsView::On);
if (opts.enabled) {
enable();
} else {
disable();
}
assistant.wait_for(std::chrono::seconds(10));
eos_static_info("msg=\"async thread started\"");
while (!assistant.terminationRequested()) {
Options opts = getOptions(LockFsView::On);
// Only a master needs to run a FileInspector
if (opts.enabled) {
enable();
} else {
disable();
}
common::IntervalStopwatch stopwatch(std::chrono::seconds(60));
if (opts.enabled && gOFS->mMaster->IsMaster()) {
eos_static_info("msg=\"scan started!\"");
{
std::lock_guard lock(mutexScanStats);
timeCurrentScan = time(NULL);
}
performCycleQDB(assistant);
eos_static_info("msg=\"scan finished!\"");
}
assistant.wait_for(stopwatch.timeRemainingInCycle());
}
}
//------------------------------------------------------------------------------
// Perform a single inspector cycle, QDB namespace
//------------------------------------------------------------------------------
void FileInspector::performCycleQDB(ThreadAssistant& assistant) noexcept
{
eos_static_info("msg=\"start FileInspector scan on QDB\"");
// Initialize qclient..
if (!mQcl) {
mQcl.reset(new qclient::QClient(gOFS->mQdbContactDetails.members,
gOFS->mQdbContactDetails.constructOptions()));
}
// Start scanning files
unsigned long long nfiles_processed;
nfiles = ndirs = nfiles_processed = 0;
time_t s_time = time(NULL);
{
eos::common::RWMutexReadLock ns_rd_lock(gOFS->eosViewRWMutex);
nfiles = (unsigned long long) gOFS->eosFileService->getNumFiles();
ndirs = (unsigned long long) gOFS->eosDirectoryService->getNumContainers();
}
Options opts = getOptions(LockFsView::On);
uint64_t interval = opts.interval.count();
FileScanner scanner(*(mQcl.get()));
time_t c_time = s_time;
while (scanner.valid()) {
scanner.next();
std::string err;
eos::ns::FileMdProto item;
if (scanner.getItem(item)) {
std::shared_ptr fmd = std::make_shared();
fmd->initialize(std::move(item));
Process(fmd);
nfiles_processed++;
scanned_percent.store(100.0 * nfiles_processed / nfiles,
std::memory_order_seq_cst);
time_t target_time = (1.0 * nfiles_processed / nfiles) * interval;
time_t is_time = time(NULL) - s_time;
if (target_time > is_time) {
uint64_t p_time = target_time - is_time;
if (p_time > 5) {
p_time = 5;
}
eos_static_debug("is:%lu target:%lu is_t:%lu target_t:%lu interval:%lu "
"- pausing for %lu seconds\n",
nfiles_processed, nfiles.load(), is_time, target_time, interval, p_time);
// pause for the diff ...
std::this_thread::sleep_for(std::chrono::seconds(p_time));
}
if (assistant.terminationRequested()) {
return;
}
if ((time(NULL) - c_time) > 60) {
c_time = time(NULL);
Options opts = getOptions(LockFsView::On);
interval = opts.interval.count();
if (!opts.enabled) {
// interrupt the scan
break;
}
if (!gOFS->mMaster->IsMaster()) {
// interrupt the scan
break;
}
}
}
if (scanner.hasError(err)) {
eos_static_err("msg=\"QDB scanner error - interrupting scan\" error=\"%s\"",
err.c_str());
break;
}
}
scanned_percent.store(100.0, std::memory_order_seq_cst);
std::lock_guard lock(mutexScanStats);
lastScanStats = currentScanStats;
lastFaultyFiles = currentFaultyFiles;
lastAccessTimeFiles = currentAccessTimeFiles;
lastAccessTimeVolume = currentAccessTimeVolume;
lastBirthTimeFiles = currentBirthTimeFiles;
lastBirthTimeVolume = currentBirthTimeVolume;
lastBirthVsAccessTimeFiles = currentBirthVsAccessTimeFiles;
lastBirthVsAccessTimeVolume = currentBirthVsAccessTimeVolume;
for (auto n=0; n<2; ++n) {
lastUserTotalCosts[n] = 0;
lastGroupTotalCosts[n] = 0;
lastUserCosts[n] = currentUserCosts[n];
lastGroupCosts[n] = currentGroupCosts[n];
lastCostsUsers[n].clear();
lastCostsGroups[n].clear();
for (auto i:lastUserCosts[n]) {
lastUserTotalCosts[n] += i.second;
lastCostsUsers[n].insert(std::pair(i.second,i.first));
}
for (auto i:lastGroupCosts[n]) {
lastGroupTotalCosts[n] += i.second;
lastCostsGroups[n].insert(std::pair(i.second,i.first));
}
lastUserTotalBytes[n] = 0;
lastGroupTotalBytes[n] = 0;
lastUserBytes[n] = currentUserBytes[n];
lastGroupBytes[n] = currentGroupBytes[n];
lastBytesUsers[n].clear();
lastBytesGroups[n].clear();
for (auto i:lastUserBytes[n]) {
lastUserTotalBytes[n] += i.second;
lastBytesUsers[n].insert(std::pair(i.second,i.first));
}
for (auto i:lastGroupBytes[n]) {
lastGroupTotalBytes[n] += i.second;
lastBytesGroups[n].insert(std::pair(i.second,i.first));
}
}
currentScanStats.clear();
currentFaultyFiles.clear();
currentAccessTimeFiles.clear();
currentAccessTimeVolume.clear();
currentBirthTimeFiles.clear();
currentBirthTimeVolume.clear();
currentBirthVsAccessTimeFiles.clear();
currentBirthVsAccessTimeVolume.clear();
currentNumFaultyFiles = 0;
for (auto n=0; n<2; n++) {
currentUserCosts[n].clear();
currentGroupCosts[n].clear();
currentUserBytes[n].clear();
currentGroupBytes[n].clear();
}
timeLastScan = timeCurrentScan.load();
}
//------------------------------------------------------------------------------
// Process a given fmd object
//------------------------------------------------------------------------------
void
FileInspector::Process(std::shared_ptr fmd)
{
if (fmd->isLink()) {
return;
}
uint64_t lid = fmd->getLayoutId();
std::lock_guard lock(mutexScanStats);
double disksize = 1.0 * fmd->getSize() * eos::common::LayoutId::GetSizeFactor(lid);
bool ontape = eos::modeFromMetadataEntry(fmd) & EOS_TAPE_MODE_T;
double tapesize = ontape?(1.0 * fmd->getSize()):0;
// zero size files
if (!fmd->getSize()) {
currentScanStats[lid]["zerosize"]++;
} else {
currentScanStats[lid]["volume"] += fmd->getSize();
currentScanStats[lid]["physicalsize"] += disksize;
}
// no location files
if (!fmd->getNumLocation()) {
currentScanStats[lid]["nolocation"]++;
if (currentNumFaultyFiles < maxfaulty) {
currentFaultyFiles["nolocation"].insert
(std::make_pair(fmd->getId(), fmd->getLayoutId()));
}
currentNumFaultyFiles++;
}
eos::IFileMD::LocationVector l = fmd->getLocations();
eos::IFileMD::LocationVector u_l = fmd->getUnlinkedLocations();
for (auto const& fs : l) {
if (!FsView::gFsView.HasMapping(fs)) {
// shadow filesystem
currentScanStats[lid]["shadowlocation"]++;
if (currentNumFaultyFiles < maxfaulty) {
currentFaultyFiles["shadowlocation"].insert
(std::make_pair(fmd->getId(), fmd->getLayoutId()));
}
currentNumFaultyFiles++;
}
}
for (auto const& fs : u_l) {
if (!FsView::gFsView.HasMapping(fs)) {
// shadow filesystem
currentScanStats[lid]["shadowdeletion"]++;
if (currentNumFaultyFiles < maxfaulty) {
currentFaultyFiles["shadowdeletion"].insert
(std::make_pair(fmd->getId(), fmd->getLayoutId()));
}
currentNumFaultyFiles++;
}
}
// unlinked locations
currentScanStats[lid]["unlinkedlocations"] += fmd->getNumUnlinkedLocation();
// linked locations
currentScanStats[lid]["locations"] += fmd->getNumLocation();
// stripe number
size_t stripes = eos::common::LayoutId::GetStripeNumber(lid) + 1;
std::string tag = "repdelta:";
int64_t sdiff = fmd->getNumLocation() - stripes;
if (sdiff == 0) {
tag += "0";
} else {
if (sdiff > 0) {
tag += "+";
}
tag += std::to_string(sdiff);
if (currentNumFaultyFiles < maxfaulty) {
currentFaultyFiles[tag].insert(std::make_pair(fmd->getId(),
fmd->getLayoutId()));
}
currentNumFaultyFiles++;
}
#define UNDEFINED_BIN (100 *365 * 86400.0)
currentScanStats[lid][tag]++;
static std::set time_bin {0, 86400ll, 7 * 86400ll, 30 * 86400ll, 90 * 86400ll,
182.5 * 86400ll, 365 * 86400ll, 2 * 365 * 86400ll, 5 * 365 * 86400ll, UNDEFINED_BIN};
size_t atime_bin=0;
{
// create access time distributions
set::reverse_iterator rev_it;
eos::IFileMD::ctime_t atime;
fmd->getATime(atime);
if (!atime.tv_sec) {
currentAccessTimeFiles[UNDEFINED_BIN]++;
currentAccessTimeVolume[UNDEFINED_BIN] += fmd->getSize();
atime_bin = UNDEFINED_BIN;
} else {
// future access time goes to bin 0
if (atime.tv_sec > timeCurrentScan) {
currentAccessTimeFiles[0]++;
currentAccessTimeVolume[0] += fmd->getSize();
atime_bin = 0;
} else {
for (auto rev_it = time_bin.rbegin(); rev_it != time_bin.rend(); rev_it++) {
if ((timeCurrentScan - (int64_t)atime.tv_sec) >= (int64_t) *rev_it) {
currentAccessTimeFiles[(uint64_t)*rev_it]++;
currentAccessTimeVolume[*rev_it] += fmd->getSize();
atime_bin = *rev_it;
break;
}
}
}
}
}
{
// create birth time distributions
set::reverse_iterator rev_it;
double ageInYears=0; // stores the ages of a file in years as a double
eos::IFileMD::ctime_t btime {0, 0};
eos::IFileMD::XAttrMap xattrs = fmd->getAttributes();
if (xattrs.count("sys.eos.btime")) {
eos::common::Timing::Timespec_from_TimespecStr(xattrs["sys.eos.btime"], btime);
if (btime.tv_sec > timeCurrentScan) {
ageInYears=0;
} else {
ageInYears = (timeCurrentScan - btime.tv_sec) / (86400*365.0);
}
} else {
eos::IFileMD::ctime_t ctime;
fmd->getCTime(ctime);
if (ctime.tv_sec > timeCurrentScan) {
ageInYears = 0;
} else {
ageInYears = (timeCurrentScan - ctime.tv_sec) / (86400*365.0);
}
}
// future birth time goes to bin 0
if (btime.tv_sec > timeCurrentScan) {
currentBirthTimeFiles[0]++;
currentBirthTimeVolume[0] += fmd->getSize();
currentBirthVsAccessTimeFiles[0][atime_bin]++;
currentBirthVsAccessTimeVolume[0][atime_bin] += fmd->getSize();
} else {
for (auto rev_it = time_bin.rbegin(); rev_it != time_bin.rend(); rev_it++) {
if ((timeCurrentScan - (int64_t)btime.tv_sec) >= (int64_t) *rev_it) {
currentBirthTimeFiles[(uint64_t)*rev_it]++;
currentBirthTimeVolume[*rev_it] += fmd->getSize();
currentBirthVsAccessTimeFiles[*rev_it][atime_bin]++;
currentBirthVsAccessTimeVolume[*rev_it][atime_bin] += fmd->getSize();
break;
}
}
}
double costdisk = disksize*PriceTbPerYearDisk*ageInYears;
double costtape = tapesize*PriceTbPerYearTape*ageInYears;
if (costdisk) {
// create costs disk
currentUserCosts[0][fmd->getCUid()] += costdisk;
currentGroupCosts[0][fmd->getCGid()] += costdisk;
}
if (costtape) {
// create costs tape
currentUserCosts[1][fmd->getCUid()] += costtape;
currentGroupCosts[1][fmd->getCGid()] += costtape;
}
if (disksize) {
// create costs disk
currentUserBytes[0][fmd->getCUid()] += disksize;
currentGroupBytes[0][fmd->getCGid()] += disksize;
}
if (tapesize) {
// create costs tape
currentUserBytes[1][fmd->getCUid()] += tapesize;
currentGroupBytes[1][fmd->getCGid()] += tapesize;
}
}
}
//------------------------------------------------------------------------------
// Dump current status
//------------------------------------------------------------------------------
void
FileInspector::Dump(std::string& out, std::string_view options,
const LockFsView lockfsview)
{
char line[4096];
time_t now = time(NULL);
const bool is_monitoring = (options.find('m') != std::string::npos);
bool printall=false; // normally we only print top 10!
bool printlayouts=true;
bool printcosts=true;
bool printusage=true;
bool printaccesstime = true;
bool printbirthtime = true;
bool printbirthvsaccesstime = true;
if ( options.find("Z") != std::string::npos ) {
printall = true;
}
if ( options.find('L') != std::string::npos ||
options.find('C') != std::string::npos ||
options.find('U') != std::string::npos ||
options.find('A') != std::string::npos ||
options.find('B') != std::string::npos ||
options.find('V') != std::string::npos) {
printlayouts=printcosts=printusage=printaccesstime=printbirthtime=printbirthvsaccesstime=false;
if (options.find('L') != std::string::npos) {
printlayouts=true;
}
if (options.find('C') != std::string::npos) {
printcosts=true;
}
if (options.find('A') != std::string::npos) {
printaccesstime=true;
}
if (options.find('U') != std::string::npos) {
printusage=true;
}
if (options.find('B') != std::string::npos) {
printbirthtime=true;
}
if (options.find('V') != std::string::npos) {
printbirthvsaccesstime=true;
}
}
if (!is_monitoring) {
out += "# ------------------------------------------------------------------------------------\n";
out += "# ";
out += eos::common::Timing::ltime(now);
out += "\n";
}
if (!enabled()) {
if (is_monitoring) {
out = "key=error space=" + mSpaceName + " msg=\"inspector disabled\"";
} else {
out += "# inspector is disabled - use 'eos space config default space.inspector=on'\n";
}
return;
}
std::lock_guard lock(mutexScanStats);
if (options.find("m") != std::string::npos) {
for (auto it = lastScanStats.begin(); it != lastScanStats.end(); ++it) {
snprintf(line, sizeof(line),
"key=last layout=%08lx type=%s nominal_stripes=%s checksum=%s "
"blockchecksum=%s blocksize=%s",
it->first,
eos::common::LayoutId::GetLayoutTypeString(it->first),
eos::common::LayoutId::GetStripeNumberString(it->first).c_str(),
eos::common::LayoutId::GetChecksumStringReal(it->first),
eos::common::LayoutId::GetBlockChecksumString(it->first),
eos::common::LayoutId::GetBlockSizeString(it->first));
out += line;
for (auto mit = it->second.begin(); mit != it->second.end(); ++mit) {
snprintf(line, sizeof(line), " %s=%lu", mit->first.c_str(), mit->second);
out += line;
}
out += "\n";
}
if (lastAccessTimeFiles.size()) {
std::string afiles = "kay=last tag=accesstime::files ";
for (auto it = lastAccessTimeFiles.begin(); it != lastAccessTimeFiles.end();
++it) {
afiles += std::to_string(it->first);
afiles += "=";
afiles += std::to_string(it->second);
afiles += " ";
}
out += afiles;
out += "\n";
}
if (lastAccessTimeVolume.size()) {
std::string avolume = "key=last tag=accesstime::volume ";
for (auto it = lastAccessTimeVolume.begin(); it != lastAccessTimeVolume.end();
++it) {
avolume += std::to_string(it->first);
avolume += "=";
avolume += std::to_string(it->second);
avolume += " ";
}
out += avolume;
out += "\n";
}
if (lastBirthTimeFiles.size()) {
std::string bfiles = "kay=last tag=birthtime::files ";
for (auto it = lastBirthTimeFiles.begin(); it != lastBirthTimeFiles.end();
++it) {
bfiles += std::to_string(it->first);
bfiles += "=";
bfiles += std::to_string(it->second);
bfiles += " ";
}
out += bfiles;
out += "\n";
}
if (lastBirthTimeVolume.size()) {
std::string bvolume = "key=last tag=birthtime::volume ";
for (auto it = lastBirthTimeVolume.begin(); it != lastBirthTimeVolume.end();
++it) {
bvolume += std::to_string(it->first);
bvolume += "=";
bvolume += std::to_string(it->second);
bvolume += " ";
}
out += bvolume;
out += "\n";
}
if (lastBirthVsAccessTimeFiles.size()) {
std::string bfiles = "kay=last tag=birthvsaccesstime::files ";
for (auto it = lastBirthVsAccessTimeFiles.begin(); it != lastBirthVsAccessTimeFiles.end();
++it) {
for ( auto iit = it->second.begin(); iit != it->second.end(); ++iit) {
bfiles += std::to_string(it->first);
bfiles += ":";
bfiles += std::to_string(iit->first);
bfiles += "=";
bfiles += std::to_string(iit->second);
bfiles += " ";
}
}
out += bfiles;
out += "\n";
}
if (lastBirthTimeVolume.size()) {
std::string bvolume = "key=last tag=birthtime::volume ";
for (auto it = lastBirthTimeVolume.begin(); it != lastBirthTimeVolume.end();
++it) {
bvolume += std::to_string(it->first);
bvolume += "=";
bvolume += std::to_string(it->second);
bvolume += " ";
}
out += bvolume;
out += "\n";
}
for (auto n=0; n<2;++n) {
std::string media= "disk";
double price=PriceTbPerYearDisk;
if (n==1) {
media="tape";
price=PriceTbPerYearTape;
}
if (lastUserCosts[n].size()) {
for ( auto it = lastUserCosts[n].begin(); it != lastUserCosts[n].end();
++it) {
std::string ucost = "key=last tag=user::cost::";
ucost += media;
ucost += " ";
int terrc=0;
std::string username = eos::common::Mapping::UidToUserName(it->first, terrc);
if (terrc) {
username = std::to_string(it->first);
}
ucost += "username=";
ucost += username;
ucost += " uid=";
ucost += std::to_string(it->first);
ucost += " cost=";
ucost += std::to_string(it->second/1000000000000.0);
ucost += " price=";
ucost += std::to_string(price);
out += ucost;
out += "\n";
}
}
if (lastGroupCosts[n].size()) {
for ( auto it = lastGroupCosts[n].begin(); it != lastGroupCosts[n].end();
++it) {
std::string gcost = "key=last tag=group::cost::";
gcost += media;
gcost += " ";
int terrc=0;
std::string groupname = eos::common::Mapping::GidToGroupName(it->first, terrc);
if (terrc) {
groupname = std::to_string(it->first);
}
gcost += "groupname=";
gcost += groupname;
gcost += " gid=";
gcost += std::to_string(it->first);
gcost += " cost=";
gcost += std::to_string(it->second/1000000000000.0);
gcost += " price=";
gcost += std::to_string(price);
out += gcost;
out += "\n";
}
}
if (lastUserBytes[n].size()) {
for ( auto it = lastUserBytes[n].begin(); it != lastUserBytes[n].end();
++it) {
std::string ubytes = "key=last tag=user::bytes::";
ubytes += media;
ubytes += " ";
int terrc=0;
std::string username = eos::common::Mapping::UidToUserName(it->first, terrc);
if (terrc) {
username = std::to_string(it->first);
}
ubytes += "username=";
ubytes += username;
ubytes += " uid=";
ubytes += std::to_string(it->first);
ubytes += " bytes=";
ubytes += std::to_string(it->second);
out += ubytes;
out += "\n";
}
}
if (lastGroupBytes[n].size()) {
for ( auto it = lastGroupBytes[n].begin(); it != lastGroupBytes[n].end();
++it) {
std::string gbytes = "key=last tag=group::bytes::";
gbytes += media;
gbytes += " ";
int terrc=0;
std::string groupname = eos::common::Mapping::GidToGroupName(it->first, terrc);
if (terrc) {
groupname = std::to_string(it->first);
}
gbytes += "groupname=";
gbytes += groupname;
gbytes += " gid=";
gbytes += std::to_string(it->first);
gbytes += " bytes=";
gbytes += std::to_string(it->second);
out += gbytes;
out += "\n";
}
}
}
return;
}
Options opts = getOptions(lockfsview);
out += "# ";
out += std::to_string((int)(scanned_percent.load()));
out += " % done - estimate to finish: ";
out += std::to_string((int)(opts.interval.count() - (scanned_percent.load() *
opts.interval.count() / 100.0)));
out += " seconds\n";
if ((options.find("c") != std::string::npos)) {
if (options.find("p") != std::string::npos) {
for (auto& i : currentFaultyFiles) {
for (auto& pair : i.second) {
out += "fxid:";
out += eos::common::FileId::Fid2Hex(pair.first);
out += " layoutid:";
out += eos::common::StringConversion::integral_to_hex(pair.second).c_str();
out += " ";
out += i.first;
out += "\n";
}
}
} else if (options.find("e") != std::string::npos) {
std::string exportname = "/var/log/eos/mgm/FileInspector.";
exportname += std::to_string(now);
exportname += ".list";
std::ofstream exportfile(exportname);
if (exportfile.is_open()) {
for (auto& i : currentFaultyFiles) {
for (auto& pair : i.second) {
exportfile << "fxid:" << eos::common::FileId::Fid2Hex(pair.first)
<< " layoutid:"
<< eos::common::StringConversion::integral_to_hex(pair.second)
<< " " << i.first << "\n";
}
}
out += "# file list exported on MGM to '";
out += exportname;
out += "'\n";
exportfile.close();
} else {
out += "# file list could not be written on MGM to '";
out += exportname;
out += "'\n";
}
} else {
out += "# current scan : ";
out += eos::common::Timing::ltime(timeCurrentScan).c_str();
out += "\n";
out += "# not-found-during-scan : ";
out += std::to_string(currentScanStats[999999999]["unfound"]);
out += "\n";
for (auto it = currentScanStats.begin(); it != currentScanStats.end(); ++it) {
if (it->first == 999999999) {
continue;
}
snprintf(line, sizeof(line),
" layout=%08lx type=%-13s nominal_stripes=%s checksum=%-8s "
"blockchecksum=%-8s blocksize=%-4s\n\n",
it->first,
eos::common::LayoutId::GetLayoutTypeString(it->first),
eos::common::LayoutId::GetStripeNumberString(it->first).c_str(),
eos::common::LayoutId::GetChecksumStringReal(it->first),
eos::common::LayoutId::GetBlockChecksumString(it->first),
eos::common::LayoutId::GetBlockSizeString(it->first));
out += "======================================================================================\n";
out += line;
for (auto mit = it->second.begin(); mit != it->second.end(); ++mit) {
snprintf(line, sizeof(line), " %-32s : %lu\n", mit->first.c_str(),
mit->second);
out += line;
}
out += "\n";
}
}
}
if ((options.find("l") != std::string::npos)) {
if (options.find("p") != std::string::npos) {
for (auto& i : lastFaultyFiles) {
for (auto& pair : i.second) {
out += "fxid:";
out += eos::common::FileId::Fid2Hex(pair.first);
out += " layoutid:";
out += eos::common::StringConversion::integral_to_hex(pair.second).c_str();
out += " ";
out += i.first;
out += "\n";
}
}
} else if (options.find("e") != std::string::npos) {
std::string exportname = "/var/log/eos/mgm/FileInspector.";
exportname += std::to_string(now);
exportname += ".list";
std::ofstream exportfile(exportname);
if (exportfile.is_open()) {
for (auto& i : lastFaultyFiles) {
for (auto& pair : i.second) {
exportfile << "fxid:" << eos::common::FileId::Fid2Hex(pair.first)
<< " layoutid:"
<< eos::common::StringConversion::integral_to_hex(pair.second)
<< " " << i.first << "\n";
}
}
out += "# file list exported on MGM to '";
out += exportname;
out += "'\n";
exportfile.close();
} else {
out += "# file list could not be written on MGM to '";
out += exportname;
out += "'\n";
}
} else {
if (printlayouts) {
out += "# last scan : ";
out += eos::common::Timing::ltime(timeLastScan).c_str();
out += "\n";
out += "# not-found-during-scan : ";
out += std::to_string(lastScanStats[999999999]["unfound"]);
out += "\n";
for (auto it = lastScanStats.begin(); it != lastScanStats.end(); ++it) {
if (it->first == 999999999) {
continue;
}
snprintf(line, sizeof(line),
" layout=%08lx type=%-13s nominal_stripes=%s checksum=%-8s "
"blockchecksum=%-8s blocksize=%-4s\n\n",
it->first,
eos::common::LayoutId::GetLayoutTypeString(it->first),
eos::common::LayoutId::GetStripeNumberString(it->first).c_str(),
eos::common::LayoutId::GetChecksumStringReal(it->first),
eos::common::LayoutId::GetBlockChecksumString(it->first),
eos::common::LayoutId::GetBlockSizeString(it->first));
out += "======================================================================================\n";
out += line;
for (auto mit = it->second.begin(); mit != it->second.end(); ++mit) {
snprintf(line, sizeof(line), " %-32s : %lu\n", mit->first.c_str(),
mit->second);
out += line;
}
out += "\n";
}
}
if (printaccesstime && lastAccessTimeFiles.size()) {
out += "======================================================================================\n";
out += " Access time distribution of files\n";
uint64_t totalfiles = 0;
for (auto it = lastAccessTimeFiles.begin(); it != lastAccessTimeFiles.end();
++it) {
totalfiles += it->second;
}
for (auto it = lastAccessTimeFiles.begin(); it != lastAccessTimeFiles.end();
++it) {
double fraction = totalfiles ? (100.0 * it->second / totalfiles) : 0;
XrdOucString age;
snprintf(line, sizeof(line), " %-32s : %s (%.02f%%)\n",
eos::common::StringConversion::GetReadableAgeString(age, it->first),
eos::common::StringConversion::GetReadableSizeString(it->second, "").c_str(),
fraction);
out += line;
}
}
if (printaccesstime && lastAccessTimeVolume.size()) {
out += "======================================================================================\n";
out += " Access time volume distribution of files\n";
uint64_t totalvolume = 0;
for (auto it = lastAccessTimeVolume.begin(); it != lastAccessTimeVolume.end();
++it) {
totalvolume += it->second;
}
for (auto it = lastAccessTimeVolume.begin(); it != lastAccessTimeVolume.end();
++it) {
double fraction = totalvolume ? (100.0 * it->second / totalvolume) : 0;
XrdOucString age;
snprintf(line, sizeof(line), " %-32s : %16s (%.02f%%)\n",
eos::common::StringConversion::GetReadableAgeString(age, it->first),
eos::common::StringConversion::GetReadableSizeString(it->second, "B").c_str(),
fraction);
out += line;
}
}
if (printbirthtime && lastBirthTimeFiles.size()) {
out += "======================================================================================\n";
out += " Birth time distribution of files\n";
uint64_t totalfiles = 0;
for (auto it = lastBirthTimeFiles.begin(); it != lastBirthTimeFiles.end();
++it) {
totalfiles += it->second;
}
for (auto it = lastBirthTimeFiles.begin(); it != lastBirthTimeFiles.end();
++it) {
double fraction = totalfiles ? (100.0 * it->second / totalfiles) : 0;
XrdOucString age;
snprintf(line, sizeof(line), " %-32s : %16s (%.02f%%)\n",
eos::common::StringConversion::GetReadableAgeString(age, it->first),
eos::common::StringConversion::GetReadableSizeString(it->second, "").c_str(),
fraction);
out += line;
}
}
if (printbirthtime && lastBirthTimeVolume.size()) {
out += "======================================================================================\n";
out += " Birth time volume distribution of files\n";
uint64_t totalvolume = 0;
for (auto it = lastBirthTimeVolume.begin(); it != lastBirthTimeVolume.end();
++it) {
totalvolume += it->second;
}
for (auto it = lastBirthTimeVolume.begin(); it != lastBirthTimeVolume.end();
++it) {
double fraction = totalvolume ? (100.0 * it->second / totalvolume) : 0;
XrdOucString age;
snprintf(line, sizeof(line), " %-32s : %16s (%.02f%%)\n",
eos::common::StringConversion::GetReadableAgeString(age, it->first),
eos::common::StringConversion::GetReadableSizeString(it->second, "B").c_str(),
fraction);
out += line;
}
}
if (printbirthvsaccesstime && lastBirthVsAccessTimeFiles.size()) {
out += "======================================================================================\n";
out += " Birth vs Access time distribution of files\n";
std::map totalfiles;
for (auto it = lastBirthVsAccessTimeFiles.begin(); it != lastBirthVsAccessTimeFiles.end();
++it) {
for ( auto iit = it->second.begin(); iit != it->second.end(); iit++) {
totalfiles[it->first] += iit->second;
}
}
for (auto it = lastBirthVsAccessTimeFiles.begin(); it != lastBirthVsAccessTimeFiles.end();
++it) {
XrdOucString age;
snprintf(line, sizeof(line), " %-8s : [ \n",
eos::common::StringConversion::GetReadableAgeString(age, it->first));
out += line;
for ( auto iit = it->second.begin(); iit != it->second.end(); ++iit) {
double fraction = totalfiles[it->first] ? (100.0 * iit->second / totalfiles[it->first]) : 0;
snprintf(line, sizeof(line), " %-8s %-32s %16s (%.02f%%)\n",
"",
eos::common::StringConversion::GetReadableAgeString(age, iit->first),
eos::common::StringConversion::GetReadableSizeString(iit->second, "").c_str(),
fraction);
out += line;
}
snprintf(line, sizeof(line), " %-8s ] \n",
"");
out += line;
}
}
if (printbirthvsaccesstime && lastBirthVsAccessTimeVolume.size()) {
out += "======================================================================================\n";
out += " Birth vs Access time volume distribution of files\n";
std::map totalfiles;
for (auto it = lastBirthVsAccessTimeVolume.begin(); it != lastBirthVsAccessTimeVolume.end();
++it) {
for ( auto iit = it->second.begin(); iit != it->second.end(); iit++) {
totalfiles[it->first] += iit->second;
}
}
for (auto it = lastBirthVsAccessTimeVolume.begin(); it != lastBirthVsAccessTimeVolume.end();
++it) {
XrdOucString age;
snprintf(line, sizeof(line), " %-8s : [ \n",
eos::common::StringConversion::GetReadableAgeString(age, it->first));
out += line;
for ( auto iit = it->second.begin(); iit != it->second.end(); ++iit) {
double fraction = totalfiles[it->first] ? (100.0 * iit->second / totalfiles[it->first]) : 0;
snprintf(line, sizeof(line), " %-8s %-32s %16s (%.02f%%)\n",
"",
eos::common::StringConversion::GetReadableAgeString(age, iit->first),
eos::common::StringConversion::GetReadableSizeString(iit->second, "B").c_str(),
fraction);
out += line;
}
snprintf(line, sizeof(line), " %-8s ] \n",
"");
out += line;
}
}
for ( auto n=0; n<2; n++) {
std::string media = "disk";
if (n==1) {
media = "tape";
}
if (printcosts && lastCostsUsers[n].size()) {
out += "======================================================================================\n";
out += " Storage Costs - User View [ "; out += media; out += " ]\n";
out += " -------------------------------------------------------------------------------------\n";
out += " Total Costs : ";
out += eos::common::StringConversion::GetReadableSizeString(lastUserTotalCosts[n]/1000000000000.0, currency.c_str()).c_str();
out += "\n";
out += " -------------------------------------------------------------------------------------\n";
size_t cnt=0;
size_t top_cnt=10;
if (printall) {
top_cnt = 1000000;
}
for ( auto it = lastCostsUsers[n].rbegin(); it != lastCostsUsers[n].rend();
++it) {
int terrc=0;
std::string username = eos::common::Mapping::UidToUserName(it->second, terrc);
if (terrc) {
username = std::to_string(it->second);
}
if (it->first <1) {
continue;
}
snprintf(line, sizeof(line), " %02ld. %-28s : %s\n",
++cnt,
username.c_str(),
eos::common::StringConversion::GetReadableSizeString(it->first/1000000000000.0, currency.c_str()).c_str());
out += line;
if (cnt >= top_cnt) {
break;
}
}
}
if (printcosts && lastCostsGroups[n].size()) {
out += "======================================================================================\n";
out += " Storage Costs - Group View [ "; out += media; out += " ]\n";
out += " -------------------------------------------------------------------------------------\n";
out += " Total Costs : ";
out += eos::common::StringConversion::GetReadableSizeString(lastGroupTotalCosts[n]/1000000000000.0, currency.c_str()).c_str();
out += "\n";
out += " -------------------------------------------------------------------------------------\n";
size_t cnt=0;
size_t top_cnt=10;
if (printall) {
top_cnt = 1000000;
}
for ( auto it = lastCostsGroups[n].rbegin(); it != lastCostsGroups[n].rend();
++it) {
int terrc=0;
std::string groupname = eos::common::Mapping::GidToGroupName(it->second, terrc);
if (terrc) {
groupname = std::to_string(it->second);
}
if (it->first <1) {
continue;
}
snprintf(line, sizeof(line), " %02ld. %-28s : %s\n",
++cnt,
groupname.c_str(),
eos::common::StringConversion::GetReadableSizeString(it->first/1000000000000.0, currency.c_str()).c_str());
out += line;
if (cnt >= top_cnt) {
break;
}
}
}
if (printusage && lastBytesUsers[n].size()) {
out += "======================================================================================\n";
out += " Storage Bytes - User View [ "; out += media; out += " ]\n";
out += " -------------------------------------------------------------------------------------\n";
out += " Total Bytes : ";
out += eos::common::StringConversion::GetReadableSizeString(lastUserTotalBytes[n], "B").c_str();
out += "\n";
out += " -------------------------------------------------------------------------------------\n";
size_t cnt=0;
size_t top_cnt=10;
if (printall) {
top_cnt=1000000;
}
for ( auto it = lastBytesUsers[n].rbegin(); it != lastBytesUsers[n].rend();
++it) {
int terrc=0;
std::string username = eos::common::Mapping::UidToUserName(it->second, terrc);
if (terrc) {
username = std::to_string(it->second);
}
if (it->first <1) {
continue;
}
snprintf(line, sizeof(line), " %02ld. %-28s : %s\n",
++cnt,
username.c_str(),
eos::common::StringConversion::GetReadableSizeString(it->first, "B").c_str());
out += line;
if (cnt >= top_cnt) {
break;
}
}
}
if (printusage && lastBytesGroups[n].size()) {
out += "======================================================================================\n";
out += " Storage Bytes - Group View [ "; out += media; out += " ]\n";
out += " -------------------------------------------------------------------------------------\n";
out += " Total Bytes : ";
out += eos::common::StringConversion::GetReadableSizeString(lastGroupTotalBytes[n], "B").c_str();
out += "\n";
out += " -------------------------------------------------------------------------------------\n";
size_t cnt=0;
size_t top_cnt=10;
if (printall) {
top_cnt = 1000000;
}
for ( auto it = lastBytesGroups[n].rbegin(); it != lastBytesGroups[n].rend();
++it) {
int terrc=0;
std::string groupname = eos::common::Mapping::GidToGroupName(it->second, terrc);
if (terrc) {
groupname = std::to_string(it->second);
}
if (it->first <1) {
continue;
}
snprintf(line, sizeof(line), " %02ld. %-28s : %s\n",
++cnt,
groupname.c_str(),
eos::common::StringConversion::GetReadableSizeString(it->first, "B").c_str());
out += line;
if (cnt >= top_cnt) {
break;
}
}
}
}
}
}
out += "# ------------------------------------------------------------------------------------\n";
}
EOSMGMNAMESPACE_END