2020#include " DefaultCacheImpl.h"
2121
2222#include < algorithm>
23+ #include < chrono>
2324
2425#include " olp/core/logging/Log.h"
2526#include " olp/core/porting/make_unique.h"
@@ -30,6 +31,10 @@ constexpr auto kLogTag = "DefaultCache";
3031constexpr auto kExpirySuffix = " ::expiry" ;
3132constexpr auto kMaxDiskSize = std::uint64_t (-1 );
3233
34+ // current epoch time contains 10 digits.
35+ constexpr auto kExpiryValueSize = 10 ;
36+ const auto kExpirySuffixLength = strlen(kExpirySuffix );
37+
3338std::string CreateExpiryKey (const std::string& key) {
3439 return key + kExpirySuffix ;
3540}
@@ -39,6 +44,10 @@ bool IsExpiryKey(const std::string& key) {
3944 return pos == 0 ;
4045}
4146
47+ bool IsExpiryValid (time_t expiry) {
48+ return expiry < olp::cache::KeyValueCache::kDefaultExpiry ;
49+ }
50+
4251time_t GetRemainingExpiryTime (const std::string& key,
4352 olp::cache::DiskCache& disk_cache) {
4453 auto expiry_key = CreateExpiryKey (key);
@@ -52,19 +61,28 @@ time_t GetRemainingExpiryTime(const std::string& key,
5261 return expiry;
5362}
5463
55- void PurgeDiskItem (const std::string& key, olp::cache::DiskCache& disk_cache) {
64+ void PurgeDiskItem (const std::string& key, olp::cache::DiskCache& disk_cache,
65+ uint64_t & removed_data_size) {
5666 auto expiry_key = CreateExpiryKey (key);
57- disk_cache.Remove (key);
58- disk_cache.Remove (expiry_key);
67+ uint64_t data_size = 0u ;
68+
69+ disk_cache.Remove (key, data_size);
70+ removed_data_size += data_size;
71+
72+ disk_cache.Remove (expiry_key, data_size);
73+ removed_data_size += data_size;
5974}
6075
61- bool StoreExpiry (const std::string& key, olp::cache::DiskCache& disk_cache,
62- time_t expiry) {
76+ size_t StoreExpiry (const std::string& key, olp::cache::DiskCache& disk_cache,
77+ time_t expiry) {
6378 auto expiry_key = CreateExpiryKey (key);
64- return disk_cache.Put (
65- expiry_key,
66- std::to_string (expiry +
67- olp::cache::InMemoryCache::DefaultTimeProvider ()()));
79+ auto time_str = std::to_string (
80+ expiry + olp::cache::InMemoryCache::DefaultTimeProvider ()());
81+ if (!disk_cache.Put (expiry_key, time_str)) {
82+ return 0 ;
83+ }
84+
85+ return expiry_key.size () + time_str.size ();
6886}
6987
7088} // namespace
@@ -78,7 +96,8 @@ DefaultCacheImpl::DefaultCacheImpl(CacheSettings settings)
7896 memory_cache_(nullptr ),
7997 mutable_cache_(nullptr ),
8098 mutable_cache_lru_(nullptr ),
81- protected_cache_(nullptr ) {}
99+ protected_cache_(nullptr ),
100+ mutable_cache_data_size_(0 ) {}
82101
83102DefaultCache::StorageOpenResult DefaultCacheImpl::Open () {
84103 std::lock_guard<std::mutex> lock (cache_lock_);
@@ -96,6 +115,7 @@ void DefaultCacheImpl::Close() {
96115 mutable_cache_.reset ();
97116 mutable_cache_lru_.reset ();
98117 protected_cache_.reset ();
118+ mutable_cache_data_size_ = 0 ;
99119 is_open_ = false ;
100120}
101121
@@ -114,6 +134,7 @@ bool DefaultCacheImpl::Clear() {
114134 }
115135
116136 if (mutable_cache_) {
137+ mutable_cache_data_size_ = 0 ;
117138 if (!mutable_cache_->Clear ()) {
118139 return false ;
119140 }
@@ -140,30 +161,7 @@ bool DefaultCacheImpl::Put(const std::string& key, const boost::any& value,
140161 }
141162 }
142163
143- if (mutable_cache_) {
144- if (expiry < KeyValueCache::kDefaultExpiry ) {
145- if (!StoreExpiry (key, *mutable_cache_, expiry)) {
146- return false ;
147- }
148- }
149-
150- if (!mutable_cache_->Put (key, encoded_item)) {
151- return false ;
152- }
153-
154- if (mutable_cache_lru_) {
155- const auto value = encoded_item.size ();
156- auto result = mutable_cache_lru_->InsertOrAssign (key, value);
157- if (result.first == mutable_cache_lru_->end () && !result.second ) {
158- OLP_SDK_LOG_WARNING_F (
159- kLogTag , " Failed to store value in mutable LRU cache, key %s" ,
160- key.c_str ());
161- return false ;
162- }
163- }
164- }
165-
166- return true ;
164+ return PutMutableCache (key, encoded_item, expiry);
167165}
168166
169167bool DefaultCacheImpl::Put (const std::string& key,
@@ -184,31 +182,9 @@ bool DefaultCacheImpl::Put(const std::string& key,
184182 }
185183 }
186184
187- if (mutable_cache_) {
188- if (expiry < KeyValueCache::kDefaultExpiry ) {
189- if (!StoreExpiry (key, *mutable_cache_, expiry)) {
190- return false ;
191- }
192- }
193-
194- leveldb::Slice slice (reinterpret_cast <const char *>(value->data ()),
195- value->size ());
196- if (!mutable_cache_->Put (key, slice)) {
197- return false ;
198- }
199-
200- if (mutable_cache_lru_) {
201- auto result = mutable_cache_lru_->InsertOrAssign (key, value->size ());
202- if (result.first == mutable_cache_lru_->end () && !result.second ) {
203- OLP_SDK_LOG_WARNING_F (
204- kLogTag , " Failed to store value inmutable LRU cache, key %s" ,
205- key.c_str ());
206- return false ;
207- }
208- }
209- }
210-
211- return true ;
185+ leveldb::Slice slice (reinterpret_cast <const char *>(value->data ()),
186+ value->size ());
187+ return PutMutableCache (key, slice, expiry);
212188}
213189
214190boost::any DefaultCacheImpl::Get (const std::string& key,
@@ -218,11 +194,10 @@ boost::any DefaultCacheImpl::Get(const std::string& key,
218194 return boost::any ();
219195 }
220196
221- PromoteKeyLru (key);
222-
223197 if (memory_cache_) {
224198 auto value = memory_cache_->Get (key);
225199 if (!value.empty ()) {
200+ PromoteKeyLru (key);
226201 return value;
227202 }
228203 }
@@ -247,12 +222,11 @@ KeyValueCache::ValueTypePtr DefaultCacheImpl::Get(const std::string& key) {
247222 return nullptr ;
248223 }
249224
250- PromoteKeyLru (key);
251-
252225 if (memory_cache_) {
253226 auto value = memory_cache_->Get (key);
254227
255228 if (!value.empty ()) {
229+ PromoteKeyLru (key);
256230 return boost::any_cast<KeyValueCache::ValueTypePtr>(value);
257231 }
258232 }
@@ -283,14 +257,15 @@ bool DefaultCacheImpl::Remove(const std::string& key) {
283257 memory_cache_->Remove (key);
284258 }
285259
286- if (mutable_cache_lru_) {
287- mutable_cache_lru_->Erase (key);
288- }
260+ RemoveKeyLru (key);
289261
290262 if (mutable_cache_) {
291- if (!mutable_cache_->Remove (key)) {
263+ uint64_t removed_data_size = 0 ;
264+ if (!mutable_cache_->Remove (key, removed_data_size)) {
292265 return false ;
293266 }
267+
268+ mutable_cache_data_size_ -= removed_data_size;
294269 }
295270
296271 return true ;
@@ -309,30 +284,63 @@ bool DefaultCacheImpl::RemoveKeysWithPrefix(const std::string& key) {
309284 RemoveKeysWithPrefixLru (key);
310285
311286 if (mutable_cache_) {
312- return mutable_cache_->RemoveKeysWithPrefix (key);
287+ uint64_t removed_data_size = 0 ;
288+ auto result = mutable_cache_->RemoveKeysWithPrefix (key, removed_data_size);
289+ mutable_cache_data_size_ -= removed_data_size;
290+ return result;
313291 }
314292 return true ;
315293}
316294
317295void DefaultCacheImpl::InitializeLru () {
318- if (!mutable_cache_ || settings_.max_disk_storage == kMaxDiskSize ||
319- settings_.eviction_policy == EvictionPolicy::kNone ) {
296+ if (!mutable_cache_) {
320297 return ;
321298 }
322299
323- mutable_cache_lru_ =
324- std::make_unique<DiskLruCache>(settings_.max_disk_storage );
300+ if (mutable_cache_ && settings_.max_disk_storage != kMaxDiskSize &&
301+ settings_.eviction_policy == EvictionPolicy::kLeastRecentlyUsed ) {
302+ mutable_cache_lru_ =
303+ std::make_unique<DiskLruCache>(settings_.max_disk_storage );
304+ }
305+
306+ if (mutable_cache_lru_) {
307+ OLP_SDK_LOG_INFO_F (kLogTag , " Initializing mutable lru cache." );
308+ }
309+
310+ const auto start = std::chrono::steady_clock::now ();
311+ auto count = 0u ;
325312 auto it = mutable_cache_->NewIterator (leveldb::ReadOptions ());
326313 for (it->SeekToFirst (); it->Valid (); it->Next ()) {
327314 const auto key = it->key ().ToString ();
328315 const auto & value = it->value ();
316+ mutable_cache_data_size_ += key.size () + value.size ();
329317
330- // Skip expiry keys
331- if (IsExpiryKey (key)) {
332- continue ;
318+ if (mutable_cache_lru_) {
319+ // Skip expiry keys
320+ if (IsExpiryKey (key)) {
321+ continue ;
322+ }
323+
324+ ++count;
325+ mutable_cache_lru_->Insert (key, value.size ());
333326 }
327+ }
328+
329+ if (mutable_cache_lru_) {
330+ const int64_t elapsed =
331+ std::chrono::duration_cast<std::chrono::milliseconds>(
332+ std::chrono::steady_clock::now () - start)
333+ .count ();
334+ OLP_SDK_LOG_INFO_F (kLogTag ,
335+ " Mutable lru cache initialized: items=%" PRIu32
336+ " , time=%" PRId64 " ms" ,
337+ count, elapsed);
338+ }
339+ }
334340
335- mutable_cache_lru_->Insert (key, value.size ());
341+ void DefaultCacheImpl::RemoveKeyLru (const std::string& key) {
342+ if (mutable_cache_lru_) {
343+ mutable_cache_lru_->Erase (key);
336344 }
337345}
338346
@@ -363,13 +371,58 @@ bool DefaultCacheImpl::PromoteKeyLru(const std::string& key) {
363371 return true ;
364372}
365373
374+ bool DefaultCacheImpl::PutMutableCache (const std::string& key,
375+ const leveldb::Slice& value,
376+ time_t expiry) {
377+ if (!mutable_cache_) {
378+ return true ;
379+ }
380+
381+ // can't put new item if cache is full and eviction disabled
382+ const auto item_size = value.size ();
383+ const auto expected_size = mutable_cache_data_size_ + item_size + key.size () +
384+ key.size () + kExpirySuffixLength +
385+ kExpiryValueSize ;
386+ if (!mutable_cache_lru_ && expected_size > settings_.max_disk_storage ) {
387+ return false ;
388+ }
389+
390+ uint64_t data_size_change = 0u ;
391+ if (IsExpiryValid (expiry)) {
392+ auto expiry_data_size = StoreExpiry (key, *mutable_cache_, expiry);
393+ if (expiry_data_size == 0 ) {
394+ return false ;
395+ }
396+ data_size_change += expiry_data_size;
397+ }
398+ data_size_change += key.size () + item_size;
399+
400+ if (!mutable_cache_->Put (key, value)) {
401+ return false ;
402+ }
403+ mutable_cache_data_size_ += data_size_change;
404+
405+ if (mutable_cache_lru_) {
406+ const auto result = mutable_cache_lru_->InsertOrAssign (key, item_size);
407+ if (result.first == mutable_cache_lru_->end () && !result.second ) {
408+ OLP_SDK_LOG_WARNING_F (
409+ kLogTag , " Failed to store value in mutable LRU cache, key %s" ,
410+ key.c_str ());
411+ return false ;
412+ }
413+ }
414+
415+ return true ;
416+ }
417+
366418DefaultCache::StorageOpenResult DefaultCacheImpl::SetupStorage () {
367419 auto result = DefaultCache::Success;
368420
369421 memory_cache_.reset ();
370422 mutable_cache_.reset ();
371423 mutable_cache_lru_.reset ();
372424 protected_cache_.reset ();
425+ mutable_cache_data_size_ = 0 ;
373426
374427 if (settings_.max_memory_cache_size > 0 ) {
375428 memory_cache_.reset (new InMemoryCache (settings_.max_memory_cache_size ));
@@ -431,13 +484,16 @@ DefaultCacheImpl::GetFromDiscCache(const std::string& key) {
431484 if (mutable_cache_) {
432485 auto expiry = GetRemainingExpiryTime (key, *mutable_cache_);
433486 if (expiry <= 0 ) {
434- PurgeDiskItem (key, *mutable_cache_);
435- if (mutable_cache_lru_) {
436- mutable_cache_lru_->Erase (key);
437- }
487+ uint64_t removed_data_size = 0u ;
488+ PurgeDiskItem (key, *mutable_cache_, removed_data_size);
489+ mutable_cache_data_size_ -= removed_data_size;
490+
491+ RemoveKeyLru (key);
438492 } else {
439493 if (!PromoteKeyLru (key)) {
440494 // If not found in LRU no need to look in disk cache either.
495+ OLP_SDK_LOG_DEBUG_F (
496+ kLogTag , " Key is not found LRU mutable cache: key %s" , key.c_str ());
441497 return boost::none;
442498 }
443499
@@ -450,5 +506,9 @@ DefaultCacheImpl::GetFromDiscCache(const std::string& key) {
450506 return boost::none;
451507}
452508
509+ std::string DefaultCacheImpl::GetExpiryKey (const std::string& key) const {
510+ return CreateExpiryKey (key);
511+ }
512+
453513} // namespace cache
454514} // namespace olp
0 commit comments