//------------------------------------------------------------------------------
// File: FsCmd.cc
// Author: Jozsef Makai - CERN
//------------------------------------------------------------------------------
/************************************************************************
* EOS - the CERN Disk Storage System *
* Copyright (C) 2017 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 "FsCmd.hh"
#include "mgm/FsView.hh"
#include "mgm/proc/proc_fs.hh"
#include "mgm/XrdMgmOfs.hh"
#include "mgm/Stat.hh"
#include "mgm/placement/FsScheduler.hh"
#include "common/LayoutId.hh"
#include "namespace/interface/IFsView.hh"
#include "namespace/interface/IView.hh"
#include "namespace/Prefetcher.hh"
#include "XrdOuc/XrdOucTokenizer.hh"
#include
EOSMGMNAMESPACE_BEGIN
XrdSysSemaphore eos::mgm::FsCmd::mSemaphore{5};
//------------------------------------------------------------------------------
// Method implementing the specific behaviour of the command executed by the
// asynchronous thread
//------------------------------------------------------------------------------
eos::console::ReplyProto
eos::mgm::FsCmd::ProcessRequest() noexcept
{
eos::console::ReplyProto reply;
eos::console::FsProto fs = mReqProto.fs();
const auto& subCmdCase = fs.subcmd_case();
if (subCmdCase == eos::console::FsProto::SubcmdCase::kAdd) {
reply.set_retc(Add(fs.add()));
} else if (subCmdCase == eos::console::FsProto::SubcmdCase::kBoot) {
reply.set_retc(Boot(fs.boot()));
} else if (subCmdCase == eos::console::FsProto::SubcmdCase::kClone) {
reply.set_retc(Clone(fs.clone()));
} else if (subCmdCase == eos::console::FsProto::SubcmdCase::kCompare) {
reply.set_retc(Compare(fs.compare()));
} else if (subCmdCase == eos::console::FsProto::SubcmdCase::kConfig) {
reply.set_retc(Config(fs.config()));
} else if (subCmdCase == eos::console::FsProto::SubcmdCase::kDropdel) {
reply.set_retc(DropDeletion(fs.dropdel()));
} else if (subCmdCase == eos::console::FsProto::SubcmdCase::kDropghosts) {
reply.set_retc(DropGhosts(fs.dropghosts()));
} else if (subCmdCase == eos::console::FsProto::SubcmdCase::kDropfiles) {
reply.set_retc(DropFiles(fs.dropfiles()));
} else if (subCmdCase == eos::console::FsProto::SubcmdCase::kDumpmd) {
reply.set_retc(DumpMd(fs.dumpmd()));
} else if (subCmdCase == eos::console::FsProto::SubcmdCase::kLs) {
mOut = List(fs.ls());
reply.set_retc(0);
} else if (subCmdCase == eos::console::FsProto::SubcmdCase::kMv) {
reply.set_retc(Mv(fs.mv()));
} else if (subCmdCase == eos::console::FsProto::SubcmdCase::kRm) {
reply.set_retc(Rm(fs.rm()));
} else if (subCmdCase == eos::console::FsProto::SubcmdCase::kStatus) {
reply.set_retc(Status(fs.status()));
} else {
reply.set_retc(EINVAL);
mErr = "error: not supported";
}
reply.set_std_out(mOut);
reply.set_std_err(mErr);
return reply;
}
//------------------------------------------------------------------------------
// Add subcommand
//------------------------------------------------------------------------------
int
FsCmd::Add(const eos::console::FsProto::AddProto& addProto)
{
std::string sfsid = addProto.manual() ? std::to_string(addProto.fsid()) : "0";
std::string uuid = addProto.uuid();
std::string nodequeue = addProto.nodequeue();
// If nodequeue is empty then we have the host or even the host and the port
if (nodequeue.empty()) {
if (addProto.hostport().empty()) {
mErr = "error: no nodequeue or or hostport specified";
return EINVAL;
}
nodequeue = "/eos/";
nodequeue += addProto.hostport();
// If only hostname present then append default FST port number 1095
if (nodequeue.find(':') == std::string::npos) {
nodequeue += ":1095";
}
nodequeue += "/fst";
}
std::string mountpoint = addProto.mountpoint();
std::string space = addProto.schedgroup();
std::string configstatus = addProto.status();
std::string sharedfs = addProto.sharedfs();
XrdOucString out, err;
mRetc = proc_fs_add(gOFS->mMessagingRealm.get(), sfsid, uuid, nodequeue,
mountpoint, space, configstatus, sharedfs, out, err, mVid);
mOut = out.c_str() != nullptr ? out.c_str() : "";
mErr = err.c_str() != nullptr ? err.c_str() : "";
return mRetc;
}
//------------------------------------------------------------------------------
// Boot subcommand
//------------------------------------------------------------------------------
int
FsCmd::Boot(const eos::console::FsProto::BootProto& bootProto)
{
std::ostringstream outStream, errStream;
if ((mVid.uid == 0) || (mVid.prot == "sss")) {
std::string node = (bootProto.id_case() ==
eos::console::FsProto::BootProto::kNodeQueue ?
bootProto.nodequeue() : "");
std::string sfsid = (bootProto.id_case() ==
eos::console::FsProto::BootProto::kFsid ?
std::to_string(bootProto.fsid()) : "0");
std::string fsuuid = (bootProto.id_case() ==
eos::console::FsProto::BootProto::kUuid ?
bootProto.uuid() : "");
bool forcemgmsync = bootProto.syncmgm();
// eos::common::FileSystem::fsid_t fsid = std::stoi(sfsid);
// @note it would be nicer if the method get refactored
eos::common::FileSystem::fsid_t fsid = 0;
try {
fsid = std::stoi(sfsid);
} catch (const std::exception& e) {
fsid = 0;
}
if (node == "*") {
// boot all filesystems
if (mVid.uid == 0) {
eos::common::RWMutexReadLock lock(FsView::gFsView.ViewMutex);
outStream << "success: boot message sent to";
for (const auto id : FsView::gFsView.mIdView) {
if ((id.second->GetConfigStatus() > eos::common::ConfigStatus::kOff)) {
eos::common::FileSystem::eBootConfig bootConfig = (forcemgmsync)
? eos::common::FileSystem::kBootResync // MGM resync
: eos::common::FileSystem::kBootForced; // local resync
auto now = time(nullptr);
id.second->SetLongLong("bootcheck", bootConfig);
id.second->SetLongLong("bootsenttime", (unsigned long long) now);
outStream << " ";
outStream << id.second->GetString("host").c_str();
outStream << ":";
outStream << id.second->GetString("path").c_str();
}
}
} else {
mRetc = EPERM;
errStream << "error: you have to take role 'root' to execute this command";
}
} else if (node.length()) {
// boot all filesystems on node queue
eos::common::RWMutexReadLock lock(FsView::gFsView.ViewMutex);
if (!FsView::gFsView.mNodeView.count(node)) {
errStream << "error: cannot boot node - no node with name=";
errStream << node.c_str();
mRetc = ENOENT;
} else {
outStream << "success: boot message sent to";
for (auto it = FsView::gFsView.mNodeView[node]->begin();
it != FsView::gFsView.mNodeView[node]->end(); ++it) {
FileSystem* fs = FsView::gFsView.mIdView.lookupByID(*it);
if (fs != nullptr) {
eos::common::FileSystem::eBootConfig bootConfig = (forcemgmsync)
? eos::common::FileSystem::kBootResync // MGM resync
: eos::common::FileSystem::kBootForced; // local resync
auto now = time(nullptr);
fs->SetLongLong("bootcheck", bootConfig);
fs->SetLongLong("bootsenttime", ((now > 0) ? now : 0));
outStream << " ";
outStream << fs->GetString("host").c_str();
outStream << ":";
outStream << fs->GetString("path").c_str();
}
}
}
} else {
// boot filesystem by fsid or uuid
FileSystem* fs = nullptr;
if (fsid) {
eos::common::RWMutexReadLock lock(FsView::gFsView.ViewMutex);
fs = FsView::gFsView.mIdView.lookupByID(fsid);
if (!fs) {
errStream << "error: cannot boot filesystem - no filesystem with fsid=";
errStream << sfsid.c_str();
mRetc = ENOENT;
}
} else if (fsuuid.length()) {
eos::common::RWMutexReadLock lock(FsView::gFsView.ViewMutex);
if (FsView::gFsView.GetMapping(fsuuid)) {
fs = FsView::gFsView.mIdView.lookupByID(FsView::gFsView.GetMapping(fsuuid));
} else {
errStream << "error: cannot boot filesystem - no filesystem with uuid=";
errStream << fsuuid.c_str();
mRetc = ENOENT;
}
}
if (fs != nullptr) {
eos::common::FileSystem::eBootConfig bootConfig = (forcemgmsync)
? eos::common::FileSystem::kBootResync // MGM resync
: eos::common::FileSystem::kBootForced; // local resync
fs->SetLongLong("bootcheck", bootConfig);
fs->SetLongLong("bootsenttime", (unsigned long long) time(nullptr));
outStream << "success: boot message sent to ";
outStream << fs->GetString("host").c_str();
outStream << ":";
outStream << fs->GetString("path").c_str();
} else if (!mRetc) {
// Should not get here
errStream << "error: could not retrieve filesystem";
mRetc = ENOENT;
}
}
} else {
mRetc = EPERM;
errStream << "error: you have to take role 'root' or connect via 'sss' "
"to execute this command";
}
mOut = outStream.str();
mErr = errStream.str();
return mRetc;
}
//------------------------------------------------------------------------------
// Config subcommand
//------------------------------------------------------------------------------
int
FsCmd::Config(const eos::console::FsProto::ConfigProto& configProto)
{
auto key = configProto.key();
auto value = configProto.value();
std::string identifier = std::to_string(configProto.fsid());
XrdOucString out, err;
mRetc = proc_fs_config(identifier, key, value, out, err,
mVid, mComment.c_str());
mOut = (out.c_str() != nullptr ? out.c_str() : "");
mErr = (err.c_str() != nullptr ? err.c_str() : "");
return mRetc;
}
//------------------------------------------------------------------------------
// Dropdeletion subcommand
//------------------------------------------------------------------------------
int
FsCmd::DropDeletion(const eos::console::FsProto::DropDeletionProto& drop_del)
{
std::string out, err;
eos::common::RWMutexReadLock rd_lock(FsView::gFsView.ViewMutex);
mRetc = proc_fs_dropdeletion(drop_del.fsid(), mVid, out, err);
mOut = out;
mErr = err;
return mRetc;
}
//------------------------------------------------------------------------------
// DropGhosts subcommand
//------------------------------------------------------------------------------
int
FsCmd::DropGhosts(const eos::console::FsProto::DropGhostsProto& drop_ghosts)
{
std::string out, err;
std::set fids;
fids.insert(drop_ghosts.fids().cbegin(), drop_ghosts.fids().cend());
eos::common::RWMutexReadLock rd_lock(FsView::gFsView.ViewMutex);
mRetc = proc_fs_dropghosts(drop_ghosts.fsid(), fids, mVid, out, err);
mOut = out;
mErr = err;
return mRetc;
}
//------------------------------------------------------------------------------
// Dumpmd subcommand
//------------------------------------------------------------------------------
int
FsCmd::DumpMd(const eos::console::FsProto::DumpMdProto& dumpmdProto)
{
XrdOucString out, err;
if ((mVid.uid == 0) || (mVid.prot == "sss")) {
// Stall if the namespace is still booting
while (!gOFS->IsNsBooted()) {
std::this_thread::sleep_for(std::chrono::seconds(2));
}
std::string sfsid = std::to_string(dumpmdProto.fsid());
XrdOucString option = dumpmdProto.display() ==
eos::console::FsProto::DumpMdProto::MONITOR ? "m" : "";
XrdOucString dp = dumpmdProto.showpath() ? "1" : "0";
XrdOucString df = dumpmdProto.showfid() ? "1" : "0";
XrdOucString ds = dumpmdProto.showsize() ? "1" : "0";
size_t entries = 0;
mRetc = SemaphoreProtectedProcDumpmd(sfsid, option, dumpmdProto.showpath(),
dumpmdProto.showfid(),
dumpmdProto.showfxid(),
dumpmdProto.showsize(),
out, err, entries);
if (!mRetc) {
gOFS->MgmStats.Add("DumpMd", mVid.uid, mVid.gid, entries);
}
} else {
mRetc = EPERM;
err = "error: you have to take role 'root' or connect via 'sss' "
"to execute this command";
}
mOut = out.c_str() != nullptr ? out.c_str() : "";
mErr = err.c_str() != nullptr ? err.c_str() : "";
return mRetc;
}
//------------------------------------------------------------------------------
// List subcommand
//------------------------------------------------------------------------------
std::string
eos::mgm::FsCmd::List(const eos::console::FsProto::LsProto& lsProto)
{
using eos::console::FsProto;
bool json_output = false;
std::string output;
// Handle listing of drain jobs
if ((lsProto.display() == FsProto::LsProto::RUNNING_DRAIN_JOBS) ||
(lsProto.display() == FsProto::LsProto::FAILED_DRAIN_JOBS)) {
bool only_failed =
(lsProto.display() == FsProto::LsProto::FAILED_DRAIN_JOBS);
eos::mgm::Drainer::DrainHdrInfo hdr_info;
if (only_failed) {
hdr_info = {{"File id", "fid"},
{"Drain fsid", "fs_src"},
{"Dst fsid", "fs_dst"},
{"Error info", "err_msg"}
};
} else {
hdr_info = {{"File id", "fid"},
{"Drain fsid", "fs_src"},
{"Src fsid", "tx_fs_src"},
{"Dst fsid", "fs_dst"},
{"Start times", "start_timestamp"},
{"Progress", "progress"},
{"Avg.(MB/s)", "speed"}
};
}
unsigned int fsid {0};
// If matchlist is present then it must be an fsid
if (!lsProto.matchlist().empty()) {
try {
fsid = std::stoul(lsProto.matchlist());
} catch (...) {
// ignore
}
}
if (!gOFS->mDrainEngine.GetJobsInfo(output, hdr_info, fsid, only_failed)) {
output = "error: failed while collecting drain jobs info";
}
return output;
}
auto display = lsProto.display();
if ((display == FsProto::LsProto::DEFAULT) && WantsJsonOutput()) {
display = FsProto::LsProto::MONITOR;
}
if (display == FsProto::LsProto::MONITOR) {
json_output = WantsJsonOutput();
}
auto display_string = DisplayModeToString(display);
auto format = FsView::GetFileSystemFormat(display_string);
if (!lsProto.brief()) {
if (format.find('S') != std::string::npos) {
format.replace(format.find('S'), 1, "s");
}
}
eos::common::RWMutexReadLock lock(FsView::gFsView.ViewMutex);
FsView::gFsView.PrintSpaces(output, "", format, 0,
lsProto.matchlist().c_str(),
display_string, mReqProto.dontcolor());
if (json_output) {
output = ResponseToJsonString(output);
}
return output;
}
//------------------------------------------------------------------------------
// Mv subcommand
//------------------------------------------------------------------------------
int
FsCmd::Mv(const eos::console::FsProto::MvProto& mvProto)
{
if (mVid.uid == 0) {
std::string source = mvProto.src();
std::string dest = mvProto.dst();
bool force = mvProto.force();
XrdOucString out, err;
mRetc = proc_fs_mv(source, dest, out, err, mVid, force,
gOFS->mMessagingRealm.get());
// do a blanket refresh of internal state
// TODO fine grain to group/disk status here
gOFS->mFsScheduler->updateClusterData();
mOut = out.c_str() != nullptr ? out.c_str() : "";
mErr = err.c_str() != nullptr ? err.c_str() : "";
} else {
mRetc = EPERM;
mErr = "error: you have to take role 'root' to execute this command";
}
return mRetc;
}
//------------------------------------------------------------------------------
// Rm subcommand
//------------------------------------------------------------------------------
int
FsCmd::Rm(const eos::console::FsProto::RmProto& rmProto)
{
std::string nodequeue;
std::string mountpoint;
std::string id = (rmProto.id_case() == eos::console::FsProto::RmProto::kFsid ?
std::to_string(rmProto.fsid()) : "");
if (rmProto.id_case() == eos::console::FsProto::RmProto::kNodeQueue) {
const auto& hostmountpoint = rmProto.nodequeue();
auto splitAt = hostmountpoint.find("/fst");
try { // @note quick patch against std::out_of_range, could be nicer
nodequeue = hostmountpoint.substr(0, splitAt + 4);
mountpoint = hostmountpoint.substr(splitAt + 4);
} catch (std::out_of_range& e) {
mOut = "";
mErr = "error: there is no such nodequeue (check format): '" +
rmProto.nodequeue() + "' " + id + "\n";
mRetc = EINVAL;
return mRetc;
}
}
XrdOucString out, err;
eos::common::RWMutexWriteLock wr_lock(FsView::gFsView.ViewMutex);
mRetc = proc_fs_rm(nodequeue, mountpoint, id, out, err, mVid);
mOut = out.c_str() != nullptr ? out.c_str() : "";
mErr = err.c_str() != nullptr ? err.c_str() : "";
return mRetc;
}
//------------------------------------------------------------------------------
// Status subcommand
//------------------------------------------------------------------------------
int
FsCmd::Status(const eos::console::FsProto::StatusProto& statusProto)
{
std::ostringstream outStream, errStream;
if ((mVid.uid == 0) || (mVid.prot == "sss")) {
eos::common::FileSystem::fsid_t fsid = 0;
XrdOucString filelisting = "";
bool listfile = false;
bool riskanalysis = false;
if (statusProto.longformat()) {
listfile = true;
riskanalysis = true;
}
if (statusProto.riskassessment()) {
riskanalysis = true;
}
if (statusProto.id_case() == eos::console::FsProto::StatusProto::kNodeQueue) {
eos::common::RWMutexReadLock lock(FsView::gFsView.ViewMutex);
const std::string& queuepath = statusProto.nodequeue();
auto pos = queuepath.find("/fst");
const std::string queue = queuepath.substr(0, pos + 4);
const std::string mount = queuepath.substr(pos + 4);
if (FsView::gFsView.mNodeView.count(queue)) {
for (auto it = FsView::gFsView.mNodeView[queue]->begin();
it != FsView::gFsView.mNodeView[queue]->end(); ++it) {
FileSystem* fs = FsView::gFsView.mIdView.lookupByID(*it);
if (fs && fs->GetPath() == mount) {
// this is the filesystem
fsid = *it;
}
}
}
if (!fsid) {
errStream << "error: no such filesystem " << queuepath;
mErr = errStream.str();
mRetc = ENOENT;
return mRetc;
}
} else {
fsid = statusProto.fsid();
}
const std::string dotted_line =
"# ------------------------------------------------------------------------------------\n";
eos::common::RWMutexReadLock lock(FsView::gFsView.ViewMutex);
FileSystem* fs = FsView::gFsView.mIdView.lookupByID(fsid);
if (fs) {
outStream << dotted_line.c_str();
outStream << "# FileSystem Variables\n";
outStream << dotted_line.c_str();
std::vector keylist;
fs->GetKeys(keylist);
std::sort(keylist.begin(), keylist.end());
for (auto& key : keylist) {
char line[1024];
snprintf(line, sizeof(line) - 1, "%-32s := %s\n", key.c_str(),
fs->GetString(key.c_str()).c_str());
outStream << line;
}
if (riskanalysis) {
outStream << dotted_line.c_str();
outStream << "# Risk Analysis\n";
outStream << dotted_line.c_str();
// get some statistics about the filesystem
//-------------------------------------------
unsigned long long nfids = 0;
unsigned long long nfids_healthy = 0;
unsigned long long nfids_risky = 0;
unsigned long long nfids_inaccessible = 0;
unsigned long long nfids_todelete = 0;
eos::Prefetcher::prefetchFilesystemFileListWithFileMDsAndParentsAndWait(
gOFS->eosView, gOFS->eosFsView, fsid);
eos::common::RWMutexReadLock viewLock(gOFS->eosViewRWMutex);
try {
nfids_todelete = gOFS->eosFsView->getNumUnlinkedFilesOnFs(fsid);
nfids = gOFS->eosFsView->getNumFilesOnFs(fsid);
for (auto it_fid = gOFS->eosFsView->getFileList(fsid);
(it_fid && it_fid->valid()); it_fid->next()) {
std::shared_ptr fmd =
gOFS->eosFileService->getFileMD(it_fid->getElement());
if (fmd) {
size_t nloc_ok = 0;
size_t nloc = fmd->getNumLocation();
for (auto& loc : fmd->getLocations()) {
if (loc) {
FileSystem* repfs = FsView::gFsView.mIdView.lookupByID(loc);
if (repfs) {
eos::common::FileSystem::fs_snapshot_t snapshot;
repfs->SnapShotFileSystem(snapshot, false);
if ((snapshot.mStatus == eos::common::BootStatus::kBooted) &&
(snapshot.mConfigStatus == eos::common::ConfigStatus::kRW) &&
(snapshot.mErrCode == 0) && // this we probably don't need
(snapshot.mActiveStatus == eos::common::ActiveStatus::kOnline)) {
nloc_ok++;
}
}
}
}
if (eos::common::LayoutId::GetLayoutType(fmd->getLayoutId()) ==
eos::common::LayoutId::kReplica) {
if (nloc_ok == nloc) {
nfids_healthy++;
} else {
if (nloc_ok == 0) {
nfids_inaccessible++;
if (listfile) {
filelisting += "status=offline path=";
filelisting += gOFS->eosView->getUri(fmd.get()).c_str();
filelisting += "\n";
}
} else {
if (nloc_ok < nloc) {
nfids_risky++;
if (listfile) {
filelisting += "status=atrisk path=";
filelisting += gOFS->eosView->getUri(fmd.get()).c_str();
filelisting += "\n";
}
}
}
}
}
if (eos::common::LayoutId::GetLayoutType(fmd->getLayoutId()) ==
eos::common::LayoutId::kPlain) {
if (nloc_ok != nloc) {
nfids_inaccessible++;
if (listfile) {
filelisting += "status=offline path=";
filelisting += gOFS->eosView->getUri(fmd.get()).c_str();
filelisting += "\n";
}
}
}
}
}
XrdOucString sizestring;
char line[1024];
snprintf(line, sizeof(line) - 1, "%-32s := %10s (%.02f%%)\n", "number of files",
eos::common::StringConversion::GetSizeString(sizestring, nfids), 100.0);
outStream << line;
snprintf(line, sizeof(line) - 1, "%-32s := %10s (%.02f%%)\n", "files healthy",
eos::common::StringConversion::GetSizeString(sizestring, nfids_healthy),
nfids ? (100.0 * nfids_healthy) / nfids : 100.0);
outStream << line;
snprintf(line, sizeof(line) - 1, "%-32s := %10s (%.02f%%)\n", "files at risk",
eos::common::StringConversion::GetSizeString(sizestring, nfids_risky),
nfids ? (100.0 * nfids_risky) / nfids : 100.0);
outStream << line;
snprintf(line, sizeof(line) - 1, "%-32s := %10s (%.02f%%)\n",
"files inaccessible", eos::common::StringConversion::GetSizeString(sizestring,
nfids_inaccessible), nfids ? (100.0 * nfids_inaccessible) / nfids : 100.0);
outStream << line;
snprintf(line, sizeof(line) - 1, "%-32s := %10s\n", "files pending deletion",
eos::common::StringConversion::GetSizeString(sizestring, nfids_todelete));
outStream << line;
outStream << dotted_line.c_str();
if (listfile) {
outStream << filelisting;
}
} catch (eos::MDException& e) {
errno = e.getErrno();
eos_static_err("caught exception %d %s\n", e.getErrno(),
e.getMessage().str().c_str());
}
}
mRetc = 0;
} else {
errStream << "error: cannot find filesystem - no filesystem with fsid=";
errStream << fsid;
mRetc = ENOENT;
}
} else {
mRetc = EPERM;
errStream << "error: you have to take role 'root' to execute this command "
"or connect via sss";
}
mOut = outStream.str();
mErr = errStream.str();
return mRetc;
}
//------------------------------------------------------------------------------
// Drop files attached to a file system by file id
//------------------------------------------------------------------------------
int
FsCmd::DropFiles(const eos::console::FsProto::DropFilesProto& dropfilesProto)
{
XrdOucErrInfo errInfo;
auto filesDeleted = 0u;
// Create a snapshot to avoid deadlock with dropstripe
std::vector fileids;
{
eos::common::RWMutexReadLock rlock(gOFS->eosViewRWMutex);
for (auto it_fid = gOFS->eosFsView->getFileList(dropfilesProto.fsid());
(it_fid && it_fid->valid()); it_fid->next()) {
try {
fileids.push_back(it_fid->getElement());
} catch (eos::MDException& e) {
eos_err("msg=\"failed to get metadata, ignore it\" fxid=%08llx",
it_fid->getElement());
}
}
}
for (const auto& fid : fileids) {
errInfo.clear();
if (gOFS->_dropstripe("", fid, errInfo, mVid, dropfilesProto.fsid(),
dropfilesProto.force()) != 0) {
eos_err("msg=\"failed to delete replica\" fxid=%08llx fsid=%lu",
fid, dropfilesProto.fsid());
} else {
filesDeleted++;
}
}
std::ostringstream oss;
oss << "Deleted " << filesDeleted << " replicas on filesystem " <<
dropfilesProto.fsid() << std::endl;
mOut = oss.str();
return SFS_OK;
}
//------------------------------------------------------------------------------
// Compare two file systemd in therm of the files they contain
//------------------------------------------------------------------------------
int
FsCmd::Compare(const eos::console::FsProto::CompareProto& compareProto)
{
std::string filePath;
std::unordered_set>
sourceHash, targetHash;
{
eos::common::RWMutexReadLock rlock(gOFS->eosViewRWMutex);
for (auto it_fid = gOFS->eosFsView->getFileList(compareProto.sourceid());
(it_fid && it_fid->valid()); it_fid->next()) {
try {
auto fmd = gOFS->eosFileService->getFileMD(it_fid->getElement());
filePath = gOFS->eosView->getUri(fmd.get());
sourceHash.insert(filePath);
} catch (eos::MDException& e) {}
}
for (auto it_fid = gOFS->eosFsView->getFileList(compareProto.targetid());
(it_fid && it_fid->valid()); it_fid->next()) {
try {
auto fmd = gOFS->eosFileService->getFileMD(it_fid->getElement());
filePath = gOFS->eosView->getUri(fmd.get());
targetHash.insert(filePath);
} catch (eos::MDException& e) {}
}
}
std::ostringstream resultStream;
for (const auto& source : sourceHash) {
if (targetHash.find(source) == targetHash.end()) {
resultStream << "path=" << source << " => found in " << compareProto.sourceid()
<< " - missing in " << compareProto.targetid() << std::endl;
}
}
for (const auto& target : targetHash) {
if (sourceHash.find(target) == sourceHash.end()) {
resultStream << "path=" << target << " => found in " << compareProto.targetid()
<< " - missing in " << compareProto.sourceid() << std::endl;
}
}
mOut = resultStream.str();
return SFS_OK;
}
//------------------------------------------------------------------------------
// Clone the contents of one file system to another
//------------------------------------------------------------------------------
int
FsCmd::Clone(const eos::console::FsProto::CloneProto& cloneProto)
{
std::string filePath;
XrdOucErrInfo errInfo;
auto success = 0u;
eos::common::RWMutexReadLock rlock(gOFS->eosViewRWMutex);
for (auto it_fid = gOFS->eosFsView->getFileList(cloneProto.sourceid());
(it_fid && it_fid->valid()); it_fid->next()) {
try {
auto fmd = gOFS->eosFileService->getFileMD(it_fid->getElement());
filePath = gOFS->eosView->getUri(fmd.get());
errInfo.clear();
if (gOFS->_copystripe(filePath.c_str(), errInfo, mVid,
cloneProto.sourceid(), cloneProto.targetid()) == 0) {
success++;
}
} catch (eos::MDException& e) {
eos_err("Could not get metadata, could not clone file replica %ul on filesystem",
it_fid->getElement());
}
}
std::ostringstream oss;
oss << "Successfully replicated " << success << " files." << endl;
mOut = oss.str();
return SFS_OK;
}
//------------------------------------------------------------------------------
// Convert display mode flags to strings
//------------------------------------------------------------------------------
std::string
eos::mgm::FsCmd::DisplayModeToString(eos::console::FsProto::LsProto::DisplayMode
mode)
{
switch (mode) {
case eos::console::FsProto::LsProto::LONG:
return "l";
case eos::console::FsProto::LsProto::MONITOR:
return "m";
case eos::console::FsProto::LsProto::DRAIN:
return "d";
case eos::console::FsProto::LsProto::ERROR:
return "e";
case eos::console::FsProto::LsProto::FSCK:
return "fsck";
case eos::console::FsProto::LsProto::IO:
return "io";
default:
return "";
}
}
int
FsCmd::SemaphoreProtectedProcDumpmd(std::string& fsid, XrdOucString& option,
bool show_path, bool show_fid,
bool show_fxid, bool show_size,
XrdOucString& out, XrdOucString& err,
size_t& entries)
{
try {
mSemaphore.Wait();
} catch (...) {
err += "error: failed while waiting on semaphore, cannot dumpmd";
return EAGAIN;
}
int lretc = proc_fs_dumpmd(fsid, option, show_path, show_fid, show_fxid,
show_size, out, err, mVid, entries);
try {
mSemaphore.Post();
} catch (...) {}
return lretc;
}
EOSMGMNAMESPACE_END