Skip to content

Commit 777ffbd

Browse files
committed
Fix moveRegularItemWithSync and add tests
1 parent 829a434 commit 777ffbd

File tree

4 files changed

+99
-4
lines changed

4 files changed

+99
-4
lines changed

cachelib/allocator/CacheAllocator-inl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1308,15 +1308,15 @@ CacheAllocator<CacheTrait>::moveRegularItemWithSync(
13081308
// make sure that no other thread removed it, and only then replaces it.
13091309
if (!replaceInMMContainer(oldItem, *newItemHdl)) {
13101310
accessContainer_->remove(*newItemHdl);
1311-
return {};
1311+
return acquire(&oldItem);
13121312
}
13131313

13141314
// Replacing into the MM container was successful, but someone could have
13151315
// called insertOrReplace() or remove() before or after the
13161316
// replaceInMMContainer() operation, which would invalidate newItemHdl.
13171317
if (!newItemHdl->isAccessible()) {
13181318
removeFromMMContainer(*newItemHdl);
1319-
return {};
1319+
return acquire(&oldItem);
13201320
}
13211321

13221322
// no one can add or remove chained items at this point

cachelib/allocator/CacheAllocator.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,8 +1496,9 @@ class CacheAllocator : public CacheBase {
14961496
// @param oldItem Reference to the item being moved
14971497
// @param newItemHdl Reference to the handle of the new item being moved into
14981498
//
1499-
// @return true If the move was completed, and the containers were updated
1500-
// successfully.
1499+
// @return the handle to the oldItem if the move was completed
1500+
// and the oldItem can be recycled.
1501+
// Otherwise an empty handle is returned.
15011502
template <typename P>
15021503
WriteHandle moveRegularItemWithSync(Item& oldItem, WriteHandle& newItemHdl, P&& predicate);
15031504

cachelib/allocator/tests/AllocatorMemoryTiersTest.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ TEST_F(LruAllocatorMemoryTiersTest, MultiTiersFromFileValid) { this->testMultiTi
2828
TEST_F(LruAllocatorMemoryTiersTest, MultiTiersValidMixed) { this->testMultiTiersValidMixed(); }
2929
TEST_F(LruAllocatorMemoryTiersTest, MultiTiersNumaBindingsSysVValid) { this->testMultiTiersNumaBindingsSysVValid(); }
3030
TEST_F(LruAllocatorMemoryTiersTest, MultiTiersNumaBindingsPosixValid) { this->testMultiTiersNumaBindingsPosixValid(); }
31+
TEST_F(LruAllocatorMemoryTiersTest, MultiTiersRemoveDuringEviction) { this->testMultiTiersRemoveDuringEviction(); }
32+
TEST_F(LruAllocatorMemoryTiersTest, MultiTiersReplaceDuringEviction) { this->testMultiTiersReplaceDuringEviction(); }
3133

3234
} // end of namespace tests
3335
} // end of namespace cachelib

cachelib/allocator/tests/AllocatorMemoryTiersTest.h

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,98 @@ class AllocatorMemoryTiersTest : public AllocatorTest<AllocatorT> {
124124
ASSERT(handle != nullptr);
125125
ASSERT_NO_THROW(alloc->insertOrReplace(handle));
126126
}
127+
128+
void testMultiTiersRemoveDuringEviction() {
129+
bool quit = false;
130+
typename AllocatorT::Config config;
131+
config.setCacheSize(4 * Slab::kSize);
132+
config.enableCachePersistence("/tmp");
133+
config.configureMemoryTiers({
134+
MemoryTierCacheConfig::fromShm()
135+
.setRatio(1).setMemBind({0}),
136+
MemoryTierCacheConfig::fromShm()
137+
.setRatio(1).setMemBind({0})
138+
});
139+
140+
std::unique_ptr<AllocatorT> alloc;
141+
std::unique_ptr<std::thread> t;
142+
143+
const auto moveCb = [&] (typename AllocatorT::Item& oldItem,
144+
typename AllocatorT::Item& newItem,
145+
typename AllocatorT::Item* /* parentPtr */) {
146+
memcpy(newItem.getMemory(), oldItem.getMemory(), oldItem.getSize());
147+
auto key = oldItem.getKey();
148+
t = std::make_unique<std::thread>([&](){ alloc->remove(key); });
149+
// sleep to make sure async thread calls remove(key)
150+
std::this_thread::sleep_for(std::chrono::milliseconds(100));
151+
quit = true;
152+
};
153+
config.enableMovingOnSlabRelease(moveCb, {} /* ChainedItemsMoveSync */,
154+
-1 /* movingAttemptsLimit */);
155+
156+
alloc = std::make_unique<AllocatorT>(AllocatorT::SharedMemNew, config);
157+
ASSERT(alloc != nullptr);
158+
auto pool = alloc->addPool("default", alloc->getCacheMemoryStats().cacheSize);
159+
160+
int i = 0;
161+
while(!quit) {
162+
auto handle = alloc->allocate(pool, std::to_string(++i), std::string("value").size());
163+
ASSERT(handle != nullptr);
164+
ASSERT_NO_THROW(alloc->insertOrReplace(handle));
165+
}
166+
167+
t->join();
168+
}
169+
170+
void testMultiTiersReplaceDuringEviction() {
171+
bool quit = false;
172+
typename AllocatorT::Config config;
173+
config.setCacheSize(4 * Slab::kSize);
174+
config.enableCachePersistence("/tmp");
175+
config.configureMemoryTiers({
176+
MemoryTierCacheConfig::fromShm()
177+
.setRatio(1).setMemBind({0}),
178+
MemoryTierCacheConfig::fromShm()
179+
.setRatio(1).setMemBind({0})
180+
});
181+
182+
std::unique_ptr<AllocatorT> alloc;
183+
PoolId pool;
184+
std::unique_ptr<std::thread> t;
185+
186+
const auto moveCb = [&] (typename AllocatorT::Item& oldItem,
187+
typename AllocatorT::Item& newItem,
188+
typename AllocatorT::Item* /* parentPtr */) {
189+
memcpy(newItem.getMemory(), oldItem.getMemory(), oldItem.getSize());
190+
auto key = oldItem.getKey();
191+
if(!quit) {
192+
// we need to replace only once because subsequent allocate calls
193+
// will cause evictions recursevly
194+
quit = true;
195+
t = std::make_unique<std::thread>([&](){
196+
auto handle = alloc->allocate(pool, key, std::string("new value").size());
197+
ASSERT_NO_THROW(alloc->insertOrReplace(handle));
198+
});
199+
// sleep to make sure async thread calls remove(key)
200+
std::this_thread::sleep_for(std::chrono::milliseconds(100));
201+
}
202+
};
203+
config.enableMovingOnSlabRelease(moveCb, {} /* ChainedItemsMoveSync */,
204+
-1 /* movingAttemptsLimit */);
205+
206+
alloc = std::make_unique<AllocatorT>(AllocatorT::SharedMemNew, config);
207+
ASSERT(alloc != nullptr);
208+
pool = alloc->addPool("default", alloc->getCacheMemoryStats().cacheSize);
209+
210+
int i = 0;
211+
while(!quit) {
212+
auto handle = alloc->allocate(pool, std::to_string(++i), std::string("value").size());
213+
ASSERT(handle != nullptr);
214+
ASSERT_NO_THROW(alloc->insertOrReplace(handle));
215+
}
216+
217+
t->join();
218+
}
127219
};
128220
} // namespace tests
129221
} // namespace cachelib

0 commit comments

Comments
 (0)