diff --git a/include/cachinglayer/CacheSlot.h b/include/cachinglayer/CacheSlot.h index 710b272..3af0faa 100644 --- a/include/cachinglayer/CacheSlot.h +++ b/include/cachinglayer/CacheSlot.h @@ -312,6 +312,17 @@ class CacheSlot final : public std::enable_shared_from_this> { return evicted; } + // Returns true if the cell is already loaded in this slot. + // This is a read-only state check and does not trigger loading or update LRU order. + [[nodiscard]] bool + IsCached(cid_t cid) const { + if (cid < 0 || cid >= static_cast(cells_.size())) { + ThrowInfo(ErrorCode::OutOfRange, "cid {} out of range, slot has {} cells. key={}", cid, cells_.size(), + translator_->key()); + } + return cells_[cid]->is_loaded_or_cached(); + } + [[nodiscard]] size_t num_cells() const { return translator_->num_cells(); diff --git a/include/cachinglayer/lrucache/ListNode.h b/include/cachinglayer/lrucache/ListNode.h index 08d9916..00c3737 100644 --- a/include/cachinglayer/lrucache/ListNode.h +++ b/include/cachinglayer/lrucache/ListNode.h @@ -75,6 +75,9 @@ class ListNode { const ResourceUsage& loaded_size() const; + [[nodiscard]] bool + is_loaded_or_cached() const; + // Manually evicts the cell if it is not pinned. // Returns true if the cell ends up in a state other than LOADED. bool diff --git a/src/cachinglayer/lrucache/ListNode.cpp b/src/cachinglayer/lrucache/ListNode.cpp index f4ddcd4..033979b 100644 --- a/src/cachinglayer/lrucache/ListNode.cpp +++ b/src/cachinglayer/lrucache/ListNode.cpp @@ -96,6 +96,12 @@ ListNode::loaded_size() const { return loaded_size_; } +bool +ListNode::is_loaded_or_cached() const { + std::shared_lock lock(mtx_); + return state_ == State::LOADED || state_ == State::CACHED; +} + std::pair>> ListNode::pin() { // must be called with lock acquired, and state must not be NOT_LOADED. diff --git a/test/test_cachinglayer/test_cache_slot.cpp b/test/test_cachinglayer/test_cache_slot.cpp index 082c263..626512f 100644 --- a/test/test_cachinglayer/test_cache_slot.cpp +++ b/test/test_cachinglayer/test_cache_slot.cpp @@ -268,6 +268,30 @@ TEST_F(CacheSlotTest, Initialization) { ASSERT_EQ(cache_slot_->num_cells(), NUM_UNIQUE_CIDS); } +TEST_F(CacheSlotTest, IsCachedReflectsLoadedAndCachedStates) { + cl_uid_t target_uid = 30; + cid_t expected_cid = 2; + + for (cid_t cid = 0; cid < static_cast(NUM_UNIQUE_CIDS); ++cid) { + EXPECT_FALSE(cache_slot_->IsCached(cid)); + } + + auto op_ctx = std::make_unique(); + auto accessor = cache_slot_->PinCellsDirect(op_ctx.get(), {target_uid}); + ASSERT_NE(accessor, nullptr); + + EXPECT_TRUE(cache_slot_->IsCached(expected_cid)); + EXPECT_FALSE(cache_slot_->IsCached(0)); + + accessor.reset(); + EXPECT_TRUE(cache_slot_->IsCached(expected_cid)); + + EXPECT_TRUE(cache_slot_->ManualEvict(expected_cid)); + EXPECT_FALSE(cache_slot_->IsCached(expected_cid)); + EXPECT_THROW(static_cast(cache_slot_->IsCached(-1)), milvus::SegcoreError); + EXPECT_THROW(static_cast(cache_slot_->IsCached(static_cast(NUM_UNIQUE_CIDS))), milvus::SegcoreError); +} + TEST_F(CacheSlotTest, PinSingleCellSuccess) { cl_uid_t target_uid = 30; cid_t expected_cid = 2;