diff options
| author | mattpetersepic <[email protected]> | 2022-01-25 06:57:47 -0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-01-25 06:57:47 -0700 |
| commit | bd85a74a9d15fd676a6677fbd4d5ab4e3dcb0d42 (patch) | |
| tree | e59bd4eccbc667088e74e989f2cfbbf82c6926c0 /zenutil/include | |
| parent | Fixed unexpected abort() call when joining an unjoinable thread (diff) | |
| download | zen-bd85a74a9d15fd676a6677fbd4d5ab4e3dcb0d42.tar.xz zen-bd85a74a9d15fd676a6677fbd4d5ab4e3dcb0d42.zip | |
Cachepolicy (#36)
* Copy CachePolicy implementation from UE5/Release-5.0. Add backwards compatability for clients and upstreams that are using the old protocol.
* Add RefPtr templated move operator and constructor, so that RefPtr<const Foo*> A = std::move(RefPtr<Foo*>()) will do a move.
* Fix broken CachePolicy tests and add tests for new Save/Load.
* Remove TODO comments
* CachePolicy Save/Load Fixes from codereview
* Fix comment to match code change.
* Remove backwards compatibility for CachePolicy change. Convert policy string tokens to PascalCase. Fix tests for new policy text. Change ParseCachePolicy to assert string is non-empty and always succeed.
* Fix release build: use ZEN_WITH_TESTS define
Diffstat (limited to 'zenutil/include')
| -rw-r--r-- | zenutil/include/zenutil/cache/cachepolicy.h | 137 |
1 files changed, 101 insertions, 36 deletions
diff --git a/zenutil/include/zenutil/cache/cachepolicy.h b/zenutil/include/zenutil/cache/cachepolicy.h index 5675ccf4d..f967f707b 100644 --- a/zenutil/include/zenutil/cache/cachepolicy.h +++ b/zenutil/include/zenutil/cache/cachepolicy.h @@ -2,10 +2,14 @@ #pragma once +#include <zencore/compactbinary.h> +#include <zencore/enumflags.h> +#include <zencore/refcount.h> #include <zencore/string.h> #include <zencore/uid.h> #include <gsl/gsl-lite.hpp> +#include <span> #include <unordered_map> namespace zen { @@ -34,16 +38,21 @@ enum class CachePolicy : uint32_t /** Skip fetching the metadata for record requests. */ SkipMeta = 1 << 4, - /** Skip fetching the value for record, chunk, or value requests. */ - SkipValue = 1 << 5, - /** Skip fetching the attachments for record requests. */ - SkipAttachments = 1 << 6, + /** Skip fetching the data for values. */ + SkipData = 1 << 5, + /** - * Skip fetching the data for any requests. + * Partial output will be provided with the error status when a required value is missing. + * + * This is meant for cases when the missing values can be individually recovered, or rebuilt, + * without rebuilding the whole record. The cache automatically adds this flag when there are + * other cache stores that it may be able to recover missing values from. + * + * Missing values will be returned in the records or chunks, but with only the hash and size. * - * Put requests with skip flags may assume that record existence implies payload existence. + * Applying this flag for a put of a record allows a partial record to be stored. */ - SkipData = SkipMeta | SkipValue | SkipAttachments, + PartialRecord = 1 << 6, /** * Keep records in the cache for at least the duration of the session. @@ -53,18 +62,6 @@ enum class CachePolicy : uint32_t */ KeepAlive = 1 << 7, - /** - * Partial output will be provided with the error status when a required payload is missing. - * - * This is meant for cases when the missing payloads can be individually recovered or rebuilt - * without rebuilding the whole record. The cache automatically adds this flag when there are - * other cache stores that it may be able to recover missing payloads from. - * - * Requests for records would return records where the missing payloads have a hash and size, - * but no data. Requests for chunks or values would return the hash and size, but no data. - */ - PartialOnError = 1 << 8, - /** Allow cache requests to query and store records and values in local caches. */ Local = QueryLocal | StoreLocal, /** Allow cache requests to query and store records and values in remote caches. */ @@ -78,35 +75,103 @@ enum class CachePolicy : uint32_t }; gsl_DEFINE_ENUM_BITMASK_OPERATORS(CachePolicy); +/** Serialize Policy to text and append to Builder. Appended text will not be empty. */ +StringBuilderBase& operator<<(StringBuilderBase& Builder, CachePolicy Policy); +/** Parse text written by operator<< back into an ECachePolicy. Text must not be empty. */ +CachePolicy ParseCachePolicy(std::string_view Text); -CachePolicy ParseQueryCachePolicy(std::string_view QueryPolicy, CachePolicy Default = CachePolicy::Query); - -CachePolicy ParseStoreCachePolicy(std::string_view StorePolicy, CachePolicy Default = CachePolicy::Store); - -CachePolicy ParseSkipCachePolicy(std::string_view SkipPolicy, CachePolicy Default = CachePolicy::None); +/** A value ID and the cache policy to use for that value. */ +struct CacheValuePolicy +{ + Oid Id; + CachePolicy Policy = CachePolicy::Default; +}; +namespace Private { + /** Interface for the private implementation of the cache record policy. */ + class ICacheRecordPolicyShared : public RefCounted + { + public: + virtual ~ICacheRecordPolicyShared() = default; + virtual std::span<const CacheValuePolicy> GetValuePolicies() const = 0; + virtual void AddValuePolicy(const CacheValuePolicy& Policy) = 0; + virtual void Build() = 0; + }; +} // namespace Private + +/** + * Flags to control the behavior of cache record requests, with optional overrides by value. + * + * Examples: + * - A base policy of Disable, with value policy overrides of Default, will fetch those values if + * they exist in the record, and skip data for any other values. + * - A base policy of Default, with value policy overrides of (Query | SkipData), will skip those + * values, but still check if they exist, and will load any other values. + */ class CacheRecordPolicy { public: + /** Construct a cache record policy that uses the default policy. */ CacheRecordPolicy() = default; - CacheRecordPolicy(const CachePolicy RecordPolicy, const CachePolicy DefaultPayloadPolicy = CachePolicy::Default); - CachePolicy GetRecordPolicy() const { return m_RecordPolicy; } - CachePolicy GetPayloadPolicy(const Oid& PayloadId) const; - CachePolicy GetDefaultPayloadPolicy() const { return m_DefaultPayloadPolicy; } + /** Construct a cache record policy with a uniform policy for the record and every value. */ + inline CacheRecordPolicy(CachePolicy Policy) : RecordPolicy(Policy), DefaultValuePolicy(Policy) {} + + /** Returns true if the record and every value use the same cache policy. */ + inline bool IsUniform() const { return !Shared && RecordPolicy == DefaultValuePolicy; } - bool HasRecordPolicy(const CachePolicy Policy) const { return (m_RecordPolicy & Policy) == Policy; } - bool HasPayloadPolicy(const Oid& PayloadId, const CachePolicy Policy) const { return (GetPayloadPolicy(PayloadId) & Policy) == Policy; } + /** Returns the cache policy to use for the record. */ + inline CachePolicy GetRecordPolicy() const { return RecordPolicy; } - static bool Load(CbObjectView RecordPolicyObject, CacheRecordPolicy& OutRecordPolicy); - static void Save(const CacheRecordPolicy& Policy, CbWriter& Writer); + /** Returns the cache policy to use for the value. */ + CachePolicy GetValuePolicy(const Oid& Id) const; + + /** Returns the cache policy to use for values with no override. */ + inline CachePolicy GetDefaultValuePolicy() const { return DefaultValuePolicy; } + + /** Returns the array of cache policy overrides for values, sorted by ID. */ + inline std::span<const CacheValuePolicy> GetValuePolicies() const + { + return Shared ? Shared->GetValuePolicies() : std::span<const CacheValuePolicy>(); + } + + /** Save the values from *this into the given writer. */ + void Save(CbWriter& Writer) const; + + /** + * Returns a policy loaded from values on Object. + * Invalid data will result in a uniform CacheRecordPolicy with defaultValuePolicy == DefaultPolicy. + */ + static CacheRecordPolicy Load(CbObjectView Object, CachePolicy DefaultPolicy = CachePolicy::Default); private: - using PayloadPolicyMap = std::unordered_map<Oid, CachePolicy, Oid::Hasher>; + friend class CacheRecordPolicyBuilder; + + CachePolicy RecordPolicy = CachePolicy::Default; + CachePolicy DefaultValuePolicy = CachePolicy::Default; + RefPtr<const Private::ICacheRecordPolicyShared> Shared; +}; - CachePolicy m_RecordPolicy = CachePolicy::Default; - CachePolicy m_DefaultPayloadPolicy = CachePolicy::Default; - PayloadPolicyMap m_PayloadPolicies; +/** A cache record policy builder is used to construct a cache record policy. */ +class CacheRecordPolicyBuilder +{ +public: + /** Construct a policy builder that uses the default policy as its base policy. */ + CacheRecordPolicyBuilder() = default; + + /** Construct a policy builder that uses the provided policy for the record and values with no override. */ + inline explicit CacheRecordPolicyBuilder(CachePolicy Policy) : BasePolicy(Policy) {} + + /** Adds a cache policy override for a value. */ + void AddValuePolicy(const CacheValuePolicy& Policy); + inline void AddValuePolicy(const Oid& Id, CachePolicy Policy) { AddValuePolicy({Id, Policy}); } + + /** Build a cache record policy, which makes this builder subsequently unusable. */ + CacheRecordPolicy Build(); + +private: + CachePolicy BasePolicy = CachePolicy::Default; + RefPtr<Private::ICacheRecordPolicyShared> Shared; }; } // namespace zen |