@@ -1389,7 +1389,7 @@ class CacheAllocator : public CacheBase {
1389
1389
double slabsApproxFreePercentage (TierId tid) const ;
1390
1390
1391
1391
// 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);
1393
1393
FOLLY_ALWAYS_INLINE RefcountWithFlags::Value decRef (Item& it);
1394
1394
1395
1395
// drops the refcount and if needed, frees the allocation back to the memory
@@ -1440,6 +1440,12 @@ class CacheAllocator : public CacheBase {
1440
1440
bool nascent = false ,
1441
1441
const Item* toRecycle = nullptr );
1442
1442
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
+
1443
1449
// acquires an handle on the item. returns an empty handle if it is null.
1444
1450
// @param it pointer to an item
1445
1451
// @return WriteHandle return a handle to this item
@@ -1550,17 +1556,17 @@ class CacheAllocator : public CacheBase {
1550
1556
// @return handle to the parent item if the validations pass
1551
1557
// otherwise, an empty Handle is returned.
1552
1558
//
1553
- ReadHandle validateAndGetParentHandleForChainedMoveLocked (
1559
+ WriteHandle validateAndGetParentHandleForChainedMoveLocked (
1554
1560
const ChainedItem& item, const Key& parentKey);
1555
1561
1556
1562
// Given an existing item, allocate a new one for the
1557
1563
// existing one to later be moved into.
1558
1564
//
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
1560
1566
//
1561
1567
// @return handle to the newly allocated item
1562
1568
//
1563
- WriteHandle allocateNewItemForOldItem (const Item& oldItem );
1569
+ WriteHandle allocateNewItemForOldItem (const Item& item );
1564
1570
1565
1571
// internal helper that grabs a refcounted handle to the item. This does
1566
1572
// not record the access to reflect in the mmContainer.
@@ -1614,18 +1620,17 @@ class CacheAllocator : public CacheBase {
1614
1620
// @param oldItem Reference to the item being moved
1615
1621
// @param newItemHdl Reference to the handle of the new item being moved into
1616
1622
//
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.
1620
1625
template <typename P>
1621
- WriteHandle moveRegularItemWithSync (Item& oldItem, WriteHandle& newItemHdl, P&& predicate);
1626
+ bool moveRegularItemWithSync (Item& oldItem, WriteHandle& newItemHdl, P&& predicate);
1622
1627
1623
1628
// Moves a regular item to a different slab. This should only be used during
1624
1629
// slab release after the item's exclusive bit has been set. The user supplied
1625
1630
// callback is responsible for copying the contents and fixing the semantics
1626
1631
// of chained item.
1627
1632
//
1628
- // @param oldItem Reference to the item being moved
1633
+ // @param oldItem item being moved
1629
1634
// @param newItemHdl Reference to the handle of the new item being moved into
1630
1635
//
1631
1636
// @return true If the move was completed, and the containers were updated
@@ -1787,7 +1792,7 @@ class CacheAllocator : public CacheBase {
1787
1792
//
1788
1793
// @return valid handle to the item. This will be the last
1789
1794
// 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);
1791
1796
1792
1797
bool tryPromoteToNextMemoryTier (TierId tid, PoolId pid, Item& item, bool fromBgThread);
1793
1798
@@ -1799,7 +1804,7 @@ class CacheAllocator : public CacheBase {
1799
1804
//
1800
1805
// @return valid handle to the item. This will be the last
1801
1806
// handle to the item. On failure an empty handle.
1802
- WriteHandle tryEvictToNextMemoryTier (Item& item, bool fromBgThread);
1807
+ bool tryEvictToNextMemoryTier (Item& item, bool fromBgThread);
1803
1808
1804
1809
size_t memoryTierSize (TierId tid) const ;
1805
1810
@@ -1878,22 +1883,23 @@ class CacheAllocator : public CacheBase {
1878
1883
1879
1884
// @return true when successfully marked as moving,
1880
1885
// 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);
1884
1889
1885
1890
// "Move" (by copying) the content in this item to another memory
1886
1891
// location by invoking the move callback.
1887
1892
//
1888
1893
//
1889
1894
// @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)
1891
1897
// @param throttler slow this function down as not to take too much cpu
1892
1898
//
1893
1899
// @return true if the item has been moved
1894
1900
// false if we have exhausted moving attempts
1895
1901
bool moveForSlabRelease (const SlabReleaseContext& ctx,
1896
- Item& item ,
1902
+ Item& oldItem ,
1897
1903
util::Throttler& throttler);
1898
1904
1899
1905
// "Move" (by copying) the content in this item to another memory
@@ -1929,6 +1935,8 @@ class CacheAllocator : public CacheBase {
1929
1935
// handle on failure. caller can retry.
1930
1936
WriteHandle evictChainedItemForSlabRelease (ChainedItem& item);
1931
1937
1938
+ typename NvmCacheT::PutToken createPutToken (Item& item);
1939
+
1932
1940
// Helper function to remove a item if predicates is true.
1933
1941
//
1934
1942
// @return last handle to the item on success. empty handle on failure.
@@ -1966,8 +1974,10 @@ class CacheAllocator : public CacheBase {
1966
1974
candidates.reserve (batch);
1967
1975
1968
1976
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) {
1971
1981
tries++;
1972
1982
Item* candidate = itr.get ();
1973
1983
XDCHECK (candidate);
@@ -1976,7 +1986,8 @@ class CacheAllocator : public CacheBase {
1976
1986
throw std::runtime_error (" Not supported for chained items" );
1977
1987
}
1978
1988
1979
- if (candidate->getRefCount () == 0 && candidate->markExclusive ()) {
1989
+ if (candidate->markExclusive ()) {
1990
+ mmContainer.remove (itr);
1980
1991
candidates.push_back (candidate);
1981
1992
}
1982
1993
@@ -1985,37 +1996,29 @@ class CacheAllocator : public CacheBase {
1985
1996
});
1986
1997
1987
1998
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);
1994
2007
}
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 ());
2011
2009
2010
+ if (candidate->hasChainedItem ()) {
2011
+ (*stats_.chainedItemEvictions )[pid][cid].inc ();
2012
2012
} else {
2013
- if (candidate->hasChainedItem ()) {
2014
- stats_.evictFailParentAC .inc ();
2015
- } else {
2016
- stats_.evictFailAC .inc ();
2017
- }
2013
+ (*stats_.regularItemEvictions )[pid][cid].inc ();
2018
2014
}
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 );
2019
2022
}
2020
2023
return evictions;
2021
2024
}
@@ -2028,7 +2031,7 @@ class CacheAllocator : public CacheBase {
2028
2031
2029
2032
size_t tries = 0 ;
2030
2033
2031
- mmContainer.withPromotionIterator ([&tries, &candidates, &batch, this ](auto &&itr){
2034
+ mmContainer.withPromotionIterator ([&tries, &candidates, &batch, &mmContainer, this ](auto &&itr){
2032
2035
while (candidates.size () < batch && (config_.maxEvictionPromotionHotness == 0 || tries < config_.maxEvictionPromotionHotness ) && itr) {
2033
2036
tries++;
2034
2037
Item* candidate = itr.get ();
@@ -2038,10 +2041,10 @@ class CacheAllocator : public CacheBase {
2038
2041
throw std::runtime_error (" Not supported for chained items" );
2039
2042
}
2040
2043
2041
-
2042
2044
// TODO: only allow it for read-only items?
2043
2045
// or implement mvcc
2044
- if (!candidate->isExpired () && candidate->markExclusive ()) {
2046
+ if (candidate->markExclusive ()) {
2047
+ mmContainer.remove (itr);
2045
2048
candidates.push_back (candidate);
2046
2049
}
2047
2050
@@ -2051,16 +2054,18 @@ class CacheAllocator : public CacheBase {
2051
2054
2052
2055
for (Item *candidate : candidates) {
2053
2056
auto promoted = tryPromoteToNextMemoryTier (*candidate, true );
2054
- auto ref = candidate->unmarkExclusive ();
2055
- if (promoted)
2057
+ if (promoted) {
2056
2058
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 );
2063
2059
}
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 );
2064
2069
}
2065
2070
2066
2071
return promotions;
@@ -2173,18 +2178,14 @@ class CacheAllocator : public CacheBase {
2173
2178
std::optional<bool > saveNvmCache ();
2174
2179
void saveRamCache ();
2175
2180
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 ;
2178
2183
}
2179
2184
2180
2185
static bool itemExpiryPredicate (const Item& item) {
2181
2186
return item.getRefCount () == 1 && item.isExpired ();
2182
2187
}
2183
2188
2184
- static bool parentEvictForSlabReleasePredicate (const Item& item) {
2185
- return item.getRefCount () == 1 && !item.isExclusive ();
2186
- }
2187
-
2188
2189
std::unique_ptr<Deserializer> createDeserializer ();
2189
2190
2190
2191
// Execute func on each item. `func` can throw exception but must ensure
0 commit comments