@@ -1389,7 +1389,7 @@ class CacheAllocator : public CacheBase {
13891389 double slabsApproxFreePercentage (TierId tid) const ;
13901390
13911391 // wrapper around Item's refcount and active handle tracking
1392- FOLLY_ALWAYS_INLINE void incRef (Item& it);
1392+ FOLLY_ALWAYS_INLINE bool incRef (Item& it);
13931393 FOLLY_ALWAYS_INLINE RefcountWithFlags::Value decRef (Item& it);
13941394
13951395 // drops the refcount and if needed, frees the allocation back to the memory
@@ -1440,6 +1440,12 @@ class CacheAllocator : public CacheBase {
14401440 bool nascent = false ,
14411441 const Item* toRecycle = nullptr );
14421442
1443+ // Must be called by the thread which called markExclusive and
1444+ // succeeded. After this call, the item is unlinked from Access and
1445+ // MM Containers. The item is no longer marked as exclusive and it's
1446+ // ref count is 0 - it's available for recycling.
1447+ void unlinkItemExclusive (Item& it);
1448+
14431449 // acquires an handle on the item. returns an empty handle if it is null.
14441450 // @param it pointer to an item
14451451 // @return WriteHandle return a handle to this item
@@ -1550,17 +1556,17 @@ class CacheAllocator : public CacheBase {
15501556 // @return handle to the parent item if the validations pass
15511557 // otherwise, an empty Handle is returned.
15521558 //
1553- ReadHandle validateAndGetParentHandleForChainedMoveLocked (
1559+ WriteHandle validateAndGetParentHandleForChainedMoveLocked (
15541560 const ChainedItem& item, const Key& parentKey);
15551561
15561562 // Given an existing item, allocate a new one for the
15571563 // existing one to later be moved into.
15581564 //
1559- // @param oldItem the item we want to allocate a new item for
1565+ // @param item reference to the item we want to allocate a new item for
15601566 //
15611567 // @return handle to the newly allocated item
15621568 //
1563- WriteHandle allocateNewItemForOldItem (const Item& oldItem );
1569+ WriteHandle allocateNewItemForOldItem (const Item& item );
15641570
15651571 // internal helper that grabs a refcounted handle to the item. This does
15661572 // not record the access to reflect in the mmContainer.
@@ -1614,18 +1620,17 @@ class CacheAllocator : public CacheBase {
16141620 // @param oldItem Reference to the item being moved
16151621 // @param newItemHdl Reference to the handle of the new item being moved into
16161622 //
1617- // @return the handle to the oldItem if the move was completed
1618- // and the oldItem can be recycled.
1619- // Otherwise an empty handle is returned.
1623+ // @return true If the move was completed, and the containers were updated
1624+ // successfully.
16201625 template <typename P>
1621- WriteHandle moveRegularItemWithSync (Item& oldItem, WriteHandle& newItemHdl, P&& predicate);
1626+ bool moveRegularItemWithSync (Item& oldItem, WriteHandle& newItemHdl, P&& predicate);
16221627
16231628 // Moves a regular item to a different slab. This should only be used during
16241629 // slab release after the item's exclusive bit has been set. The user supplied
16251630 // callback is responsible for copying the contents and fixing the semantics
16261631 // of chained item.
16271632 //
1628- // @param oldItem Reference to the item being moved
1633+ // @param oldItem item being moved
16291634 // @param newItemHdl Reference to the handle of the new item being moved into
16301635 //
16311636 // @return true If the move was completed, and the containers were updated
@@ -1787,7 +1792,7 @@ class CacheAllocator : public CacheBase {
17871792 //
17881793 // @return valid handle to the item. This will be the last
17891794 // handle to the item. On failure an empty handle.
1790- WriteHandle tryEvictToNextMemoryTier (TierId tid, PoolId pid, Item& item, bool fromBgThread);
1795+ bool tryEvictToNextMemoryTier (TierId tid, PoolId pid, Item& item, bool fromBgThread);
17911796
17921797 bool tryPromoteToNextMemoryTier (TierId tid, PoolId pid, Item& item, bool fromBgThread);
17931798
@@ -1799,7 +1804,7 @@ class CacheAllocator : public CacheBase {
17991804 //
18001805 // @return valid handle to the item. This will be the last
18011806 // handle to the item. On failure an empty handle.
1802- WriteHandle tryEvictToNextMemoryTier (Item& item, bool fromBgThread);
1807+ bool tryEvictToNextMemoryTier (Item& item, bool fromBgThread);
18031808
18041809 size_t memoryTierSize (TierId tid) const ;
18051810
@@ -1878,22 +1883,23 @@ class CacheAllocator : public CacheBase {
18781883
18791884 // @return true when successfully marked as moving,
18801885 // fasle when this item has already been freed
1881- bool markExclusiveForSlabRelease (const SlabReleaseContext& ctx,
1882- void * alloc,
1883- util::Throttler& throttler);
1886+ bool markMovingForSlabRelease (const SlabReleaseContext& ctx,
1887+ void * alloc,
1888+ util::Throttler& throttler);
18841889
18851890 // "Move" (by copying) the content in this item to another memory
18861891 // location by invoking the move callback.
18871892 //
18881893 //
18891894 // @param ctx slab release context
1890- // @param item old item to be moved elsewhere
1895+ // @param oldItem old item to be moved elsewhere
1896+ // @param handle handle to the item or to it's parent (if chained)
18911897 // @param throttler slow this function down as not to take too much cpu
18921898 //
18931899 // @return true if the item has been moved
18941900 // false if we have exhausted moving attempts
18951901 bool moveForSlabRelease (const SlabReleaseContext& ctx,
1896- Item& item ,
1902+ Item& oldItem ,
18971903 util::Throttler& throttler);
18981904
18991905 // "Move" (by copying) the content in this item to another memory
@@ -1929,6 +1935,8 @@ class CacheAllocator : public CacheBase {
19291935 // handle on failure. caller can retry.
19301936 WriteHandle evictChainedItemForSlabRelease (ChainedItem& item);
19311937
1938+ typename NvmCacheT::PutToken createPutToken (Item& item);
1939+
19321940 // Helper function to remove a item if predicates is true.
19331941 //
19341942 // @return last handle to the item on success. empty handle on failure.
@@ -1966,8 +1974,10 @@ class CacheAllocator : public CacheBase {
19661974 candidates.reserve (batch);
19671975
19681976 size_t tries = 0 ;
1969- mmContainer.withEvictionIterator ([&tries, &candidates, &batch, this ](auto &&itr){
1970- while (candidates.size () < batch && (config_.maxEvictionPromotionHotness == 0 || tries < config_.maxEvictionPromotionHotness ) && itr) {
1977+ mmContainer.withEvictionIterator ([&tries, &candidates, &batch, &mmContainer, this ](auto &&itr) {
1978+ while (candidates.size () < batch &&
1979+ (config_.maxEvictionPromotionHotness == 0 || tries < config_.maxEvictionPromotionHotness ) &&
1980+ itr) {
19711981 tries++;
19721982 Item* candidate = itr.get ();
19731983 XDCHECK (candidate);
@@ -1976,7 +1986,8 @@ class CacheAllocator : public CacheBase {
19761986 throw std::runtime_error (" Not supported for chained items" );
19771987 }
19781988
1979- if (candidate->getRefCount () == 0 && candidate->markExclusive ()) {
1989+ if (candidate->markExclusive ()) {
1990+ mmContainer.remove (itr);
19801991 candidates.push_back (candidate);
19811992 }
19821993
@@ -1985,37 +1996,29 @@ class CacheAllocator : public CacheBase {
19851996 });
19861997
19871998 for (Item *candidate : candidates) {
1988- {
1989- auto toReleaseHandle =
1990- evictNormalItem (*candidate,
1991- true /* skipIfTokenInvalid */ , true /* from BG thread */ );
1992- // destroy toReleseHandle. The item won't be release to allocator
1993- // since we marked it as exclusive.
1999+ auto evictedToNext = tryEvictToNextMemoryTier (*candidate, true /* from BgThread */ );
2000+ XDCHECK (evictedToNext);
2001+ if (evictedToNext) {
2002+ auto ref = candidate->unmarkExclusive ();
2003+ XDCHECK (ref == 0u );
2004+ evictions++;
2005+ } else {
2006+ unlinkItemExclusive (*candidate);
19942007 }
1995- auto ref = candidate->unmarkExclusive ();
1996-
1997- if (ref == 0u ) {
1998- if (candidate->hasChainedItem ()) {
1999- (*stats_.chainedItemEvictions )[pid][cid].inc ();
2000- } else {
2001- (*stats_.regularItemEvictions )[pid][cid].inc ();
2002- }
2003-
2004- evictions++;
2005- // it's safe to recycle the item here as there are no more
2006- // references and the item could not been marked as moving
2007- // by other thread since it's detached from MMContainer.
2008- auto res = releaseBackToAllocator (*candidate, RemoveContext::kEviction ,
2009- /* isNascent */ false );
2010- XDCHECK (res == ReleaseRes::kReleased );
2008+ XDCHECK (!candidate->isExclusive () && !candidate->isMoving ());
20112009
2010+ if (candidate->hasChainedItem ()) {
2011+ (*stats_.chainedItemEvictions )[pid][cid].inc ();
20122012 } else {
2013- if (candidate->hasChainedItem ()) {
2014- stats_.evictFailParentAC .inc ();
2015- } else {
2016- stats_.evictFailAC .inc ();
2017- }
2013+ (*stats_.regularItemEvictions )[pid][cid].inc ();
20182014 }
2015+
2016+ // it's safe to recycle the item here as there are no more
2017+ // references and the item could not been marked as moving
2018+ // by other thread since it's detached from MMContainer.
2019+ auto res = releaseBackToAllocator (*candidate, RemoveContext::kEviction ,
2020+ /* isNascent */ false );
2021+ XDCHECK (res == ReleaseRes::kReleased );
20192022 }
20202023 return evictions;
20212024 }
@@ -2028,7 +2031,7 @@ class CacheAllocator : public CacheBase {
20282031
20292032 size_t tries = 0 ;
20302033
2031- mmContainer.withPromotionIterator ([&tries, &candidates, &batch, this ](auto &&itr){
2034+ mmContainer.withPromotionIterator ([&tries, &candidates, &batch, &mmContainer, this ](auto &&itr){
20322035 while (candidates.size () < batch && (config_.maxEvictionPromotionHotness == 0 || tries < config_.maxEvictionPromotionHotness ) && itr) {
20332036 tries++;
20342037 Item* candidate = itr.get ();
@@ -2038,10 +2041,10 @@ class CacheAllocator : public CacheBase {
20382041 throw std::runtime_error (" Not supported for chained items" );
20392042 }
20402043
2041-
20422044 // TODO: only allow it for read-only items?
20432045 // or implement mvcc
2044- if (!candidate->isExpired () && candidate->markExclusive ()) {
2046+ if (candidate->markExclusive ()) {
2047+ mmContainer.remove (itr);
20452048 candidates.push_back (candidate);
20462049 }
20472050
@@ -2051,16 +2054,18 @@ class CacheAllocator : public CacheBase {
20512054
20522055 for (Item *candidate : candidates) {
20532056 auto promoted = tryPromoteToNextMemoryTier (*candidate, true );
2054- auto ref = candidate->unmarkExclusive ();
2055- if (promoted)
2057+ if (promoted) {
20562058 promotions++;
2057-
2058- if (ref == 0u ) {
2059- // stats_.promotionMoveSuccess.inc();
2060- auto res = releaseBackToAllocator (*candidate, RemoveContext::kEviction ,
2061- /* isNascent */ false );
2062- XDCHECK (res == ReleaseRes::kReleased );
20632059 }
2060+ unlinkItemExclusive (*candidate);
2061+ XDCHECK (!candidate->isExclusive () && !candidate->isMoving ());
2062+
2063+ // it's safe to recycle the item here as there are no more
2064+ // references and the item could not been marked as moving
2065+ // by other thread since it's detached from MMContainer.
2066+ auto res = releaseBackToAllocator (*candidate, RemoveContext::kEviction ,
2067+ /* isNascent */ false );
2068+ XDCHECK (res == ReleaseRes::kReleased );
20642069 }
20652070
20662071 return promotions;
@@ -2173,18 +2178,14 @@ class CacheAllocator : public CacheBase {
21732178 std::optional<bool > saveNvmCache ();
21742179 void saveRamCache ();
21752180
2176- static bool itemExclusivePredicate (const Item& item) {
2177- return item.getRefCount () == 0 ;
2181+ static bool itemSlabMovePredicate (const Item& item) {
2182+ return item.isMoving () && item. getRefCount () == 0 ;
21782183 }
21792184
21802185 static bool itemExpiryPredicate (const Item& item) {
21812186 return item.getRefCount () == 1 && item.isExpired ();
21822187 }
21832188
2184- static bool parentEvictForSlabReleasePredicate (const Item& item) {
2185- return item.getRefCount () == 1 && !item.isExclusive ();
2186- }
2187-
21882189 std::unique_ptr<Deserializer> createDeserializer ();
21892190
21902191 // Execute func on each item. `func` can throw exception but must ensure
0 commit comments