|
20 | 20 | #include "cachelib/allocator/MemoryTierCacheConfig.h"
|
21 | 21 | #include "cachelib/allocator/tests/TestBase.h"
|
22 | 22 |
|
| 23 | +#include <folly/synchronization/Latch.h> |
| 24 | + |
23 | 25 | namespace facebook {
|
24 | 26 | namespace cachelib {
|
25 | 27 | namespace tests {
|
26 | 28 |
|
27 | 29 | template <typename AllocatorT>
|
28 | 30 | class AllocatorMemoryTiersTest : public AllocatorTest<AllocatorT> {
|
| 31 | + private: |
| 32 | + template<typename MvCallback> |
| 33 | + void testMultiTiersAsyncOpDuringMove(std::unique_ptr<AllocatorT>& alloc, |
| 34 | + PoolId& pool, bool& quit, MvCallback&& moveCb) { |
| 35 | + typename AllocatorT::Config config; |
| 36 | + config.setCacheSize(4 * Slab::kSize); |
| 37 | + config.enableCachePersistence("/tmp"); |
| 38 | + config.configureMemoryTiers({ |
| 39 | + MemoryTierCacheConfig::fromShm() |
| 40 | + .setRatio(1).setMemBind({0}), |
| 41 | + MemoryTierCacheConfig::fromShm() |
| 42 | + .setRatio(1).setMemBind({0}) |
| 43 | + }); |
| 44 | + |
| 45 | + config.enableMovingOnSlabRelease(moveCb, {} /* ChainedItemsMoveSync */, |
| 46 | + -1 /* movingAttemptsLimit */); |
| 47 | + |
| 48 | + alloc = std::make_unique<AllocatorT>(AllocatorT::SharedMemNew, config); |
| 49 | + ASSERT(alloc != nullptr); |
| 50 | + pool = alloc->addPool("default", alloc->getCacheMemoryStats().cacheSize); |
| 51 | + |
| 52 | + int i = 0; |
| 53 | + while(!quit) { |
| 54 | + auto handle = alloc->allocate(pool, std::to_string(++i), std::string("value").size()); |
| 55 | + ASSERT(handle != nullptr); |
| 56 | + ASSERT_NO_THROW(alloc->insertOrReplace(handle)); |
| 57 | + } |
| 58 | + } |
29 | 59 | public:
|
30 | 60 | void testMultiTiersFormFileInvalid() {
|
31 | 61 | typename AllocatorT::Config config;
|
@@ -124,6 +154,70 @@ class AllocatorMemoryTiersTest : public AllocatorTest<AllocatorT> {
|
124 | 154 | ASSERT(handle != nullptr);
|
125 | 155 | ASSERT_NO_THROW(alloc->insertOrReplace(handle));
|
126 | 156 | }
|
| 157 | + |
| 158 | + void testMultiTiersRemoveDuringEviction() { |
| 159 | + std::unique_ptr<AllocatorT> alloc; |
| 160 | + PoolId pool; |
| 161 | + std::unique_ptr<std::thread> t; |
| 162 | + folly::Latch latch(1); |
| 163 | + bool quit = false; |
| 164 | + |
| 165 | + auto moveCb = [&] (typename AllocatorT::Item& oldItem, |
| 166 | + typename AllocatorT::Item& newItem, |
| 167 | + typename AllocatorT::Item* /* parentPtr */) { |
| 168 | + |
| 169 | + auto key = oldItem.getKey(); |
| 170 | + t = std::make_unique<std::thread>([&](){ |
| 171 | + // remove() function is blocked by wait context |
| 172 | + // till item is moved to next tier. So that, we should |
| 173 | + // notify latch before calling remove() |
| 174 | + latch.count_down(); |
| 175 | + alloc->remove(key); |
| 176 | + }); |
| 177 | + // wait till async thread is running |
| 178 | + latch.wait(); |
| 179 | + memcpy(newItem.getMemory(), oldItem.getMemory(), oldItem.getSize()); |
| 180 | + quit = true; |
| 181 | + }; |
| 182 | + |
| 183 | + testMultiTiersAsyncOpDuringMove(alloc, pool, quit, moveCb); |
| 184 | + |
| 185 | + t->join(); |
| 186 | + } |
| 187 | + |
| 188 | + void testMultiTiersReplaceDuringEviction() { |
| 189 | + std::unique_ptr<AllocatorT> alloc; |
| 190 | + PoolId pool; |
| 191 | + std::unique_ptr<std::thread> t; |
| 192 | + folly::Latch latch(1); |
| 193 | + bool quit = false; |
| 194 | + |
| 195 | + auto moveCb = [&] (typename AllocatorT::Item& oldItem, |
| 196 | + typename AllocatorT::Item& newItem, |
| 197 | + typename AllocatorT::Item* /* parentPtr */) { |
| 198 | + auto key = oldItem.getKey(); |
| 199 | + if(!quit) { |
| 200 | + // we need to replace only once because subsequent allocate calls |
| 201 | + // will cause evictions recursevly |
| 202 | + quit = true; |
| 203 | + t = std::make_unique<std::thread>([&](){ |
| 204 | + auto handle = alloc->allocate(pool, key, std::string("new value").size()); |
| 205 | + // insertOrReplace() function is blocked by wait context |
| 206 | + // till item is moved to next tier. So that, we should |
| 207 | + // notify latch before calling insertOrReplace() |
| 208 | + latch.count_down(); |
| 209 | + ASSERT_NO_THROW(alloc->insertOrReplace(handle)); |
| 210 | + }); |
| 211 | + // wait till async thread is running |
| 212 | + latch.wait(); |
| 213 | + } |
| 214 | + memcpy(newItem.getMemory(), oldItem.getMemory(), oldItem.getSize()); |
| 215 | + }; |
| 216 | + |
| 217 | + testMultiTiersAsyncOpDuringMove(alloc, pool, quit, moveCb); |
| 218 | + |
| 219 | + t->join(); |
| 220 | + } |
127 | 221 | };
|
128 | 222 | } // namespace tests
|
129 | 223 | } // namespace cachelib
|
|
0 commit comments