@@ -1349,7 +1349,7 @@ class CacheAllocator : public CacheBase {
13491349
13501350 private: 
13511351  //  wrapper around Item's refcount and active handle tracking
1352-   FOLLY_ALWAYS_INLINE bool  incRef (Item& it);
1352+   FOLLY_ALWAYS_INLINE RefcountWithFlags::incResult  incRef (Item& it);
13531353  FOLLY_ALWAYS_INLINE RefcountWithFlags::Value decRef (Item& it);
13541354
13551355  //  drops the refcount and if needed, frees the allocation back to the memory
@@ -1473,26 +1473,13 @@ class CacheAllocator : public CacheBase {
14731473  //  The parent handle parameter here is mainly used to find the
14741474  //  correct pool to allocate memory for this chained item
14751475  // 
1476-   //  @param parent    handle to  the cache  item
1476+   //  @param parent    the parent  item
14771477  //  @param size      the size for the chained allocation
14781478  // 
14791479  //  @return    handle to the chained allocation
14801480  //  @throw     std::invalid_argument if the size requested is invalid or
14811481  //             if the item is invalid
1482-   WriteHandle allocateChainedItemInternal (const  ReadHandle& parent,
1483-                                           uint32_t  size);
1484- 
1485-   //  Given an item and its parentKey, validate that the parentKey
1486-   //  corresponds to an item that's the parent of the supplied item.
1487-   // 
1488-   //  @param item       item that we want to get the parent handle for
1489-   //  @param parentKey  key of the item's parent
1490-   // 
1491-   //  @return  handle to the parent item if the validations pass
1492-   //           otherwise, an empty Handle is returned.
1493-   // 
1494-   ReadHandle validateAndGetParentHandleForChainedMoveLocked (
1495-       const  ChainedItem& item, const  Key& parentKey);
1482+   WriteHandle allocateChainedItemInternal (const  Item& parent, uint32_t  size);
14961483
14971484  //  Given an existing item, allocate a new one for the
14981485  //  existing one to later be moved into.
@@ -1609,7 +1596,7 @@ class CacheAllocator : public CacheBase {
16091596  //  @param newParent the new parent for the chain
16101597  // 
16111598  //  @throw if any of the conditions for parent or newParent are not met.
1612-   void  transferChainLocked (WriteHandle & parent, WriteHandle& newParent);
1599+   void  transferChainLocked (Item & parent, WriteHandle& newParent);
16131600
16141601  //  replace a chained item in the existing chain. This needs to be called
16151602  //  with the chained item lock held exclusive
@@ -1623,6 +1610,24 @@ class CacheAllocator : public CacheBase {
16231610                                       WriteHandle newItemHdl,
16241611                                       const  Item& parent);
16251612
1613+   // 
1614+   //  Performs the actual inplace replace - it is called from
1615+   //  moveChainedItem and replaceChainedItemLocked
1616+   //  must hold chainedItemLock
1617+   // 
1618+   //  @param oldItem  the item we are replacing in the chain
1619+   //  @param newItem  the item we are replacing it with
1620+   //  @param parent   the parent for the chain
1621+   //  @param fromMove used to determine if the replaced was called from
1622+   //                  moveChainedItem - we avoid the handle destructor
1623+   //                  in this case.
1624+   // 
1625+   //  @return handle to the oldItem
1626+   void  replaceInChainLocked (Item& oldItem,
1627+                             WriteHandle& newItemHdl,
1628+                             const  Item& parent,
1629+                             bool  fromMove);
1630+ 
16261631  //  Insert an item into MM container. The caller must hold a valid handle for
16271632  //  the item.
16281633  // 
@@ -1731,6 +1736,19 @@ class CacheAllocator : public CacheBase {
17311736
17321737  using  EvictionIterator = typename  MMContainer::LockedIterator;
17331738
1739+   //  Wakes up waiters if there are any
1740+   // 
1741+   //  @param item    wakes waiters that are waiting on that item
1742+   //  @param handle  handle to pass to the waiters
1743+   void  wakeUpWaiters (Item& item, WriteHandle handle);
1744+ 
1745+   //  Unmarks item as moving and wakes up any waiters waiting on that item
1746+   // 
1747+   //  @param item    wakes waiters that are waiting on that item
1748+   //  @param handle  handle to pass to the waiters
1749+   typename  RefcountWithFlags::Value unmarkMovingAndWakeUpWaiters (
1750+       Item& item, WriteHandle handle);
1751+ 
17341752  //  Deserializer CacheAllocatorMetadata and verify the version
17351753  // 
17361754  //  @param  deserializer   Deserializer object
@@ -1824,16 +1842,6 @@ class CacheAllocator : public CacheBase {
18241842                          Item& item,
18251843                          util::Throttler& throttler);
18261844
1827-   //  "Move" (by copying) the content in this item to another memory
1828-   //  location by invoking the move callback.
1829-   // 
1830-   //  @param item         old item to be moved elsewhere
1831-   //  @param newItemHdl   handle of new item to be moved into
1832-   // 
1833-   //  @return    true  if the item has been moved
1834-   //             false if we have exhausted moving attempts
1835-   bool  tryMovingForSlabRelease (Item& item, WriteHandle& newItemHdl);
1836- 
18371845  //  Evict an item from access and mm containers and
18381846  //  ensure it is safe for freeing.
18391847  // 
@@ -1844,6 +1852,11 @@ class CacheAllocator : public CacheBase {
18441852                           Item& item,
18451853                           util::Throttler& throttler);
18461854
1855+   //  Helper function to create PutToken
1856+   // 
1857+   //  @return valid token if the item should be written to NVM cache.
1858+   typename  NvmCacheT::PutToken createPutToken (Item& item);
1859+ 
18471860  //  Helper function to evict a normal item for slab release
18481861  // 
18491862  //  @return last handle for corresponding to item on success. empty handle on
@@ -2082,6 +2095,88 @@ class CacheAllocator : public CacheBase {
20822095
20832096  //  BEGIN private members
20842097
2098+   bool  tryGetHandleWithWaitContextForMovingItem (Item& item,
2099+                                                 WriteHandle& handle);
2100+ 
2101+   size_t  wakeUpWaitersLocked (folly::StringPiece key, WriteHandle&& handle);
2102+ 
2103+   class  MoveCtx  {
2104+    public: 
2105+     MoveCtx () {}
2106+ 
2107+     ~MoveCtx () {
2108+       //  prevent any further enqueue to waiters
2109+       //  Note: we don't need to hold locks since no one can enqueue
2110+       //  after this point.
2111+       wakeUpWaiters ();
2112+     }
2113+ 
2114+     //  record the item handle. Upon destruction we will wake up the waiters
2115+     //  and pass a clone of the handle to the callBack. By default we pass
2116+     //  a null handle
2117+     void  setItemHandle (WriteHandle _it) { it = std::move (_it); }
2118+ 
2119+     //  enqueue a waiter into the waiter list
2120+     //  @param  waiter       WaitContext
2121+     void  addWaiter (std::shared_ptr<WaitContext<ReadHandle>> waiter) {
2122+       XDCHECK (waiter);
2123+       waiters.push_back (std::move (waiter));
2124+     }
2125+ 
2126+     size_t  numWaiters () const  { return  waiters.size (); }
2127+ 
2128+    private: 
2129+     //  notify all pending waiters that are waiting for the fetch.
2130+     void  wakeUpWaiters () {
2131+       bool  refcountOverflowed = false ;
2132+       for  (auto & w : waiters) {
2133+         //  If refcount overflowed earlier, then we will return miss to
2134+         //  all subsequent waiters.
2135+         if  (refcountOverflowed) {
2136+           w->set (WriteHandle{});
2137+           continue ;
2138+         }
2139+ 
2140+         try  {
2141+           w->set (it.clone ());
2142+         } catch  (const  exception::RefcountOverflow&) {
2143+           //  We'll return a miss to the user's pending read,
2144+           //  so we should enqueue a delete via NvmCache.
2145+           //  TODO: cache.remove(it);
2146+           refcountOverflowed = true ;
2147+         }
2148+       }
2149+     }
2150+ 
2151+     WriteHandle it; //  will be set when Context is being filled
2152+     std::vector<std::shared_ptr<WaitContext<ReadHandle>>> waiters; //  list of
2153+                                                                    //  waiters
2154+   };
2155+   using  MoveMap =
2156+       folly::F14ValueMap<folly::StringPiece,
2157+                          std::unique_ptr<MoveCtx>,
2158+                          folly::HeterogeneousAccessHash<folly::StringPiece>>;
2159+ 
2160+   static  size_t  getShardForKey (folly::StringPiece key) {
2161+     return  folly::Hash ()(key) % kShards ;
2162+   }
2163+ 
2164+   MoveMap& getMoveMapForShard (size_t  shard) {
2165+     return  movesMap_[shard].movesMap_ ;
2166+   }
2167+ 
2168+   MoveMap& getMoveMap (folly::StringPiece key) {
2169+     return  getMoveMapForShard (getShardForKey (key));
2170+   }
2171+ 
2172+   std::unique_lock<std::mutex> getMoveLockForShard (size_t  shard) {
2173+     return  std::unique_lock<std::mutex>(moveLock_[shard].moveLock_ );
2174+   }
2175+ 
2176+   std::unique_lock<std::mutex> getMoveLock (folly::StringPiece key) {
2177+     return  getMoveLockForShard (getShardForKey (key));
2178+   }
2179+ 
20852180  //  Whether the memory allocator for this cache allocator was created on shared
20862181  //  memory. The hash table, chained item hash table etc is also created on
20872182  //  shared memory except for temporary shared memory mode when they're created
@@ -2175,6 +2270,22 @@ class CacheAllocator : public CacheBase {
21752270  //  poolResizer_, poolOptimizer_, memMonitor_, reaper_
21762271  mutable  std::mutex workersMutex_;
21772272
2273+   static  constexpr  size_t  kShards  = 8192 ; //  TODO: need to define right value
2274+ 
2275+   struct  MovesMapShard  {
2276+     alignas (folly::hardware_destructive_interference_size) MoveMap movesMap_;
2277+   };
2278+ 
2279+   struct  MoveLock  {
2280+     alignas (folly::hardware_destructive_interference_size) std::mutex moveLock_;
2281+   };
2282+ 
2283+   //  a map of all pending moves
2284+   std::vector<MovesMapShard> movesMap_;
2285+ 
2286+   //  a map of move locks for each shard
2287+   std::vector<MoveLock> moveLock_;
2288+ 
21782289  //  time when the ram cache was first created
21792290  const  uint32_t  cacheCreationTime_{0 };
21802291
0 commit comments