Skip to content

Commit 773f1bf

Browse files
Hao Wufacebook-github-bot
Hao Wu
authored andcommitted
Allow object cache with NVM cache
Summary: Open issue: If a NvmCache::createItem without inserting into DRAM cache, we need to find a way to clear up the memory. This happens in peek, and if the regular find failed to insert (due to replaced item refcount overflow), and getSampleItem (createAsIoBuf but not for item destructor) Reviewed By: lacora2017 Differential Revision: D58921494 fbshipit-source-id: 61c9f4db55bc03c73c838fae0dd1a16fbd9f2546
1 parent b8c4358 commit 773f1bf

File tree

5 files changed

+171
-55
lines changed

5 files changed

+171
-55
lines changed

cachelib/navy/block_cache/BlockCache.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ BlockCache::Config& BlockCache::Config::validate() {
4242
if (!device || !evictionPolicy) {
4343
throw std::invalid_argument("missing required param");
4444
}
45-
if (regionSize > 256u << 20) {
45+
if (regionSize > 1024u << 20) {
4646
// We allocate region in memory to reclaim. Too large region will cause
4747
// problems: at least, long allocation times.
4848
throw std::invalid_argument("region is too large");

cachelib/navy/common/Buffer.h

+4
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,10 @@ inline BufferView makeView(folly::StringPiece str) {
261261
return {str.size(), reinterpret_cast<const uint8_t*>(str.data())};
262262
}
263263

264+
inline Buffer makeBuffer(folly::StringPiece str) {
265+
return Buffer{makeView(str)};
266+
}
267+
264268
inline folly::StringPiece toStringPiece(BufferView view) {
265269
return {reinterpret_cast<const char*>(view.data()), view.size()};
266270
}

cachelib/object_cache/ObjectCache.h

+18-4
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,10 @@ class ObjectCache : public ObjectCacheBase<AllocatorT> {
159159
using Restorer = Restorer<ObjectCache<AllocatorT>>;
160160
using EvictionIterator = typename AllocatorT::EvictionIterator;
161161
using AccessIterator = typename AllocatorT::AccessIterator;
162+
using NvmCache = typename AllocatorT::NvmCacheT;
163+
using NvmCacheConfig = typename AllocatorT::NvmCacheT::Config;
164+
using WriteHandle = typename AllocatorT::WriteHandle;
165+
using CacheItem = typename AllocatorT::Item;
162166

163167
enum class AllocStatus { kSuccess, kAllocError, kKeyAlreadyExists };
164168

@@ -430,7 +434,11 @@ class ObjectCache : public ObjectCacheBase<AllocatorT> {
430434
util::stopPeriodicWorker(kSizeControllerName, sizeController_, timeout);
431435
success &= util::stopPeriodicWorker(kSizeDistTrackerName, sizeDistTracker_,
432436
timeout);
433-
success &= this->l1Cache_->stopWorkers(timeout);
437+
// Nullproof. This function can be called in the destructor before init()
438+
// completes successfully.
439+
if (this->l1Cache_) {
440+
success &= this->l1Cache_->stopWorkers(timeout);
441+
}
434442
return success;
435443
}
436444

@@ -615,6 +623,10 @@ void ObjectCache<AllocatorT>::init() {
615623
l1Config.setDelayCacheWorkersStart();
616624
}
617625

626+
if (config_.nvmConfig.has_value()) {
627+
l1Config.nvmConfig.assign(std::move(config_.nvmConfig.value()));
628+
}
629+
618630
this->l1Cache_ = std::make_unique<AllocatorT>(l1Config);
619631
// add a pool per shard
620632
for (size_t i = 0; i < config_.l1NumShards; i++) {
@@ -880,9 +892,11 @@ template <typename AllocatorT>
880892
ObjectCache<AllocatorT>::~ObjectCache() {
881893
stopAllWorkers();
882894

883-
for (auto itr = this->l1Cache_->begin(); itr != this->l1Cache_->end();
884-
++itr) {
885-
this->l1Cache_->remove(itr.asHandle());
895+
if (this->l1Cache_) {
896+
for (auto itr = this->l1Cache_->begin(); itr != this->l1Cache_->end();
897+
++itr) {
898+
this->l1Cache_->remove(itr.asHandle());
899+
}
886900
}
887901
}
888902

cachelib/object_cache/ObjectCacheConfig.h

+65
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <string>
2121

2222
#include "cachelib/allocator/KAllocation.h"
23+
#include "cachelib/allocator/nvmcache/NvmItem.h"
2324
#include "cachelib/common/EventInterface.h"
2425
#include "cachelib/common/Throttler.h"
2526

@@ -36,6 +37,9 @@ struct ObjectCacheConfig {
3637
using SerializeCb = typename ObjectCache::SerializeCb;
3738
using DeserializeCb = typename ObjectCache::DeserializeCb;
3839
using EvictionPolicyConfig = typename ObjectCache::EvictionPolicyConfig;
40+
using NvmCacheConfig = typename ObjectCache::NvmCacheConfig;
41+
using ToBlobCb = std::function<std::unique_ptr<folly::IOBuf>(uintptr_t)>;
42+
using ToPtrCb = std::function<uintptr_t(folly::StringPiece)>;
3943

4044
// Set cache name as a string
4145
ObjectCacheConfig& setCacheName(const std::string& _cacheName);
@@ -147,6 +151,12 @@ struct ObjectCacheConfig {
147151
// ObjectCache::startCacheWorkers()
148152
ObjectCacheConfig& setDelayCacheWorkersStart();
149153

154+
/**
155+
* Enable NVM cache.
156+
*/
157+
ObjectCacheConfig& enableNvm(NvmCacheConfig config);
158+
ObjectCacheConfig& overrideNvmCbs(ToBlobCb blobCb, ToPtrCb ptrCb);
159+
150160
// With size controller disabled, above this many entries, L1 will start
151161
// evicting.
152162
// With size controller enabled, this is only a hint used for initialization.
@@ -237,6 +247,8 @@ struct ObjectCacheConfig {
237247
// ObjectCache::startCacheWorkers()
238248
bool delayCacheWorkersStart{false};
239249

250+
std::optional<typename ObjectCache::NvmCacheConfig> nvmConfig{};
251+
240252
const ObjectCacheConfig& validate() const;
241253
};
242254

@@ -353,6 +365,7 @@ ObjectCacheConfig<T>& ObjectCacheConfig<T>::enablePersistence(
353365
"Serialize and deserialize callback must be set to enable cache "
354366
"persistence");
355367
}
368+
persistenceEnabled = true;
356369
persistThreadCount = threadCount;
357370
persistBaseFilePath = basefilePath;
358371
serializeCb = std::move(serializeCallback);
@@ -379,6 +392,7 @@ ObjectCacheConfig<T>& ObjectCacheConfig<T>::enablePersistenceWithEvictionOrder(
379392
"Serialize and deserialize callback must be set to enable cache "
380393
"persistence");
381394
}
395+
persistenceEnabled = true;
382396
persistThreadCount = 1;
383397
persistBaseFilePath = basefilePath;
384398
serializeCb = std::move(serializeCallback);
@@ -413,6 +427,56 @@ ObjectCacheConfig<T>& ObjectCacheConfig<T>::setDelayCacheWorkersStart() {
413427
return *this;
414428
}
415429

430+
template <typename T>
431+
ObjectCacheConfig<T>& ObjectCacheConfig<T>::enableNvm(NvmCacheConfig config) {
432+
nvmConfig = std::move(config);
433+
return *this;
434+
}
435+
436+
template <typename T>
437+
ObjectCacheConfig<T>& ObjectCacheConfig<T>::overrideNvmCbs(ToBlobCb blobCb,
438+
ToPtrCb ptrCb) {
439+
if (!nvmConfig || nvmConfig->makeBlobCb || nvmConfig->makeObjCb) {
440+
throw std::invalid_argument(
441+
"Do not set makeBlobCb or makeObjCb in nvmConfig before calling "
442+
"overriceNvmCbs.");
443+
}
444+
445+
nvmConfig->makeBlobCb =
446+
[blobCb = std::move(blobCb)](
447+
const typename T::CacheItem& item,
448+
folly::Range<typename T::NvmCache::ChainedItemIter>) {
449+
uintptr_t ptr =
450+
item.template getMemoryAs<typename T::Item>()->objectPtr;
451+
auto blob = blobCb(ptr);
452+
std::vector<BufferedBlob> blobs;
453+
if (blob == nullptr) {
454+
return blobs;
455+
}
456+
blobs.emplace_back(BufferedBlob{static_cast<uint32_t>(item.getSize()),
457+
std::move(blob)});
458+
return blobs;
459+
};
460+
461+
nvmConfig->makeObjCb =
462+
[ptrCb = std::move(ptrCb)](
463+
const NvmItem& nvmItem, typename T::CacheItem& it,
464+
folly::Range<typename T::NvmCache::WritableChainedItemIter>) {
465+
// Create ptr. Do not consider chained item.
466+
auto pBlob = nvmItem.getBlob(0);
467+
uintptr_t ptr = ptrCb(pBlob.data);
468+
// TODO: Is there a better way to do this?
469+
if (ptr == reinterpret_cast<uintptr_t>(nullptr)) {
470+
return false;
471+
}
472+
*it.template getMemoryAs<typename T::Item>() =
473+
typename T::Item{ptr, pBlob.data.size()};
474+
475+
return true;
476+
};
477+
return *this;
478+
}
479+
416480
template <typename T>
417481
const ObjectCacheConfig<T>& ObjectCacheConfig<T>::validate() const {
418482
// checking missing params
@@ -450,6 +514,7 @@ const ObjectCacheConfig<T>& ObjectCacheConfig<T>::validate() const {
450514
"Object size tracking has to be enabled to track object size "
451515
"distribution");
452516
}
517+
453518
return *this;
454519
}
455520

0 commit comments

Comments
 (0)