/************************************************************************
* EOS - the CERN Disk Storage System *
* Copyright (C) 2016 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 "namespace/ns_quarkdb/ContainerMD.hh"
#include "namespace/interface/IContainerMDSvc.hh"
#include "namespace/interface/IFileMDSvc.hh"
#include "namespace/ns_quarkdb/Constants.hh"
#include "namespace/ns_quarkdb/persistency/ContainerMDSvc.hh"
#include "namespace/utils/DataHelper.hh"
#include "namespace/utils/StringConvertion.hh"
#include "namespace/ns_quarkdb/persistency/Serialization.hh"
#include "namespace/ns_quarkdb/persistency/MetadataFetcher.hh"
#include "namespace/PermissionHandler.hh"
#include "google/protobuf/io/zero_copy_stream_impl.h"
#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
#include "common/Assert.hh"
#include "common/StacktraceHere.hh"
#include "common/StringConversion.hh"
#include "common/Logging.hh"
#include
#include
#include
#include
EOSNSNAMESPACE_BEGIN
//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
QuarkContainerMD::QuarkContainerMD(IContainerMD::id_t id, IFileMDSvc* file_svc,
IContainerMDSvc* cont_svc)
: IContainerMD(),
pFilesKey(stringify(id) + constants::sMapFilesSuffix),
pDirsKey(stringify(id) + constants::sMapDirsSuffix)
{
mSubcontainers->set_deleted_key("");
mFiles->set_deleted_key("");
mSubcontainers->set_empty_key("##_EMPTY_##");
mFiles->set_empty_key("##_EMPTY_##");
mCont.set_id(id);
mCont.set_mode(040755);
mClock = std::chrono::high_resolution_clock::now().time_since_epoch().count();
if (!cont_svc && !file_svc) {
// "Standalone" ContainerMD, without associated container service.
// Don't call functions which might modify metadata..
// This is a hack, it would be probably cleaner to remove the services
// from this class altogether.
return;
}
setServices(file_svc, cont_svc);
}
//------------------------------------------------------------------------------
// Set namespace services
//------------------------------------------------------------------------------
void QuarkContainerMD::setServices(IFileMDSvc* file_svc,
IContainerMDSvc* cont_svc)
{
eos_assert(pFileSvc == nullptr && pContSvc == nullptr);
eos_assert(file_svc != nullptr && cont_svc != nullptr);
pFileSvc = file_svc;
pContSvc = cont_svc;
QuarkContainerMDSvc* impl_cont_svc = dynamic_cast
(cont_svc);
if (!impl_cont_svc) {
MDException e(EFAULT);
e.getMessage() << __FUNCTION__ << " ContainerMDSvc dynamic cast failed";
throw e;
}
pQcl = impl_cont_svc->pQcl;
pFlusher = impl_cont_svc->pFlusher;
}
//------------------------------------------------------------------------------
// Virtual copy constructor
//------------------------------------------------------------------------------
QuarkContainerMD*
QuarkContainerMD::clone() const
{
return new QuarkContainerMD(*this);
}
//------------------------------------------------------------------------------
// Copy constructor
//------------------------------------------------------------------------------
QuarkContainerMD::QuarkContainerMD(const QuarkContainerMD& other)
{
mCont = other.mCont;
pContSvc = other.pContSvc;
pFileSvc = other.pFileSvc;
pQcl = other.pQcl;
mClock = other.mClock;
pFlusher = other.pFlusher;
pDirsKey = other.pDirsKey;
pFilesKey = other.pFilesKey;
}
//------------------------------------------------------------------------------
// Children inheritance
//------------------------------------------------------------------------------
void
QuarkContainerMD::InheritChildren(const IContainerMD& other)
{
QuarkContainerMD& otherContainer =
dynamic_cast(const_cast(other));
mFiles.get() = otherContainer.copyFileMap();
mSubcontainers.get() = otherContainer.copyContainerMap();
setTreeSize(otherContainer.getTreeSize());
}
//------------------------------------------------------------------------------
// Turn a ContainerMDPtr into FileOrContainerMD.
//------------------------------------------------------------------------------
static FileOrContainerMD wrapContainerMD(IContainerMDPtr ptr)
{
return FileOrContainerMD {nullptr, ptr};
}
//------------------------------------------------------------------------------
// Turn a FileMDPtr into FileOrContainerMD.
//------------------------------------------------------------------------------
static FileOrContainerMD wrapFileMD(IFileMDPtr ptr)
{
return FileOrContainerMD {ptr, nullptr};
}
//------------------------------------------------------------------------------
// Extract FileMDPtr out of FileOrContainerMD.
//------------------------------------------------------------------------------
static IFileMDPtr extractFileMD(FileOrContainerMD ptr)
{
return ptr.file;
}
//------------------------------------------------------------------------------
// Extract ContainerMDPtr out of FileOrContainerMD.
//------------------------------------------------------------------------------
static IContainerMDPtr extractContainerMD(FileOrContainerMD ptr)
{
return ptr.container;
}
//------------------------------------------------------------------------------
// Find item
//------------------------------------------------------------------------------
folly::Future
QuarkContainerMD::findItem(const std::string& name)
{
std::optional targetContainer;
std::optional targetFile;
//Only the search within the files and the sub containers need to be read locked.
runReadOp([this,name,&targetContainer, &targetFile](){
// We're looking for "name". Look inside subcontainer map to check if there's
// a container with such name.
auto iter = mSubcontainers->find(name);
if (iter != mSubcontainers->end()) {
targetContainer = ContainerIdentifier(iter->second);
return;
}
// This is not a ContainerMD.. maybe it's a FileMD?
auto iter2 = mFiles->find(name);
if (iter2 != mFiles->end()) {
targetFile = FileIdentifier(iter2->second);
return;
}
});
if(targetContainer) {
folly::Future fut =
pContSvc->getContainerMDFut(
targetContainer->getUnderlyingUInt64())
.thenValue(wrapContainerMD)
.thenError([this, name](const folly::exception_wrapper & e) {
// Should not happen...
eos_static_crit("Exception occurred while looking up container with "
"name %s in subcontainer with id %llu: %s", name.c_str(),
getId(), e.what().c_str());
return FileOrContainerMD {};
});
return fut;
}
if(targetFile){
folly::Future fut =
pFileSvc->getFileMDFut(
targetFile->getUnderlyingUInt64())
.thenValue(wrapFileMD)
.thenError([this, name](const folly::exception_wrapper & e) {
// Should not happen...
eos_static_crit("Exception occurred while looking up file with name %s "
"in subcontainer with id %llu: %s", name.c_str(), getId(),
e.what().c_str());
return FileOrContainerMD {};
});
return fut;
}
// Nope, "name" doesn't exist in this container.
return FileOrContainerMD {};
}
//----------------------------------------------------------------------------
//! Find item read locked
//----------------------------------------------------------------------------
FileOrContainerMDLocked QuarkContainerMD::findItemReadLocked(const std::string& name) {
return IMDLockHelper::lock(findItem(name).get());
}
//----------------------------------------------------------------------------
//! Find item write locked
//----------------------------------------------------------------------------
FileOrContainerMDLocked QuarkContainerMD::findItemWriteLocked(const std::string& name) {
return IMDLockHelper::lock(findItem(name).get());
}
//------------------------------------------------------------------------------
// Remove container
//------------------------------------------------------------------------------
void
QuarkContainerMD::removeContainer(const std::string& name)
{
runWriteOp([this,&name](){
auto it = mSubcontainers->find(name);
if (it == mSubcontainers->end()) {
MDException e(ENOENT);
e.getMessage() << __FUNCTION__ << " Container " << name << " not found";
throw e;
}
mSubcontainers->erase(it);
// mSubcontainers->resize(0);
// Delete container also from KV backend
pFlusher->hdel(pDirsKey, name);
});
}
//------------------------------------------------------------------------------
// Add container
//------------------------------------------------------------------------------
void
QuarkContainerMD::addContainer(IContainerMD* container)
{
runWriteOp([this,container](){
if (container->getName().empty()) {
eos_static_crit(eos::common::getStacktrace().c_str());
throw_mdexception(EINVAL,
"Attempted to add container with empty name! ID: " << container->getId() <<
", target container ID: " << mCont.id());
}
auto containerConflict = mSubcontainers->find(container->getName());
if (containerConflict != mSubcontainers->end() &&
containerConflict->second != container->getId()) {
eos_static_crit(eos::common::getStacktrace().c_str());
throw_mdexception(EEXIST, "Attempted to add container with name "
<< container->getName()
<< " while a different subcontainer exists already there.");
}
auto fileConflict = mFiles->find(container->getName());
if (fileConflict != mFiles->end()) {
eos_static_crit(eos::common::getStacktrace().c_str());
throw_mdexception(EEXIST, "Attempted to add container with name "
<< container->getName()
<< " while a file exists already there.");
}
container->setParentId(mCont.id());
(void) mSubcontainers->insert(std::make_pair(container->getName(),
container->getId()));
// Add to new container to KV backend
pFlusher->hset(pDirsKey, container->getName(), stringify(container->getId()));
});
}
//------------------------------------------------------------------------------
// Find file, asynchronous API
//------------------------------------------------------------------------------
folly::Future
QuarkContainerMD::findFileFut(const std::string& name)
{
return this->findItem(name).thenValue(extractFileMD);
}
//------------------------------------------------------------------------------
// Find file
//------------------------------------------------------------------------------
std::shared_ptr
QuarkContainerMD::findFile(const std::string& name)
{
return this->findItem(name).get().file;
}
//----------------------------------------------------------------------------
//! Find file and read lock it. Returns nullptr in case the file is not found
//----------------------------------------------------------------------------
std::unique_ptr QuarkContainerMD::findFileReadLocked(const std::string & name) {
return findItemReadLocked(name).fileLocked;
}
//----------------------------------------------------------------------------
//! Find file and write lock it. Returns nullptr in case the file is not found
//----------------------------------------------------------------------------
std::unique_ptr QuarkContainerMD::findFileWriteLocked(const std::string & name) {
return findItemWriteLocked(name).fileLocked;
}
//------------------------------------------------------------------------------
// Find subcontainer, asynchronous API
//------------------------------------------------------------------------------
folly::Future
QuarkContainerMD::findContainerFut(const std::string& name)
{
return this->findItem(name).thenValue(extractContainerMD);
}
//------------------------------------------------------------------------------
// Find subcontainer
//------------------------------------------------------------------------------
std::shared_ptr
QuarkContainerMD::findContainer(const std::string& name)
{
return this->findItem(name).get().container;
}
//----------------------------------------------------------------------------
//! Find sub container and write lock it, returns nullptr if container does not exist
//----------------------------------------------------------------------------
IContainerMD::IContainerMDWriteLockerPtr
QuarkContainerMD::findContainerWriteLocked(const std::string & name)
{
return findItemWriteLocked(name).containerLocked;
}
//----------------------------------------------------------------------------
//! Find sub container and read lock it, returns nullptr if container does not exist
//----------------------------------------------------------------------------
IContainerMD::IContainerMDReadLockerPtr
QuarkContainerMD::findContainerReadLocked(const std::string & name)
{
return findItemReadLocked(name).containerLocked;
}
//------------------------------------------------------------------------------
// Add file
//------------------------------------------------------------------------------
void
QuarkContainerMD::addFile(IFileMD* file)
{
runWriteOp([this,file](){
if (file->getName().empty()) {
eos_static_crit(eos::common::getStacktrace().c_str());
throw_mdexception(EINVAL,
"Attempted to add file with empty filename! ID: " << file->getId() <<
", target container ID: " << mCont.id());
}
auto containerConflict = mSubcontainers->find(file->getName());
if (containerConflict != mSubcontainers->end()) {
eos_static_crit(eos::common::getStacktrace().c_str());
throw_mdexception(EEXIST,
"Attempted to add file with name " << file->getName() <<
" while a subcontainer exists already there.");
}
auto fileConflict = mFiles->find(file->getName());
if (fileConflict != mFiles->end() && fileConflict->second != file->getId()) {
eos_static_crit(eos::common::getStacktrace().c_str());
throw_mdexception(EEXIST,
"Attempted to add file with name " << file->getName() <<
" while a different file exists already there.");
}
file->setContainerId(mCont.id());
(void)mFiles->insert(std::make_pair(file->getName(), file->getId()));
pFlusher->hset(pFilesKey, file->getName(), std::to_string(file->getId()));
});
if (file->getSize() != 0u) {
IFileMDChangeListener::Event e(file, IFileMDChangeListener::SizeChange, 0,
file->getSize());
pFileSvc->notifyListeners(&e);
}
}
//------------------------------------------------------------------------------
// Remove file
//------------------------------------------------------------------------------
void
QuarkContainerMD::removeFile(const std::string& name)
{
bool found = false;
IFileMD::id_t id;
runWriteOp([this,&name,&found,&id](){
auto iter = mFiles->find(name);
if (iter != mFiles->end()) {
found = true;
id = iter->second;
mFiles->erase(iter);
// mFiles->resize(0);
pFlusher->hdel(pFilesKey, name);
}
});
if(found){
try {
std::shared_ptr file = pFileSvc->getFileMD(id);
// NOTE: This is an ugly hack. The file object has no reference to the
// container id, therefore we hijack the "location" member of the Event
// class to pass in the container id.
IFileMDChangeListener::Event
e(file.get(), IFileMDChangeListener::SizeChange, mCont.id(), -file->getSize());
pFileSvc->notifyListeners(&e);
} catch (MDException& e) {
// File already removed
}
}
}
//------------------------------------------------------------------------------
// Get number of files
//------------------------------------------------------------------------------
size_t
QuarkContainerMD::getNumFiles()
{
return runReadOp([this](){
return mFiles->size();
});
}
//----------------------------------------------------------------------------
// Get number of containers
//----------------------------------------------------------------------------
size_t
QuarkContainerMD::getNumContainers()
{
return runReadOp([this](){
return mSubcontainers->size();
});
}
//------------------------------------------------------------------------------
// Check the access permissions
//------------------------------------------------------------------------------
bool
QuarkContainerMD::access(uid_t uid, gid_t gid, int flags)
{
// root can do everything
if (uid == 0) {
return true;
}
// daemon can read everything
if ((uid == 2) && ((flags & W_OK) == 0)) {
return true;
}
// Filter out based on sys.mask
mode_t filteredMode = PermissionHandler::filterWithSysMask(mCont.xattrs(),
mCont.mode());
// Convert the flags
char convFlags = PermissionHandler::convertRequested(flags);
return runReadOp([this,uid,gid,filteredMode,convFlags](){
// Check the perms
if (uid == mCont.uid()) {
char user = PermissionHandler::convertModetUser(filteredMode);
return PermissionHandler::checkPerms(user, convFlags);
}
if (gid == mCont.gid()) {
char group = PermissionHandler::convertModetGroup(filteredMode);
return PermissionHandler::checkPerms(group, convFlags);
}
char other = PermissionHandler::convertModetOther(filteredMode);
return PermissionHandler::checkPerms(other, convFlags);
});
}
//------------------------------------------------------------------------------
// Set name
//------------------------------------------------------------------------------
void
QuarkContainerMD::setName(const std::string& name)
{
runWriteOp([this,name](){
if (mCont.id() != 1 && name.find('/') != std::string::npos) {
eos_static_crit("msg=\"detected slashes in container name\" cxid=%08llx "
"trace=\"%s\"", mCont.id(),
eos::common::getStacktrace().c_str());
throw_mdexception(EINVAL, "Bug: detected slashes in container name: " << name);
}
if (name.empty()) {
eos_static_crit("msg=\"detected empty container name\" cxid=%08llx "
"trace=\"%s\"", mCont.id(),
eos::common::getStacktrace().c_str());
throw_mdexception(EINVAL, "Bug: detected empty container name");
}
// // Check that there is no clash with other subcontainers having the same name
// if (mCont.parent_id() != 0u) {
// auto parent = pContSvc->getContainerMD(mCont.parent_id());
// if (parent->findContainer(name)) {
// eos::MDException e(EINVAL);
// e.getMessage() << "Container with name \"" << name << "\" already exists";
// throw e;
// }
// }
mCont.set_name(name);
});
}
//------------------------------------------------------------------------------
// Set creation time
//------------------------------------------------------------------------------
void
QuarkContainerMD::setCTime(ctime_t ctime)
{
runWriteOp([this,ctime](){
mCont.set_ctime(&ctime, sizeof(ctime));
});
}
//------------------------------------------------------------------------------
// Set creation time to now
//------------------------------------------------------------------------------
void
QuarkContainerMD::setCTimeNow()
{
struct timespec tnow;
#ifdef __APPLE__
struct timeval tv;
gettimeofday(&tv, 0);
tnow.tv_sec = tv.tv_sec;
tnow.tv_nsec = tv.tv_usec * 1000;
#else
clock_gettime(CLOCK_REALTIME, &tnow);
#endif
setCTime(tnow);
}
//------------------------------------------------------------------------------
// Get creation time
//------------------------------------------------------------------------------
void
QuarkContainerMD::getCTime(ctime_t& ctime) const
{
runReadOp([this,&ctime](){
getCTimeNoLock(ctime);
});
}
//------------------------------------------------------------------------------
// Get creation time, no locks
//------------------------------------------------------------------------------
void
QuarkContainerMD::getCTimeNoLock(ctime_t& ctime) const
{
(void) memcpy(&ctime, mCont.ctime().data(), sizeof(ctime));
}
//------------------------------------------------------------------------------
// Set modification time
//------------------------------------------------------------------------------
void
QuarkContainerMD::setMTime(mtime_t mtime)
{
runWriteOp([this,mtime](){
mCont.set_mtime(&mtime, sizeof(mtime));
});
}
//------------------------------------------------------------------------------
// Set creation time to now
//------------------------------------------------------------------------------
void
QuarkContainerMD::setMTimeNow()
{
struct timespec tnow;
#ifdef __APPLE__
struct timeval tv = {0};
gettimeofday(&tv, 0);
tnow.tv_sec = tv.tv_sec;
tnow.tv_nsec = tv.tv_usec * 1000;
#else
clock_gettime(CLOCK_REALTIME, &tnow);
#endif
setMTime(tnow);
}
//------------------------------------------------------------------------------
// Get modification time
//------------------------------------------------------------------------------
void
QuarkContainerMD::getMTime(mtime_t& mtime) const
{
return runReadOp([this,&mtime](){
getMTimeNoLock(mtime);
});
}
//------------------------------------------------------------------------------
// Get modification time, no lock
//------------------------------------------------------------------------------
void
QuarkContainerMD::getMTimeNoLock(mtime_t& mtime) const
{
(void) memcpy(&mtime, mCont.mtime().data(), sizeof(mtime));
}
//------------------------------------------------------------------------------
// Set propagated modification time (if newer)
//------------------------------------------------------------------------------
bool
QuarkContainerMD::setTMTime(tmtime_t tmtime)
{
return runWriteOp([this,&tmtime](){
tmtime_t tmt;
getTMTimeNoLock(tmt);
tmtime_t now;
clock_gettime(CLOCK_REALTIME, &now);
if ((tmtime.tv_sec == 0) || (tmtime.tv_sec > now.tv_sec)) {
tmtime = now;
}
if (((tmt.tv_sec == 0) && (tmt.tv_nsec == 0)) ||
(tmtime.tv_sec > tmt.tv_sec) ||
((tmtime.tv_sec == tmt.tv_sec) &&
(tmtime.tv_nsec > tmt.tv_nsec))) {
mCont.set_stime(&tmtime, sizeof(tmtime));
return true;
}
return false;
});
}
//------------------------------------------------------------------------------
// Set propagated modification time to now
//------------------------------------------------------------------------------
void
QuarkContainerMD::setTMTimeNow()
{
tmtime_t tmtime = {0};
setTMTime(tmtime);
}
//------------------------------------------------------------------------------
// Get propagated modification time, no locks
//------------------------------------------------------------------------------
void
QuarkContainerMD::getTMTimeNoLock(tmtime_t& tmtime)
{
tmtime = {};
if (mCont.stime().length()) {
(void) memcpy(&tmtime, mCont.stime().data(), sizeof(tmtime));
} else {
(void) memcpy(&tmtime, mCont.mtime().data(), sizeof(tmtime));
}
}
//------------------------------------------------------------------------------
// Get propagated modification time
//------------------------------------------------------------------------------
void
QuarkContainerMD::getTMTime(tmtime_t& tmtime)
{
runReadOp([this,&tmtime](){
getTMTimeNoLock(tmtime);
});
}
//------------------------------------------------------------------------------
// Trigger an mtime change event
//------------------------------------------------------------------------------
void
QuarkContainerMD::notifyMTimeChange(IContainerMDSvc* containerMDSvc)
{
containerMDSvc->notifyListeners(this,
IContainerMDChangeListener::MTimeChange);
}
//------------------------------------------------------------------------------
// Update tree size
//------------------------------------------------------------------------------
uint64_t
QuarkContainerMD::updateTreeSize(int64_t delta)
{
return runWriteOp([this,delta](){
uint64_t sz = mCont.tree_size();
// Avoid negative tree size
if ((delta < 0) && (static_cast(std::llabs(delta)) > sz)) {
sz = 0;
} else {
sz += delta;
}
mCont.set_tree_size(sz);
return sz;
});
}
//------------------------------------------------------------------------------
// Get the attribute
//------------------------------------------------------------------------------
std::string
QuarkContainerMD::getAttribute(const std::string& name) const
{
return runReadOp([this,name](){
auto it = mCont.xattrs().find(name);
if (it == mCont.xattrs().end()) {
MDException e(ENOENT);
e.getMessage() << __FUNCTION__ << " Attribute: " << name << " not found";
throw e;
}
return it->second;
});
}
//------------------------------------------------------------------------------
// Remove attribute
//------------------------------------------------------------------------------
void
QuarkContainerMD::removeAttribute(const std::string& name)
{
runWriteOp([this,name](){
auto it = mCont.xattrs().find(name);
if (it != mCont.xattrs().end()) {
mCont.mutable_xattrs()->erase(it->first);
}
});
}
//------------------------------------------------------------------------------
// Serialize the object to a buffer
//------------------------------------------------------------------------------
void
QuarkContainerMD::serialize(Buffer& buffer)
{
runReadOp([this,&buffer](){
// Align the buffer to 4 bytes to efficiently compute the checksum
mClock = std::chrono::high_resolution_clock::now().time_since_epoch().count();
#if GOOGLE_PROTOBUF_VERSION < 3004000
size_t obj_size = mCont.ByteSize();
#else
size_t obj_size = mCont.ByteSizeLong();
#endif
uint32_t align_size = (obj_size + 3) >> 2 << 2;
size_t sz = sizeof(align_size);
size_t msg_size = align_size + 2 * sz;
buffer.setSize(msg_size);
// Write the checksum value, size of the raw protobuf object and then the
// actual protobuf object serialized
const char* ptr = buffer.getDataPtr() + 2 * sz;
google::protobuf::io::ArrayOutputStream aos((void*)ptr, align_size);
if (!mCont.SerializeToZeroCopyStream(&aos)) {
MDException ex(EIO);
ex.getMessage() << "Failed while serializing buffer";
throw ex;
}
// Compute the CRC32C checkusm
uint32_t cksum = DataHelper::computeCRC32C((void*)ptr, align_size);
cksum = DataHelper::finalizeCRC32C(cksum);
// Point to the beginning to fill in the checksum and size of useful data
ptr = buffer.getDataPtr();
(void) memcpy((void*)ptr, &cksum, sz);
ptr += sz;
(void) memcpy((void*)ptr, &obj_size, sz);
});
}
//------------------------------------------------------------------------------
// Load children
//------------------------------------------------------------------------------
void
QuarkContainerMD::loadChildren()
{
// Requires lock be taken outside.
// Rebuild the file and subcontainer keys
pFilesKey = stringify(mCont.id()) + constants::sMapFilesSuffix;
pDirsKey = stringify(mCont.id()) + constants::sMapDirsSuffix;
if (pQcl) {
mFiles = MetadataFetcher::getFileMap(*pQcl,
ContainerIdentifier(mCont.id()));
mSubcontainers = MetadataFetcher::getContainerMap(*pQcl,
ContainerIdentifier(mCont.id()));
} else {
// I think this case only happens inside some tests.. remove eventually?
mFiles->clear();
mSubcontainers->clear();
}
}
//------------------------------------------------------------------------------
// Deserialize from buffer
//------------------------------------------------------------------------------
void
QuarkContainerMD::deserialize(Buffer& buffer)
{
runWriteOp([this,&buffer](){
Serialization::deserializeContainer(buffer, mCont);
loadChildren();
});
}
//------------------------------------------------------------------------------
// Initialize, inject children
//------------------------------------------------------------------------------
void
QuarkContainerMD::initialize(eos::ns::ContainerMdProto&& proto,
IContainerMD::FileMap&& fileMap, IContainerMD::ContainerMap&& containerMap)
{
runWriteOp([this,Proto = std::move(proto),FileMap = std::move(fileMap),ContainerMap = std::move(containerMap)](){
mCont = std::move(Proto);
mFiles.get() = std::move(FileMap);
mSubcontainers.get() = std::move(ContainerMap);
// Rebuild the file and subcontainer keys
pFilesKey = stringify(mCont.id()) + constants::sMapFilesSuffix;
pDirsKey = stringify(mCont.id()) + constants::sMapDirsSuffix;
});
}
//------------------------------------------------------------------------------
// Initialize from a ContainerMdProto object, without loading children maps.
//------------------------------------------------------------------------------
void
QuarkContainerMD::initializeWithoutChildren(eos::ns::ContainerMdProto&& proto)
{
runWriteOp([this,Proto = std::move(proto)](){
mCont = std::move(Proto);
});
}
//------------------------------------------------------------------------------
// Get map copy of the extended attributes
//------------------------------------------------------------------------------
eos::IFileMD::XAttrMap
QuarkContainerMD::getAttributes() const
{
return runReadOp([this](){
XAttrMap xattrs;
for (const auto& elem : mCont.xattrs()) {
xattrs.insert(elem);
}
return xattrs;
});
}
//------------------------------------------------------------------------------
// Get env representation of the container object
//------------------------------------------------------------------------------
void
QuarkContainerMD::getEnv(std::string& env, bool escapeAnd)
{
runReadOp([this,&env,escapeAnd](){
env.clear();
std::ostringstream oss;
std::string saveName = mCont.name();
if (escapeAnd) {
if (!saveName.empty()) {
saveName = eos::common::StringConversion::SealXrdPath(saveName);
}
}
ctime_t ctime;
ctime_t mtime;
ctime_t stime;
(void) getCTimeNoLock(ctime);
(void) getMTimeNoLock(mtime);
(void) getTMTimeNoLock(stime);
oss << "name=" << saveName
<< "&id=" << mCont.id()
<< "&uid=" << mCont.uid() << "&gid=" << mCont.gid()
<< "&parentid=" << mCont.parent_id()
<< "&mode=" << std::oct << mCont.mode() << std::dec
<< "&flags=" << std::oct << mCont.flags() << std::dec
<< "&treesize=" << mCont.tree_size()
<< "&ctime=" << ctime.tv_sec << "&ctime_ns=" << ctime.tv_nsec
<< "&mtime=" << mtime.tv_sec << "&mtime_ns=" << mtime.tv_nsec
<< "&stime=" << stime.tv_sec << "&stime_ns=" << stime.tv_nsec;
for (const auto& elem : mCont.xattrs()) {
oss << "&" << elem.first << "=" << elem.second;
}
env += oss.str();
});
}
//------------------------------------------------------------------------------
// Get a copy of ContainerMap
//------------------------------------------------------------------------------
IContainerMD::ContainerMap
QuarkContainerMD::copyContainerMap() const
{
IContainerMD::ContainerMap retval;
retval.set_deleted_key("");
retval.set_empty_key("##_EMPTY_##");
return runReadOp([this,&retval](){
for (auto it = mSubcontainers->begin(); it != mSubcontainers->end(); ++it) {
retval.insert(std::make_pair(it->first, it->second));
}
return retval;
});
}
//------------------------------------------------------------------------------
// Get a copy of FileMap
//------------------------------------------------------------------------------
IContainerMD::FileMap
QuarkContainerMD::copyFileMap() const
{
IContainerMD::FileMap retval;
retval.set_deleted_key("");
retval.set_empty_key("##_EMPTY_##");
return runReadOp([this,&retval](){
for (auto it = mFiles->begin(); it != mFiles->end(); ++it) {
retval.insert(std::make_pair(it->first, it->second));
}
return retval;
});
}
EOSNSNAMESPACE_END