@@ -1466,51 +1466,58 @@ CacheAllocator<CacheTrait>::findEviction(TierId tid, PoolId pid, ClassId cid) {
14661466 ++itr;
14671467 continue ;
14681468 }
1469+
1470+ if (candidate->isChainedItem ()) {
1471+ candidate = &candidate->asChainedItem ().getParentItem (compressor_);
1472+ }
1473+
1474+ {
1475+ auto toReleaseHandle = accessContainer_->find (*candidate);
1476+ if (!toReleaseHandle) {
1477+ ++itr;
1478+ continue ;
1479+ }
1480+ toReleaseHandle.release ();
1481+ }
1482+ // incRef(*candidate);
14691483
1470- incRef (*candidate);
14711484 itr.destroy ();
14721485
14731486 // for chained items, the ownership of the parent can change. We try to
14741487 // evict what we think as parent and see if the eviction of parent
14751488 // recycles the child we intend to.
14761489
1477- WriteHandle toReleaseHandle = tryEvictToNextMemoryTier (tid, pid, candidate);
14781490 bool movedToNextTier = false ;
1479- if (toReleaseHandle) {
1480- movedToNextTier = true ;
1481- } else {
1482- toReleaseHandle = candidate->isChainedItem ()
1483- ? tryEvictChainedItem (mmContainer, *candidate)
1484- : tryEvictRegularItem (mmContainer, *candidate);
1485- // XXX: fix chained item
1491+ bool evicted = false ;
1492+ {
1493+ auto h = tryEvictToNextMemoryTier (tid, pid, candidate);
1494+ if (h) {
1495+ movedToNextTier = true ;
1496+ evicted = true ;
1497+ h.release ();
1498+ decRef (*candidate);
1499+ }
14861500 }
1487-
1488- if (toReleaseHandle) {
1489- if (toReleaseHandle->hasChainedItem ()) {
1501+ if (!movedToNextTier) {
1502+ evicted = tryEvictItem (mmContainer, *candidate);
1503+ }
1504+ if (evicted) {
1505+ if (candidate->hasChainedItem ()) {
14901506 (*stats_.chainedItemEvictions )[pid][cid].inc ();
14911507 } else {
14921508 (*stats_.regularItemEvictions )[pid][cid].inc ();
14931509 }
14941510
1495- // we must be the last handle and for chained items, this will be
1496- // the parent.
1497- XDCHECK (toReleaseHandle.get () == candidate || candidate->isChainedItem ());
1498- XDCHECK_EQ (2u , toReleaseHandle->getRefCount ());
1499-
1500- // We manually release the item here because we don't want to
1501- // invoke the Item Handle's destructor which will be decrementing
1502- // an already zero refcount, which will throw exception
1503- auto & itemToRelease = *toReleaseHandle.release ();
1511+ XDCHECK_EQ (1u , candidate->getRefCount ());
15041512
15051513 // Decrementing the refcount because we want to recycle the item
1506- decRef (itemToRelease);
1507- const auto ref = decRef (itemToRelease);
1514+ const auto ref = decRef (*candidate);
15081515 XDCHECK_EQ (0u , ref);
15091516
15101517 // check if by releasing the item we intend to, we actually
15111518 // recycle the candidate.
15121519 if (ReleaseRes::kRecycled ==
1513- releaseBackToAllocator (itemToRelease , RemoveContext::kEviction ,
1520+ releaseBackToAllocator (*candidate , RemoveContext::kEviction ,
15141521 /* isNascent */ movedToNextTier, candidate)) {
15151522 return candidate;
15161523 }
@@ -1611,9 +1618,8 @@ CacheAllocator<CacheTrait>::tryEvictToNextMemoryTier(Item* item) {
16111618}
16121619
16131620template <typename CacheTrait>
1614- typename CacheAllocator<CacheTrait>::WriteHandle
1615- CacheAllocator<CacheTrait>::tryEvictRegularItem(MMContainer& mmContainer,
1616- Item& item) {
1621+ bool CacheAllocator<CacheTrait>::tryEvictItem(MMContainer& mmContainer,
1622+ Item &item) {
16171623 // we should flush this to nvmcache if it is not already present in nvmcache
16181624 // and the item is not expired.
16191625 const bool evictToNvmCache = shouldWriteToNvmCache (item);
@@ -1623,21 +1629,25 @@ CacheAllocator<CacheTrait>::tryEvictRegularItem(MMContainer& mmContainer,
16231629 // record the in-flight eviciton. If not, we move on to next item to avoid
16241630 // stalling eviction.
16251631 if (evictToNvmCache && !token.isValid ()) {
1626- stats_.evictFailConcurrentFill .inc ();
1632+ if (item.isChainedItem ())
1633+ stats_.evictFailConcurrentFill .inc ();
1634+ else
1635+ stats_.evictFailConcurrentFill .inc ();
16271636 decRef (item);
1628- return WriteHandle{} ;
1637+ return false ;
16291638 }
16301639
1631- // If there are other accessors, we should abort. Acquire a handle here since
1632- // if we remove the item from both access containers and mm containers
1633- // below, we will need a handle to ensure proper cleanup in case we end up
1634- // not evicting this item
1640+ // If there are other accessors, we should abort. We should be the only
1641+ // handle owner.
16351642 auto evictHandle = accessContainer_->removeIf (item, &itemEvictionPredicate);
1643+ decRef (item);
16361644
16371645 if (!evictHandle) {
1638- stats_.evictFailAC .inc ();
1639- decRef (item);
1640- return evictHandle;
1646+ if (item.isChainedItem ())
1647+ stats_.evictFailParentAC .inc ();
1648+ else
1649+ stats_.evictFailAC .inc ();
1650+ return false ;
16411651 }
16421652
16431653 auto removed = mmContainer.remove (item);
@@ -1652,81 +1662,24 @@ CacheAllocator<CacheTrait>::tryEvictRegularItem(MMContainer& mmContainer,
16521662 // for eviction. It is safe to destroy the handle here since the moving bit
16531663 // is set. Iterator was already advance by the remove call above.
16541664 if (evictHandle->isMoving ()) {
1655- stats_.evictFailMove .inc ();
1656- decRef (item);
1657- return WriteHandle{};
1665+ if (item.isChainedItem ())
1666+ stats_.evictFailParentMove .inc ();
1667+ else
1668+ stats_.evictFailMove .inc ();
1669+ return false ;
16581670 }
16591671
16601672 // Ensure that there are no accessors after removing from the access
1661- // container
1662- XDCHECK (evictHandle->getRefCount () == 2 );
1673+ // container. handle and evictHandle should be the only two handles.
1674+ XDCHECK (evictHandle->getRefCount () == 1 );
16631675
16641676 if (evictToNvmCache && shouldWriteToNvmCacheExclusive (item)) {
16651677 XDCHECK (token.isValid ());
16661678 nvmCache_->put (evictHandle, std::move (token));
16671679 }
1668- return evictHandle;
1669- }
1670-
1671- template <typename CacheTrait>
1672- typename CacheAllocator<CacheTrait>::WriteHandle
1673- CacheAllocator<CacheTrait>::tryEvictChainedItem(MMContainer& mmContainer, Item& item) {
1674- XDCHECK (item.isChainedItem ());
1675-
1676- ChainedItem* candidate = &item.asChainedItem ();
1677-
1678- // The parent could change at any point through transferChain. However, if
1679- // that happens, we would realize that the releaseBackToAllocator return
1680- // kNotRecycled and we would try another chained item, leading to transient
1681- // failure.
1682- auto & parent = candidate->getParentItem (compressor_);
1683-
1684- const bool evictToNvmCache = shouldWriteToNvmCache (parent);
16851680
1686- auto token = evictToNvmCache ? nvmCache_->createPutToken (parent.getKey ())
1687- : typename NvmCacheT::PutToken{};
1688-
1689- // if token is invalid, return. iterator is already advanced.
1690- if (evictToNvmCache && !token.isValid ()) {
1691- stats_.evictFailConcurrentFill .inc ();
1692- return ItemHandle{};
1693- }
1694-
1695- // check if the parent exists in the hashtable and refcount is drained.
1696- auto parentHandle =
1697- accessContainer_->removeIf (parent, &itemEvictionPredicate);
1698- if (!parentHandle) {
1699- stats_.evictFailParentAC .inc ();
1700- return parentHandle;
1701- }
1702-
1703- // Ensure we have the correct parent and we're the only user of the
1704- // parent, then free it from access container. Otherwise, we abort
1705- auto removed = mmContainer.remove (item);
1706- XDCHECK (removed);
1707- XDCHECK_EQ (reinterpret_cast <uintptr_t >(&parent),
1708- reinterpret_cast <uintptr_t >(parentHandle.get ()));
1709- XDCHECK_EQ (2u , parent.getRefCount ()); // XXX?
1710- XDCHECK (!parent.isInMMContainer ());
1711- XDCHECK (!parent.isAccessible ());
1712-
1713- // TODO: add multi-tier support (similar as for unchained items)
1714-
1715- // We need to make sure the parent is not marked as moving
1716- // and we're the only holder of the parent item. Safe to destroy the handle
1717- // here since moving bit is set.
1718- if (parentHandle->isMoving ()) {
1719- stats_.evictFailParentMove .inc ();
1720- return ItemHandle{};
1721- }
1722-
1723- if (evictToNvmCache && shouldWriteToNvmCacheExclusive (*parentHandle)) {
1724- XDCHECK (token.isValid ());
1725- XDCHECK (parentHandle->hasChainedItem ());
1726- nvmCache_->put (parentHandle, std::move (token));
1727- }
1728-
1729- return parentHandle;
1681+ evictHandle.release ();
1682+ return true ;
17301683}
17311684
17321685template <typename CacheTrait>
0 commit comments