driver/sliding_expiration_cache.h (84 lines of code) (raw):
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License, version 2.0
// (GPLv2), as published by the Free Software Foundation, with the
// following additional permissions:
//
// This program is distributed with certain software that is licensed
// under separate terms, as designated in a particular file or component
// or in the license documentation. Without limiting your rights under
// the GPLv2, the authors of this program hereby grant you an additional
// permission to link the program and your derivative works with the
// separately licensed software that they have included with the program.
//
// Without limiting the foregoing grant of rights under the GPLv2 and
// additional permission as to separately licensed software, this
// program is also subject to the Universal FOSS Exception, version 1.0,
// a copy of which can be found along with its FAQ at
// http://oss.oracle.com/licenses/universal-foss-exception.
//
// 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, version 2.0, for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see
// http://www.gnu.org/licenses/gpl-2.0.html.
#ifndef __SLIDING_EXPIRATION_CACHE__
#define __SLIDING_EXPIRATION_CACHE__
#include <atomic>
#include <chrono>
#include <functional>
#include <memory>
#include <unordered_map>
template <class T>
class SHOULD_DISPOSE_FUNC {
public:
virtual ~SHOULD_DISPOSE_FUNC() = default;
virtual bool should_dispose(T item) { return true; };
};
template <class T>
class ITEM_DISPOSAL_FUNC {
public:
virtual ~ITEM_DISPOSAL_FUNC() = default;
virtual void dispose(T item) {/* Do nothing. */};
};
template <class K, class V>
class SLIDING_EXPIRATION_CACHE {
public:
class CACHE_ITEM {
public:
CACHE_ITEM() = default;
CACHE_ITEM(V item, std::chrono::steady_clock::time_point expiration_time)
: item(item), expiration_time(expiration_time){};
~CACHE_ITEM() = default;
V item;
CACHE_ITEM* with_extend_expiration(long long item_expiration_nanos) {
this->expiration_time = std::chrono::steady_clock::now() + std::chrono::nanoseconds(item_expiration_nanos);
return this;
}
bool should_clean_up(std::shared_ptr<SHOULD_DISPOSE_FUNC<V>> should_dispose_func) {
if (should_dispose_func != nullptr) {
return std::chrono::steady_clock::now() > this->expiration_time &&
should_dispose_func->should_dispose(this->item);
}
return std::chrono::steady_clock::now() > this->expiration_time;
}
private:
std::chrono::steady_clock::time_point expiration_time;
};
SLIDING_EXPIRATION_CACHE() {
this->should_dispose_func = nullptr;
this->item_disposal_func = nullptr;
}
SLIDING_EXPIRATION_CACHE(std::shared_ptr<SHOULD_DISPOSE_FUNC<V>> should_dispose_func,
std::shared_ptr<ITEM_DISPOSAL_FUNC<V>> item_disposal_func)
: should_dispose_func(should_dispose_func), item_disposal_func(item_disposal_func){};
SLIDING_EXPIRATION_CACHE(std::shared_ptr<SHOULD_DISPOSE_FUNC<V>> should_dispose_func,
std::shared_ptr<ITEM_DISPOSAL_FUNC<V>> item_disposal_func, long long clean_up_interval_nanos)
: clean_up_interval_nanos(clean_up_interval_nanos),
should_dispose_func(std::move(should_dispose_func)),
item_disposal_func(std::move(item_disposal_func)){};
V compute_if_absent(K key, std::function<V(K)> mapping_function, long long item_expiration_nanos);
V put(K key, V value, long long item_expiration_nanos);
V get(K key, long long item_expiration_nanos, V default_value);
void remove(K key);
/**
* Remove and dispose of all entries in the cache.
*/
void clear();
/**
* Get a map copy of all entries in the cache, including expired entries.
*/
std::unordered_map<K, V> get_entries();
/**
* Get the current size of the cache, including expired entries.
*/
int size();
/**
* Set the cleanup interval for the cache. At cleanup time, expired entries marked for cleanup via
* ShouldDisposeFunc (if defined) are disposed.
*/
void set_clean_up_interval_nanos(long long clean_up_interval_nanos);
protected:
std::unordered_map<K, std::shared_ptr<CACHE_ITEM>> cache;
long long clean_up_interval_nanos = 6000000000; // 1 minutes
std::atomic<std::chrono::steady_clock::time_point> clean_up_time_nanos;
std::shared_ptr<SHOULD_DISPOSE_FUNC<V>> should_dispose_func;
std::shared_ptr<ITEM_DISPOSAL_FUNC<V>> item_disposal_func;
void remove_and_dispose(K key);
void remove_if_expired(K key) {
if (this->cache.count(key)) {
std::shared_ptr<CACHE_ITEM> cache_item = this->cache[key];
if (cache_item != nullptr && cache_item->should_clean_up(this->should_dispose_func)) {
if (item_disposal_func != nullptr) {
item_disposal_func->dispose(cache_item->item);
}
this->cache.erase(key);
}
}
}
void clean_up();
};
#endif