Skip to content

Commit bb35a05

Browse files
committed
Bckground eviction for multi-tier
Part 4. ------------------------------- batch eviction / promotion - these changes are pretty significant so we would avoid squashing this commit in any prior background evictor patch
1 parent a76bcf7 commit bb35a05

File tree

10 files changed

+914
-313
lines changed

10 files changed

+914
-313
lines changed

cachelib/allocator/CacheAllocator.h

Lines changed: 645 additions & 292 deletions
Large diffs are not rendered by default.

cachelib/allocator/MM2Q.h

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,18 @@ class MM2Q {
461461
// is unchanged.
462462
bool add(T& node) noexcept;
463463

464+
// helper function to add the node under the container lock
465+
void addNodeLocked(T& node, const Time& currTime);
466+
467+
// adds the given nodes into the container and marks each as being present in
468+
// the container. The nodes are added to the head of the lru.
469+
//
470+
// @param vector of nodes The nodes to be added to the container.
471+
// @return number of nodes added - it is up to user to verify all
472+
// expected nodes have been added.
473+
template <typename It>
474+
uint32_t addBatch(It begin, It end) noexcept;
475+
464476
// removes the node from the lru and sets it previous and next to nullptr.
465477
//
466478
// @param node The node to be removed from the container.
@@ -895,16 +907,41 @@ bool MM2Q::Container<T, HookPtr>::add(T& node) noexcept {
895907
if (node.isInMMContainer()) {
896908
return false;
897909
}
910+
addNodeLocked(node, currTime);
911+
return true;
912+
});
913+
}
898914

899-
markHot(node);
900-
unmarkCold(node);
901-
unmarkTail(node);
902-
lru_.getList(LruType::Hot).linkAtHead(node);
903-
rebalance();
915+
// adds the node to the list assuming not in
916+
// container and holding container lock
917+
template <typename T, MM2Q::Hook<T> T::*HookPtr>
918+
void MM2Q::Container<T, HookPtr>::addNodeLocked(T& node, const Time& currTime) {
919+
XDCHECK(!node.isInMMContainer());
920+
markHot(node);
921+
unmarkCold(node);
922+
unmarkTail(node);
923+
lru_.getList(LruType::Hot).linkAtHead(node);
924+
rebalance();
925+
926+
node.markInMMContainer();
927+
setUpdateTime(node, currTime);
928+
}
904929

905-
node.markInMMContainer();
906-
setUpdateTime(node, currTime);
907-
return true;
930+
template <typename T, MM2Q::Hook<T> T::*HookPtr>
931+
template <typename It>
932+
uint32_t MM2Q::Container<T, HookPtr>::addBatch(It begin, It end) noexcept {
933+
const auto currTime = static_cast<Time>(util::getCurrentTimeSec());
934+
return lruMutex_->lock_combine([this, begin, end, currTime]() {
935+
uint32_t i = 0;
936+
for (auto itr = begin; itr != end; itr++) {
937+
T* node = *itr;
938+
if (node->isInMMContainer()) {
939+
return i;
940+
}
941+
addNodeLocked(*node,currTime);
942+
i++;
943+
}
944+
return i;
908945
});
909946
}
910947

@@ -935,6 +972,7 @@ MM2Q::Container<T, HookPtr>::withPromotionIterator(F&& fun) {
935972
fun(LockedIterator{LockHolder{}, lru_.begin(LruType::Hot)});
936973
});
937974
}
975+
938976
template <typename T, MM2Q::Hook<T> T::*HookPtr>
939977
template <typename F>
940978
void MM2Q::Container<T, HookPtr>::withContainerLock(F&& fun) {

cachelib/allocator/MMLru.h

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,18 @@ class MMLru {
337337
// is unchanged.
338338
bool add(T& node) noexcept;
339339

340+
// helper function to add the node under the container lock
341+
void addNodeLocked(T& node, const Time& currTime);
342+
343+
// adds the given nodes into the container and marks each as being present in
344+
// the container. The nodes are added to the head of the lru.
345+
//
346+
// @param vector of nodes The nodes to be added to the container.
347+
// @return number of nodes added - it is up to user to verify all
348+
// expected nodes have been added.
349+
template <typename It>
350+
uint32_t addBatch(It begin, It end) noexcept;
351+
340352
// removes the node from the lru and sets it previous and next to nullptr.
341353
//
342354
// @param node The node to be removed from the container.
@@ -690,19 +702,46 @@ bool MMLru::Container<T, HookPtr>::add(T& node) noexcept {
690702
if (node.isInMMContainer()) {
691703
return false;
692704
}
693-
if (config_.lruInsertionPointSpec == 0 || insertionPoint_ == nullptr) {
694-
lru_.linkAtHead(node);
695-
} else {
696-
lru_.insertBefore(*insertionPoint_, node);
697-
}
698-
node.markInMMContainer();
699-
setUpdateTime(node, currTime);
700-
unmarkAccessed(node);
701-
updateLruInsertionPoint();
705+
addNodeLocked(node,currTime);
702706
return true;
703707
});
704708
}
705709

