Skip to content

Commit 432ffa7

Browse files
pbhandar2meta-codesync[bot]
authored andcommitted
use a bit in CacheItem to indicate if it is a large item
Summary: During NVM promotion in NvmCache::createItem(), we set the kNvmLargeItem flag on the DRAM item to track whether its NVM copy lives in BlockCache or BigHash. This flag is later used at DRAM eviction time (e.g., to populate the AccessTimeMap for BlockCache items). The size check that determines this — smallItemMaxSize_ == 0 || key.size() + nvmItem.totalSize() > smallItemMaxSize_ — was duplicated in both branches of createItem() (the makeObjCb path and the standard memcpy path). This duplicates the routing logic from EnginePair::isItemLarge() and is easy to get out of sync if the threshold semantics ever change. Extract the check into a private isNvmItemLarge(key, nvmItem) helper with a comment explaining how it mirrors the Navy-side routing: EnginePair::isItemLarge() compares key.size() + value.size() against smallItemMaxSize_, and since the put() path passes toIOBuf(nvmItem) to Navy, value.size() == nvmItem.totalSize(). Reviewed By: rlyerly Differential Revision: D98267676 fbshipit-source-id: f54d9a35d9fbff5a30807f6bea4991beab1bac6e
1 parent f280dee commit 432ffa7

File tree

4 files changed

+73
-2
lines changed

4 files changed

+73
-2
lines changed

