diff options
| author | Per Larsson <[email protected]> | 2022-01-28 13:07:36 +0100 |
|---|---|---|
| committer | Per Larsson <[email protected]> | 2022-01-28 13:07:36 +0100 |
| commit | bd43839e042425d72b584b33c7dbb86dabc95e12 (patch) | |
| tree | 1e663395ac626f3863ef92e95952b3c4245abf76 /zenutil | |
| parent | Get access token from auth mgr. (diff) | |
| parent | Compile fix (diff) | |
| download | zen-bd43839e042425d72b584b33c7dbb86dabc95e12.tar.xz zen-bd43839e042425d72b584b33c7dbb86dabc95e12.zip | |
Merged main.
Diffstat (limited to 'zenutil')
| -rw-r--r-- | zenutil/cache/cachepolicy.cpp | 299 | ||||
| -rw-r--r-- | zenutil/include/zenutil/cache/cachekey.h | 6 | ||||
| -rw-r--r-- | zenutil/include/zenutil/cache/cachepolicy.h | 141 | ||||
| -rw-r--r-- | zenutil/include/zenutil/zenserverprocess.h | 9 | ||||
| -rw-r--r-- | zenutil/zenserverprocess.cpp | 28 |
5 files changed, 322 insertions, 161 deletions
diff --git a/zenutil/cache/cachepolicy.cpp b/zenutil/cache/cachepolicy.cpp index e1c31d885..3bf7a0c67 100644 --- a/zenutil/cache/cachepolicy.cpp +++ b/zenutil/cache/cachepolicy.cpp @@ -4,64 +4,115 @@ #include <zencore/compactbinary.h> #include <zencore/compactbinarybuilder.h> +#include <zencore/enumflags.h> #include <zencore/string.h> +#include <algorithm> +#include <unordered_map> + namespace zen { using namespace std::literals; -namespace detail { namespace cacheopt { - constexpr std::string_view Local = "local"sv; - constexpr std::string_view Remote = "remote"sv; - constexpr std::string_view Data = "data"sv; - constexpr std::string_view Meta = "meta"sv; - constexpr std::string_view Value = "value"sv; - constexpr std::string_view Attachments = "attachments"sv; -}} // namespace detail::cacheopt +namespace detail::CachePolicyImpl { + constexpr char DelimiterChar = ','; + constexpr std::string_view None = "None"sv; + constexpr std::string_view QueryLocal = "QueryLocal"sv; + constexpr std::string_view QueryRemote = "QueryRemote"sv; + constexpr std::string_view Query = "Query"sv; + constexpr std::string_view StoreLocal = "StoreLocal"sv; + constexpr std::string_view StoreRemote = "StoreRemote"sv; + constexpr std::string_view Store = "Store"sv; + constexpr std::string_view SkipMeta = "SkipMeta"sv; + constexpr std::string_view SkipData = "SkipData"sv; + constexpr std::string_view PartialRecord = "PartialRecord"sv; + constexpr std::string_view KeepAlive = "KeepAlive"sv; + constexpr std::string_view Local = "Local"sv; + constexpr std::string_view Remote = "Remote"sv; + constexpr std::string_view Default = "Default"sv; + constexpr std::string_view Disable = "Disable"sv; -CachePolicy -ParseQueryCachePolicy(std::string_view QueryPolicy, CachePolicy Default) -{ - if (QueryPolicy.empty()) - { - return Default; - } + using TextToPolicyMap = std::unordered_map<std::string_view, CachePolicy>; + const TextToPolicyMap TextToPolicy = {{None, CachePolicy::None}, + {QueryLocal, CachePolicy::QueryLocal}, + {QueryRemote, CachePolicy::QueryRemote}, + {Query, CachePolicy::Query}, + {StoreLocal, CachePolicy::StoreLocal}, + {StoreRemote, CachePolicy::StoreRemote}, + {Store, CachePolicy::Store}, + {SkipMeta, CachePolicy::SkipMeta}, + {SkipData, CachePolicy::SkipData}, + {PartialRecord, CachePolicy::PartialRecord}, + {KeepAlive, CachePolicy::KeepAlive}, + {Local, CachePolicy::Local}, + {Remote, CachePolicy::Remote}, + {Default, CachePolicy::Default}, + {Disable, CachePolicy::Disable}}; - CachePolicy Result = CachePolicy::None; + using PolicyTextPair = std::pair<CachePolicy, std::string_view>; + const PolicyTextPair FlagsToString[]{ + // Order of these Flags is important: we want the aliases before the atomic values, + // and the bigger aliases first, to reduce the number of tokens we add + {CachePolicy::Default, Default}, + {CachePolicy::Remote, Remote}, + {CachePolicy::Local, Local}, + {CachePolicy::Store, Store}, + {CachePolicy::Query, Query}, - ForEachStrTok(QueryPolicy, ',', [&Result](const std::string_view& Token) { - if (Token == detail::cacheopt::Local) - { - Result |= CachePolicy::QueryLocal; - } - if (Token == detail::cacheopt::Remote) + // Order of Atomics doesn't matter, so arbitrarily we list them in enum order + {CachePolicy::QueryLocal, QueryLocal}, + {CachePolicy::QueryRemote, QueryRemote}, + {CachePolicy::StoreLocal, StoreLocal}, + {CachePolicy::StoreRemote, StoreRemote}, + {CachePolicy::SkipMeta, SkipMeta}, + {CachePolicy::SkipData, SkipData}, + {CachePolicy::PartialRecord, PartialRecord}, + {CachePolicy::KeepAlive, KeepAlive}, + + // None must come at the end of the array, to write out only if no others exist + {CachePolicy::None, None}, + }; + constexpr CachePolicy KnownFlags = + CachePolicy::Default | CachePolicy::SkipMeta | CachePolicy::SkipData | CachePolicy::KeepAlive | CachePolicy::PartialRecord; +} // namespace detail::CachePolicyImpl + +StringBuilderBase& +AppendToBuilderImpl(StringBuilderBase& Builder, CachePolicy Policy) +{ + // Remove any bits we don't recognize; write None if there are not any bits we recognize + Policy = Policy & detail::CachePolicyImpl::KnownFlags; + for (const detail::CachePolicyImpl::PolicyTextPair& Pair : detail::CachePolicyImpl::FlagsToString) + { + if (EnumHasAllFlags(Policy, Pair.first)) { - Result |= CachePolicy::QueryRemote; + EnumRemoveFlags(Policy, Pair.first); + Builder << Pair.second << detail::CachePolicyImpl::DelimiterChar; + if (Policy == CachePolicy::None) + { + break; + } } - return true; - }); - - return Result; + } + Builder.RemoveSuffix(1); // Text will have been added by CachePolicy::None if not by anything else + return Builder; +} +StringBuilderBase& +operator<<(StringBuilderBase& Builder, CachePolicy Policy) +{ + return AppendToBuilderImpl(Builder, Policy); } CachePolicy -ParseStoreCachePolicy(std::string_view StorePolicy, CachePolicy Default) +ParseCachePolicy(std::string_view Text) { - if (StorePolicy.empty()) - { - return Default; - } + ZEN_ASSERT(!Text.empty()); // Empty string is not valid input to ParseCachePolicy CachePolicy Result = CachePolicy::None; - - ForEachStrTok(StorePolicy, ',', [&Result](const std::string_view& Token) { - if (Token == detail::cacheopt::Local) - { - Result |= CachePolicy::StoreLocal; - } - if (Token == detail::cacheopt::Remote) + ForEachStrTok(Text, detail::CachePolicyImpl::DelimiterChar, [&Result](const std::string_view& Token) { + auto it = detail::CachePolicyImpl::TextToPolicy.find(Token); + if (it != detail::CachePolicyImpl::TextToPolicy.end()) { - Result |= CachePolicy::StoreRemote; + Result |= it->second; } return true; }); @@ -69,101 +120,139 @@ ParseStoreCachePolicy(std::string_view StorePolicy, CachePolicy Default) return Result; } -CachePolicy -ParseSkipCachePolicy(std::string_view SkipPolicy, CachePolicy Default) -{ - if (SkipPolicy.empty()) +namespace Private { + + class CacheRecordPolicyShared final : public ICacheRecordPolicyShared { - return Default; - } + public: + inline std::span<const CacheValuePolicy> GetValuePolicies() const final { return Values; } - CachePolicy Result = CachePolicy::None; + inline void AddValuePolicy(const CacheValuePolicy& Policy) final { Values.push_back(Policy); } - ForEachStrTok(SkipPolicy, ',', [&Result](const std::string_view& Token) { - if (Token == detail::cacheopt::Meta) - { - Result |= CachePolicy::SkipMeta; - } - if (Token == detail::cacheopt::Value) + inline void Build() final { - Result |= CachePolicy::SkipValue; + std::sort(Values.begin(), Values.end(), [](const CacheValuePolicy& A, const CacheValuePolicy& B) { return A.Id < B.Id; }); } - if (Token == detail::cacheopt::Attachments) - { - Result |= CachePolicy::SkipAttachments; - } - if (Token == detail::cacheopt::Data) - { - Result |= CachePolicy::SkipData; - } - return true; - }); - return Result; -} + private: + std::vector<CacheValuePolicy> Values; + }; -CacheRecordPolicy::CacheRecordPolicy(const CachePolicy RecordPolicy, const CachePolicy PayloadPolicy) -: m_RecordPolicy(RecordPolicy) -, m_DefaultPayloadPolicy(PayloadPolicy) -{ -} +} // namespace Private CachePolicy -CacheRecordPolicy::GetPayloadPolicy(const Oid& PayloadId) const +CacheRecordPolicy::GetValuePolicy(const Oid& Id) const { - if (const auto It = m_PayloadPolicies.find(PayloadId); It != m_PayloadPolicies.end()) + if (Shared) { - return It->second; + if (std::span<const CacheValuePolicy> Values = Shared->GetValuePolicies(); !Values.empty()) + { + auto Iter = + std::lower_bound(Values.begin(), Values.end(), Id, [](const CacheValuePolicy& A, const Oid& B) { return A.Id < B; }); + if (Iter != Values.end() && Iter->Id == Id) + { + return Iter->Policy; + } + } } + return DefaultValuePolicy; +} - return m_DefaultPayloadPolicy; +void +CacheRecordPolicy::Save(CbWriter& Writer) const +{ + Writer.BeginObject(); + { + // The RecordPolicy is calculated from the ValuePolicies and does not need to be saved separately. + Writer << "DefaultValuePolicy"sv << WriteToString<128>(GetDefaultValuePolicy()); + if (!IsUniform()) + { + // FCacheRecordPolicyBuilder guarantees IsUniform -> non-empty GetValuePolicies. Small size penalty here if not. + Writer.BeginArray("ValuePolicies"sv); + { + for (const CacheValuePolicy& ValuePolicy : GetValuePolicies()) + { + // FCacheRecordPolicyBuilder is responsible for ensuring that each ValuePolicy != DefaultValuePolicy + // If it lets any duplicates through we will incur a small serialization size penalty here + Writer.BeginObject(); + Writer << "Id"sv << ValuePolicy.Id; + Writer << "Policy"sv << WriteToString<128>(ValuePolicy.Policy); + Writer.EndObject(); + } + } + Writer.EndArray(); + } + } + Writer.EndObject(); } -bool -CacheRecordPolicy::Load(CbObjectView RecordPolicyObject, CacheRecordPolicy& OutRecordPolicy) +CacheRecordPolicy +CacheRecordPolicy::Load(CbObjectView Object, CachePolicy DefaultPolicy) { - using namespace std::literals; + std::string_view PolicyText = Object["DefaultValuePolicy"sv].AsString(); + CachePolicy DefaultValuePolicy = !PolicyText.empty() ? ParseCachePolicy(PolicyText) : DefaultPolicy; - const uint32_t RecordPolicy = RecordPolicyObject["RecordPolicy"sv].AsUInt32(static_cast<uint32_t>(CachePolicy::Default)); - const uint32_t DefaultPayloadPolicy = - RecordPolicyObject["DefaultPayloadPolicy"sv].AsUInt32(static_cast<uint32_t>(CachePolicy::Default)); + CacheRecordPolicyBuilder Builder(DefaultValuePolicy); + for (CbFieldView ValueObjectField : Object["ValuePolicies"sv]) + { + CbObjectView ValueObject = ValueObjectField.AsObjectView(); + const Oid ValueId = ValueObject["Id"sv].AsObjectId(); + PolicyText = ValueObject["Policy"sv].AsString(); + CachePolicy ValuePolicy = !PolicyText.empty() ? ParseCachePolicy(PolicyText) : DefaultValuePolicy; + // FCacheRecordPolicyBuilder should guarantee that FValueId(ValueId).IsValid and ValuePolicy != DefaultValuePolicy + // If it lets any through we will have unused data in the record we create. + Builder.AddValuePolicy(ValueId, ValuePolicy); + } - OutRecordPolicy.m_RecordPolicy = static_cast<CachePolicy>(RecordPolicy); - OutRecordPolicy.m_DefaultPayloadPolicy = static_cast<CachePolicy>(DefaultPayloadPolicy); + return Builder.Build(); +} - for (CbFieldView PayloadPolicyView : RecordPolicyObject["PayloadPolicies"sv]) +CacheRecordPolicy +CacheRecordPolicy::ConvertToUpstream() const +{ + auto DownstreamToUpstream = [](CachePolicy P) { + // Remote|Local -> Set Remote + // Delete Skip Flags + // Maintain Remaining Flags + return (EnumHasAllFlags(P, CachePolicy::QueryRemote) ? CachePolicy::QueryLocal : CachePolicy::None) | + (EnumHasAllFlags(P, CachePolicy::StoreRemote) ? CachePolicy::StoreLocal : CachePolicy::None) | + (P & ~(CachePolicy::SkipData | CachePolicy::SkipMeta)); + }; + CacheRecordPolicyBuilder Builder(DownstreamToUpstream(GetDefaultValuePolicy())); + for (const CacheValuePolicy& ValuePolicy : GetValuePolicies()) { - CbObjectView PayloadPolicyObject = PayloadPolicyView.AsObjectView(); - const Oid PayloadId = PayloadPolicyObject["Id"sv].AsObjectId(); - const uint32_t PayloadPolicy = PayloadPolicyObject["Policy"sv].AsUInt32(); - - if (PayloadId != Oid::Zero && PayloadPolicy != 0) - { - OutRecordPolicy.m_PayloadPolicies.emplace(PayloadId, static_cast<CachePolicy>(PayloadPolicy)); - } + Builder.AddValuePolicy(ValuePolicy.Id, DownstreamToUpstream(ValuePolicy.Policy)); } - - return true; + return Builder.Build(); } void -CacheRecordPolicy::Save(const CacheRecordPolicy& Policy, CbWriter& Writer) +CacheRecordPolicyBuilder::AddValuePolicy(const CacheValuePolicy& Policy) { - Writer << "RecordPolicy"sv << static_cast<uint32_t>(Policy.GetRecordPolicy()); - Writer << "DefaultPayloadPolicy"sv << static_cast<uint32_t>(Policy.GetDefaultPayloadPolicy()); + if (!Shared) + { + Shared = new Private::CacheRecordPolicyShared; + } + Shared->AddValuePolicy(Policy); +} - if (!Policy.m_PayloadPolicies.empty()) +CacheRecordPolicy +CacheRecordPolicyBuilder::Build() +{ + CacheRecordPolicy Policy(BasePolicy); + if (Shared) { - Writer.BeginArray("PayloadPolicies"sv); - for (const auto& Kv : Policy.m_PayloadPolicies) + Shared->Build(); + const auto PolicyOr = [](CachePolicy A, CachePolicy B) { return A | (B & ~CachePolicy::SkipData); }; + const std::span<const CacheValuePolicy> Values = Shared->GetValuePolicies(); + Policy.RecordPolicy = BasePolicy; + for (const CacheValuePolicy& ValuePolicy : Values) { - Writer.BeginObject(); - Writer.AddObjectId("Id"sv, Kv.first); - Writer << "Policy"sv << static_cast<uint32_t>(Kv.second); - Writer.EndObject(); + Policy.RecordPolicy = PolicyOr(Policy.RecordPolicy, ValuePolicy.Policy); } - Writer.EndArray(); + Policy.Shared = std::move(Shared); } + return Policy; } } // namespace zen diff --git a/zenutil/include/zenutil/cache/cachekey.h b/zenutil/include/zenutil/cache/cachekey.h index fb36c7759..a0a83a883 100644 --- a/zenutil/include/zenutil/cache/cachekey.h +++ b/zenutil/include/zenutil/cache/cachekey.h @@ -44,7 +44,7 @@ struct CacheChunkRequest { CacheKey Key; IoHash ChunkId; - Oid PayloadId; + Oid ValueId; uint64_t RawOffset = 0ull; uint64_t RawSize = ~uint64_t(0); CachePolicy Policy = CachePolicy::Default; @@ -69,11 +69,11 @@ operator<(const CacheChunkRequest& A, const CacheChunkRequest& B) { return false; } - if (A.PayloadId < B.PayloadId) + if (A.ValueId < B.ValueId) { return true; } - if (B.PayloadId < A.PayloadId) + if (B.ValueId < A.ValueId) { return false; } diff --git a/zenutil/include/zenutil/cache/cachepolicy.h b/zenutil/include/zenutil/cache/cachepolicy.h index 5675ccf4d..b3602edbd 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,107 @@ 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; } + + /** Returns the cache policy to use for the record. */ + inline CachePolicy GetRecordPolicy() const { return RecordPolicy; } - 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 value. */ + CachePolicy GetValuePolicy(const Oid& Id) const; - static bool Load(CbObjectView RecordPolicyObject, CacheRecordPolicy& OutRecordPolicy); - static void Save(const CacheRecordPolicy& Policy, CbWriter& Writer); + /** 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); + + /** Return *this converted into the equivalent policy that the upstream should use when forwarding a put or get to an upstream server. + */ + CacheRecordPolicy ConvertToUpstream() const; 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; +}; + +/** 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; - CachePolicy m_RecordPolicy = CachePolicy::Default; - CachePolicy m_DefaultPayloadPolicy = CachePolicy::Default; - PayloadPolicyMap m_PayloadPolicies; + /** 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 diff --git a/zenutil/include/zenutil/zenserverprocess.h b/zenutil/include/zenutil/zenserverprocess.h index 55b9a50cd..2a3146e2d 100644 --- a/zenutil/include/zenutil/zenserverprocess.h +++ b/zenutil/include/zenutil/zenserverprocess.h @@ -100,11 +100,12 @@ public: // additional state. For example, you can use the session ID // to introduce additional named objects std::atomic<uint32_t> Pid; - std::atomic<uint16_t> ListenPort; + std::atomic<uint16_t> DesiredListenPort; std::atomic<uint16_t> Flags; uint8_t SessionId[12]; std::atomic<uint32_t> SponsorPids[8]; - uint8_t Padding[12]; + std::atomic<uint16_t> EffectiveListenPort; + uint8_t Padding[10]; enum class FlagsEnum : uint16_t { @@ -125,8 +126,8 @@ public: void Initialize(); [[nodiscard]] bool InitializeReadOnly(); - [[nodiscard]] ZenServerEntry* Lookup(int ListenPort); - ZenServerEntry* Register(int ListenPort); + [[nodiscard]] ZenServerEntry* Lookup(int DesiredListenPort); + ZenServerEntry* Register(int DesiredListenPort); void Sweep(); void Snapshot(std::function<void(const ZenServerEntry&)>&& Callback); inline bool IsReadOnly() const { return m_IsReadOnly; } diff --git a/zenutil/zenserverprocess.cpp b/zenutil/zenserverprocess.cpp index fe6236d18..5bddc72bc 100644 --- a/zenutil/zenserverprocess.cpp +++ b/zenutil/zenserverprocess.cpp @@ -230,11 +230,11 @@ ZenServerState::InitializeReadOnly() } ZenServerState::ZenServerEntry* -ZenServerState::Lookup(int ListenPort) +ZenServerState::Lookup(int DesiredListenPort) { for (int i = 0; i < m_MaxEntryCount; ++i) { - if (m_Data[i].ListenPort == ListenPort) + if (m_Data[i].DesiredListenPort == DesiredListenPort) { return &m_Data[i]; } @@ -244,7 +244,7 @@ ZenServerState::Lookup(int ListenPort) } ZenServerState::ZenServerEntry* -ZenServerState::Register(int ListenPort) +ZenServerState::Register(int DesiredListenPort) { if (m_Data == nullptr) { @@ -259,17 +259,18 @@ ZenServerState::Register(int ListenPort) { ZenServerEntry& Entry = m_Data[i]; - if (Entry.ListenPort.load(std::memory_order_relaxed) == 0) + if (Entry.DesiredListenPort.load(std::memory_order_relaxed) == 0) { uint16_t Expected = 0; - if (Entry.ListenPort.compare_exchange_strong(Expected, uint16_t(ListenPort))) + if (Entry.DesiredListenPort.compare_exchange_strong(Expected, uint16_t(DesiredListenPort))) { // Successfully allocated entry m_OurEntry = &Entry; - Entry.Pid = Pid; - Entry.Flags = 0; + Entry.Pid = Pid; + Entry.EffectiveListenPort = 0; + Entry.Flags = 0; const Oid SesId = GetSessionId(); memcpy(Entry.SessionId, &SesId, sizeof SesId); @@ -296,11 +297,11 @@ ZenServerState::Sweep() { ZenServerEntry& Entry = m_Data[i]; - if (Entry.ListenPort) + if (Entry.DesiredListenPort) { if (IsProcessRunning(Entry.Pid) == false) { - ZEN_DEBUG("Sweep - pid {} not running, reclaiming entry (port {})", Entry.Pid, Entry.ListenPort); + ZEN_DEBUG("Sweep - pid {} not running, reclaiming entry (port {})", Entry.Pid, Entry.DesiredListenPort); Entry.Reset(); } @@ -320,7 +321,7 @@ ZenServerState::Snapshot(std::function<void(const ZenServerEntry&)>&& Callback) { ZenServerEntry& Entry = m_Data[i]; - if (Entry.ListenPort) + if (Entry.DesiredListenPort) { Callback(Entry); } @@ -330,9 +331,10 @@ ZenServerState::Snapshot(std::function<void(const ZenServerEntry&)>&& Callback) void ZenServerState::ZenServerEntry::Reset() { - Pid = 0; - ListenPort = 0; - Flags = 0; + Pid = 0; + DesiredListenPort = 0; + Flags = 0; + EffectiveListenPort = 0; } void |