diff --git a/src/xrpld/app/ledger/LedgerHistory.cpp b/src/xrpld/app/ledger/LedgerHistory.cpp index ccec209bd4..466b7d7063 100644 --- a/src/xrpld/app/ledger/LedgerHistory.cpp +++ b/src/xrpld/app/ledger/LedgerHistory.cpp @@ -27,8 +27,6 @@ namespace ripple { -// FIXME: Need to clean up ledgers by index at some point - LedgerHistory::LedgerHistory( beast::insight::Collector::ptr const& collector, Application& app) @@ -47,6 +45,7 @@ LedgerHistory::LedgerHistory( std::chrono::minutes{5}, stopwatch(), app_.journal("TaggedCache")) + , mLedgersByIndex(256) , j_(app.journal("LedgerHistory")) { } @@ -68,7 +67,13 @@ LedgerHistory::insert( bool const alreadyHad = m_ledgers_by_hash.canonicalize_replace_cache( ledger->info().hash, ledger); if (validated) + { mLedgersByIndex[ledger->info().seq] = ledger->info().hash; + JLOG(j_.info()) << "LedgerHistory::insert: mLedgersByIndex size: " + << mLedgersByIndex.size() << " , total size: " + << mLedgersByIndex.size() * + (sizeof(LedgerIndex) + sizeof(LedgerHash)); + } return alreadyHad; } @@ -115,6 +120,11 @@ LedgerHistory::getLedgerBySeq(LedgerIndex index) "ripple::LedgerHistory::getLedgerBySeq : immutable result ledger"); m_ledgers_by_hash.canonicalize_replace_client(ret->info().hash, ret); mLedgersByIndex[ret->info().seq] = ret->info().hash; + JLOG(j_.info()) + << "LedgerHistory::getLedgerBySeq: mLedgersByIndex size: " + << mLedgersByIndex.size() << " , total size: " + << mLedgersByIndex.size() * + (sizeof(LedgerIndex) + sizeof(LedgerHash)); return (ret->info().seq == index) ? ret : nullptr; } } diff --git a/src/xrpld/app/ledger/LedgerHistory.h b/src/xrpld/app/ledger/LedgerHistory.h index 33f8bf1d96..b1acc3cb2e 100644 --- a/src/xrpld/app/ledger/LedgerHistory.h +++ b/src/xrpld/app/ledger/LedgerHistory.h @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -149,7 +150,7 @@ private: ConsensusValidated m_consensus_validated; // Maps ledger indexes to the corresponding hash. - std::map mLedgersByIndex; // validated ledgers + LRUMap mLedgersByIndex; // validated ledgers beast::Journal j_; }; diff --git a/src/xrpld/core/detail/LRUMap.h b/src/xrpld/core/detail/LRUMap.h new file mode 100644 index 0000000000..45e9a6b028 --- /dev/null +++ b/src/xrpld/core/detail/LRUMap.h @@ -0,0 +1,147 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_APP_LRU_MAP_H_INCLUDED +#define RIPPLE_APP_LRU_MAP_H_INCLUDED + +#include +#include +#include + +namespace ripple { + +template +class LRUMap +{ +public: + explicit LRUMap(std::size_t capacity) : capacity_(capacity) + { + // TODO: check capacity_ > 0 + } + + Value& + operator[](Key const& key) + { + auto it = data_.find(key); + if (it != data_.end()) + { + bump_to_front(key); + return it->second; + } + if (data_.size() >= capacity_) + { + Key const& lru = usage_list_.back(); + usage_list_.pop_back(); + data_.erase(lru); + } + usage_list_.push_front(key); + return data_[key]; + } + + auto + find(Key const& key) + { + return data_.find(key); + } + auto + find(Key const& key) const + { + return data_.find(key); + } + + auto + begin() + { + return data_.begin(); + } + auto + begin() const + { + return data_.begin(); + } + auto + end() + { + return data_.end(); + } + auto + end() const + { + return data_.end(); + } + + bool + erase(Key const& key) + { + auto it = data_.find(key); + if (it == data_.end()) + return false; + for (auto list_it = usage_list_.begin(); list_it != usage_list_.end(); + ++list_it) + { + if (*list_it == key) + { + usage_list_.erase(list_it); + break; + } + } + data_.erase(it); + return true; + } + + std::size_t + size() const noexcept + { + return data_.size(); + } + std::size_t + capacity() const noexcept + { + return capacity_; + } + void + clear() + { + data_.clear(); + usage_list_.clear(); + } + +private: + void + bump_to_front(Key const& key) + { + for (auto it = usage_list_.begin(); it != usage_list_.end(); ++it) + { + if (*it == key) + { + usage_list_.erase(it); + usage_list_.push_front(key); + return; + } + } + } + + std::size_t capacity_; + std::map data_; + std::list usage_list_; +}; + +} // namespace ripple + +#endif \ No newline at end of file