#pragma once #include #include #include #include namespace NSQLComplete { struct TLocalCacheConfig { size_t ByteCapacity = 1 * 1024 * 1024; TDuration TTL = TDuration::Seconds(8); }; namespace NPrivate { template struct TLocalCacheCell { TValue Value; NMonotonic::TMonotonic Deadline; size_t KeyByteSize = 0; size_t CellByteSize = 0; }; template class TLocalCache: public ICache { private: using TEntry = ICache::TEntry; using TCell = TLocalCacheCell; struct TLRUSizeProvider { size_t operator()(const TCell& x) noexcept { const size_t listItemContent = x.CellByteSize; const size_t listItemPtrs = sizeof(TIntrusiveListItem); const size_t listItem = listItemContent + listItemPtrs; const size_t cacheIndexKey = x.KeyByteSize; const size_t cacheIndexListItemPtr = sizeof(void*); const size_t cacheIndexEntry = cacheIndexKey + cacheIndexListItemPtr; return listItem + cacheIndexEntry; } }; using TStorage = TLRUCache; public: TLocalCache(TIntrusivePtr clock, TLocalCacheConfig config) : Clock_(std::move(clock)) , Config_(std::move(config)) , Origin_(/* maxSize = */ Config_.ByteCapacity) { } NThreading::TFuture Get(const TKey& key) const override { TEntry entry; with_lock (Mutex_) { if (auto it = Origin_.Find(key); it != Origin_.End()) { entry.Value = it->Value; entry.IsExpired = (it->Deadline <= Clock_->Now()); } } return NThreading::MakeFuture(std::move(entry)); } NThreading::TFuture Update(const TKey& key, TValue value) const override { TCell cell = { .Value = std::move(value), .Deadline = Clock_->Now() + Config_.TTL, .KeyByteSize = TByteSize()(key), }; cell.CellByteSize = TByteSize()(cell.Value) + sizeof(cell.Deadline) + cell.KeyByteSize; with_lock (Mutex_) { Origin_.Update(key, std::move(cell)); } return NThreading::MakeFuture(); } private: TIntrusivePtr Clock_; TLocalCacheConfig Config_; TMutex Mutex_; mutable TStorage Origin_; }; } // namespace NPrivate template ICache::TPtr MakeLocalCache( TIntrusivePtr clock, TLocalCacheConfig config) { return new NPrivate::TLocalCache(std::move(clock), std::move(config)); } template struct TByteSize> { size_t operator()(const NPrivate::TLocalCacheCell& x) const noexcept { return x.CellByteSize; } }; } // namespace NSQLComplete