Keep track of a bunch of objects, each with an associated time used to allow data to 'expire'. More...
#include <TimedCache.h>
Classes | |
| struct | CacheElement |
| everything here is optional ;-) But typically, its fKey, fValue, fLastRefreshedAt More... | |
Public Member Functions | |
| TimedCache () | |
| nonvirtual TimeStampDifferenceType | GetMaxAge () const |
| nonvirtual void | SetMaxAge (TimeStampDifferenceType maxAge) |
| nonvirtual Traversal::Iterable< CacheElement > | Elements () const |
| template<typename K = KEY> requires (IKeyedCache<K>) | |
| nonvirtual Traversal::Iterable< K > | Keys () const |
| template<typename K = KEY> requires (IKeyedCache<K>) | |
| nonvirtual optional< VALUE > | Lookup (typename Common::ArgByValueType< K > key) const |
| Returns the value associated with argument 'key', or nullopt, if its missing (missing same as expired). Can be used to retrieve lastRefreshedAt. | |
| template<typename K = KEY> requires (kTrackExpiration and IKeyedCache<K>) | |
| nonvirtual optional< tuple< VALUE, TimeStampType > > | LookupDetails (typename Common::ArgByValueType< K > key) const |
| Returns the value associated with argument 'key' (if IKeyedCache), or nullopt, if its missing (missing same as expired). Like Lookup but also returns expiration information. | |
| template<typename K = KEY> requires (not IKeyedCache<K>) | |
| nonvirtual optional< TimeStampType > | GetExpiration () const |
| Get the Expiration of object or nullopt of item expired/not in cache. | |
| template<typename K = KEY, Common::invocable_r< VALUE, KEY > CACHE_FILLTER_T> requires (IKeyedCache<K>) | |
| nonvirtual VALUE | LookupValue (typename Common::ArgByValueType< K > key, CACHE_FILLTER_T &&cacheFiller) |
| Lookup value, and if missing, fetch it with argument cacheFiller (and add/return its value). | |
| template<typename K = KEY> requires (IKeyedCache<K> and IValuelessCache<VALUE>) | |
| nonvirtual void | Add (typename Common::ArgByValueType< K > key) |
| template<Traversal::IIterableOfTo< KEY > ITERABLE_OF_KEY_TYPE> | |
| nonvirtual void | RetainAll (const ITERABLE_OF_KEY_TYPE &items2Keep) |
| like Mapping<>::RetainAll () - throw away all elements not in items2Keep | |
| nonvirtual void | clear () |
| nonvirtual void | ClearExpiredData () |
| template<typename K = KEY> | |
| nonvirtual optional< VALUE > | Lookup (typename Common::ArgByValueType< K > key, LookupMarksDataAsRefreshed successfulLookupRefreshesAcceesFlag) |
Static Public Attributes | |
| static constexpr bool | kTrackExpiration = TRAITS::kTrackExpiration |
| Track on a per-item when it expires. If not tracked, we use expiresAt as whenAdded + maxAge This is false by default. | |
| static constexpr bool | kTrackFreshness = TRAITS::kTrackFreshness |
| freshness means when last added/updated (or if kAutomaticallyMarkDataAsRefreshedEachTimeAccessed) then last accessed too) This is true by default | |
Keep track of a bunch of objects, each with an associated time used to allow data to 'expire'.
This expiration time is handled PRINCIPALLY, in one of two ways: kTrackExpiration: In this case, at the time the data is ADDED, a time of expiration is captured and associated with the datum.
kTrackFreshness: In this case, the time the data is Added (last-refreshed) is associated with the datum, and expiration computed later. this is the default
More about kTrackFreshness: We define 'fresheness' somewhat arbitrarily, but by default, this means since the item was added. However, the TimedCache also provides other apis to update the 'freshness' of a stored object, depending on application needs.
Keeps track of all items - indexed by Key - but throws away items which are any more stale than given by the staleness limit.
When/Why to use?: (
For example, consider a system where memory is stored across a slow bus, and several components need to read data from across that bus. But the different components have different tolerance for staleness (e.g. PID loop needs fresh temperature sensor data but GUI can use more stale data).
This CallerStalenessCache will store when the value is updated, and let the caller either return the value from cache, or fetch it and update the cache if needed.
This differs from other forms of caches in that: o It records the timestamp when a value is last-updated o It doesn't EXPIRE the data ever (except by explicit Clear or ClearOlderThan call) o The lookup caller specifies its tolerance for data staleness, and refreshes the data as needed.
To use TimedCache<> to 'own' a set of objects (say a set caches where we are the only
possible updater) - you can make the 'VALUE' type a shared_ptr<X>, and use Lookup (...,eTreatFoundThroughLookupAsRefreshed) instead
of Lookup ().
In this example, there is a set of files on disk in a folder, which is complex to analyze
but once analyzed, lots of calls come in at once to read (and maybe update) the set of files
and once nobody has asked for a while, we throw that cache away, and rebuild it as needed.
This example ALSO shows how to wrap a cache object in 'Synchronized' for thread safety.
\code
using ScanFolderKey_ = String;
static constexpr Time::DurationSeconds kAgeForScanPersistenceCache_{5 * 60.0s};
struct FolderDetails_ {
int size; // ...info to cache about a folder
};
Synchronized<Cache::TimedCache<
ScanFolderKey_,
shared_ptr<FolderDetails_>,
shared_ptr<FolderDetails_>>>
sCachedScanFoldersDetails_{kAgeForScanPersistenceCache_};
shared_ptr<FolderDetails_> AccessFolder_ (const ScanFolderKey_& folder)
{
auto lockedCache = sCachedScanFoldersDetails_.rwget ();
if (optional<shared_ptr<FolderDetails_>> o = lockedCache->Lookup (folder, eTreatFoundThroughLookupAsRefreshed)) {
return *o;
}
else {
shared_ptr<FolderDetails_> fd = MakeSharedPtr<FolderDetails_> (); // and fill in default values looking at disk
lockedCache->Add (folder, fd);
return fd;
}
}
void DoIt ()
{
auto f1 = AccessFolder_ ("folder1"_k);
auto f2 = AccessFolder_ ("folder2"_k);
auto f1again = AccessFolder_ ("folder1"); // if you trace through the debug code you'll see this is a cache hit
}
\endcode
Definition at line 572 of file TimedCache.h.
| Stroika::Foundation::Cache::TimedCache< KEY, VALUE, TRAITS >::TimedCache | ( | ) |
Note that TimedCache is copyable and moveable by value.
It MAYBE default constructible (if there is a kDefaultMaxAge - defaults to true).
Definition at line 44 of file TimedCache.inl.
| auto Stroika::Foundation::Cache::TimedCache< KEY, VALUE, TRAITS >::GetMaxAge | ( | ) | const |
When items are added to the timed cache, there is a universal (for the entire cache) minimum allowed freshness (how old item allowed to be before thrown away).
\alias Note - 'allowed freshness' == 'time to live' == 'TTL'. GetMinimumFreshness, GetTimeout, TTL, GetDefaultMaxAge ().
So an item added 30 seconds ago (freshness = 30s), would be thrown away/not returned as part of the cache if the minimum allowed freshness was 5 seconds.
Definition at line 123 of file TimedCache.inl.
| void Stroika::Foundation::Cache::TimedCache< KEY, VALUE, TRAITS >::SetMaxAge | ( | TimeStampDifferenceType | maxAge | ) |
Definition at line 134 of file TimedCache.inl.
| auto Stroika::Foundation::Cache::TimedCache< KEY, VALUE, TRAITS >::Elements | ( | ) | const |
@todo could use overload taking TTL argumnet (if track freshness)
Definition at line 145 of file TimedCache.inl.
| nonvirtual Traversal::Iterable< K > Stroika::Foundation::Cache::TimedCache< KEY, VALUE, TRAITS >::Keys | ( | ) | const |
@todo could use overload taking TTL argumnet (if track freshness)
| nonvirtual optional< VALUE > Stroika::Foundation::Cache::TimedCache< KEY, VALUE, TRAITS >::Lookup | ( | typename Common::ArgByValueType< K > | key | ) | const |
Returns the value associated with argument 'key', or nullopt, if its missing (missing same as expired). Can be used to retrieve lastRefreshedAt.
Occasionally, a caller might want to ASSURE it gets data, and just use the cached value if fresh enuf, and specify a lookup lambda to fetch the actual data if its not fresh, in which case call LookupValue ().
| nonvirtual optional< tuple< VALUE, TimeStampType > > Stroika::Foundation::Cache::TimedCache< KEY, VALUE, TRAITS >::LookupDetails | ( | typename Common::ArgByValueType< K > | key | ) | const |
Returns the value associated with argument 'key' (if IKeyedCache), or nullopt, if its missing (missing same as expired). Like Lookup but also returns expiration information.
Occasionally, a caller might want to ASSURE it gets data, and just use the cached value if fresh enuf, and specify a lookup lambda to fetch the actual data if its not fresh, in which case call LookupValue ().
| nonvirtual optional< TimeStampType > Stroika::Foundation::Cache::TimedCache< KEY, VALUE, TRAITS >::GetExpiration | ( | ) | const |
Get the Expiration of object or nullopt of item expired/not in cache.
in the case of IKeyedCache, it returns the expiration of the given key (or nullopt if not present or expired). in the case of NOT IKeyedCache, it refers to the single cached item, but otherwise acts the same.
| nonvirtual VALUE Stroika::Foundation::Cache::TimedCache< KEY, VALUE, TRAITS >::LookupValue | ( | typename Common::ArgByValueType< K > | key, |
| CACHE_FILLTER_T && | cacheFiller | ||
| ) |
Lookup value, and if missing, fetch it with argument cacheFiller (and add/return its value).
This operates as if: if (auto ov = Lookup (key)) { return *ov; } else { VALUE r = cacheFiller(); Add (r); return r; }
Usually one will use this as:
| nonvirtual void Stroika::Foundation::Cache::TimedCache< KEY, VALUE, TRAITS >::Add | ( | typename Common::ArgByValueType< K > | key | ) |
Adds/Updates the given value associated with key. if kTrackFreshness (the default) o The new items freshness is TRAITS::GetCurrentTimestamp (), or the value given as argument if kTrackExpiration o The new item's expiration is either given by expiresAt or now+ttl, or defaults to GetMaxAge()
| void Stroika::Foundation::Cache::TimedCache< KEY, VALUE, TRAITS >::clear | ( | ) |
Remove everything from the cache
Definition at line 769 of file TimedCache.inl.
| void Stroika::Foundation::Cache::TimedCache< KEY, VALUE, TRAITS >::ClearExpiredData | ( | ) |
May be called occasionally to free resources used by cached items that are out of date. Not necessary to call - but can save memory.
Can be triggered automatically - see TRAITS::kAutomaticPurgeFrequency
Definition at line 775 of file TimedCache.inl.
| nonvirtual optional< VALUE > Stroika::Foundation::Cache::TimedCache< KEY, VALUE, TRAITS >::Lookup | ( | typename Common::ArgByValueType< K > | key, |
| LookupMarksDataAsRefreshed | successfulLookupRefreshesAcceesFlag | ||
| ) |
Before Stroika 3.0d1, we used to remove the entry from the list (an optimization). But that required Lookup to be non-const (with synchronization in mind probably a pessimization). So instead, count on PurgeUnusedData being called automatically on future adds, explicit user calls to purge unused data.
i = fData_.erase (i);
Definition at line 974 of file TimedCache.h.
|
staticconstexpr |
Track on a per-item when it expires. If not tracked, we use expiresAt as whenAdded + maxAge This is false by default.
Definition at line 593 of file TimedCache.h.
|
staticconstexpr |
freshness means when last added/updated (or if kAutomaticallyMarkDataAsRefreshedEachTimeAccessed) then last accessed too) This is true by default
Definition at line 602 of file TimedCache.h.