Skip to content
Draft
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
b791b77
Run centos and debian workflows on push and PR
igchor Nov 2, 2021
470f563
Introduce 'markedForEviction' state for the Item.
igchor Dec 15, 2022
c1020df
Adds createPutToken and switches findEviction
byrnedj Feb 4, 2023
9bb6775
- Change the cache size calculation to use getCacheSize()
byrnedj Jan 4, 2023
1759e83
- Add memory tier configs to cache allocator based on NUMA bindings
byrnedj Jan 4, 2023
62b0c41
added ability for compressed pointer to use full 32 bits for addressi…
guptask Nov 14, 2022
b7459ee
Add memory usage statistics for allocation classes
igchor Jul 6, 2022
fafface
Initial multi-tier support implementation (rebased with NUMA and cs p…
igchor Sep 28, 2021
369e55b
AC stats multi-tier
byrnedj Jan 17, 2023
713c6d9
This commit contains the additional memory tiers tests
byrnedj Feb 8, 2023
d209d78
This is the additional multi-tier support needed
guptask Nov 14, 2022
e74fa40
added per pool class rolling average latency (upstream PR version)
guptask Jul 21, 2022
bab780a
added per tier pool class rolling average latency (based on upstream PR)
guptask Jul 21, 2022
f0baeb1
MM2Q promotion iterators (#1)
byrnedj Aug 9, 2022
8ab8c75
CS Patch Part 2 for mulit-tier cachelib:
byrnedj Feb 7, 2023
2152639
basic multi-tier test based on numa bindings
igchor Dec 30, 2021
e303104
Aadding new configs to hit_ratio/graph_cache_leader_fobj
vinser52 Jan 27, 2022
1e40a00
Do not block reader if a child item is moving
igchor Dec 19, 2022
b99bb9d
Background data movement (#20)
byrnedj Oct 21, 2022
08bf0b4
fix race in moveRegularItemWith sync where insertOrReplace can cause …
byrnedj Feb 16, 2023
8f88aa6
Add extra allocation/eviction policies
igchor Mar 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Do not block reader if a child item is moving
This would lead to deadlock (.e.g in forEachChainedItem)
if the child is moving (e.g. marked by Slab Release thread).

Instead treat moving bit only to prevent freeing the item and
do all synchronization on parent.
  • Loading branch information
igchor authored and byrnedj committed Mar 3, 2023
commit 1e40a00e58c9265fe960fad804f3c6f20d01aa3f
93 changes: 58 additions & 35 deletions cachelib/allocator/CacheAllocator-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -988,7 +988,8 @@ CacheAllocator<CacheTrait>::acquire(Item* it) {

SCOPE_FAIL { stats_.numRefcountOverflow.inc(); };

auto failIfMoving = getNumTiers() > 1;
// TODO: do not block incRef for child items to avoid deadlock
auto failIfMoving = getNumTiers() > 1 && !it->isChainedItem();
auto incRes = incRef(*it, failIfMoving);
if (LIKELY(incRes == RefcountWithFlags::incResult::incOk)) {
return WriteHandle{it, *this};
Expand Down Expand Up @@ -3024,7 +3025,8 @@ bool CacheAllocator<CacheTrait>::tryMovingForSlabRelease(
// a regular item or chained item is synchronized with any potential
// user-side mutation.
std::unique_ptr<SyncObj> syncObj;
if (config_.movingSync) {
if (config_.movingSync && getNumTiers() == 1) {
// TODO: use moving-bit synchronization for single tier as well
if (!oldItem.isChainedItem()) {
syncObj = config_.movingSync(oldItem.getKey());
} else {
Expand Down Expand Up @@ -3122,47 +3124,51 @@ void CacheAllocator<CacheTrait>::evictForSlabRelease(
Item* evicted;
if (item.isChainedItem()) {
auto& expectedParent = item.asChainedItem().getParentItem(compressor_);
const std::string parentKey = expectedParent.getKey().str();
auto l = chainedItemLocks_.lockExclusive(parentKey);

// check if the child is still in mmContainer and the expected parent is
// valid under the chained item lock.
if (expectedParent.getKey() != parentKey || !item.isInMMContainer() ||
item.isOnlyMoving() ||
&expectedParent != &item.asChainedItem().getParentItem(compressor_) ||
!expectedParent.isAccessible() || !expectedParent.hasChainedItem()) {
continue;
}

// search if the child is present in the chain
{
auto parentHandle = findInternal(parentKey);
if (!parentHandle || parentHandle != &expectedParent) {
if (getNumTiers() == 1) {
// TODO: unify this with multi-tier implementation
// right now, taking a chained item lock here would lead to deadlock
const std::string parentKey = expectedParent.getKey().str();
auto l = chainedItemLocks_.lockExclusive(parentKey);

// check if the child is still in mmContainer and the expected parent is
// valid under the chained item lock.
if (expectedParent.getKey() != parentKey || !item.isInMMContainer() ||
item.isOnlyMoving() ||
&expectedParent != &item.asChainedItem().getParentItem(compressor_) ||
!expectedParent.isAccessible() || !expectedParent.hasChainedItem()) {
continue;
}

ChainedItem* head = nullptr;
{ // scope for the handle
auto headHandle = findChainedItem(expectedParent);
head = headHandle ? &headHandle->asChainedItem() : nullptr;
}
// search if the child is present in the chain
{
auto parentHandle = findInternal(parentKey);
if (!parentHandle || parentHandle != &expectedParent) {
continue;
}

bool found = false;
while (head) {
if (head == &item) {
found = true;
break;
ChainedItem* head = nullptr;
{ // scope for the handle
auto headHandle = findChainedItem(expectedParent);
head = headHandle ? &headHandle->asChainedItem() : nullptr;
}
head = head->getNext(compressor_);
}

if (!found) {
continue;
bool found = false;
while (head) {
if (head == &item) {
found = true;
break;
}
head = head->getNext(compressor_);
}

if (!found) {
continue;
}
}
}

evicted = &expectedParent;

token = createPutToken(*evicted);
if (evicted->markForEviction()) {
// unmark the child so it will be freed
Expand All @@ -3173,6 +3179,9 @@ void CacheAllocator<CacheTrait>::evictForSlabRelease(
// no other reader can be added to the waiters list
wakeUpWaiters(*evicted, {});
} else {
// TODO: potential deadlock with markUseful for parent item
// for now, we do not block any reader on child items but this
// should probably be fixed
continue;
}
} else {
Expand Down Expand Up @@ -3204,7 +3213,17 @@ void CacheAllocator<CacheTrait>::evictForSlabRelease(
XDCHECK(evicted->getRefCount() == 0);
const auto res =
releaseBackToAllocator(*evicted, RemoveContext::kEviction, false);
XDCHECK(res == ReleaseRes::kReleased);

if (getNumTiers() == 1) {
XDCHECK(res == ReleaseRes::kReleased);
} else {
const bool isAlreadyFreed =
!markMovingForSlabRelease(ctx, &item, throttler);
if (!isAlreadyFreed) {
continue;
}
}

return;
}
}
Expand Down Expand Up @@ -3252,11 +3271,15 @@ bool CacheAllocator<CacheTrait>::markMovingForSlabRelease(
bool itemFreed = true;
bool markedMoving = false;
TierId tid = getTierId(alloc);
const auto fn = [&markedMoving, &itemFreed](void* memory) {
auto numTiers = getNumTiers();
const auto fn = [&markedMoving, &itemFreed, numTiers](void* memory) {
// Since this callback is executed, the item is not yet freed
itemFreed = false;
Item* item = static_cast<Item*>(memory);
if (item->markMoving(false)) {
// TODO: for chained items, moving bit is only used to avoid
// freeing the item prematurely
auto failIfRefNotZero = numTiers > 1 && !item->isChainedItem();
if (item->markMoving(failIfRefNotZero)) {
markedMoving = true;
}
};
Expand Down