Haio 0.2.X
Homebrew Asset IO/CDN
Loading...
Searching...
No Matches
memory.cpp
Go to the documentation of this file.
1#include <haio_cache.hpp>
2
3#include <boost/asio/use_awaitable.hpp>
4
5#include <chrono>
6#include <list>
7#include <unordered_map>
8
9namespace asio = boost::asio;
10
11namespace {
12
13using Clock = std::chrono::steady_clock;
14
15/**
16 * least recently used, bounded by the total size of the bodies it holds. the bound is
17 * on bytes rather than on entries because one creative can be a thousand times the
18 * size of another, and a count would let a handful of them take the whole box.
19 */
20class MemoryStore final : public Haio::Cdn::CacheStore {
21public:
22 MemoryStore(size_t maxUsage, std::chrono::seconds ttl) : maxUsage_(maxUsage), ttl_(ttl) {}
23
24 asio::awaitable<std::optional<Haio::Cdn::CacheEntry>> get(const std::string& key) override {
25 const auto found = index_.find(key);
26 if (found == index_.end()) co_return std::nullopt;
27
28 if (Clock::now() >= found->second->storedUntil) {
29 drop(found);
30 co_return std::nullopt;
31 }
32
33 // a hit is both a promotion and a renewal: asking for something keeps it
34 order_.splice(order_.begin(), order_, found->second);
35 found->second->storedUntil = Clock::now() + ttl_;
36 co_return found->second->entry;
37 }
38
39 asio::awaitable<void> put(const std::string& key, const Haio::Cdn::CacheEntry& entry) override {
40 const auto size = sizeOf(entry);
41 if (size > maxUsage_) co_return; // one entry that cannot fit never evicts the rest
42
43 if (const auto found = index_.find(key); found != index_.end()) drop(found);
44
45 order_.push_front(Node{key, entry, Clock::now() + ttl_, size});
46 index_.emplace(key, order_.begin());
47 held_ += size;
48
49 while (held_ > maxUsage_ && !order_.empty()) {
50 const auto last = std::prev(order_.end());
51 held_ -= last->size;
52 index_.erase(last->key);
53 order_.erase(last);
54 }
55 co_return;
56 }
57
58private:
59 struct Node {
60 std::string key;
61 Haio::Cdn::CacheEntry entry;
62 Clock::time_point storedUntil;
63 size_t size = 0;
64 };
65
66 static size_t sizeOf(const Haio::Cdn::CacheEntry& entry) {
67 return entry.data.size() + entry.contentType.size() + entry.filename.size();
68 }
69
70 void drop(std::unordered_map<std::string, std::list<Node>::iterator>::iterator found) {
71 held_ -= found->second->size;
72 order_.erase(found->second);
73 index_.erase(found);
74 }
75
76 size_t maxUsage_;
77 std::chrono::seconds ttl_;
78 size_t held_ = 0;
79 std::list<Node> order_;
80 std::unordered_map<std::string, std::list<Node>::iterator> index_;
81};
82
83}
84
85namespace Haio::Cdn {
86
87std::unique_ptr<CacheStore> makeMemoryStore(size_t maxUsage, std::chrono::seconds ttl) {
88 return std::make_unique<MemoryStore>(maxUsage, ttl);
89}
90
91}
std::vector< uint8_t > data
std::string contentType
std::unique_ptr< CacheStore > makeMemoryStore(size_t maxUsage, std::chrono::seconds ttl)
Definition memory.cpp:87
Result< size_t > sizeOf(Color color, Size size)
Definition sizes.cpp:6