Skip to content

Commit bbc733d

Browse files
authored
Track mutable cache size. (#787)
Size of mutable cache limited by DiskCacheSizeLimitEnv. Because of leveldb implementation, its size increasing even after removing items from the cache. So env can't be used for cache size limitation and eviction. Resolves: olpedge-1592 Signed-off-by: Kostiantyn Zvieriev <ext-kostiantyn.zvieriev@here.com>
1 parent 84ac613 commit bbc733d

File tree

5 files changed

+480
-97
lines changed

5 files changed

+480
-97
lines changed

olp-cpp-sdk-core/src/cache/DefaultCacheImpl.cpp

Lines changed: 140 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
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";
3031
constexpr auto kExpirySuffix = "::expiry";
3132
constexpr 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+
3338
std::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+
4251
time_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

83102
DefaultCache::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

169167
bool 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

214190
boost::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

317295
void 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+
366418
DefaultCache::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

Comments
 (0)