/************************************************************************
* 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 .*
************************************************************************/
//------------------------------------------------------------------------------
//! @author Elvin Sindrilaru
//! @brief The filesystem view stored in QuarkDB
//------------------------------------------------------------------------------
#ifndef EOS_NS_FILESYSTEM_VIEW_HH
#define EOS_NS_FILESYSTEM_VIEW_HH
#include "namespace/MDException.hh"
#include "namespace/Namespace.hh"
#include "namespace/interface/IFsView.hh"
#include "namespace/ns_quarkdb/Constants.hh"
#include "namespace/ns_quarkdb/accounting/FileSystemView.hh"
#include "namespace/ns_quarkdb/accounting/FileSystemHandler.hh"
#include "common/AssistedThread.hh"
#include "qclient/QClient.hh"
#include
EOSNSNAMESPACE_BEGIN
class MetadataFlusher;
//------------------------------------------------------------------------------
//! File System iterator implementation on top of QuarkDB.
//! The proper solution would be that the object itself contacts redis running
//! SCAN, but this should be fine for now.
//------------------------------------------------------------------------------
class QdbFileSystemIterator:
public ICollectionIterator
{
public:
//----------------------------------------------------------------------------
//! Constructor
//----------------------------------------------------------------------------
QdbFileSystemIterator(std::set&& filesystems)
{
pFilesystems = std::move(filesystems);
iterator = pFilesystems.begin();
}
//----------------------------------------------------------------------------
//! Destructor
//----------------------------------------------------------------------------
virtual ~QdbFileSystemIterator() = default;
//----------------------------------------------------------------------------
//! Get current fsid
//----------------------------------------------------------------------------
IFileMD::location_t getElement() override
{
return *iterator;
}
//----------------------------------------------------------------------------
//! Check if iterator is valid
//----------------------------------------------------------------------------
bool valid() override
{
return iterator != pFilesystems.end();
}
//----------------------------------------------------------------------------
//! Progress iterator by 1 - only has any effect if iterator is valid
//----------------------------------------------------------------------------
void next() override
{
if (valid()) {
iterator++;
}
}
private:
std::set pFilesystems;
std::set::iterator iterator;
};
//------------------------------------------------------------------------------
// File System iterator implementation of a in-memory namespace
// Trivial implementation, using the same logic to iterate over filesystems
// as we did with "getNumFileSystems" before.
//------------------------------------------------------------------------------
class ListFileSystemIterator:
public ICollectionIterator
{
public:
//----------------------------------------------------------------------------
//! Constructor
//----------------------------------------------------------------------------
ListFileSystemIterator(
const std::map>& map
)
{
for (const auto& pair : map) {
mList.push_back(pair.first);
}
mIt = mList.cbegin();
}
//----------------------------------------------------------------------------
//! Destructor
//----------------------------------------------------------------------------
virtual ~ListFileSystemIterator() = default;
//----------------------------------------------------------------------------
//! Get current fsid
//----------------------------------------------------------------------------
IFileMD::location_t getElement() override
{
return *mIt;
}
//----------------------------------------------------------------------------
//! Check if iterator is valid
//----------------------------------------------------------------------------
bool valid() override
{
return (mIt != mList.cend());
}
//----------------------------------------------------------------------------
//! Retrieve next fsid - returns false when no more filesystems exist
//----------------------------------------------------------------------------
void next() override
{
if (valid()) {
++mIt;
}
}
private:
std::list mList;
std::list::const_iterator mIt;
};
//------------------------------------------------------------------------------
//! FileSystemView implementation on top of QuarkDB
//!
//! This class keeps a mapping between filesystem ids and the actual file ids
//! that reside on that particular filesystem. For each fsid we keep a set
//! structure in Redis i.e. fs_id:fsview_files that holds the file ids. E.g.:
//!
//! fsview:1:files --> fid4, fid87, fid1002 etc.
//! fsview:2:files ...
//! ...
//! fsview:n:files ...
//!
//! Besides these data structures we also have:
//!
//! fsview_noreplicas - file ids that don't have any replicas on any fs
//! fsview:x:unlinked - set of file ids that are unlinked on file system "x"
//------------------------------------------------------------------------------
class QuarkFileSystemView : public IFsView
{
public:
//----------------------------------------------------------------------------
//! Constructor
//----------------------------------------------------------------------------
QuarkFileSystemView(qclient::QClient* qcl, MetadataFlusher* flusher);
//----------------------------------------------------------------------------
//! Destructor
//----------------------------------------------------------------------------
virtual ~QuarkFileSystemView();
//----------------------------------------------------------------------------
//! Notify me about the changes in the main view
//----------------------------------------------------------------------------
virtual void fileMDChanged(IFileMDChangeListener::Event* e) override;
//----------------------------------------------------------------------------
//! Notify me about files when recovering from changelog - not used
//----------------------------------------------------------------------------
virtual void fileMDRead(IFileMD* obj) override {};
//----------------------------------------------------------------------------
//! Recheck the current file object and make any modifications necessary so
//! that the information is consistent in the back-end KV store.
//!
//! @param file file object to be checked
//!
//! @return true if successful, otherwise false
//----------------------------------------------------------------------------
virtual bool fileMDCheck(IFileMD* file) override;
//----------------------------------------------------------------------------
//! Erase an entry from all filesystem view collections
//!
//! @param file id
//!
//! @return
//----------------------------------------------------------------------------
virtual void eraseEntry(IFileMD::location_t location, IFileMD::id_t) override;
//----------------------------------------------------------------------------
//! Get iterator to list of files on a particular file system
//!
//! @param location file system id
//!
//! @return shared ptr to collection iterator
//----------------------------------------------------------------------------
std::shared_ptr>
getFileList(IFileMD::location_t location) override;
//----------------------------------------------------------------------------
//! Get streaming iterator to list of files on a particular file system
//!
//! @param location file system id
//!
//! @return shared ptr to collection iterator
//----------------------------------------------------------------------------
std::shared_ptr>
getStreamingFileList(IFileMD::location_t location) override;
//----------------------------------------------------------------------------
//! Get an approximately random file residing within the given filesystem.
//!
//! @param location file system id
//! @param retval a file id residing within the given filesystem
//!
//! @return bool indicating whether the operation was successful
//----------------------------------------------------------------------------
bool getApproximatelyRandomFileInFs(IFileMD::location_t location,
IFileMD::id_t& retval) override;
//----------------------------------------------------------------------------
//! Get number of files on the given file system
//!
//! @param fs_id file system id
//!
//! @return number of files
//----------------------------------------------------------------------------
uint64_t getNumFilesOnFs(IFileMD::location_t fs_id) override;
//----------------------------------------------------------------------------
//! Get iterator to list of unlinked files on a particular file system
//!
//! @param location file system id
//!
//! @return shared ptr to collection iterator
//----------------------------------------------------------------------------
std::shared_ptr>
getUnlinkedFileList(IFileMD::location_t location) override;
//----------------------------------------------------------------------------
//! Get number of unlinked files on the given file system
//!
//! @param fs_id file system id
//!
//! @return number of files
//----------------------------------------------------------------------------
uint64_t getNumUnlinkedFilesOnFs(IFileMD::location_t fs_id) override;
//----------------------------------------------------------------------------
//! Get iterator to list of files without replicas
//!
//! @return shard ptr to collection iterator
//----------------------------------------------------------------------------
std::shared_ptr>
getNoReplicasFileList() override;
//----------------------------------------------------------------------------
//! Get streaming iterator to list of files without replicas
//!
//! @return shard ptr to collection iterator
//----------------------------------------------------------------------------
std::shared_ptr>
getStreamingNoReplicasFileList() override;
//----------------------------------------------------------------------------
//! Get number of files with no replicas
//----------------------------------------------------------------------------
uint64_t getNumNoReplicasFiles() override;
//----------------------------------------------------------------------------
//! Clear unlinked files for filesystem
//!
//! @param location filssystem id
//!
//! @return true if cleanup done successfully, otherwise false
//----------------------------------------------------------------------------
bool clearUnlinkedFileList(IFileMD::location_t location) override;
//----------------------------------------------------------------------------
//! Get iterator object to run through all currently active filesystem IDs
//----------------------------------------------------------------------------
std::shared_ptr>
getFileSystemIterator() override;
//----------------------------------------------------------------------------
//! Check if file system has file id
//!
//! @param fid file id
//! @param fs_id file system id
//!
//! @return true if file is on the provided file system, otherwise false
//----------------------------------------------------------------------------
bool hasFileId(IFileMD::id_t fid, IFileMD::location_t fs_id) override;
//----------------------------------------------------------------------------
//! Configure
//!
//! @param config map of configuration parameters
//----------------------------------------------------------------------------
void configure(const std::map& config) override;
//----------------------------------------------------------------------------
//! Finalize - no-op for this type of view
//----------------------------------------------------------------------------
void finalize() override {};
//----------------------------------------------------------------------------
//! Shrink maps - no-op for this type of view
//----------------------------------------------------------------------------
void shrink() override {};
//----------------------------------------------------------------------------
//! Add tree - no-op for this type of view
//----------------------------------------------------------------------------
void AddTree(IContainerMD* obj, int64_t dsize) override {};
//----------------------------------------------------------------------------
//! Remove tree - no-op for this type of view
//----------------------------------------------------------------------------
void RemoveTree(IContainerMD* obj, int64_t dsize) override {};
private:
//----------------------------------------------------------------------------
//! Load view from backend
//----------------------------------------------------------------------------
void loadFromBackend();
//----------------------------------------------------------------------------
//! Get iterator object to run through all the filesystem IDs stored in the
//! backend.
//----------------------------------------------------------------------------
std::shared_ptr>
getQdbFileSystemIterator(const std::string& pattern);
//----------------------------------------------------------------------------
//! Initialize FileSystemHandler for given filesystem ID, if not already
//! initialized. Otherwise, do nothing.
//!
//! In any case, return pointer to the corresponding FileSystemHandler.
//!
//! @param fsid file system id
//----------------------------------------------------------------------------
FileSystemHandler* initializeRegularFilelist(IFileMD::location_t fsid);
//----------------------------------------------------------------------------
//! Fetch FileSystemHandler for a given filesystem ID, but do not initialize
//! if it doesn't exist, give back nullptr.
//!
//! @param fsid file system id
//----------------------------------------------------------------------------
FileSystemHandler* fetchRegularFilelistIfExists(IFileMD::location_t fsid);
//----------------------------------------------------------------------------
//! Initialize unlinked FileSystemHandler for given filesystem ID,
//! if not already initialized. Otherwise, do nothing.
//!
//! In any case, return pointer to the corresponding FileSystemHandler.
//!
//! @param fsid file system id
//----------------------------------------------------------------------------
FileSystemHandler* initializeUnlinkedFilelist(IFileMD::location_t fsid);
//----------------------------------------------------------------------------
//! Fetch unlinked FileSystemHandler for a given filesystem ID, but do not
//! initialize if it doesn't exist, give back nullptr.
//!
//! @param fsid file system id
//----------------------------------------------------------------------------
FileSystemHandler* fetchUnlinkedFilelistIfExists(IFileMD::location_t fsid);
//----------------------------------------------------------------------------
//! Run cache cleanup of the different FileSystemHandle objects tracked by
//! the FileSystemView in order to keep the memory overhead under control
//!
//! @param assistand thread responsible for this activity
//----------------------------------------------------------------------------
void CleanCacheJob(ThreadAssistant& assistant) noexcept;
///! Metadata flusher object
MetadataFlusher* pFlusher;
///! QClient object
qclient::QClient* pQcl;
///! Folly executor
std::unique_ptr mExecutor;
///! No replicas handler
std::unique_ptr mNoReplicas;
///! Regular filelists
std::map> mFiles;
///! Unlinked filelists
std::map>
mUnlinkedFiles;
///! Mutex protecting access to the maps. Not the contents of the maps,
///! though.
std::mutex mMutex;
//! Thread cleaning the FileSystemHandler cache regularly
AssistedThread mCacheCleanerThread;
//! Period after which the thread cache cleaner will run. Default 45 min.
static const std::chrono::minutes sCacheCleanerTimeout;
};
//------------------------------------------------------------------------------
//! Parse an fs set key, returning its id and whether it points to "files" or
//! "unlinked"
//!
//! @param str input stirng
//! @param fsid parsed fsids
//! @param unlinked if true then this is an fsid from an unlinked list
//!
//! @return true if parsing successful, otherwise false
//------------------------------------------------------------------------------
bool parseFsId(const std::string& str, IFileMD::location_t& fsid,
bool& unlinked);
EOSNSNAMESPACE_END
#endif // __EOS_NS_FILESYSTEM_VIEW_HH__