Skip to content

Commit 5d5f3f3

Browse files
committed
Shorten critical section in findEviction
Remove the item from mmContainer and drop the lock before attempting eviction.
1 parent fa2e533 commit 5d5f3f3

File tree

2 files changed

+20
-53
lines changed

2 files changed

+20
-53
lines changed

cachelib/allocator/CacheAllocator-inl.h

Lines changed: 14 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,13 +1202,15 @@ CacheAllocator<CacheTrait>::findEviction(PoolId pid, ClassId cid) {
12021202
++searchTries;
12031203

12041204
Item* candidate = itr.get();
1205+
mmContainer.remove(itr);
1206+
itr.destroy();
1207+
12051208
// for chained items, the ownership of the parent can change. We try to
12061209
// evict what we think as parent and see if the eviction of parent
12071210
// recycles the child we intend to.
1208-
auto toReleaseHandle =
1209-
itr->isChainedItem()
1210-
? advanceIteratorAndTryEvictChainedItem(itr)
1211-
: advanceIteratorAndTryEvictRegularItem(mmContainer, itr);
1211+
auto toReleaseHandle = candidate->isChainedItem()
1212+
? tryEvictChainedItem(*candidate)
1213+
: tryEvictRegularItem(mmContainer, *candidate);
12121214

12131215
if (toReleaseHandle) {
12141216
if (toReleaseHandle->hasChainedItem()) {
@@ -1217,10 +1219,6 @@ CacheAllocator<CacheTrait>::findEviction(PoolId pid, ClassId cid) {
12171219
(*stats_.regularItemEvictions)[pid][cid].inc();
12181220
}
12191221

1220-
// Invalidate iterator since later on we may use this mmContainer
1221-
// again, which cannot be done unless we drop this iterator
1222-
itr.destroy();
1223-
12241222
// we must be the last handle and for chained items, this will be
12251223
// the parent.
12261224
XDCHECK(toReleaseHandle.get() == candidate || candidate->isChainedItem());
@@ -1244,11 +1242,9 @@ CacheAllocator<CacheTrait>::findEviction(PoolId pid, ClassId cid) {
12441242
}
12451243
}
12461244

1247-
// If we destroyed the itr to possibly evict and failed, we restart
1248-
// from the beginning again
1249-
if (!itr) {
1250-
itr.resetToBegin();
1251-
}
1245+
// Insert item back to the mmContainer if eviction failed.
1246+
mmContainer.add(*candidate);
1247+
itr.resetToBegin();
12521248
}
12531249
return nullptr;
12541250
}
@@ -1303,19 +1299,17 @@ bool CacheAllocator<CacheTrait>::shouldWriteToNvmCacheExclusive(
13031299

13041300
template <typename CacheTrait>
13051301
typename CacheAllocator<CacheTrait>::ItemHandle
1306-
CacheAllocator<CacheTrait>::advanceIteratorAndTryEvictRegularItem(
1307-
MMContainer& mmContainer, EvictionIterator& itr) {
1302+
CacheAllocator<CacheTrait>::tryEvictRegularItem(MMContainer& mmContainer,
1303+
Item& item) {
13081304
// we should flush this to nvmcache if it is not already present in nvmcache
13091305
// and the item is not expired.
1310-
Item& item = *itr;
13111306
const bool evictToNvmCache = shouldWriteToNvmCache(item);
13121307

13131308
auto token = evictToNvmCache ? nvmCache_->createPutToken(item.getKey())
13141309
: typename NvmCacheT::PutToken{};
13151310
// record the in-flight eviciton. If not, we move on to next item to avoid
13161311
// stalling eviction.
13171312
if (evictToNvmCache && !token.isValid()) {
1318-
++itr;
13191313
stats_.evictFailConcurrentFill.inc();
13201314
return ItemHandle{};
13211315
}
@@ -1327,12 +1321,10 @@ CacheAllocator<CacheTrait>::advanceIteratorAndTryEvictRegularItem(
13271321
auto evictHandle = accessContainer_->removeIf(item, &itemEvictionPredicate);
13281322

13291323
if (!evictHandle) {
1330-
++itr;
13311324
stats_.evictFailAC.inc();
13321325
return evictHandle;
13331326
}
13341327

1335-
mmContainer.remove(itr);
13361328
XDCHECK_EQ(reinterpret_cast<uintptr_t>(evictHandle.get()),
13371329
reinterpret_cast<uintptr_t>(&item));
13381330
XDCHECK(!evictHandle->isInMMContainer());
@@ -1347,15 +1339,6 @@ CacheAllocator<CacheTrait>::advanceIteratorAndTryEvictRegularItem(
13471339
return ItemHandle{};
13481340
}
13491341

1350-
// Invalidate iterator since later on if we are not evicting this
1351-
// item, we may need to rely on the handle we created above to ensure
1352-
// proper cleanup if the item's raw refcount has dropped to 0.
1353-
// And since this item may be a parent item that has some child items
1354-
// in this very same mmContainer, we need to make sure we drop this
1355-
// exclusive iterator so we can gain access to it when we're cleaning
1356-
// up the child items
1357-
itr.destroy();
1358-
13591342
// Ensure that there are no accessors after removing from the access
13601343
// container
13611344
XDCHECK(evictHandle->getRefCount() == 1);
@@ -1369,12 +1352,10 @@ CacheAllocator<CacheTrait>::advanceIteratorAndTryEvictRegularItem(
13691352

13701353
template <typename CacheTrait>
13711354
typename CacheAllocator<CacheTrait>::ItemHandle
1372-
CacheAllocator<CacheTrait>::advanceIteratorAndTryEvictChainedItem(
1373-
EvictionIterator& itr) {
1374-
XDCHECK(itr->isChainedItem());
1355+
CacheAllocator<CacheTrait>::tryEvictChainedItem(Item& item) {
1356+
XDCHECK(item.isChainedItem());
13751357

1376-
ChainedItem* candidate = &itr->asChainedItem();
1377-
++itr;
1358+
ChainedItem* candidate = &item.asChainedItem();
13781359

13791360
// The parent could change at any point through transferChain. However, if
13801361
// that happens, we would realize that the releaseBackToAllocator return
@@ -1401,23 +1382,11 @@ CacheAllocator<CacheTrait>::advanceIteratorAndTryEvictChainedItem(
14011382
return parentHandle;
14021383
}
14031384

1404-
// Invalidate iterator since later on we may use the mmContainer
1405-
// associated with this iterator which cannot be done unless we
1406-
// drop this iterator
1407-
//
1408-
// This must be done once we know the parent is not nullptr.
1409-
// Since we can very well be the last holder of this parent item,
1410-
// which may have a chained item that is linked in this MM container.
1411-
itr.destroy();
1412-
14131385
// Ensure we have the correct parent and we're the only user of the
14141386
// parent, then free it from access container. Otherwise, we abort
14151387
XDCHECK_EQ(reinterpret_cast<uintptr_t>(&parent),
14161388
reinterpret_cast<uintptr_t>(parentHandle.get()));
14171389
XDCHECK_EQ(1u, parent.getRefCount());
1418-
1419-
removeFromMMContainer(*parentHandle);
1420-
14211390
XDCHECK(!parent.isInMMContainer());
14221391
XDCHECK(!parent.isAccessible());
14231392

cachelib/allocator/CacheAllocator.h

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1566,24 +1566,22 @@ class CacheAllocator : public CacheBase {
15661566

15671567
using EvictionIterator = typename MMContainer::Iterator;
15681568

1569-
// Advance the current iterator and try to evict a regular item
1569+
// Try to evict a regular item.
15701570
//
15711571
// @param mmContainer the container to look for evictions.
1572-
// @param itr iterator holding the item
1572+
// @param item item to evict
15731573
//
15741574
// @return valid handle to regular item on success. This will be the last
15751575
// handle to the item. On failure an empty handle.
1576-
ItemHandle advanceIteratorAndTryEvictRegularItem(MMContainer& mmContainer,
1577-
EvictionIterator& itr);
1576+
ItemHandle tryEvictRegularItem(MMContainer& mmContainer, Item& item);
15781577

1579-
// Advance the current iterator and try to evict a chained item
1580-
// Iterator may also be reset during the course of this function
1578+
// Try to evict a chained item.
15811579
//
1582-
// @param itr iterator holding the item
1580+
// @param item item to evict
15831581
//
15841582
// @return valid handle to the parent item on success. This will be the last
15851583
// handle to the item
1586-
ItemHandle advanceIteratorAndTryEvictChainedItem(EvictionIterator& itr);
1584+
ItemHandle tryEvictChainedItem(Item& item);
15871585

15881586
// Deserializer CacheAllocatorMetadata and verify the version
15891587
//

0 commit comments

Comments
 (0)