// ---------------------------------------------------------------------- // File: SpaceToTapeGcMap.cc // Author: Steven Murray - CERN // ---------------------------------------------------------------------- /************************************************************************ * EOS - the CERN Disk Storage System * * Copyright (C) 2011 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 "mgm/tgc/MaxLenExceeded.hh" #include "mgm/tgc/SpaceToTapeGcMap.hh" #include #include /*----------------------------------------------------------------------------*/ /** * @file SpaceToTapeAwareGcMap.cc * * @brief Class implementing a thread safe map from EOS space name to tape * ware garbage collector * */ /*----------------------------------------------------------------------------*/ EOSTGCNAMESPACE_BEGIN //---------------------------------------------------------------------------- //! Constructor //---------------------------------------------------------------------------- SpaceToTapeGcMap::SpaceToTapeGcMap(ITapeGcMgm &mgm): m_mgm(mgm) { } //---------------------------------------------------------------------------- //! Create a tape aware garbage collector for the specified EOS space. //---------------------------------------------------------------------------- TapeGc& SpaceToTapeGcMap::createGc(const std::string &space) { if(space.empty()) { std::ostringstream msg; msg << "EOS space passed to " << __FUNCTION__ << " is an empty string"; throw std::runtime_error(msg.str()); } std::lock_guard lock(m_mutex); auto itor = m_gcs.find(space); if(m_gcs.end() != itor) { std::ostringstream msg; msg << "A tape aware garbage collector already exists for EOS space " << space; throw GcAlreadyExists(msg.str()); } const auto result = m_gcs.emplace(space, std::make_unique(m_mgm, space)); if(!result.second) { std::ostringstream msg; msg << "Failed to insert new TapeGC for EOS space " << space << " into internal map"; throw std::runtime_error(msg.str()); } return *(result.first->second); } //---------------------------------------------------------------------------- //! Destroys the tape aware garbage collectors for all EOS spaces. //---------------------------------------------------------------------------- void SpaceToTapeGcMap::destroyAllGc() { std::lock_guard lock(m_mutex); m_gcs.clear(); } //---------------------------------------------------------------------------- //! Returns the garbage collector associated with the specified EOS space. //---------------------------------------------------------------------------- TapeGc &SpaceToTapeGcMap::getGc(const std::string &space) const { if(space.empty()) { std::ostringstream msg; msg << "EOS space passed to " << __FUNCTION__ << " is an empty string"; throw std::runtime_error(msg.str()); } std::lock_guard lock(m_mutex); auto itor = m_gcs.find(space); if(m_gcs.end() == itor) { std::ostringstream msg; msg << "EOS space " << space << " is unknown to " << __FUNCTION__; throw UnknownEOSSpace(msg.str()); } auto &gc = itor->second; if(!gc) { std::stringstream msg; msg << "Encountered unexpected nullptr to TapeGc for EOS space " << space; throw std::runtime_error(msg.str()); } return *gc; } //---------------------------------------------------------------------------- //! @return map from EOS space name to tape-aware GC statistics //---------------------------------------------------------------------------- std::map SpaceToTapeGcMap::getStats() const { std::map stats; std::lock_guard lock(m_mutex); for(auto &spaceAndTapeGc : m_gcs) { if(nullptr != spaceAndTapeGc.second) { stats[spaceAndTapeGc.first] = spaceAndTapeGc.second->getStats(); } } return stats; } //---------------------------------------------------------------------------- // Return the names of the EOS spaces being garbage collected //---------------------------------------------------------------------------- std::set SpaceToTapeGcMap::getSpaces() const { std::set spaces; std::lock_guard lock(m_mutex); for (auto &spaceAndTapeGc : m_gcs) { if (nullptr != spaceAndTapeGc.second) { if (0 != spaces.count(spaceAndTapeGc.first)) { std::ostringstream msg; msg << __FUNCTION__ << " failed: Detected two garbage collectors working on the same EOS space: space=" << spaceAndTapeGc.first; throw std::runtime_error(msg.str()); } spaces.insert(spaceAndTapeGc.first); } } return spaces; } //---------------------------------------------------------------------------- // Return A JSON string representation of this map //---------------------------------------------------------------------------- void SpaceToTapeGcMap::toJson(std::ostringstream &os, std::uint64_t maxLen) const { os << "{"; { bool isFirstGc = true; std::lock_guard lock(m_mutex); for (auto &spaceAndTapeGc : m_gcs) { if (isFirstGc) { isFirstGc = false; } else { os << ","; } if (nullptr != spaceAndTapeGc.second) { os << "\"" << spaceAndTapeGc.first << "\":"; spaceAndTapeGc.second->toJson(os, maxLen); const auto osSize = os.tellp(); if (0 > osSize) throw std::runtime_error(std::string(__FUNCTION__) + ": os.tellp() returned a negative number"); if (maxLen && maxLen < (std::string::size_type)osSize) { std::ostringstream msg; msg << __FUNCTION__ << ": maxLen exceeded: maxLen=" << maxLen; throw MaxLenExceeded(msg.str()); } } } } os << "}"; { const auto osSize = os.tellp(); if (0 > osSize) throw std::runtime_error(std::string(__FUNCTION__) + ": os.tellp() returned a negative number"); if (maxLen && maxLen < (std::string::size_type)osSize) { std::ostringstream msg; msg << __FUNCTION__ << ": maxLen exceeded: maxLen=" << maxLen; throw MaxLenExceeded(msg.str()); } } } //-------------------------------------------------------------------------- // Start the worker thread of each garbage collector //-------------------------------------------------------------------------- void SpaceToTapeGcMap::startGcWorkerThreads() { std::lock_guard lock(m_mutex); for(auto &spaceAndTapeGc : m_gcs) { if(nullptr != spaceAndTapeGc.second) { spaceAndTapeGc.second->startWorkerThread(); } } } EOSTGCNAMESPACE_END