@@ -823,28 +823,29 @@ CacheAllocator<CacheTrait>::releaseBackToAllocator(Item& it,
823
823
824
824
removeFromMMContainer (*head);
825
825
826
- // If this chained item is marked as exclusive , we will not free it.
827
- // We must capture the exclusive state before we do the decRef when
826
+ // If this chained item is marked as moving , we will not free it.
827
+ // We must capture the moving state before we do the decRef when
828
828
// we know the item must still be valid
829
- const bool wasExclusive = head->isExclusive ();
829
+ const bool wasMoving = head->isMoving ();
830
+ XDCHECK (!head->isMarkedForEviction ());
830
831
831
832
// Decref and check if we were the last reference. Now if the item
832
- // was marked exclusive , after decRef, it will be free to be released
833
+ // was marked moving , after decRef, it will be free to be released
833
834
// by slab release thread
834
835
const auto childRef = head->decRef ();
835
836
836
- // If the item is already exclusive and we already decremented the
837
+ // If the item is already moving and we already decremented the
837
838
// refcount, we don't need to free this item. We'll let the slab
838
839
// release thread take care of that
839
- if (!wasExclusive ) {
840
+ if (!wasMoving ) {
840
841
if (childRef != 0 ) {
841
842
throw std::runtime_error (folly::sformat (
842
843
" chained item refcount is not zero. We cannot proceed! "
843
844
" Ref: {}, Chained Item: {}" ,
844
845
childRef, head->toString ()));
845
846
}
846
847
847
- // Item is not exclusive and refcount is 0, we can proceed to
848
+ // Item is not moving and refcount is 0, we can proceed to
848
849
// free it or recylce the memory
849
850
if (head == toRecycle) {
850
851
XDCHECK (ReleaseRes::kReleased != res);
@@ -872,9 +873,12 @@ CacheAllocator<CacheTrait>::releaseBackToAllocator(Item& it,
872
873
}
873
874
874
875
template <typename CacheTrait>
875
- void CacheAllocator<CacheTrait>::incRef(Item& it) {
876
- it.incRef ();
877
- ++handleCount_.tlStats ();
876
+ bool CacheAllocator<CacheTrait>::incRef(Item& it) {
877
+ if (it.incRef ()) {
878
+ ++handleCount_.tlStats ();
879
+ return true ;
880
+ }
881
+ return false ;
878
882
}
879
883
880
884
template <typename CacheTrait>
@@ -894,8 +898,12 @@ CacheAllocator<CacheTrait>::acquire(Item* it) {
894
898
895
899
SCOPE_FAIL { stats_.numRefcountOverflow .inc (); };
896
900
897
- incRef (*it);
898
- return WriteHandle{it, *this };
901
+ if (LIKELY (incRef (*it))) {
902
+ return WriteHandle{it, *this };
903
+ } else {
904
+ // item is being evicted
905
+ return WriteHandle{};
906
+ }
899
907
}
900
908
901
909
template <typename CacheTrait>
@@ -1170,7 +1178,7 @@ bool CacheAllocator<CacheTrait>::moveChainedItem(ChainedItem& oldItem,
1170
1178
1171
1179
// This item has been unlinked from its parent and we're the only
1172
1180
// owner of it, so we're done here
1173
- if (!oldItem.isInMMContainer () || oldItem.isOnlyExclusive ()) {
1181
+ if (!oldItem.isInMMContainer () || oldItem.isOnlyMoving ()) {
1174
1182
return false ;
1175
1183
}
1176
1184
@@ -1201,7 +1209,7 @@ bool CacheAllocator<CacheTrait>::moveChainedItem(ChainedItem& oldItem,
1201
1209
1202
1210
// In case someone else had removed this chained item from its parent by now
1203
1211
// So we check again to see if the it has been unlinked from its parent
1204
- if (!oldItem.isInMMContainer () || oldItem.isOnlyExclusive ()) {
1212
+ if (!oldItem.isInMMContainer () || oldItem.isOnlyMoving ()) {
1205
1213
return false ;
1206
1214
}
1207
1215
@@ -1217,7 +1225,7 @@ bool CacheAllocator<CacheTrait>::moveChainedItem(ChainedItem& oldItem,
1217
1225
// parent's chain and the MMContainer.
1218
1226
auto oldItemHandle =
1219
1227
replaceChainedItemLocked (oldItem, std::move (newItemHdl), *parentHandle);
1220
- XDCHECK (oldItemHandle->isExclusive ());
1228
+ XDCHECK (oldItemHandle->isMoving ());
1221
1229
XDCHECK (!oldItemHandle->isInMMContainer ());
1222
1230
1223
1231
return true ;
@@ -1246,7 +1254,7 @@ CacheAllocator<CacheTrait>::findEviction(PoolId pid, ClassId cid) {
1246
1254
: toRecycle;
1247
1255
1248
1256
// make sure no other thead is evicting the item
1249
- if (candidate->getRefCount () != 0 || !candidate->markExclusive ()) {
1257
+ if (candidate->getRefCount () != 0 || !candidate->markMoving ()) {
1250
1258
++itr;
1251
1259
continue ;
1252
1260
}
@@ -1261,11 +1269,11 @@ CacheAllocator<CacheTrait>::findEviction(PoolId pid, ClassId cid) {
1261
1269
? advanceIteratorAndTryEvictChainedItem (itr)
1262
1270
: advanceIteratorAndTryEvictRegularItem (mmContainer, itr);
1263
1271
evictionSuccessful = toReleaseHandle != nullptr ;
1264
- // destroy toReleseHandle . The item won't be released to allocator
1265
- // since we marked it as exclusive .
1272
+ // destroy toReleaseHandle . The item won't be released to allocator
1273
+ // since we marked for eviction .
1266
1274
}
1267
1275
1268
- const auto ref = candidate->unmarkExclusive ();
1276
+ const auto ref = candidate->unmarkMoving ();
1269
1277
if (ref == 0u ) {
1270
1278
// Invalidate iterator since later on we may use this mmContainer
1271
1279
// again, which cannot be done unless we drop this iterator
@@ -2352,7 +2360,7 @@ void CacheAllocator<CacheTrait>::releaseSlabImpl(
2352
2360
// Need to mark an item for release before proceeding
2353
2361
// If we can't mark as moving, it means the item is already freed
2354
2362
const bool isAlreadyFreed =
2355
- !markExclusiveForSlabRelease (releaseContext, alloc, throttler);
2363
+ !markMovingForSlabRelease (releaseContext, alloc, throttler);
2356
2364
if (isAlreadyFreed) {
2357
2365
continue ;
2358
2366
}
@@ -2397,8 +2405,8 @@ bool CacheAllocator<CacheTrait>::moveForSlabRelease(
2397
2405
stats_.numMoveAttempts .inc ();
2398
2406
2399
2407
// Nothing to move and the key is likely also bogus for chained items.
2400
- if (oldItem.isOnlyExclusive ()) {
2401
- oldItem.unmarkExclusive ();
2408
+ if (oldItem.isOnlyMoving ()) {
2409
+ oldItem.unmarkMoving ();
2402
2410
const auto res =
2403
2411
releaseBackToAllocator (oldItem, RemoveContext::kNormal , false );
2404
2412
XDCHECK (res == ReleaseRes::kReleased );
@@ -2437,7 +2445,7 @@ bool CacheAllocator<CacheTrait>::moveForSlabRelease(
2437
2445
// that's identical to this one to replace it. Here we just need to wait
2438
2446
// until all users have dropped the item handles before we can proceed.
2439
2447
startTime = util::getCurrentTimeSec ();
2440
- while (!oldItem.isOnlyExclusive ()) {
2448
+ while (!oldItem.isOnlyMoving ()) {
2441
2449
throttleWith (throttler, [&] {
2442
2450
XLOGF (WARN,
2443
2451
" Spent {} seconds, slab release still waiting for refcount to "
@@ -2491,8 +2499,8 @@ CacheAllocator<CacheTrait>::allocateNewItemForOldItem(const Item& oldItem) {
2491
2499
return {};
2492
2500
}
2493
2501
2494
- // Set up the destination for the move. Since oldChainedItem would have
2495
- // the exclusive bit set , it won't be picked for eviction.
2502
+ // Set up the destination for the move. Since oldChainedItem would be
2503
+ // marked as moving , it won't be picked for eviction.
2496
2504
auto newItemHdl =
2497
2505
allocateChainedItemInternal (parentHandle, oldChainedItem.getSize ());
2498
2506
if (!newItemHdl) {
@@ -2544,7 +2552,7 @@ bool CacheAllocator<CacheTrait>::tryMovingForSlabRelease(
2544
2552
// item is still valid.
2545
2553
const std::string parentKey =
2546
2554
oldItem.asChainedItem ().getParentItem (compressor_).getKey ().str ();
2547
- if (oldItem.isOnlyExclusive ()) {
2555
+ if (oldItem.isOnlyMoving ()) {
2548
2556
// If chained item no longer has a refcount, its parent is already
2549
2557
// being released, so we abort this try to moving.
2550
2558
return false ;
@@ -2574,10 +2582,10 @@ void CacheAllocator<CacheTrait>::evictForSlabRelease(
2574
2582
stats_.numEvictionAttempts .inc ();
2575
2583
2576
2584
// if the item is already in a state where only the exclusive bit is set,
2577
- // nothing needs to be done. We simply need to unmark exclusive bit and free
2585
+ // nothing needs to be done. We simply need to call unmarkMoving and free
2578
2586
// the item.
2579
- if (item.isOnlyExclusive ()) {
2580
- item.unmarkExclusive ();
2587
+ if (item.isOnlyMoving ()) {
2588
+ item.unmarkMoving ();
2581
2589
const auto res =
2582
2590
releaseBackToAllocator (item, RemoveContext::kNormal , false );
2583
2591
XDCHECK (ReleaseRes::kReleased == res);
@@ -2608,7 +2616,7 @@ void CacheAllocator<CacheTrait>::evictForSlabRelease(
2608
2616
stats_.numEvictionSuccesses .inc ();
2609
2617
2610
2618
// we have the last handle. no longer need to hold on to the exclusive bit
2611
- item.unmarkExclusive ();
2619
+ item.unmarkMoving ();
2612
2620
2613
2621
// manually decrement the refcount to call releaseBackToAllocator
2614
2622
const auto ref = decRef (*owningHandle);
@@ -2620,7 +2628,7 @@ void CacheAllocator<CacheTrait>::evictForSlabRelease(
2620
2628
}
2621
2629
2622
2630
if (shutDownInProgress_) {
2623
- item.unmarkExclusive ();
2631
+ item.unmarkMoving ();
2624
2632
allocator_->abortSlabRelease (ctx);
2625
2633
throw exception::SlabReleaseAborted (
2626
2634
folly::sformat (" Slab Release aborted while trying to evict"
@@ -2766,9 +2774,9 @@ CacheAllocator<CacheTrait>::advanceIteratorAndTryEvictChainedItem(
2766
2774
template <typename CacheTrait>
2767
2775
typename CacheAllocator<CacheTrait>::WriteHandle
2768
2776
CacheAllocator<CacheTrait>::evictNormalItemForSlabRelease(Item& item) {
2769
- XDCHECK (item.isExclusive ());
2777
+ XDCHECK (item.isMoving ());
2770
2778
2771
- if (item.isOnlyExclusive ()) {
2779
+ if (item.isOnlyMoving ()) {
2772
2780
return WriteHandle{};
2773
2781
}
2774
2782
@@ -2780,7 +2788,7 @@ CacheAllocator<CacheTrait>::evictNormalItemForSlabRelease(Item& item) {
2780
2788
2781
2789
// We remove the item from both access and mm containers. It doesn't matter
2782
2790
// if someone else calls remove on the item at this moment, the item cannot
2783
- // be freed as long as we have the exclusive bit set .
2791
+ // be freed as long as it's marked for eviction .
2784
2792
auto handle = accessContainer_->removeIf (item, std::move (predicate));
2785
2793
2786
2794
if (!handle) {
@@ -2804,7 +2812,7 @@ CacheAllocator<CacheTrait>::evictNormalItemForSlabRelease(Item& item) {
2804
2812
template <typename CacheTrait>
2805
2813
typename CacheAllocator<CacheTrait>::WriteHandle
2806
2814
CacheAllocator<CacheTrait>::evictChainedItemForSlabRelease(ChainedItem& child) {
2807
- XDCHECK (child.isExclusive ());
2815
+ XDCHECK (child.isMoving ());
2808
2816
2809
2817
// We have the child marked as moving, but dont know anything about the
2810
2818
// state of the parent. Unlike the case of regular eviction where we are
@@ -2826,7 +2834,7 @@ CacheAllocator<CacheTrait>::evictChainedItemForSlabRelease(ChainedItem& child) {
2826
2834
// check if the child is still in mmContainer and the expected parent is
2827
2835
// valid under the chained item lock.
2828
2836
if (expectedParent.getKey () != parentKey || !child.isInMMContainer () ||
2829
- child.isOnlyExclusive () ||
2837
+ child.isOnlyMoving () ||
2830
2838
&expectedParent != &child.getParentItem (compressor_) ||
2831
2839
!expectedParent.isAccessible () || !expectedParent.hasChainedItem ()) {
2832
2840
return {};
@@ -2881,14 +2889,14 @@ CacheAllocator<CacheTrait>::evictChainedItemForSlabRelease(ChainedItem& child) {
2881
2889
2882
2890
// In case someone else had removed this chained item from its parent by now
2883
2891
// So we check again to see if it has been unlinked from its parent
2884
- if (!child.isInMMContainer () || child.isOnlyExclusive ()) {
2892
+ if (!child.isInMMContainer () || child.isOnlyMoving ()) {
2885
2893
return {};
2886
2894
}
2887
2895
2888
2896
// check after removing from the MMContainer that the parent is still not
2889
2897
// being marked as moving. If parent is moving, it will release the child
2890
2898
// item and we will wait for that.
2891
- if (parentHandle->isExclusive ()) {
2899
+ if (parentHandle->isMoving ()) {
2892
2900
return {};
2893
2901
}
2894
2902
@@ -2921,7 +2929,7 @@ bool CacheAllocator<CacheTrait>::removeIfExpired(const ReadHandle& handle) {
2921
2929
}
2922
2930
2923
2931
template <typename CacheTrait>
2924
- bool CacheAllocator<CacheTrait>::markExclusiveForSlabRelease (
2932
+ bool CacheAllocator<CacheTrait>::markMovingForSlabRelease (
2925
2933
const SlabReleaseContext& ctx, void * alloc, util::Throttler& throttler) {
2926
2934
// MemoryAllocator::processAllocForRelease will execute the callback
2927
2935
// if the item is not already free. So there are three outcomes here:
@@ -2940,7 +2948,7 @@ bool CacheAllocator<CacheTrait>::markExclusiveForSlabRelease(
2940
2948
// Since this callback is executed, the item is not yet freed
2941
2949
itemFreed = false ;
2942
2950
Item* item = static_cast <Item*>(memory);
2943
- if (item->markExclusive ()) {
2951
+ if (item->markMoving ()) {
2944
2952
markedMoving = true ;
2945
2953
}
2946
2954
};
0 commit comments