in cachelib/allocator/CacheAllocator-inl.h [2395:2467]
bool CacheAllocator<CacheTrait>::moveForSlabRelease(
const SlabReleaseContext& ctx, Item& oldItem, util::Throttler& throttler) {
if (!config_.moveCb) {
return false;
}
bool isMoved = false;
auto startTime = util::getCurrentTimeSec();
WriteHandle newItemHdl = allocateNewItemForOldItem(oldItem);
for (unsigned int itemMovingAttempts = 0;
itemMovingAttempts < config_.movingTries;
++itemMovingAttempts) {
stats_.numMoveAttempts.inc();
// Nothing to move and the key is likely also bogus for chained items.
if (oldItem.isOnlyMoving()) {
oldItem.unmarkMoving();
const auto res =
releaseBackToAllocator(oldItem, RemoveContext::kNormal, false);
XDCHECK(res == ReleaseRes::kReleased);
return true;
}
if (!newItemHdl) {
// try to allocate again if it previously wasn't successful
newItemHdl = allocateNewItemForOldItem(oldItem);
}
// if we have a valid handle, try to move, if not, we retry.
if (newItemHdl) {
isMoved = tryMovingForSlabRelease(oldItem, newItemHdl);
if (isMoved) {
break;
}
}
throttleWith(throttler, [&] {
XLOGF(WARN,
"Spent {} seconds, slab release still trying to move Item: {}. "
"Pool: {}, Class: {}.",
util::getCurrentTimeSec() - startTime, oldItem.toString(),
ctx.getPoolId(), ctx.getClassId());
});
}
// Return false if we've exhausted moving tries.
if (!isMoved) {
return false;
}
// Since item has been moved, we can directly free it. We don't need to
// worry about any stats related changes, because there is another item
// that's identical to this one to replace it. Here we just need to wait
// until all users have dropped the item handles before we can proceed.
startTime = util::getCurrentTimeSec();
while (!oldItem.isOnlyMoving()) {
throttleWith(throttler, [&] {
XLOGF(WARN,
"Spent {} seconds, slab release still waiting for refcount to "
"drain Item: {}. Pool: {}, Class: {}.",
util::getCurrentTimeSec() - startTime, oldItem.toString(),
ctx.getPoolId(), ctx.getClassId());
});
}
const auto allocInfo = allocator_->getAllocInfo(oldItem.getMemory());
allocator_->free(&oldItem);
(*stats_.fragmentationSize)[allocInfo.poolId][allocInfo.classId].sub(
util::getFragmentation(*this, oldItem));
stats_.numMoveSuccesses.inc();
return true;
}