Skip to content

Commit 8c9712f

Browse files
committed
[meta] lru cache support inner last access time field
1 parent 7e3408a commit 8c9712f

17 files changed

Lines changed: 574 additions & 440 deletions

kv_cache_manager/common/cache/advanced_cache.h

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -415,12 +415,22 @@ class Cache {
415415
void(const std::string_view &key, ObjectPtr obj, size_t charge, const CacheItemHelper *helper)> &callback,
416416
const ApplyToAllEntriesOptions &opts) = 0;
417417

418+
// Callback invoked (while holding the shard mutex) whenever the LRU tail
419+
// of a shard changes. Parameters: (shard_id, tail_value_ptr).
420+
// tail_value_ptr is nullptr when the shard becomes empty.
421+
using TailChangeCallback = std::function<void(uint32_t shard_id, ObjectPtr tail_value)>;
422+
423+
// Register a callback that is invoked whenever the LRU tail of any shard
424+
// changes. The callback is called inside the shard lock, so it must be
425+
// very lightweight (e.g. a single atomic store).
426+
// Default implementation is a no-op (not supported).
427+
virtual void SetTailChangeCallback(TailChangeCallback /*callback*/) {}
428+
418429
// Returns up to `count` oldest (least recently used) keys from the
419430
// specified shard. Returns the number of keys actually collected.
420431
// Default implementation returns 0 (not supported).
421-
virtual size_t GetOldestKeysInShard(uint32_t /*shard_id*/,
422-
size_t /*count*/,
423-
std::vector<std::string> & /*out_keys*/) {
432+
virtual size_t
433+
GetOldestKeysInShard(uint32_t /*shard_id*/, size_t /*count*/, std::vector<std::string> & /*out_keys*/) {
424434
return 0;
425435
}
426436

@@ -431,9 +441,9 @@ class Cache {
431441
// Default implementation is a no-op (not supported).
432442
virtual void ApplyToSingleShard(
433443
uint32_t /*shard_id*/,
434-
const std::function<
435-
void(const std::string_view &key, ObjectPtr obj, size_t charge, const CacheItemHelper *helper)>
436-
& /*callback*/) {}
444+
const std::function<void(
445+
const std::string_view &key, ObjectPtr obj, size_t charge, const CacheItemHelper *helper)> & /*callback*/) {
446+
}
437447

438448
// Insert a mapping from key->object only if the key does not already exist.
439449
// Returns EC_OK on successful insertion, EC_EXIST if the key is already
@@ -680,8 +690,8 @@ class CacheWrapper : public Cache {
680690
void ApplyToSingleShard(
681691
uint32_t shard_id,
682692
const std::function<
683-
void(const std::string_view &key, ObjectPtr value, size_t charge, const CacheItemHelper *helper)>
684-
&callback) override {
693+
void(const std::string_view &key, ObjectPtr value, size_t charge, const CacheItemHelper *helper)> &callback)
694+
override {
685695
target_->ApplyToSingleShard(shard_id, callback);
686696
}
687697

kv_cache_manager/common/cache/lru_cache.cc

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ void LRUHandleTable::Resize() {
8787

8888
uint32_t old_length = uint32_t{1} << length_bits_;
8989
int new_length_bits = length_bits_ + 1;
90-
std::unique_ptr<LRUHandle *[]> new_list{new LRUHandle *[size_t{1} << new_length_bits] {}};
90+
std::unique_ptr<LRUHandle *[]> new_list { new LRUHandle *[size_t{1} << new_length_bits] {} };
9191
[[maybe_unused]] uint32_t count = 0;
9292
for (uint32_t i = 0; i < old_length; i++) {
9393
LRUHandle *h = list_[i];
@@ -225,6 +225,7 @@ double LRUCacheShard::GetLowPriPoolRatio() {
225225
void LRUCacheShard::LRU_Remove(LRUHandle *e) {
226226
assert(e->next != nullptr);
227227
assert(e->prev != nullptr);
228+
bool was_tail = (lru_.next == e);
228229
if (lru_low_pri_ == e) {
229230
lru_low_pri_ = e->prev;
230231
}
@@ -244,11 +245,15 @@ void LRUCacheShard::LRU_Remove(LRUHandle *e) {
244245
assert(low_pri_pool_usage_ >= e->total_charge);
245246
low_pri_pool_usage_ -= e->total_charge;
246247
}
248+
if (was_tail) {
249+
NotifyTailChange();
250+
}
247251
}
248252

249253
void LRUCacheShard::LRU_Insert(LRUHandle *e) {
250254
assert(e->next == nullptr);
251255
assert(e->prev == nullptr);
256+
bool was_empty = (lru_.next == &lru_);
252257
if (high_pri_pool_ratio_ > 0 && (e->IsHighPri() || e->HasHit())) {
253258
// Inset "e" to head of LRU list.
254259
e->next = &lru_;
@@ -285,6 +290,10 @@ void LRUCacheShard::LRU_Insert(LRUHandle *e) {
285290
lru_bottom_pri_ = e;
286291
}
287292
lru_usage_ += e->total_charge;
293+
if (was_empty) {
294+
// List went from 0 to 1 entry: the newly inserted node is the tail.
295+
NotifyTailChange();
296+
}
288297
}
289298

290299
void LRUCacheShard::MaintainPoolSize() {
@@ -358,8 +367,8 @@ void LRUCacheShard::SetStrictCapacityLimit(bool strict_capacity_limit) {
358367
strict_capacity_limit_ = strict_capacity_limit;
359368
}
360369

361-
ErrorCode LRUCacheShard::DoInsertItemUnsafe(LRUHandle *e, LRUHandle **handle,
362-
autovector<LRUHandle *> *last_reference_list) {
370+
ErrorCode
371+
LRUCacheShard::DoInsertItemUnsafe(LRUHandle *e, LRUHandle **handle, autovector<LRUHandle *> *last_reference_list) {
363372
// Free the space following strict LRU policy until enough space
364373
// is freed or the lru list is empty.
365374
EvictFromLRU(e->total_charge, last_reference_list);
@@ -679,6 +688,28 @@ size_t LRUCacheShard::GetOldestKeys(size_t count, std::vector<std::string> &out_
679688
return collected;
680689
}
681690

691+
void LRUCacheShard::SetTailChangeCallback(uint32_t shard_id, const Cache::TailChangeCallback &callback) {
692+
std::lock_guard<std::mutex> l(mutex_);
693+
shard_id_ = shard_id;
694+
tail_change_callback_ = callback;
695+
// Notify immediately with current tail state so the caller gets the
696+
// initial value.
697+
NotifyTailChange();
698+
}
699+
700+
void LRUCacheShard::NotifyTailChange() {
701+
if (!tail_change_callback_) {
702+
return;
703+
}
704+
LRUHandle *tail = lru_.next;
705+
if (tail == &lru_) {
706+
// LRU list is empty.
707+
tail_change_callback_(shard_id_, nullptr);
708+
} else {
709+
tail_change_callback_(shard_id_, tail->value);
710+
}
711+
}
712+
682713
void LRUCacheShard::AppendPrintableOptions(std::string &str) const {
683714
const int kBufferSize = 200;
684715
char buffer[kBufferSize];
@@ -739,16 +770,21 @@ size_t LRUCache::TEST_GetLRUSize() {
739770

740771
double LRUCache::GetHighPriPoolRatio() { return GetShard(0).GetHighPriPoolRatio(); }
741772

742-
size_t LRUCache::GetOldestKeysInShard(uint32_t shard_id,
743-
size_t count,
744-
std::vector<std::string> &out_keys) {
773+
size_t LRUCache::GetOldestKeysInShard(uint32_t shard_id, size_t count, std::vector<std::string> &out_keys) {
745774
uint32_t num_shards = GetNumShards();
746775
if (shard_id >= num_shards || count == 0) {
747776
return 0;
748777
}
749778
return GetShard(shard_id).GetOldestKeys(count, out_keys);
750779
}
751780

781+
void LRUCache::SetTailChangeCallback(TailChangeCallback callback) {
782+
uint32_t num_shards = GetNumShards();
783+
for (uint32_t i = 0; i < num_shards; ++i) {
784+
GetShard(i).SetTailChangeCallback(i, callback);
785+
}
786+
}
787+
752788
} // namespace lru_cache
753789

754790
std::shared_ptr<Cache> LRUCacheOptions::MakeSharedCache() const {

kv_cache_manager/common/cache/lru_cache.h

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,10 @@ class ALIGN_AS(CACHE_LINE_SIZE) LRUCacheShard final : public CacheShardBase {
367367
// Returns the number of keys actually collected.
368368
size_t GetOldestKeys(size_t count, std::vector<std::string> &out_keys);
369369

370+
// Set the shard id and tail-change callback for this shard.
371+
// The callback is invoked inside the shard mutex whenever the LRU tail changes.
372+
void SetTailChangeCallback(uint32_t shard_id, const Cache::TailChangeCallback &callback);
373+
370374
private:
371375
friend class LRUCache;
372376
// Insert an item into the hash table and, if handle is null, insert into
@@ -468,6 +472,14 @@ class ALIGN_AS(CACHE_LINE_SIZE) LRUCacheShard final : public CacheShardBase {
468472

469473
// A reference to Cache::eviction_callback_
470474
const Cache::EvictionCallback &eviction_callback_;
475+
476+
// Tail-change notification support.
477+
uint32_t shard_id_{0};
478+
Cache::TailChangeCallback tail_change_callback_;
479+
480+
// Must be called while holding mutex_. Invokes tail_change_callback_ with
481+
// the current tail value (nullptr if the LRU list is empty).
482+
void NotifyTailChange();
471483
};
472484

473485
class LRUCache
@@ -494,9 +506,10 @@ class LRUCache
494506
double GetHighPriPoolRatio();
495507

496508
// Returns up to `count` oldest keys from the specified shard.
497-
size_t GetOldestKeysInShard(uint32_t shard_id,
498-
size_t count,
499-
std::vector<std::string> &out_keys) override;
509+
size_t GetOldestKeysInShard(uint32_t shard_id, size_t count, std::vector<std::string> &out_keys) override;
510+
511+
// Register a callback invoked whenever the LRU tail of any shard changes.
512+
void SetTailChangeCallback(TailChangeCallback callback) override;
500513
};
501514

502515
} // namespace lru_cache

kv_cache_manager/meta/meta_cached_backend.cc

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -305,15 +305,6 @@ std::vector<ErrorCode> MetaCachedBackend::Upsert(const KeyTypeVec &keys, const F
305305
return local_backend_->Upsert(keys, field_maps, persistent_results);
306306
}
307307

308-
std::vector<ErrorCode> MetaCachedBackend::IncrFields(const KeyTypeVec &keys,
309-
const std::map<std::string, int64_t> &field_amounts) noexcept {
310-
if (recover_state_.load(std::memory_order_acquire) == RecoverState::kRecover) {
311-
EnsureKeyInLocal(keys);
312-
}
313-
std::vector<ErrorCode> persistent_results = persistent_backend_->IncrFields(keys, field_amounts);
314-
return local_backend_->IncrFields(keys, field_amounts, persistent_results);
315-
}
316-
317308
std::vector<ErrorCode> MetaCachedBackend::Delete(const KeyTypeVec &keys) noexcept {
318309
std::vector<ErrorCode> persistent_results = persistent_backend_->Delete(keys);
319310

@@ -451,16 +442,7 @@ ErrorCode MetaCachedBackend::SampleReclaimKeys(const int64_t count, std::vector<
451442
}
452443

453444
ErrorCode MetaCachedBackend::PutMetaData(const FieldMap &field_maps) noexcept {
454-
ErrorCode persistent_ec = persistent_backend_->PutMetaData(field_maps);
455-
if (persistent_ec != EC_OK) {
456-
return persistent_ec;
457-
}
458-
ErrorCode cache_ec = local_backend_->PutMetaData(field_maps);
459-
if (cache_ec != EC_OK) {
460-
KVCM_LOG_ERROR("meta cached backend: cache PutMetaData failed ec[%d], persistent succeeded", cache_ec);
461-
return cache_ec;
462-
}
463-
return EC_OK;
445+
return persistent_backend_->PutMetaData(field_maps);
464446
}
465447

466448
ErrorCode MetaCachedBackend::GetMetaData(FieldMap &field_maps) noexcept {

kv_cache_manager/meta/meta_cached_backend.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ class MetaCachedBackend : public MetaStorageBackend {
3838
std::vector<ErrorCode> Put(const KeyTypeVec &keys, const FieldMapVec &field_maps) noexcept override;
3939
std::vector<ErrorCode> UpdateFields(const KeyTypeVec &keys, const FieldMapVec &field_maps) noexcept override;
4040
std::vector<ErrorCode> Upsert(const KeyTypeVec &keys, const FieldMapVec &field_maps) noexcept override;
41-
std::vector<ErrorCode> IncrFields(const KeyTypeVec &keys,
42-
const std::map<std::string, int64_t> &field_amounts) noexcept override;
4341
std::vector<ErrorCode> Delete(const KeyTypeVec &keys) noexcept override;
4442

4543
// read

0 commit comments

Comments
 (0)