cachelib/allocator/CacheItem.h

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,13 @@ class CACHELIB_PACKED_ATTR CacheItem {
252252
void unmarkNvmEvicted() noexcept;
253253
bool isNvmEvicted() const noexcept;
254254

255+
/**
256+
* Track whether the item was routed to BlockCache (large item) in NVM.
257+
* Set during NVM promotion when the exact NVM buffer size is known.
258+
*/
259+
void markNvmLargeItem() noexcept;
260+
bool isNvmLargeItem() const noexcept;
261+
255262
/**
256263
* Function to set the timestamp for when to expire an item
257264
*
@@ -735,13 +742,14 @@ std::string CacheItem<CacheTrait>::toString() const {
735742
"isInMMContainer={}:isAccessible={}:isMarkedForEviction={}:"
736743
"isMoving={}:references={}:ctime="
737744
"{}:"
738-
"expTime={}:updateTime={}:isNvmClean={}:isNvmEvicted={}:hasChainedItem="
745+
"expTime={}:updateTime={}:isNvmClean={}:isNvmEvicted={}:"
746+
"isNvmLargeItem={}:hasChainedItem="
739747
"{}",
740748
this, getRefCountAndFlagsRaw(), getSize(),
741749
folly::humanify(getKey().str()), folly::hexlify(getKey()),
742750
isInMMContainer(), isAccessible(), isMarkedForEviction(), isMoving(),
743751
getRefCount(), getCreationTime(), getExpiryTime(), getLastAccessTime(),
744-
isNvmClean(), isNvmEvicted(), hasChainedItem());
752+
isNvmClean(), isNvmEvicted(), isNvmLargeItem(), hasChainedItem());
745753
}
746754
}
747755

@@ -866,6 +874,16 @@ bool CacheItem<CacheTrait>::isNvmEvicted() const noexcept {
866874
return ref_.isNvmEvicted();
867875
}
868876

877+
template <typename CacheTrait>
878+
void CacheItem<CacheTrait>::markNvmLargeItem() noexcept {
879+
ref_.markNvmLargeItem();
880+
}
881+
882+
template <typename CacheTrait>
883+
bool CacheItem<CacheTrait>::isNvmLargeItem() const noexcept {
884+
return ref_.isNvmLargeItem();
885+
}
886+
869887
template <typename CacheTrait>
870888
void CacheItem<CacheTrait>::markIsChainedItem() noexcept {
871889
XDCHECK(!hasChainedItem());

cachelib/allocator/Refcount.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ class FOLLY_PACK_ATTR RefcountWithFlags {
116116
// unevictable in the past.
117117
kUnevictable_NOOP,
118118

119+
// Item was routed to BlockCache (large item) in NVM.
120+
// Set during NVM promotion when the exact NVM buffer size is known.
121+
kNvmLargeItem,
122+
119123
// Unused. This is just to indciate the maximum number of flags
120124
kFlagMax,
121125
};
@@ -422,6 +426,13 @@ class FOLLY_PACK_ATTR RefcountWithFlags {
422426
void unmarkNvmEvicted() noexcept { return unSetFlag<kNvmEvicted>(); }
423427
bool isNvmEvicted() const noexcept { return isFlagSet<kNvmEvicted>(); }
424428

429+
/**
430+
* Track whether the item was routed to BlockCache (large item) in NVM.
431+
* Set during NVM promotion when the exact NVM buffer size is known.
432+
*/
433+
void markNvmLargeItem() noexcept { return setFlag<kNvmLargeItem>(); }
434+
bool isNvmLargeItem() const noexcept { return isFlagSet<kNvmLargeItem>(); }
435+
425436
// Whether or not an item is completely drained of access
426437
// Refcount is 0 and the item is not linked, accessible, nor exclusive
427438
bool isDrained() const noexcept { return getRefWithAccessAndAdmin() == 0; }

cachelib/allocator/nvmcache/NvmCache.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1430,11 +1430,17 @@ typename NvmCache<C>::WriteHandle NvmCache<C>::createItem(
14301430
// not visible to other threads).
14311431
it.unmarkNascent();
14321432
it->markNvmClean();
1433+
if (isNvmItemLarge(key, nvmItem)) {
1434+
it->markNvmLargeItem();
1435+
}
14331436
} else {
14341437
XDCHECK_LE(pBlob.data.size(), getStorageSizeInNvm(*it));
14351438
XDCHECK_LE(pBlob.origAllocSize, pBlob.data.size());
14361439
::memcpy(it->getMemory(), pBlob.data.data(), pBlob.data.size());
14371440
it->markNvmClean();
1441+
if (isNvmItemLarge(key, nvmItem)) {
1442+
it->markNvmLargeItem();
1443+
}
14381444

14391445
// if we have more, then we need to allocate them as chained items and add
14401446
// them in the same order. To do that, we need to add them from the inverse

cachelib/allocator/nvmcache/tests/NvmCacheTests.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2978,6 +2978,42 @@ TEST_F(NvmCacheTest, NvmHitTTATracking) {
29782978
// 6. Verify TTA was tracked (>= 1 second)
29792979
EXPECT_GE(stats.nvmHitTTASecs.p50, 1);
29802980
}
2981+
TEST_F(NvmCacheTest, NvmLargeItemFlagOnPromotion) {
2982+
// Verify that the NvmLargeItem flag is set correctly on promotion:
2983+
// - Items routed to BlockCache (large) should have the flag set.
2984+
// - Items routed to BigHash (small) should NOT have the flag set.
2985+
this->config_.setSimpleFile(cacheDir_ + "/navy", 200 * 1024ULL * 1024ULL,
2986+
true /* truncateFile */);
2987+
LruAllocator::NvmCacheConfig nvmConfig;
2988+
nvmConfig.navyConfig = this->config_;
2989+
nvmConfig.truncateItemToOriginalAllocSizeInNvm = true;
2990+
auto& config = this->getConfig();
2991+
config.enableNvmCache(nvmConfig);
2992+
this->poolAllocsizes_ = {20 * 1024};
2993+
auto& cache = this->makeCache();
2994+
auto pid = this->poolId();
2995+
2996+
auto testNvmLargeItemFlag = [&](const std::string& key, uint32_t valSize,
2997+
char fillChar) -> bool {
2998+
{
2999+
auto it = cache.allocate(pid, key, valSize);
3000+
EXPECT_NE(nullptr, it);
3001+
::memset(it->getMemory(), fillChar, it->getSize());
3002+
cache.insertOrReplace(it);
3003+
}
3004+
EXPECT_TRUE(this->pushToNvmCacheFromRamForTesting(key));
3005+
cache.flushNvmCache();
3006+
this->removeFromRamForTesting(key);
3007+
auto hdl = this->fetch(key, false /* ramOnly */);
3008+
EXPECT_NE(nullptr, hdl);
3009+
EXPECT_TRUE(hdl->isNvmClean());
3010+
return hdl->isNvmLargeItem();
3011+
};
3012+
3013+
EXPECT_TRUE(testNvmLargeItemFlag("bc", 15 * 1024, 'L'));
3014+
EXPECT_FALSE(testNvmLargeItemFlag("bh", 50, 'S'));
3015+
}
3016+
29813017
} // namespace tests
29823018
} // namespace cachelib
29833019
} // namespace facebook

0 commit comments

Comments
 (0)