Skip to content

Commit c572aa2

Browse files
committed
test case for acquire parent
1 parent 3d73cfe commit c572aa2

File tree

5 files changed

+91
-3
lines changed

5 files changed

+91
-3
lines changed

cachelib/allocator/CacheAllocator-inl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -862,13 +862,13 @@ CacheAllocator<CacheTrait>::releaseBackToAllocator(Item& it,
862862
headHandle.reset();
863863

864864
if (head == nullptr || &head->getParentItem(compressor_) != &it) {
865-
throw std::runtime_error(folly::sformat(
865+
throw exception::ChainedItemInvalid(folly::sformat(
866866
"Mismatch parent pointer. This should not happen. Key: {}",
867867
it.getKey()));
868868
}
869869

870870
if (!chainedItemAccessContainer_->remove(*head)) {
871-
throw std::runtime_error(folly::sformat(
871+
throw exception::ChainedItemInvalid(folly::sformat(
872872
"Chained item associated with {} cannot be removed from hash table "
873873
"This should not happen here.",
874874
it.getKey()));

cachelib/allocator/Handle.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <mutex>
2727

2828
#include "cachelib/allocator/nvmcache/WaitContext.h"
29+
#include "cachelib/common/Exceptions.h"
2930

3031
namespace facebook {
3132
namespace cachelib {
@@ -70,8 +71,10 @@ struct ReadHandleImpl {
7071
assert(alloc_ != nullptr);
7172
try {
7273
alloc_->release(it_, isNascent());
74+
} catch (const exception::ChainedItemInvalid& e) {
75+
XDCHECK(false) << e.what();
7376
} catch (const std::exception& e) {
74-
XLOGF(CRITICAL, "Failed to release {:#10x} : {}", static_cast<void*>(it_),
77+
XLOGF(CRITICAL, "Failed to release {} : {}", static_cast<void*>(it_),
7578
e.what());
7679
}
7780
it_ = nullptr;

cachelib/allocator/tests/AllocatorTypeTest.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,11 @@ TYPED_TEST(BaseAllocatorTest, TransferChainAfterMoving) {
292292
this->testTransferChainAfterMoving();
293293
}
294294

295+
TYPED_TEST(BaseAllocatorTest, ChainedItemParentAcquireAfterMove) {
296+
ASSERT_EXIT(this->testChainedItemParentAcquireAfterMoveLoop(),
297+
testing::ExitedWithCode(0), ".*");
298+
}
299+
295300
TYPED_TEST(BaseAllocatorTest, AddAndPopChainedItemMultithread) {
296301
this->testAddAndPopChainedItemMultithread();
297302
}

cachelib/allocator/tests/BaseAllocatorTest.h

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <folly/Random.h>
2020
#include <folly/Singleton.h>
2121
#include <folly/synchronization/Baton.h>
22+
#include <folly/synchronization/Latch.h>
2223

2324
#include <algorithm>
2425
#include <chrono>
@@ -2469,6 +2470,80 @@ class BaseAllocatorTest : public AllocatorTest<AllocatorT> {
24692470
}
24702471
}
24712472

2473+
// tests case that correct parent item is acquired after move
2474+
void testChainedItemParentAcquireAfterMoveLoop() {
2475+
// create an allocator worth 250 slabs
2476+
// first slab is for overhead, second is parent class
2477+
// third is chained item 1 and rest are for new chained item alloc
2478+
// to move to.
2479+
std::unique_ptr<AllocatorT> alloc;
2480+
typename AllocatorT::Config config;
2481+
config.configureChainedItems();
2482+
config.setCacheSize(250 * Slab::kSize);
2483+
2484+
const std::set<uint32_t> allocSizes = {1024, 2048};
2485+
auto sizes = std::vector<uint32_t>{500, 1500};
2486+
std::atomic<uint64_t> numMoves{0};
2487+
std::atomic<uint64_t> numReplaces{0};
2488+
PoolId pid;
2489+
2490+
using Item = typename AllocatorT::Item;
2491+
config.enableMovingOnSlabRelease([&](Item& oldItem, Item& newItem,
2492+
Item* parentPtr) {
2493+
assert(oldItem.getSize() == newItem.getSize());
2494+
assert(oldItem.isChainedItem());
2495+
std::memcpy(newItem.getMemory(), oldItem.getMemory(), oldItem.getSize());
2496+
folly::Latch latch(1);
2497+
auto insertThread = std::make_unique<std::thread>([&]() {
2498+
ASSERT_NO_THROW({
2499+
auto parentReplacement =
2500+
alloc->allocate(pid, parentPtr->getKey(), sizes[0]);
2501+
Item* parentCopy = parentPtr;
2502+
latch.count_down();
2503+
while (parentCopy->isMoving())
2504+
;
2505+
alloc->insertOrReplace(parentReplacement);
2506+
++numReplaces;
2507+
});
2508+
});
2509+
insertThread->detach();
2510+
latch.wait();
2511+
++numMoves;
2512+
});
2513+
2514+
alloc = std::make_unique<AllocatorT>(config);
2515+
2516+
const size_t numBytes = alloc->getCacheMemoryStats().ramCacheSize;
2517+
const auto poolSize = numBytes;
2518+
pid = alloc->addPool("one", poolSize, allocSizes);
2519+
2520+
auto allocFn = [&](std::string keyPrefix, std::vector<uint32_t> sizes) {
2521+
for (unsigned int loop = 0; loop < 20; ++loop) {
2522+
for (unsigned int i = 0; i < 2048; ++i) {
2523+
const auto key = keyPrefix + folly::to<std::string>(loop) + "_" +
2524+
folly::to<std::string>(i);
2525+
auto itemHandle =
2526+
util::allocateAccessible(*alloc, pid, key, sizes[0]);
2527+
auto childItem = alloc->allocateChainedItem(itemHandle, sizes[1]);
2528+
ASSERT_NE(nullptr, childItem);
2529+
2530+
alloc->addChainedItem(itemHandle, std::move(childItem));
2531+
}
2532+
}
2533+
};
2534+
allocFn(std::string{"yolo"}, sizes);
2535+
2536+
ClassId cid = static_cast<ClassId>(1);
2537+
for (int i = 0; i < 20; i++) {
2538+
alloc->releaseSlab(pid, cid, SlabReleaseMode::kRebalance);
2539+
}
2540+
while (alloc->getSlabReleaseStats().numSlabReleaseForRebalance < 20) {
2541+
sleep(1);
2542+
}
2543+
// for ASSERT_EXIT
2544+
exit(0);
2545+
}
2546+
24722547
// create a chain of allocations, replace the allocation and ensure that the
24732548
// order is preserved.
24742549
void testChainedAllocsReplaceInChain() {

cachelib/common/Exceptions.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ class SlabReleaseAborted : public std::runtime_error {
6767
using std::runtime_error::runtime_error;
6868
};
6969

70+
class ChainedItemInvalid : public std::runtime_error {
71+
public:
72+
using std::runtime_error::runtime_error;
73+
};
74+
7075
// An allocation error. This could be a genuine std::bad_alloc from
7176
// the global allocator, or it can be an internal allocation error
7277
// from the backing cachelib item.

0 commit comments

Comments
 (0)