@@ -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