Skip to content

Commit ce79bd9

Browse files
byrnedjigchor
andauthored
Chained item movement between tiers - sync on the parent item (#84)
* Chained item movement between tiers - currently sync on the parent item for moving. - updated tests accordingly, note that we can no longer swap parent item if chained item is being moved for slab release. * added some debug checks around chained item check --------- Co-authored-by: Igor Chorazewicz <[email protected]>
1 parent 946b95b commit ce79bd9

19 files changed

+605
-532
lines changed

cachelib/allocator/CacheAllocator-inl.h

+438-437
Large diffs are not rendered by default.

cachelib/allocator/CacheAllocator.h

+49-30
Original file line numberDiff line numberDiff line change
@@ -1387,7 +1387,7 @@ class CacheAllocator : public CacheBase {
13871387

13881388
private:
13891389
// wrapper around Item's refcount and active handle tracking
1390-
FOLLY_ALWAYS_INLINE RefcountWithFlags::incResult incRef(Item& it, bool failIfMoving);
1390+
FOLLY_ALWAYS_INLINE RefcountWithFlags::incResult incRef(Item& it);
13911391
FOLLY_ALWAYS_INLINE RefcountWithFlags::Value decRef(Item& it);
13921392

13931393
// drops the refcount and if needed, frees the allocation back to the memory
@@ -1551,6 +1551,26 @@ class CacheAllocator : public CacheBase {
15511551
WriteHandle allocateChainedItemInternal(const ReadHandle& parent,
15521552
uint32_t size);
15531553

1554+
// Allocate a chained item to a specific tier
1555+
//
1556+
// The resulting chained item does not have a parent item yet
1557+
// and if we fail to link to the chain for any reasoin
1558+
// the chained item will be freed once the handle is dropped.
1559+
//
1560+
// The parent item parameter here is mainly used to find the
1561+
// correct pool to allocate memory for this chained item
1562+
//
1563+
// @param parent parent item
1564+
// @param size the size for the chained allocation
1565+
// @param tid the tier to allocate on
1566+
//
1567+
// @return handle to the chained allocation
1568+
// @throw std::invalid_argument if the size requested is invalid or
1569+
// if the item is invalid
1570+
WriteHandle allocateChainedItemInternalTier(const Item& parent,
1571+
uint32_t size,
1572+
TierId tid);
1573+
15541574
// Given an item and its parentKey, validate that the parentKey
15551575
// corresponds to an item that's the parent of the supplied item.
15561576
//
@@ -1626,19 +1646,17 @@ class CacheAllocator : public CacheBase {
16261646
//
16271647
// @return true If the move was completed, and the containers were updated
16281648
// successfully.
1629-
bool moveRegularItemWithSync(Item& oldItem, WriteHandle& newItemHdl);
1649+
bool moveRegularItem(Item& oldItem, WriteHandle& newItemHdl);
16301650

1631-
// Moves a regular item to a different slab. This should only be used during
1632-
// slab release after the item's exclusive bit has been set. The user supplied
1633-
// callback is responsible for copying the contents and fixing the semantics
1634-
// of chained item.
1651+
// Moves a chained item to a different memory tier.
16351652
//
1636-
// @param oldItem item being moved
1653+
// @param oldItem Reference to the item being moved
16371654
// @param newItemHdl Reference to the handle of the new item being moved into
1655+
// @param parentHandle Reference to the handle of the parent item
16381656
//
16391657
// @return true If the move was completed, and the containers were updated
16401658
// successfully.
1641-
bool moveRegularItem(Item& oldItem, WriteHandle& newItemHdl);
1659+
bool moveChainedItem(ChainedItem& oldItem, WriteHandle& newItemHdl, Item& parentItem);
16421660

16431661
// template class for viewAsChainedAllocs that takes either ReadHandle or
16441662
// WriteHandle
@@ -1651,29 +1669,12 @@ class CacheAllocator : public CacheBase {
16511669
template <typename Handle>
16521670
folly::IOBuf convertToIOBufT(Handle& handle);
16531671

1654-
// Moves a chained item to a different slab. This should only be used during
1655-
// slab release after the item's exclusive bit has been set. The user supplied
1656-
// callback is responsible for copying the contents and fixing the semantics
1657-
// of chained item.
1658-
//
1659-
// Note: If we have successfully moved the old item into the new, the
1660-
// newItemHdl is reset and no longer usable by the caller.
1661-
//
1662-
// @param oldItem Reference to the item being moved
1663-
// @param newItemHdl Reference to the handle of the new item being
1664-
// moved into
1665-
//
1666-
// @return true If the move was completed, and the containers were updated
1667-
// successfully.
1668-
bool moveChainedItem(ChainedItem& oldItem, WriteHandle& newItemHdl);
1669-
16701672
// Transfers the chain ownership from parent to newParent. Parent
16711673
// will be unmarked as having chained allocations. Parent will not be null
16721674
// after calling this API.
16731675
//
1674-
// Parent and NewParent must be valid handles to items with same key and
1675-
// parent must have chained items and parent handle must be the only
1676-
// outstanding handle for parent. New parent must be without any chained item
1676+
// NewParent must be valid handles to item with same key as Parent and
1677+
// Parent must have chained items. New parent must be without any chained item
16771678
// handles.
16781679
//
16791680
// Chained item lock for the parent's key needs to be held in exclusive mode.
@@ -1682,7 +1683,7 @@ class CacheAllocator : public CacheBase {
16821683
// @param newParent the new parent for the chain
16831684
//
16841685
// @throw if any of the conditions for parent or newParent are not met.
1685-
void transferChainLocked(WriteHandle& parent, WriteHandle& newParent);
1686+
void transferChainLocked(Item& parent, WriteHandle& newParent);
16861687

16871688
// replace a chained item in the existing chain. This needs to be called
16881689
// with the chained item lock held exclusive
@@ -1696,6 +1697,24 @@ class CacheAllocator : public CacheBase {
16961697
WriteHandle newItemHdl,
16971698
const Item& parent);
16981699

1700+
//
1701+
// Performs the actual inplace replace - it is called from
1702+
// moveChainedItem and replaceChainedItemLocked
1703+
// must hold chainedItemLock
1704+
//
1705+
// @param oldItem the item we are replacing in the chain
1706+
// @param newItem the item we are replacing it with
1707+
// @param parent the parent for the chain
1708+
// @param fromMove used to determine if the replaced was called from
1709+
// moveChainedItem - we avoid the handle destructor
1710+
// in this case.
1711+
//
1712+
// @return handle to the oldItem
1713+
void replaceInChainLocked(Item& oldItem,
1714+
WriteHandle& newItemHdl,
1715+
const Item& parent,
1716+
bool fromMove);
1717+
16991718
// Insert an item into MM container. The caller must hold a valid handle for
17001719
// the item.
17011720
//
@@ -1986,7 +2005,7 @@ auto& mmContainer = getMMContainer(tid, pid, cid);
19862005
throw std::runtime_error("Not supported for chained items");
19872006
}
19882007

1989-
if (candidate->markMoving(true)) {
2008+
if (candidate->markMoving()) {
19902009
mmContainer.remove(itr);
19912010
candidates.push_back(candidate);
19922011
} else {
@@ -2059,7 +2078,7 @@ auto& mmContainer = getMMContainer(tid, pid, cid);
20592078

20602079
// TODO: only allow it for read-only items?
20612080
// or implement mvcc
2062-
if (candidate->markMoving(true)) {
2081+
if (candidate->markMoving()) {
20632082
// promotions should rarely fail since we already marked moving
20642083
mmContainer.remove(itr);
20652084
candidates.push_back(candidate);

cachelib/allocator/CacheItem-inl.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,8 @@ bool CacheItem<CacheTrait>::markForEvictionWhenMoving() {
238238
}
239239

240240
template <typename CacheTrait>
241-
bool CacheItem<CacheTrait>::markMoving(bool failIfRefNotZero) {
242-
return ref_.markMoving(failIfRefNotZero);
241+
bool CacheItem<CacheTrait>::markMoving() {
242+
return ref_.markMoving();
243243
}
244244

245245
template <typename CacheTrait>

cachelib/allocator/CacheItem.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -312,9 +312,9 @@ class CACHELIB_PACKED_ATTR CacheItem {
312312
//
313313
// @return true on success, failure if item is marked as exclusive
314314
// @throw exception::RefcountOverflow on ref count overflow
315-
FOLLY_ALWAYS_INLINE RefcountWithFlags::incResult incRef(bool failIfMoving) {
315+
FOLLY_ALWAYS_INLINE RefcountWithFlags::incResult incRef() {
316316
try {
317-
return ref_.incRef(failIfMoving);
317+
return ref_.incRef();
318318
} catch (exception::RefcountOverflow& e) {
319319
throw exception::RefcountOverflow(
320320
folly::sformat("{} item: {}", e.what(), toString()));
@@ -381,7 +381,7 @@ class CACHELIB_PACKED_ATTR CacheItem {
381381
* Unmarking moving will also return the refcount at the moment of
382382
* unmarking.
383383
*/
384-
bool markMoving(bool failIfRefNotZero);
384+
bool markMoving();
385385
RefcountWithFlags::Value unmarkMoving() noexcept;
386386
bool isMoving() const noexcept;
387387
bool isOnlyMoving() const noexcept;

cachelib/allocator/MM2Q-inl.h

+6
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,12 @@ MM2Q::Container<T, HookPtr>::getEvictionIterator() const noexcept {
247247
return LockedIterator{std::move(l), lru_.rbegin()};
248248
}
249249

250+
template <typename T, MM2Q::Hook<T> T::*HookPtr>
251+
template <typename F>
252+
void MM2Q::Container<T, HookPtr>::withContainerLock(F&& fun) {
253+
lruMutex_->lock_combine([this, &fun]() { fun(); });
254+
}
255+
250256
template <typename T, MM2Q::Hook<T> T::*HookPtr>
251257
template <typename F>
252258
void MM2Q::Container<T, HookPtr>::withEvictionIterator(F&& fun) {

cachelib/allocator/MM2Q.h

+4
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,10 @@ class MM2Q {
503503
template <typename F>
504504
void withEvictionIterator(F&& f);
505505

506+
// Execute provided function under container lock.
507+
template <typename F>
508+
void withContainerLock(F&& f);
509+
506510
// Execute provided function under container lock. Function gets
507511
// iterator passed as parameter.
508512
template <typename F>

cachelib/allocator/MMLru-inl.h

+6
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,12 @@ MMLru::Container<T, HookPtr>::getEvictionIterator() const noexcept {
218218
return LockedIterator{std::move(l), lru_.rbegin()};
219219
}
220220

221+
template <typename T, MMLru::Hook<T> T::*HookPtr>
222+
template <typename F>
223+
void MMLru::Container<T, HookPtr>::withContainerLock(F&& fun) {
224+
lruMutex_->lock_combine([this, &fun]() { fun(); });
225+
}
226+
221227
template <typename T, MMLru::Hook<T> T::*HookPtr>
222228
template <typename F>
223229
void MMLru::Container<T, HookPtr>::withEvictionIterator(F&& fun) {

cachelib/allocator/MMLru.h

+4
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,10 @@ class MMLru {
377377
template <typename F>
378378
void withEvictionIterator(F&& f);
379379

380+
// Execute provided function under container lock.
381+
template <typename F>
382+
void withContainerLock(F&& f);
383+
380384
template <typename F>
381385
void withPromotionIterator(F&& f);
382386

cachelib/allocator/MMTinyLFU-inl.h

+7
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,13 @@ MMTinyLFU::Container<T, HookPtr>::getEvictionIterator() const noexcept {
220220
return LockedIterator{std::move(l), *this};
221221
}
222222

223+
template <typename T, MMTinyLFU::Hook<T> T::*HookPtr>
224+
template <typename F>
225+
void MMTinyLFU::Container<T, HookPtr>::withContainerLock(F&& fun) {
226+
LockHolder l(lruMutex_);
227+
fun();
228+
}
229+
223230
template <typename T, MMTinyLFU::Hook<T> T::*HookPtr>
224231
template <typename F>
225232
void MMTinyLFU::Container<T, HookPtr>::withEvictionIterator(F&& fun) {

cachelib/allocator/MMTinyLFU.h

+4
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,10 @@ class MMTinyLFU {
497497
template <typename F>
498498
void withEvictionIterator(F&& f);
499499

500+
// Execute provided function under container lock.
501+
template <typename F>
502+
void withContainerLock(F&& f);
503+
500504
template <typename F>
501505
void withPromotionIterator(F&& f);
502506

cachelib/allocator/Refcount.h

+9-6
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,9 @@ class FOLLY_PACK_ATTR RefcountWithFlags {
140140
// @return true if refcount is bumped. false otherwise (if item is exclusive)
141141
// @throw exception::RefcountOverflow if new count would be greater than
142142
// maxCount
143-
FOLLY_ALWAYS_INLINE incResult incRef(bool failIfMoving) {
143+
FOLLY_ALWAYS_INLINE incResult incRef() {
144144
incResult res = incOk;
145-
auto predicate = [failIfMoving, &res](const Value curValue) {
145+
auto predicate = [&res](const Value curValue) {
146146
Value bitMask = getAdminRef<kExclusive>();
147147

148148
const bool exlusiveBitIsSet = curValue & bitMask;
@@ -151,7 +151,7 @@ class FOLLY_PACK_ATTR RefcountWithFlags {
151151
} else if (exlusiveBitIsSet && (curValue & kAccessRefMask) == 0) {
152152
res = incFailedEviction;
153153
return false;
154-
} else if (exlusiveBitIsSet && failIfMoving) {
154+
} else if (exlusiveBitIsSet) {
155155
res = incFailedMoving;
156156
return false;
157157
}
@@ -320,12 +320,15 @@ class FOLLY_PACK_ATTR RefcountWithFlags {
320320
*
321321
* Unmarking moving does not depend on `isInMMContainer`
322322
*/
323-
bool markMoving(bool failIfRefNotZero) {
324-
auto predicate = [failIfRefNotZero](const Value curValue) {
323+
bool markMoving() {
324+
auto predicate = [](const Value curValue) {
325325
Value conditionBitMask = getAdminRef<kLinked>();
326326
const bool flagSet = curValue & conditionBitMask;
327327
const bool alreadyExclusive = curValue & getAdminRef<kExclusive>();
328-
if (failIfRefNotZero && (curValue & kAccessRefMask) != 0) {
328+
const bool isChained = curValue & getFlag<kIsChainedItem>();
329+
330+
// chained item can have ref count == 1, this just means it's linked in the chain
331+
if ((curValue & kAccessRefMask) > isChained ? 1 : 0) {
329332
return false;
330333
}
331334
if (!flagSet || alreadyExclusive) {

cachelib/allocator/tests/AllocatorTypeTest.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,8 @@ TYPED_TEST(BaseAllocatorTest, AddChainedItemMultiThreadWithMovingAndSync) {
288288
this->testAddChainedItemMultithreadWithMovingAndSync();
289289
}
290290

291-
TYPED_TEST(BaseAllocatorTest, TransferChainWhileMoving) {
292-
this->testTransferChainWhileMoving();
291+
TYPED_TEST(BaseAllocatorTest, TransferChainAfterMoving) {
292+
this->testTransferChainAfterMoving();
293293
}
294294

295295
TYPED_TEST(BaseAllocatorTest, AddAndPopChainedItemMultithread) {

0 commit comments

Comments
 (0)