Skip to content

Commit 06eefb9

Browse files
committed
initial sync logic
1 parent d51fade commit 06eefb9

File tree

3 files changed

+100
-10
lines changed

3 files changed

+100
-10
lines changed

cachelib/allocator/CacheAllocator-inl.h

Lines changed: 93 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,10 +1559,13 @@ CacheAllocator<CacheTrait>::findEviction(TierId tid, PoolId pid, ClassId cid) {
15591559
config_.evictionSearchTries > searchTries)) {
15601560

15611561
Item* toRecycle = nullptr;
1562+
Item* toRecycleParent = nullptr;
15621563
Item* candidate = nullptr;
1564+
WriteHandle headHandle{};
15631565
typename NvmCacheT::PutToken token;
15641566

1565-
mmContainer.withEvictionIterator([this, tid, pid, cid, &candidate, &toRecycle,
1567+
mmContainer.withEvictionIterator([this, tid, pid, cid, &candidate,
1568+
&toRecycle, &toRecycleParent, &headHandle,
15661569
&searchTries, &mmContainer, &lastTier,
15671570
&token](auto&& itr) {
15681571
if (!itr) {
@@ -1577,12 +1580,48 @@ CacheAllocator<CacheTrait>::findEviction(TierId tid, PoolId pid, ClassId cid) {
15771580
++searchTries;
15781581
(*stats_.evictionAttempts)[tid][pid][cid].inc();
15791582

1580-
auto* toRecycle_ = itr.get();
1581-
auto* candidate_ =
1583+
Item* toRecycle_ = itr.get();
1584+
Item* toRecycleParent_ =
15821585
toRecycle_->isChainedItem()
15831586
? &toRecycle_->asChainedItem().getParentItem(compressor_)
1584-
: toRecycle_;
1585-
1587+
: nullptr;
1588+
WriteHandle headHandle_{};
1589+
WriteHandle parentHandle_{};
1590+
Item* candidate_;
1591+
bool isHead = false;
1592+
if (!lastTier && toRecycle_->isChainedItem()) {
1593+
const auto parentKey = toRecycleParent_->getKey();
1594+
auto lock = chainedItemLocks_.tryLockExclusive(parentKey);
1595+
if (!lock || &toRecycle_->asChainedItem().getParentItem(compressor_) !=
1596+
toRecycleParent_) {
1597+
++itr;
1598+
continue;
1599+
}
1600+
XDCHECK_EQ(&toRecycle_->asChainedItem().getParentItem(compressor_),
1601+
toRecycleParent_);
1602+
headHandle_ = findChainedItem(*toRecycleParent_);
1603+
if (headHandle_) {
1604+
if (headHandle_.get() == toRecycle_) {
1605+
//we don't need to mark head handle as moving
1606+
headHandle_.reset();
1607+
isHead = true;
1608+
} else {
1609+
bool marked = headHandle_->markMoving();
1610+
if (!marked) {
1611+
++itr;
1612+
continue;
1613+
}
1614+
}
1615+
} else {
1616+
++itr;
1617+
continue;
1618+
}
1619+
candidate_ = toRecycle_;
1620+
} else if (lastTier && toRecycle_->isChainedItem()) {
1621+
candidate_ = toRecycleParent_;
1622+
} else {
1623+
candidate_ = toRecycle_;
1624+
}
15861625
if (lastTier) {
15871626
// if it's last tier, the item will be evicted
15881627
// need to create put token before marking it exclusive
@@ -1594,21 +1633,33 @@ CacheAllocator<CacheTrait>::findEviction(TierId tid, PoolId pid, ClassId cid) {
15941633
} else if ( (lastTier && candidate_->markForEviction()) ||
15951634
(!lastTier && candidate_->markMoving()) ) {
15961635
XDCHECK(candidate_->isMoving() || candidate_->isMarkedForEviction());
1636+
if (isHead) {
1637+
XDCHECK(!headHandle);
1638+
}
1639+
if (headHandle_) {
1640+
XDCHECK(headHandle_->isMoving());
1641+
headHandle = std::move(headHandle_);
1642+
}
1643+
toRecycleParent = toRecycleParent_;
15971644
// markForEviction to make sure no other thead is evicting the item
15981645
// nor holding a handle to that item if this is last tier
15991646
// since we won't be moving the item to the next tier
16001647
toRecycle = toRecycle_;
16011648
candidate = candidate_;
1602-
16031649
// Check if parent changed for chained items - if yes, we cannot
16041650
// remove the child from the mmContainer as we will not be evicting
16051651
// it. We could abort right here, but we need to cleanup in case
16061652
// unmarkForEviction() returns 0 - so just go through normal path.
16071653
if (!toRecycle_->isChainedItem() ||
16081654
&toRecycle->asChainedItem().getParentItem(compressor_) ==
1609-
candidate)
1655+
toRecycleParent_) {
16101656
mmContainer.remove(itr);
1657+
}
16111658
return;
1659+
} else if (headHandle_) {
1660+
XDCHECK(headHandle_->isMoving());
1661+
headHandle_->unmarkMoving();
1662+
wakeUpWaiters(*headHandle_,std::move(headHandle_));
16121663
}
16131664

16141665
if (candidate_->hasChainedItem()) {
@@ -1632,6 +1683,34 @@ CacheAllocator<CacheTrait>::findEviction(TierId tid, PoolId pid, ClassId cid) {
16321683
auto evictedToNext = lastTier ? nullptr
16331684
: tryEvictToNextMemoryTier(*candidate, false);
16341685
if (!evictedToNext) {
1686+
//failed to move a chained item - so evict the entire chain
1687+
if (candidate->isChainedItem()) {
1688+
//candidate should be parent now
1689+
if (headHandle) {
1690+
XDCHECK_EQ( &headHandle->asChainedItem().getParentItem(compressor_),
1691+
toRecycleParent );
1692+
XDCHECK_EQ( &candidate->asChainedItem().getParentItem(compressor_),
1693+
toRecycleParent );
1694+
}
1695+
bool marked = toRecycleParent->markMoving();
1696+
while (!marked) {
1697+
//we have a candidated marked moving and we failed to mark the parent
1698+
//we can't evict this item since we failed to allocate in next tier
1699+
//we might have to
1700+
marked = toRecycleParent->markMoving();
1701+
}
1702+
XDCHECK(marked);
1703+
candidate->unmarkMoving(); //old candidate was the child item
1704+
toRecycle = candidate; //we really want to recycle the child
1705+
candidate = toRecycleParent; //but now we evict the chain and in
1706+
//doing so recycle the child
1707+
if (headHandle) {
1708+
XDCHECK_EQ(headHandle->getRefCount(),2);
1709+
headHandle->unmarkMoving();
1710+
headHandle.reset();
1711+
XDCHECK(!headHandle);
1712+
}
1713+
}
16351714
//if insertOrReplace was called during move
16361715
//then candidate will not be accessible (failed replace during tryEvict)
16371716
// - therefore this was why we failed to
@@ -1677,6 +1756,10 @@ CacheAllocator<CacheTrait>::findEviction(TierId tid, PoolId pid, ClassId cid) {
16771756

16781757
(*stats_.numWritebacks)[tid][pid][cid].inc();
16791758
wakeUpWaiters(*candidate, std::move(evictedToNext));
1759+
if (headHandle) {
1760+
headHandle->unmarkMoving();
1761+
wakeUpWaiters(*headHandle,std::move(headHandle));
1762+
}
16801763
}
16811764

16821765
XDCHECK(!candidate->isMarkedForEviction() && !candidate->isMoving());
@@ -1761,7 +1844,9 @@ CacheAllocator<CacheTrait>::tryEvictToNextMemoryTier(
17611844
TierId tid, PoolId pid, Item& item, bool fromBgThread) {
17621845
XDCHECK(item.isMoving());
17631846
XDCHECK(item.getRefCount() == 0);
1764-
if(item.hasChainedItem()) return WriteHandle{}; // TODO: We do not support ChainedItem yet
1847+
if(item.isChainedItem() || item.hasChainedItem()) {
1848+
return WriteHandle{};
1849+
}
17651850
if(item.isExpired()) {
17661851
accessContainer_->remove(item);
17671852
item.unmarkMoving();

cachelib/allocator/Refcount.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,8 +330,7 @@ class FOLLY_PACK_ATTR RefcountWithFlags {
330330
// chained item can have ref count == 1, this just means it's linked in the chain
331331
if (isChained && (curValue & kAccessRefMask) > 1) {
332332
return false;
333-
}
334-
if ((curValue & kAccessRefMask) != 0) {
333+
} else if ((curValue & kAccessRefMask) != 0) {
335334
return false;
336335
}
337336
if (!flagSet || alreadyExclusive) {

cachelib/common/Mutex.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ class RWBucketLocks : public BaseBucketLocks<LockType, LockAlignmentType> {
341341
using Lock = LockType;
342342
using ReadLockHolder = ReadLockHolderType;
343343
using WriteLockHolder = WriteLockHolderType;
344+
using LockHolder = std::unique_lock<Lock>;
344345

345346
RWBucketLocks(uint32_t locksPower, std::shared_ptr<Hash> hasher)
346347
: Base::BaseBucketLocks(locksPower, std::move(hasher)) {}
@@ -357,6 +358,11 @@ class RWBucketLocks : public BaseBucketLocks<LockType, LockAlignmentType> {
357358
return WriteLockHolder{Base::getLock(args...)};
358359
}
359360

361+
template <typename... Args>
362+
LockHolder tryLockExclusive(Args... args) noexcept {
363+
return LockHolder(Base::getLock(args...), std::try_to_lock);
364+
}
365+
360366
// try to grab the reader lock for a limit _timeout_ duration
361367
template <typename... Args>
362368
ReadLockHolder lockShared(const std::chrono::microseconds& timeout,

0 commit comments

Comments
 (0)