github.com/igggame/nebulas-go@v2.1.0+incompatible/nbre/util/lru_cache.h (about)

     1  // Copyright (C) 2018 go-nebulas authors
     2  //
     3  // This file is part of the go-nebulas library.
     4  //
     5  // the go-nebulas library is free software: you can redistribute it and/or
     6  // modify
     7  // it under the terms of the GNU General Public License as published by
     8  // the Free Software Foundation, either version 3 of the License, or
     9  // (at your option) any later version.
    10  //
    11  // the go-nebulas library is distributed in the hope that it will be useful,
    12  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  // GNU General Public License for more details.
    15  //
    16  // You should have received a copy of the GNU General Public License
    17  // along with the go-nebulas library.  If not, see
    18  // <http://www.gnu.org/licenses/>.
    19  //
    20  
    21  #pragma once
    22  
    23  #include "common/common.h"
    24  #include <atomic>
    25  #include <list>
    26  #include <mutex>
    27  #include <thread>
    28  
    29  namespace neb {
    30  namespace util {
    31  
    32  template <class Key, class Value, class Lock = std::mutex,
    33            int32_t CacheCleanPeriod = 1, int32_t CacheCleanCounter = 64>
    34  class lru_cache {
    35  public:
    36    typedef std::unordered_map<Key, Value> map_t;
    37    typedef Lock lock_t;
    38    using guard_t = std::lock_guard<lock_t>;
    39  
    40    lru_cache() : m_thread_exit_flag(0) {
    41      m_thread = std::make_unique<std::thread>([&]() {
    42        while (!m_thread_exit_flag) {
    43          decrease_counter_and_clean_cache();
    44          std::this_thread::sleep_for(std::chrono::seconds(CacheCleanPeriod));
    45        }
    46      });
    47    }
    48    virtual ~lru_cache() {
    49      m_thread_exit_flag = 1;
    50      m_thread->join();
    51    };
    52  
    53    size_t size() const {
    54      guard_t __l(m_lock);
    55      return m_cache_map.size();
    56    }
    57  
    58    bool empty() const {
    59      guard_t __l(m_lock);
    60      return m_cache_map.empty();
    61    }
    62  
    63    void clear() {
    64      guard_t __l(m_lock);
    65      m_cache_map.clear();
    66      m_counter.clear();
    67    }
    68  
    69    void set(const Key &k, const Value &v) {
    70      guard_t __l(m_lock);
    71      const auto iter = m_cache_map.find(k);
    72      if (iter != m_cache_map.end()) {
    73        return;
    74      }
    75  
    76      m_cache_map[k] = v;
    77      m_counter[k] = CacheCleanCounter;
    78    }
    79  
    80    bool get(const Key &k, Value &v) {
    81      guard_t __l(m_lock);
    82      const auto iter = m_cache_map.find(k);
    83      if (iter == m_cache_map.end()) {
    84        return false;
    85      }
    86      v = iter->second;
    87      m_counter[k] = CacheCleanCounter;
    88  
    89      return true;
    90    }
    91  
    92    bool exists(const Key &k) const {
    93      guard_t __l(m_lock);
    94      return m_cache_map.find(k) != m_cache_map.end();
    95    }
    96  
    97    template <typename F> void watch(F &&f) const {
    98      guard_t __l(m_lock);
    99      std::for_each(
   100          m_cache_map.begin(), m_cache_map.end(),
   101          [&f](const std::pair<Key, Value> &it) { f(it.first, it.second); });
   102    }
   103  
   104  protected:
   105    void decrease_counter_and_clean_cache() {
   106      guard_t __l(m_lock);
   107      std::unordered_set<Key> to_remove_sets;
   108      for (auto it = m_counter.begin(); it != m_counter.end(); ++it) {
   109        it->second--;
   110        if (it->second <= 0) {
   111          to_remove_sets.insert(it->first);
   112        }
   113      }
   114      for (auto key : to_remove_sets) {
   115        m_cache_map.erase(key);
   116        m_counter.erase(key);
   117      }
   118    }
   119  
   120  private:
   121    mutable Lock m_lock;
   122    map_t m_cache_map;
   123    std::unordered_map<Key, int32_t> m_counter;
   124    std::unique_ptr<std::thread> m_thread;
   125    std::atomic_int m_thread_exit_flag;
   126  };
   127  } // namespace util
   128  } // namespace neb