void CacheAllocator::evictForSlabRelease()

in cachelib/allocator/CacheAllocator-inl.h [2581:2659]


void CacheAllocator<CacheTrait>::evictForSlabRelease(
    const SlabReleaseContext& ctx, Item& item, util::Throttler& throttler) {
  XDCHECK(!config_.isEvictionDisabled());

  auto startTime = util::getCurrentTimeSec();
  while (true) {
    stats_.numEvictionAttempts.inc();

    // if the item is already in a state where only the moving bit is set,
    // nothing needs to be done. We simply need to unmark moving bit and free
    // the item.
    if (item.isOnlyMoving()) {
      item.unmarkMoving();
      const auto res =
          releaseBackToAllocator(item, RemoveContext::kNormal, false);
      XDCHECK(ReleaseRes::kReleased == res);
      return;
    }

    // Since we couldn't move, we now evict this item. Owning handle will be
    // the item's handle for regular/normal items and will be the parent
    // handle for chained items.
    auto owningHandle =
        item.isChainedItem()
            ? evictChainedItemForSlabRelease(item.asChainedItem())
            : evictNormalItemForSlabRelease(item);

    // we managed to evict the corresponding owner of the item and have the
    // last handle for the owner.
    if (owningHandle) {
      const auto allocInfo =
          allocator_->getAllocInfo(static_cast<const void*>(&item));
      if (owningHandle->hasChainedItem()) {
        (*stats_.chainedItemEvictions)[allocInfo.poolId][allocInfo.classId]
            .inc();
      } else {
        (*stats_.regularItemEvictions)[allocInfo.poolId][allocInfo.classId]
            .inc();
      }

      stats_.numEvictionSuccesses.inc();

      // we have the last handle. no longer need to hold on to the moving bit
      item.unmarkMoving();

      XDCHECK(owningHandle->isExclusive());

      // manually decrement the refcount to call releaseBackToAllocator
      const auto ref = decRef(*owningHandle);
      XDCHECK(ref == 0);
      const auto res = releaseBackToAllocator(*owningHandle.release(),
                                              RemoveContext::kEviction, false);
      XDCHECK(res == ReleaseRes::kReleased);
      return;
    }

    if (shutDownInProgress_) {
      item.unmarkMoving();
      allocator_->abortSlabRelease(ctx);
      throw exception::SlabReleaseAborted(
          folly::sformat("Slab Release aborted while trying to evict"
                         " Item: {} Pool: {}, Class: {}.",
                         item.toString(), ctx.getPoolId(), ctx.getClassId()));
    }
    throttleWith(throttler, [&] {
      XLOGF(WARN,
            "Spent {} seconds, slab release still trying to evict Item: {}. "
            "Pool: {}, Class: {}.",
            util::getCurrentTimeSec() - startTime, item.toString(),
            ctx.getPoolId(), ctx.getClassId())
          << (item.isChainedItem()
                  ? folly::sformat(" Parent: {}",
                                   item.asChainedItem()
                                       .getParentItem(compressor_)
                                       .toString())
                  : "");
    });
  }
}