/************************************************************************
* 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 .*
************************************************************************/
//------------------------------------------------------------------------------
//! @author Georgios Bitzes
//! @brief Metadata prefetching engine
//------------------------------------------------------------------------------
#include "namespace/interface/IFileMDSvc.hh"
#include "namespace/interface/IContainerMDSvc.hh"
#include "namespace/interface/IView.hh"
#include "namespace/interface/IFsView.hh"
#include "namespace/interface/ContainerIterators.hh"
#include "namespace/Prefetcher.hh"
#include "common/FileId.hh"
#include "common/Logging.hh"
using std::placeholders::_1;
EOSNSNAMESPACE_BEGIN
//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
Prefetcher::Prefetcher(IView* view)
{
pView = view;
pFileMDSvc = pView->getFileMDSvc();
pContainerMDSvc = pView->getContainerMDSvc();
}
//------------------------------------------------------------------------------
// Declare an intent to access FileMD with the given id soon
//------------------------------------------------------------------------------
void Prefetcher::stageFileMD(IFileMD::id_t id)
{
if (pView->inMemory()) {
return;
}
mFileMDs.emplace_back(pFileMDSvc->getFileMDFut(id));
}
//------------------------------------------------------------------------------
// Prefetch Uri of IFileMDPtr
//------------------------------------------------------------------------------
folly::Future Prefetcher::prefetchFileUri(IFileMDPtr file) {
if(file) {
return this->pView->getUriFut(file->getIdentifier());
}
return "";
}
//------------------------------------------------------------------------------
// Prefetch Uri of IContainerMDPtr
//------------------------------------------------------------------------------
folly::Future Prefetcher::prefetchContUri(IContainerMDPtr cont) {
if(cont) {
return this->pView->getUriFut(cont->getIdentifier());
}
return "";
}
//------------------------------------------------------------------------------
// Declare an intent to access FileMD with the given id soon, along with
// its parents
//------------------------------------------------------------------------------
void Prefetcher::stageFileMDWithParents(IFileMD::id_t id)
{
if (pView->inMemory()) {
return;
}
mUris.emplace_back(pFileMDSvc->getFileMDFut(id).thenValue(std::bind(&Prefetcher::prefetchFileUri, this, _1)));
}
//------------------------------------------------------------------------------
// Declare an intent to access ContainerMD with the given id soon, along with
// its parents
//------------------------------------------------------------------------------
void Prefetcher::stageContainerMDWithParents(IContainerMD::id_t id)
{
if (pView->inMemory()) {
return;
}
mUris.emplace_back(pContainerMDSvc->getContainerMDFut(id).thenValue(std::bind(&Prefetcher::prefetchContUri, this, _1)));
}
//----------------------------------------------------------------------------
// Declare an intent to access FileMD with the given path soon
//----------------------------------------------------------------------------
void Prefetcher::stageFileMD(const std::string& path, bool follow)
{
if (pView->inMemory()) {
return;
}
try {
mFileMDs.emplace_back(pView->getFileFut(path, follow));
}
catch(MDException &exc) {
eos_static_warning("Exception in Prefetcher while looking up FileMD path %s: %s, benign race condition?", path.c_str(), exc.getMessage().str().c_str());
}
}
//------------------------------------------------------------------------------
// Declare an intent to access ContainerMD with the given id soon
//------------------------------------------------------------------------------
void Prefetcher::stageContainerMD(IContainerMD::id_t id)
{
if (pView->inMemory()) {
return;
}
mContainerMDs.emplace_back(pContainerMDSvc->getContainerMDFut(id));
}
//----------------------------------------------------------------------------
// Declare an intent to access ContainerMD with the given path soon
//----------------------------------------------------------------------------
void Prefetcher::stageContainerMD(const std::string& path, bool follow)
{
if (pView->inMemory()) {
return;
}
try {
mContainerMDs.emplace_back(pView->getContainerFut(path, follow));
}
catch(MDException &exc) {
eos_static_warning("Exception in Prefetcher while looking up ContainerMD path %s: %s, benign race condition?", path.c_str(), exc.getMessage().str().c_str());
}
}
//------------------------------------------------------------------------------
//! Declare an intent to access the given path soon. We don't know if there's
//! a file, or directory there.
//------------------------------------------------------------------------------
void Prefetcher::stageItem(const std::string& path, bool follow)
{
if (pView->inMemory()) {
return;
}
mItems.emplace_back(pView->getItem(path, follow));
}
//------------------------------------------------------------------------------
// Wait until all staged requests have been loaded in cache.
//------------------------------------------------------------------------------
void Prefetcher::wait()
{
if (pView->inMemory()) {
return;
}
for (size_t i = 0; i < mFileMDs.size(); i++) {
mFileMDs[i].wait();
}
for (size_t i = 0; i < mContainerMDs.size(); i++) {
mContainerMDs[i].wait();
}
for (size_t i = 0; i < mUris.size(); i++) {
mUris[i].wait();
}
}
//------------------------------------------------------------------------------
// Prefetch FileMD by path and wait
//------------------------------------------------------------------------------
void Prefetcher::prefetchFileMDAndWait(IView* view, const std::string& path,
bool follow)
{
Prefetcher prefetcher(view);
prefetcher.stageFileMD(path, follow);
prefetcher.wait();
}
//------------------------------------------------------------------------------
// Prefetch FileMD by id and wait
//------------------------------------------------------------------------------
void Prefetcher::prefetchFileMDAndWait(IView* view, IFileMD::id_t id)
{
Prefetcher prefetcher(view);
prefetcher.stageFileMD(id);
prefetcher.wait();
}
//------------------------------------------------------------------------------
// Prefetch ContainerMD and wait
//------------------------------------------------------------------------------
void Prefetcher::prefetchContainerMDAndWait(IView* view,
const std::string& path, bool follow)
{
Prefetcher prefetcher(view);
prefetcher.stageContainerMD(path, follow);
prefetcher.wait();
}
//------------------------------------------------------------------------------
// Prefetch ContainerMD and wait
//------------------------------------------------------------------------------
void Prefetcher::prefetchContainerMDAndWait(IView* view, IContainerMD::id_t id)
{
Prefetcher prefetcher(view);
prefetcher.stageContainerMD(id);
prefetcher.wait();
}
//------------------------------------------------------------------------------
// Prefetch item and wait. We don't know if there's a file, or container under
// that path.
//------------------------------------------------------------------------------
void Prefetcher::prefetchItemAndWait(IView* view, const std::string& path,
bool follow)
{
Prefetcher prefetcher(view);
prefetcher.stageItem(path, follow);
prefetcher.wait();
}
//------------------------------------------------------------------------------
// Prefetch ContainerMD, along with all its children, and wait
//------------------------------------------------------------------------------
void Prefetcher::prefetchContainerMDWithChildrenAndWait(IView* view,
const std::string& path, bool follow, bool onlyDirs, bool limitresult, uint64_t dir_limit, uint64_t file_limit)
{
if (view->inMemory()) {
return;
}
folly::Future fut = view->getContainerFut(path, follow);
fut.wait();
if (fut.hasException()) {
return;
}
IContainerMDPtr cmd = std::move(fut).get();
if(std::chrono::steady_clock::now() - cmd->getLastPrefetch() <= std::chrono::minutes(10)) {
return;
}
Prefetcher prefetcher(view);
std::vector paths;
if (limitresult) {
uint64_t dirsfound=0;
for (auto dit = eos::ContainerMapIterator(cmd); dit.valid() && dirsfoundsetLastPrefetch(std::chrono::steady_clock::now());
}
//------------------------------------------------------------------------------
// Prefetch inode metadata, automatically detect if it's a file or directory
//------------------------------------------------------------------------------
void Prefetcher::prefetchInodeAndWait(IView* view, uint64_t ino)
{
if(view->inMemory() || ino == 0) {
return;
}
if(eos::common::FileId::IsFileInode(ino)) {
prefetchFileMDAndWait(view, eos::common::FileId::InodeToFid(ino));
}
else {
prefetchContainerMDAndWait(view, ino);
}
}
//------------------------------------------------------------------------------
// Prefetch inode metadata with all children (if any), automatically detect if
// it's a file or directory
//------------------------------------------------------------------------------
void Prefetcher::prefetchInodeWithChildrenAndWait(IView* view, uint64_t ino)
{
if(view->inMemory() || ino == 0) {
return;
}
if(eos::common::FileId::IsFileInode(ino)) {
prefetchFileMDAndWait(view, eos::common::FileId::InodeToFid(ino));
}
else {
prefetchContainerMDWithChildrenAndWait(view, ino);
}
}
//------------------------------------------------------------------------------
// Prefetch ContainerMD, along with all its children, and wait
//------------------------------------------------------------------------------
void Prefetcher::prefetchContainerMDWithChildrenAndWait(IView* view,
IContainerMD::id_t id, bool onlyDirs, bool limitresults, uint64_t dir_limit, uint64_t file_limit)
{
if (view->inMemory()) {
return;
}
folly::Future fut =
view->getContainerMDSvc()->getContainerMDFut(id);
fut.wait();
if (fut.hasException()) {
return;
}
IContainerMDPtr cmd = std::move(fut).get();
if(std::chrono::steady_clock::now() - cmd->getLastPrefetch() <= std::chrono::minutes(10)) {
return;
}
Prefetcher prefetcher(view);
std::vector paths;
if (limitresults) {
uint64_t dirsfound=0;
for (auto dit = eos::ContainerMapIterator(cmd); dit.valid() && dirsfoundsetLastPrefetch(std::chrono::steady_clock::now());
}
//------------------------------------------------------------------------------
// Prefetch FileMD inode, along with all its parents, and wait
//------------------------------------------------------------------------------
void Prefetcher::prefetchFileMDWithParentsAndWait(IView* view,
IFileMD::id_t id)
{
if (view->inMemory()) {
return;
}
Prefetcher prefetcher(view);
prefetcher.stageFileMDWithParents(id);
prefetcher.wait();
}
//------------------------------------------------------------------------------
// Prefetch ContainerMD inode, along with all its parents, and wait
//------------------------------------------------------------------------------
void Prefetcher::prefetchContainerMDWithParentsAndWait(IView* view,
IContainerMD::id_t id)
{
if (view->inMemory()) {
return;
}
Prefetcher prefetcher(view);
prefetcher.stageContainerMDWithParents(id);
prefetcher.wait();
}
//------------------------------------------------------------------------------
// Prefetch FileList for the given filesystem ID
//------------------------------------------------------------------------------
void Prefetcher::prefetchFilesystemFileListAndWait(IView* view, IFsView* fsview,
IFileMD::location_t location)
{
if (view->inMemory()) {
return;
}
auto it = fsview->getFileList(location);
}
//----------------------------------------------------------------------------
// Prefetch unlinked FileList for the given filesystem ID
//----------------------------------------------------------------------------
void Prefetcher::prefetchFilesystemUnlinkedFileListAndWait(IView* view,
IFsView* fsview, IFileMD::location_t location)
{
if (view->inMemory()) {
return;
}
auto it = fsview->getUnlinkedFileList(location);
}
//----------------------------------------------------------------------------
// Prefetch unlinked FileList for the given filesystem ID, along with all
// contained FileMDs.
//----------------------------------------------------------------------------
void Prefetcher::prefetchFilesystemUnlinkedFileListWithFileMDsAndWait(
IView* view, IFsView* fsview, IFileMD::location_t location)
{
if (view->inMemory()) {
return;
}
Prefetcher prefetcher(view);
for (auto it = fsview->getUnlinkedFileList(location); it &&
it->valid(); it->next()) {
prefetcher.stageFileMD(it->getElement());
}
prefetcher.wait();
}
//------------------------------------------------------------------------------
// Prefetch FileList for the given filesystem ID, along with all contained
// FileMDs.
//------------------------------------------------------------------------------
void Prefetcher::prefetchFilesystemFileListWithFileMDsAndWait(IView* view,
IFsView* fsview, IFileMD::location_t location)
{
if (view->inMemory()) {
return;
}
Prefetcher prefetcher(view);
for (auto it = fsview->getFileList(location); it && it->valid(); it->next()) {
prefetcher.stageFileMD(it->getElement());
}
prefetcher.wait();
}
//------------------------------------------------------------------------------
// Prefetch FileList for the given filesystem ID, along with all contained
// FileMDs, and all parents of those.
//------------------------------------------------------------------------------
void Prefetcher::prefetchFilesystemFileListWithFileMDsAndParentsAndWait(
IView* view, IFsView* fsview, IFileMD::location_t location)
{
if (view->inMemory()) {
return;
}
Prefetcher prefetcher(view);
for (auto it = fsview->getFileList(location); it && it->valid(); it->next()) {
prefetcher.stageFileMDWithParents(it->getElement());
}
prefetcher.wait();
}
EOSNSNAMESPACE_END