diff options
Diffstat (limited to 'zenserver/cache/structuredcachestore.h')
| -rw-r--r-- | zenserver/cache/structuredcachestore.h | 107 |
1 files changed, 65 insertions, 42 deletions
diff --git a/zenserver/cache/structuredcachestore.h b/zenserver/cache/structuredcachestore.h index e6e9942bb..3d2896ff8 100644 --- a/zenserver/cache/structuredcachestore.h +++ b/zenserver/cache/structuredcachestore.h @@ -132,13 +132,48 @@ struct DiskIndexEntry static_assert(sizeof(DiskIndexEntry) == 32); +// This store the access time as seconds since epoch internally in a 32-bit value giving is a range of 136 years since epoch +struct AccessTime +{ + explicit AccessTime(GcClock::Tick Tick) noexcept : SecondsSinceEpoch(ToSeconds(Tick)) {} + AccessTime& operator=(GcClock::Tick Tick) noexcept + { + SecondsSinceEpoch.store(ToSeconds(Tick), std::memory_order_relaxed); + return *this; + } + operator GcClock::Tick() const noexcept + { + return std::chrono::duration_cast<GcClock::Duration>(std::chrono::seconds(SecondsSinceEpoch.load(std::memory_order_relaxed))) + .count(); + } + + AccessTime(AccessTime&& Rhs) noexcept : SecondsSinceEpoch(Rhs.SecondsSinceEpoch.load(std::memory_order_relaxed)) {} + AccessTime(const AccessTime& Rhs) noexcept : SecondsSinceEpoch(Rhs.SecondsSinceEpoch.load(std::memory_order_relaxed)) {} + AccessTime& operator=(AccessTime&& Rhs) noexcept + { + SecondsSinceEpoch.store(Rhs.SecondsSinceEpoch.load(std::memory_order_relaxed), std::memory_order_relaxed); + return *this; + } + AccessTime& operator=(const AccessTime& Rhs) noexcept + { + SecondsSinceEpoch.store(Rhs.SecondsSinceEpoch.load(std::memory_order_relaxed), std::memory_order_relaxed); + return *this; + } + +private: + static uint32_t ToSeconds(GcClock::Tick Tick) + { + return gsl::narrow<uint32_t>(std::chrono::duration_cast<std::chrono::seconds>(GcClock::Duration(Tick)).count()); + } + std::atomic_uint32_t SecondsSinceEpoch; +}; + /** In-memory cache storage Intended for small values which are frequently accessed This should have a better memory management policy to maintain reasonable footprint. - */ class ZenCacheMemoryLayer { @@ -184,28 +219,24 @@ public: private: struct CacheBucket { - struct BucketValue +#pragma pack(push) +#pragma pack(1) + struct BucketPayload { - IoBuffer Payload; - std::atomic_int64_t LastAccess; - - BucketValue() : Payload(), LastAccess() {} - BucketValue(IoBuffer Value, const int64_t Timestamp) : Payload(Value), LastAccess(Timestamp) {} - BucketValue(const BucketValue& V) : Payload(V.Payload), LastAccess(V.LastAccess.load(std::memory_order_relaxed)) {} - BucketValue(BucketValue&& V) : Payload(std::move(V.Payload)), LastAccess(V.LastAccess.load(std::memory_order_relaxed)) {} - - BucketValue& operator=(const BucketValue& V) { return *this = BucketValue(V); } - BucketValue& operator=(BucketValue&& V) - { - Payload = std::move(V.Payload); - LastAccess.store(V.LastAccess.load(), std::memory_order_relaxed); - return *this; - } + IoBuffer Payload; // 8 + uint32_t RawSize; // 4 + IoHash RawHash; // 20 }; +#pragma pack(pop) + static_assert(sizeof(BucketPayload) == 32u); + static_assert(sizeof(AccessTime) == 4u); + + mutable RwLock m_BucketLock; + std::vector<AccessTime> m_AccessTimes; + std::vector<BucketPayload> m_Payloads; + tsl::robin_map<IoHash, uint32_t> m_CacheMap; - mutable RwLock m_BucketLock; - tsl::robin_map<IoHash, BucketValue> m_CacheMap; - std::atomic_uint64_t m_TotalSize{}; + std::atomic_uint64_t m_TotalSize{}; bool Get(const IoHash& HashKey, ZenCacheValue& OutValue); void Put(const IoHash& HashKey, const ZenCacheValue& Value); @@ -259,7 +290,6 @@ public: void GatherReferences(GcContext& GcCtx); void CollectGarbage(GcContext& GcCtx); void UpdateAccessTimes(const zen::access_tracking::AccessTimes& AccessTimes); - // void IterateBuckets(const std::function<void(std::string_view Bucket)>& Callback) const; void DiscoverBuckets(); uint64_t TotalSize() const; @@ -305,31 +335,24 @@ private: TCasLogFile<DiskIndexEntry> m_SlogFile; uint64_t m_LogFlushPosition = 0; - struct IndexEntry +#pragma pack(push) +#pragma pack(1) + struct BucketPayload { - DiskLocation Location; - std::atomic_int64_t LastAccess; - - IndexEntry() : Location(), LastAccess() {} - IndexEntry(const DiskLocation& Loc, const int64_t Timestamp) : Location(Loc), LastAccess(Timestamp) {} - IndexEntry(const IndexEntry& E) : Location(E.Location), LastAccess(E.LastAccess.load(std::memory_order_relaxed)) {} - IndexEntry(IndexEntry&& E) noexcept : Location(std::move(E.Location)), LastAccess(E.LastAccess.load(std::memory_order_relaxed)) - { - } - - IndexEntry& operator=(const IndexEntry& E) { return *this = IndexEntry(E); } - IndexEntry& operator=(IndexEntry&& E) noexcept - { - Location = std::move(E.Location); - LastAccess.store(E.LastAccess.load(), std::memory_order_relaxed); - return *this; - } + DiskLocation Location; // 12 + uint64_t RawSize; // 8 + IoHash RawHash; // 20 }; +#pragma pack(pop) + static_assert(sizeof(BucketPayload) == 40u); + static_assert(sizeof(AccessTime) == 4u); - using IndexMap = tsl::robin_map<IoHash, IndexEntry, IoHash::Hasher>; + using IndexMap = tsl::robin_map<IoHash, size_t, IoHash::Hasher>; - mutable RwLock m_IndexLock; - IndexMap m_Index; + mutable RwLock m_IndexLock; + std::vector<AccessTime> m_AccessTimes; + std::vector<BucketPayload> m_Payloads; + IndexMap m_Index; std::atomic_uint64_t m_TotalStandaloneSize{}; |