710+
template <typename T, MMLru::Hook<T> T::*HookPtr>
711+
void MMLru::Container<T, HookPtr>::addNodeLocked(T& node, const Time& currTime) {
712+
XDCHECK(!node.isInMMContainer());
713+
if (config_.lruInsertionPointSpec == 0 || insertionPoint_ == nullptr) {
714+
lru_.linkAtHead(node);
715+
} else {
716+
lru_.insertBefore(*insertionPoint_, node);
717+
}
718+
node.markInMMContainer();
719+
setUpdateTime(node, currTime);
720+
unmarkAccessed(node);
721+
updateLruInsertionPoint();
722+
}
723+
724+
template <typename T, MMLru::Hook<T> T::*HookPtr>
725+
template <typename It>
726+
uint32_t MMLru::Container<T, HookPtr>::addBatch(It begin, It end) noexcept {
727+
const auto currTime = static_cast<Time>(util::getCurrentTimeSec());
728+
return lruMutex_->lock_combine([this, begin, end, currTime]() {
729+
uint32_t i = 0;
730+
for (auto itr = begin; itr != end; ++itr) {
731+
T* node = *itr;
732+
XDCHECK(!node->isInMMContainer());
733+
if (node->isInMMContainer()) {
734+
throw std::runtime_error(
735+
folly::sformat("Was not able to add all new items, failed item {}",
736+
node->toString()));
737+
}
738+
addNodeLocked(*node,currTime);
739+
i++;
740+
}
741+
return i;
742+
});
743+
}
744+
706745
template <typename T, MMLru::Hook<T> T::*HookPtr>
707746
typename MMLru::Container<T, HookPtr>::LockedIterator
708747
MMLru::Container<T, HookPtr>::getEvictionIterator() const noexcept {

cachelib/allocator/MMTinyLFU.h

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,18 @@ class MMTinyLFU {
376376
// if the node was already in the contianer. On error state of node
377377
// is unchanged.
378378
bool add(T& node) noexcept;
379+
380+
// helper function to add the node under the container lock
381+
void addNodeLocked(T& node, const Time& currTime);
382+
383+
// adds the given nodes into the container and marks each as being present in
384+
// the container. The nodes are added to the head of the lru.
385+
//
386+
// @param vector of nodes The nodes to be added to the container.
387+
// @return number of nodes added - it is up to user to verify all
388+
// expected nodes have been added.
389+
template <typename It>
390+
uint32_t addBatch(It begin, It end) noexcept;
379391

380392
// removes the node from the lru and sets it previous and next to nullptr.
381393
//
@@ -861,7 +873,15 @@ bool MMTinyLFU::Container<T, HookPtr>::add(T& node) noexcept {
861873
if (node.isInMMContainer()) {
862874
return false;
863875
}
876+
addNodeLocked(node, currTime);
877+
return true;
878+
}
864879

880+
// adds the node to the list assuming not in
881+
// container and holding container lock
882+
template <typename T, MMTinyLFU::Hook<T> T::*HookPtr>
883+
void MMTinyLFU::Container<T, HookPtr>::addNodeLocked(T& node, const Time &currTime) {
884+
XDCHECK(!node.isInMMContainer());
865885
auto& tinyLru = lru_.getList(LruType::Tiny);
866886
tinyLru.linkAtHead(node);
867887
markTiny(node);
@@ -889,7 +909,23 @@ bool MMTinyLFU::Container<T, HookPtr>::add(T& node) noexcept {
889909
node.markInMMContainer();
890910
setUpdateTime(node, currTime);
891911
unmarkAccessed(node);
892-
return true;
912+
}
913+
914+
template <typename T, MMTinyLFU::Hook<T> T::*HookPtr>
915+
template <typename It>
916+
uint32_t MMTinyLFU::Container<T, HookPtr>::addBatch(It begin, It end) noexcept {
917+
const auto currTime = static_cast<Time>(util::getCurrentTimeSec());
918+
LockHolder l(lruMutex_);
919+
uint32_t i = 0;
920+
for (auto itr = begin; itr != end; itr++) {
921+
T* node = *itr;
922+
if (node->isInMMContainer()) {
923+
return i;
924+
}
925+
addNodeLocked(*node, currTime);
926+
i++;
927+
}
928+
return i;
893929
}
894930

895931
template <typename T, MMTinyLFU::Hook<T> T::*HookPtr>

cachelib/allocator/memory/AllocationClass.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,26 @@ void* AllocationClass::addSlabAndAllocate(Slab* slab) {
140140
});
141141
}
142142

143+
std::vector<void*> AllocationClass::addSlabAndAllocateBatch(Slab* slab, uint64_t batch) {
144+
XDCHECK_NE(nullptr, slab);
145+
std::vector<void*> allocs;
146+
allocs.reserve(batch);
147+
lock_->lock_combine([this, slab, batch, &allocs]() {
148+
addSlabLocked(slab);
149+
uint64_t total = 0;
150+
while (total < batch) {
151+
void *alloc = allocateLocked();
152+
if (alloc != nullptr) {
153+
allocs.push_back(alloc);
154+
total++;
155+
} else {
156+
break;
157+
}
158+
}
159+
});
160+
return allocs;
161+
}
162+
143163
void* AllocationClass::allocateFromCurrentSlabLocked() noexcept {
144164
XDCHECK(canAllocateFromCurrentSlabLocked());
145165
void* ret = currSlab_->memoryAtOffset(currOffset_);
@@ -159,6 +179,26 @@ void* AllocationClass::allocate() {
159179
return lock_->lock_combine([this]() -> void* { return allocateLocked(); });
160180
}
161181

182+
std::vector<void*> AllocationClass::allocateBatch(uint64_t batch) {
183+
std::vector<void*> allocs;
184+
if (!canAllocate_) {
185+
return allocs;
186+
}
187+
lock_->lock_combine([this, &allocs, batch]() {
188+
uint64_t total = 0;
189+
while (total < batch) {
190+
void *alloc = allocateLocked();
191+
if (alloc != nullptr) {
192+
allocs.push_back(alloc);
193+
total++;
194+
} else {
195+
break;
196+
}
197+
}
198+
});
199+
return allocs;
200+
}
201+
162202
void* AllocationClass::allocateLocked() {
163203
// fast path for case when the cache is mostly full.
164204
if (freedAllocations_.empty() && freeSlabs_.empty() &&

cachelib/allocator/memory/AllocationClass.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ class AllocationClass {
116116
// don't have any free memory. The caller will have to add a slab
117117
// to this slab class to make further allocations out of it.
118118
void* allocate();
119+
std::vector<void*> allocateBatch(uint64_t batch);
119120

120121
// @param ctx release context for the slab owning this alloc
121122
// @param memory memory to check
@@ -227,6 +228,7 @@ class AllocationClass {
227228
// @param slab a new slab to be added. This can NOT be nullptr.
228229
// @return new allocation. This cannot fail.
229230
void* addSlabAndAllocate(Slab* slab);
231+
std::vector<void*> addSlabAndAllocateBatch(Slab* slab, uint64_t batch);
230232

231233
// Releasing a slab is a two step process.
232234
// 1. Mark a slab for release, by calling `startSlabRelease`.

cachelib/allocator/memory/MemoryAllocator.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,16 @@ void* MemoryAllocator::allocate(PoolId id, uint32_t size) {
7171
return mp.allocate(size);
7272
}
7373

74+
void* MemoryAllocator::allocateByCid(PoolId id, ClassId cid) {
75+
auto& mp = memoryPoolManager_.getPoolById(id);
76+
return mp.allocateByCid(cid);
77+
}
78+
79+
std::vector<void*> MemoryAllocator::allocateByCidBatch(PoolId id, ClassId cid, uint64_t batch) {
80+
auto& mp = memoryPoolManager_.getPoolById(id);
81+
return mp.allocateByCidBatch(cid, batch);
82+
}
83+
7484
void* MemoryAllocator::allocateZeroedSlab(PoolId id) {
7585
if (!config_.enableZeroedSlabAllocs) {
7686
throw std::logic_error("Zeroed Slab allcoation is not enabled");

cachelib/allocator/memory/MemoryAllocator.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ class MemoryAllocator {
167167
// @throw std::invalid_argument if the poolId is invalid or the size is
168168
// invalid.
169169
void* allocate(PoolId id, uint32_t size);
170+
void* allocateByCid(PoolId id, ClassId cid);
171+
std::vector<void*> allocateByCidBatch(PoolId id, ClassId cid, uint64_t batch);
170172

171173
// Allocate a zeroed Slab
172174
//

0 commit comments

Comments
 (0)