aboutsummaryrefslogtreecommitdiff
path: root/zenutil/include
diff options
context:
space:
mode:
authormattpetersepic <[email protected]>2022-01-25 06:57:47 -0700
committerGitHub <[email protected]>2022-01-25 06:57:47 -0700
commitbd85a74a9d15fd676a6677fbd4d5ab4e3dcb0d42 (patch)
treee59bd4eccbc667088e74e989f2cfbbf82c6926c0 /zenutil/include
parentFixed unexpected abort() call when joining an unjoinable thread (diff)
downloadzen-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.h137
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