// ---------------------------------------------------------------------- // File: Lru.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/Lru.hh" #include "mgm/tgc/MaxLenExceeded.hh" #include #include EOSTGCNAMESPACE_BEGIN //------------------------------------------------------------------------------ //! Constructor //------------------------------------------------------------------------------ Lru::Lru(const FidQueue::size_type maxQueueSize): mMaxQueueSize(maxQueueSize), mMaxQueueSizeExceeded(false) { if(0 == maxQueueSize) { throw MaxQueueSizeIsZero(std::string(__FUNCTION__) + " failed: maxQueueSize must be greater than 0"); } } //------------------------------------------------------------------------------ //! Notify the queue a file has been accessed //------------------------------------------------------------------------------ void Lru::fileAccessed(const IFileMD::id_t fid) { const auto mapEntry = mFidToQueueEntry.find(fid); // If a new file has been accessed if(mFidToQueueEntry.end() == mapEntry) { newFileHasBeenAccessed(fid); } else { queuedFileHasBeenAccessed(fid, mapEntry.value()); } } //------------------------------------------------------------------------------ // Handle the fact a new file has been accessed //------------------------------------------------------------------------------ void Lru::newFileHasBeenAccessed(const IFileMD::id_t fid) { // Ignore the new file if the maximum queue size has been reached // IMPORTANT: This should be a rare situation if(mFidToQueueEntry.size() == mMaxQueueSize) { mMaxQueueSizeExceeded = true; } else { // Add file to the front of the LRU queue mQueue.push_front(fid); mFidToQueueEntry[fid] = mQueue.begin(); } } //------------------------------------------------------------------------------ // Handle the fact that a file already in the queue has been accessed //------------------------------------------------------------------------------ void Lru::queuedFileHasBeenAccessed(const IFileMD::id_t fid, FidQueue::iterator &queueItor) { // Erase the existing file from the LRU queue mQueue.erase(queueItor); // Push the identifier of the file onto the front of the LRU queue mQueue.push_front(fid); mFidToQueueEntry[fid] = mQueue.begin(); } //------------------------------------------------------------------------------ //! Notify the queue a file has been deleted from the EOS namespace //------------------------------------------------------------------------------ void Lru::fileDeletedFromNamespace(const IFileMD::id_t fid) { const auto mapEntry = mFidToQueueEntry.find(fid); if(mFidToQueueEntry.end() != mapEntry) { mQueue.erase(mapEntry.value()); mFidToQueueEntry.erase(mapEntry); } } //------------------------------------------------------------------------------ // Return true if the queue is empty //------------------------------------------------------------------------------ bool Lru::empty() const { return mQueue.empty(); } //------------------------------------------------------------------------------ // Return queue size //------------------------------------------------------------------------------ Lru::FidQueue::size_type Lru::size() const { return mFidToQueueEntry.size(); } //------------------------------------------------------------------------------ // Pop and return the identifier of the least used file //------------------------------------------------------------------------------ IFileMD::id_t Lru::getAndPopFidOfLeastUsedFile() { if(mQueue.empty()) { throw QueueIsEmpty(std::string(__FUNCTION__) + " failed: The queue is empty"); } else { mMaxQueueSizeExceeded = false; const auto lruFid = mQueue.back(); mQueue.pop_back(); mFidToQueueEntry.erase(lruFid); return lruFid; } } //------------------------------------------------------------------------------ // Return true if the maximum queue size has been exceeded //------------------------------------------------------------------------------ bool Lru::maxQueueSizeExceeded() const noexcept { return mMaxQueueSizeExceeded; } //---------------------------------------------------------------------------- // Return A JSON string representation of the LRU queue //---------------------------------------------------------------------------- void Lru::toJson(std::ostringstream &os, const std::uint64_t maxLen) const { os << "{\"size\":\"" << size() << "\",\"fids_from_MRU_to_LRU\":"; os << std::setfill('0') << std::hex << "["; bool isFirstFid = true; for (const auto fid: mQueue) { if (isFirstFid) { isFirstFid = false; } else { os << ","; } os << "\"0x" << std::setw(16) << fid << "\""; { 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()); } } } EOSTGCNAMESPACE_END