// ----------------------------------------------------------------------
// File: Drop.cc
// Author: Andreas-Joachim Peters - CERN
// ----------------------------------------------------------------------
/************************************************************************
* EOS - the CERN Disk Storage System *
* Copyright (C) 2018 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/Logging.hh"
#include "common/SymKeys.hh"
#include "namespace/Prefetcher.hh"
#include "namespace/interface/IView.hh"
#include "namespace/interface/IQuota.hh"
#include "namespace/interface/IFileMD.hh"
#include "namespace/interface/IFsView.hh"
#include "namespace/interface/IContainerMD.hh"
#include "namespace/interface/IFileMDSvc.hh"
#include "namespace/interface/IContainerMDSvc.hh"
#include "mgm/Stat.hh"
#include "mgm/XrdMgmOfs.hh"
#include "mgm/Macros.hh"
#include "mgm/Iostat.hh"
#include
//----------------------------------------------------------------------------
// Drop a replica
//----------------------------------------------------------------------------
int
XrdMgmOfs::Drop(const char* path,
const char* ininfo,
XrdOucEnv& env,
XrdOucErrInfo& error,
eos::common::VirtualIdentity& vid,
const XrdSecEntity* client)
{
static const char* epname = "Drop";
REQUIRE_SSS_OR_LOCAL_AUTH;
ACCESSMODE_W;
MAYSTALL;
MAYREDIRECT;
EXEC_TIMING_BEGIN("Drop");
int envlen;
eos_thread_info("drop request for %s", env.Env(envlen));
char* afid = env.Get("mgm.fid");
char* afsid = env.Get("mgm.fsid");
char* report = env.Get("mgm.report");
if (afid && afsid) {
eos::IFileMD::id_t fid = eos::common::FileId::Hex2Fid(afid);
unsigned long fsid = strtoul(afsid, 0, 10);
std::shared_ptr container;
std::shared_ptr fmd;
eos::IQuotaNode* ns_quota = nullptr;
eos::Prefetcher::prefetchFilesystemFileListAndWait(gOFS->eosView,
gOFS->eosFsView, fsid);
eos::Prefetcher::prefetchFileMDWithParentsAndWait(gOFS->eosView, fid);
{
eos::common::RWMutexWriteLock ns_wr_lock(gOFS->eosViewRWMutex);
try {
fmd = eosFileService->getFileMD(fid);
} catch (...) {
eos_thread_warning("msg=\"no meta record exists anymore\" fxid=%s", afid);
// Nevertheless drop the file identifier from the file system view
gOFS->eosFsView->eraseEntry(fsid, fid);
}
if (fmd) {
std::string locations;
try {
locations = fmd->getAttribute("sys.fs.tracking");
} catch (...) {}
try {
container =
gOFS->eosDirectoryService->getContainerMD(fmd->getContainerId());
} catch (eos::MDException& e) {}
if (container) {
try {
ns_quota = gOFS->eosView->getQuotaNode(container.get());
} catch (eos::MDException& e) {
ns_quota = nullptr;
}
}
try {
std::vector drop_fsid;
bool updatestore = false;
// If mgm.dropall flag is set then it means we got a deleteOnClose
// at the gateway node and we need to delete all replicas
char* drop_all = env.Get("mgm.dropall");
if (drop_all) {
for (unsigned int i = 0; i < fmd->getNumLocation(); i++) {
drop_fsid.push_back(fmd->getLocation(i));
}
} else {
drop_fsid.push_back(fsid);
}
// Drop the selected replicas
for (const auto& id : drop_fsid) {
eos_thread_debug("msg=\"remove location\" fxid=%s fsid=%lu", afid, id);
updatestore = false;
if (fmd->hasLocation(id)) {
fmd->unlinkLocation(id);
updatestore = true;
locations += "-";
locations += std::to_string(id);
}
if (fmd->hasUnlinkedLocation(id)) {
fmd->removeLocation(id);
updatestore = true;
locations += "/";
locations += std::to_string(id);
}
if (updatestore) {
fmd->setAttribute("sys.fs.tracking",
eos::common::StringConversion::ReduceString(locations).c_str());
gOFS->eosView->updateFileStore(fmd.get());
// After update we might have to get the new address
fmd = eosFileService->getFileMD(eos::common::FileId::Hex2Fid(afid));
} else {
// The FileSystem view has a reference for this file but the file
// has no replicas registered on the current file system - we need
// to force delete the entry from the FileSystem view
gOFS->eosFsView->eraseEntry(id, fid);
}
}
// Delete the record only if all replicas are dropped
if ((!fmd->getNumUnlinkedLocation()) && (!fmd->getNumLocation())
&& (drop_all || updatestore)) {
// However we should only remove the file from the namespace, if
// there was indeed a replica to be dropped, otherwise we get
// unlinked files if the secondary replica fails to write but
// the machine can call the MGM
if (ns_quota) {
// If we were still attached to a container, we can now detach
// and count the file as removed
ns_quota->removeFile(fmd.get());
}
gOFS->eosView->removeFile(fmd.get());
if (container) {
container->setMTimeNow();
gOFS->eosView->updateContainerStore(container.get());
container->notifyMTimeChange(gOFS->eosDirectoryService);
eos::ContainerIdentifier container_id = container->getIdentifier();
eos::ContainerIdentifier container_pid = container->getParentIdentifier();
ns_wr_lock.Release();
gOFS->FuseXCastRefresh(container_id, container_pid);
}
}
} catch (...) {
eos_thread_warning("no meta record exists anymore for fxid=%s", afid);
}
}
}
if (report) {
// write the report via IoStat
std::string deletionreport64 = report;
std::string deletionreport;
if (eos::common::SymKey::ZDeBase64(deletionreport64, deletionreport)) {
gOFS->IoStats->WriteRecord(deletionreport);
} else {
eos_thread_err("failed to decode report '%s'", deletionreport64.c_str());
}
}
} else {
eos_thread_err("drop message does not contain all meta information: %s",
env.Env(envlen));
return Emsg(epname, error, EIO, "drop replica [EIO]",
"missing meta information");
}
gOFS->MgmStats.Add("Drop", vid.uid, vid.gid, 1);
const char* ok = "OK";
error.setErrInfo(strlen(ok) + 1, ok);
EXEC_TIMING_END("Drop");
return SFS_DATA;
}