Haio
0.2.X
Homebrew Asset IO/CDN
Toggle main menu visibility
Loading...
Searching...
No Matches
haio_cache.hpp
Go to the documentation of this file.
1
#pragma once
2
3
#include "
haio.hpp
"
4
5
#include <boost/asio/any_io_executor.hpp>
6
#include <boost/asio/awaitable.hpp>
7
8
#include <chrono>
9
#include <filesystem>
10
#include <functional>
11
#include <memory>
12
#include <optional>
13
#include <span>
14
#include <string>
15
16
namespace
Haio::Cdn
{
17
18
/**
19
* what the cache holds is a finished response, not an image: the work being saved is
20
* the fetch and the whole conversion behind it, so replaying an entry costs a copy.
21
*/
22
struct
CacheEntry
{
23
std::vector<uint8_t>
data
;
24
std::string
contentType
;
25
std::string
filename
;
26
};
27
28
struct
CacheConfig
{
29
std::chrono::seconds
ttl
{0};
// zero leaves the cache off
30
size_t
maxUsage
= 64u << 20;
// bytes the store may hold, whichever store it is
31
std::string
url
;
// empty keeps entries in this process
32
};
33
34
/**
35
* a backend is chosen at runtime from the scheme of the url, which is why this is a
36
* virtual interface rather than a concept the way the codecs do it: the answer is in
37
* a config file, not in the build.
38
*/
39
class
CacheStore
{
40
public
:
41
virtual
~CacheStore
() =
default
;
42
/**
43
* a hit renews the entry's ttl, so what is being asked for keeps living and what
44
* nobody wants ages out. the window is therefore since the last read, not since
45
* the write: a popular creative is never rebuilt on a clock.
46
*/
47
virtual
boost::asio::awaitable<std::optional<CacheEntry>>
get
(
const
std::string& key) = 0;
48
virtual
boost::asio::awaitable<void>
put
(
const
std::string& key,
const
CacheEntry
& entry) = 0;
49
};
50
51
/**
52
* the md5 of the bucket, the path and the query, in the order they were written.
53
*
54
* the query is not sorted, and must not be: it spells out a pipeline, so crop before
55
* resize is a different picture from resize before crop. sorting would collide two
56
* different requests onto one entry and serve the wrong image, which is a worse fault
57
* than keeping two entries for one answer. the method is left out so a HEAD finds
58
* what a GET stored.
59
*/
60
std::string
cacheKey
(std::string_view bucket, std::string_view path, std::string_view query);
61
62
/** the framing the file and redis backends share; the memory one keeps the struct */
63
std::vector<uint8_t>
encodeEntry
(
const
CacheEntry
& entry);
64
std::optional<CacheEntry>
decodeEntry
(std::span<const uint8_t> raw);
65
66
std::unique_ptr<CacheStore>
makeMemoryStore
(
size_t
maxUsage, std::chrono::seconds ttl);
67
std::unique_ptr<CacheStore>
makeFileStore
(std::filesystem::path root, std::chrono::seconds ttl,
size_t
maxUsage);
68
std::unique_ptr<CacheStore>
makeRedisStore
(std::string url, std::chrono::seconds ttl,
size_t
maxUsage, boost::asio::any_io_executor executor);
69
70
/**
71
* the store, plus the part that keeps one key from being produced many times at once.
72
*
73
* the two are independent on purpose: deduplication needs no store and stays on even
74
* when no cache is configured, because a burst on one key sending one upstream
75
* request per caller is an amplifier whether or not the answer is kept afterwards.
76
*/
77
class
Cache
{
78
public
:
79
using
Producer
= std::function<boost::asio::awaitable<Result<CacheEntry>>()>;
80
81
Cache
() =
default
;
82
/**
83
* maxEntriesByIp is spelled in [security] rather than in [cache], because it is a
84
* limit on a caller and not on the store. it is passed rather than copied into
85
* CacheConfig so that the number lives in exactly one place.
86
*/
87
Cache
(
CacheConfig
config,
size_t
maxEntriesByIp, boost::asio::any_io_executor executor);
88
89
/** true when entries are kept; deduplication happens either way */
90
bool
enabled
()
const
;
91
92
/**
93
* returns the stored entry, or runs the producer once and stores what it made.
94
*
95
* client is the address the request came from, and it is only used to decide
96
* whether the result may be stored. reading is always free: the limit is there to
97
* stop one caller from filling the cache with keys nobody else will ask for, and
98
* evicting everyone else's entries on the way.
99
*/
100
boost::asio::awaitable<Result<CacheEntry>>
fetch
(std::string key, std::string client,
Producer
produce);
101
102
private
:
103
struct
Impl
;
104
std::shared_ptr<Impl> impl_;
105
};
106
107
}
Haio::Cdn::CacheStore
Definition
haio_cache.hpp:39
Haio::Cdn::CacheStore::~CacheStore
virtual ~CacheStore()=default
Haio::Cdn::CacheStore::get
virtual boost::asio::awaitable< std::optional< CacheEntry > > get(const std::string &key)=0
Haio::Cdn::CacheStore::put
virtual boost::asio::awaitable< void > put(const std::string &key, const CacheEntry &entry)=0
Haio::Cdn::Cache::fetch
boost::asio::awaitable< Result< CacheEntry > > fetch(std::string key, std::string client, Producer produce)
Definition
cache.cpp:59
Haio::Cdn::Cache::Producer
std::function< boost::asio::awaitable< Result< CacheEntry > >()> Producer
Definition
haio_cache.hpp:79
Haio::Cdn::Cache::enabled
bool enabled() const
Definition
cache.cpp:55
Haio::Cdn::Cache::Cache
Cache()=default
haio.hpp
Haio::Cdn
Definition
haio_cache.hpp:16
Haio::Cdn::decodeEntry
std::optional< CacheEntry > decodeEntry(std::span< const uint8_t > raw)
Definition
key.cpp:58
Haio::Cdn::CacheEntry::data
std::vector< uint8_t > data
Definition
haio_cache.hpp:23
Haio::Cdn::CacheEntry::contentType
std::string contentType
Definition
haio_cache.hpp:24
Haio::Cdn::CacheEntry::filename
std::string filename
Definition
haio_cache.hpp:25
Haio::Cdn::encodeEntry
std::vector< uint8_t > encodeEntry(const CacheEntry &entry)
Definition
key.cpp:45
Haio::Cdn::makeMemoryStore
std::unique_ptr< CacheStore > makeMemoryStore(size_t maxUsage, std::chrono::seconds ttl)
Definition
memory.cpp:87
Haio::Cdn::makeRedisStore
std::unique_ptr< CacheStore > makeRedisStore(std::string url, std::chrono::seconds ttl, size_t maxUsage, boost::asio::any_io_executor executor)
Haio::Cdn::cacheKey
std::string cacheKey(std::string_view bucket, std::string_view path, std::string_view query)
Definition
key.cpp:34
Haio::Cdn::CacheConfig::maxUsage
size_t maxUsage
Definition
haio_cache.hpp:30
Haio::Cdn::makeFileStore
std::unique_ptr< CacheStore > makeFileStore(std::filesystem::path root, std::chrono::seconds ttl, size_t maxUsage)
Definition
file.cpp:171
Haio::Cdn::CacheConfig::ttl
std::chrono::seconds ttl
Definition
haio_cache.hpp:29
Haio::Cdn::CacheConfig::url
std::string url
Definition
haio_cache.hpp:31
Haio::Cdn::CacheConfig
Definition
haio_cache.hpp:28
Haio::Cdn::CacheEntry
Definition
haio_cache.hpp:22
Haio::Cdn::Cache::Impl
Definition
cache.cpp:13
include
haio_cache.hpp
Generated by
1.18.0