|
22 | 22 | #include "cachelib/allocator/FreeThresholdStrategy.h"
|
23 | 23 | #include "cachelib/allocator/PromotionStrategy.h"
|
24 | 24 |
|
| 25 | +#include <fcntl.h> |
| 26 | +#include <unistd.h> |
| 27 | +#include <ctype.h> |
| 28 | +#include <semaphore.h> |
25 | 29 | #include <folly/synchronization/Latch.h>
|
26 | 30 |
|
27 | 31 | namespace facebook {
|
@@ -234,6 +238,127 @@ class AllocatorMemoryTiersTest : public AllocatorTest<AllocatorT> {
|
234 | 238 | testMultiTiersAsyncOpDuringMove(alloc, pool, quit, moveCb);
|
235 | 239 |
|
236 | 240 | t->join();
|
| 241 | + |
| 242 | + } |
| 243 | + |
| 244 | + |
| 245 | + void gdb_sync1() {} |
| 246 | + void gdb_sync2() {} |
| 247 | + void gdb_sync3() {} |
| 248 | + using ReadHandle = typename AllocatorT::ReadHandle; |
| 249 | + void testMultiTiersReplaceDuringEvictionWithReader() { |
| 250 | + sem_unlink ("/gdb1_sem"); |
| 251 | + sem_t *sem = sem_open ("/gdb1_sem", O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 0); |
| 252 | + int gdbfd = open("/tmp/gdb1.gdb",O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR); |
| 253 | + char gdbcmds[] = |
| 254 | + "set attached=1\n" |
| 255 | + "break gdb_sync1\n" |
| 256 | + "break gdb_sync2\n" |
| 257 | + "break moveRegularItem\n" |
| 258 | + "c\n" |
| 259 | + "set scheduler-locking on\n" |
| 260 | + "thread 1\n" |
| 261 | + "c\n" |
| 262 | + "thread 4\n" |
| 263 | + "c\n" |
| 264 | + "thread 5\n" |
| 265 | + "break nativeFutexWaitImpl thread 5\n" |
| 266 | + "c\n" |
| 267 | + "thread 4\n" |
| 268 | + "break nativeFutexWaitImpl thread 4\n" |
| 269 | + "c\n" |
| 270 | + "thread 1\n" |
| 271 | + "break releaseBackToAllocator\n" |
| 272 | + "c\n" |
| 273 | + "c\n" |
| 274 | + "thread 5\n" |
| 275 | + "c\n" |
| 276 | + "thread 4\n" |
| 277 | + "c\n" |
| 278 | + "thread 1\n" |
| 279 | + "break gdb_sync3\n" |
| 280 | + "c\n" |
| 281 | + "quit\n"; |
| 282 | + int ret = write(gdbfd,gdbcmds,strlen(gdbcmds)); |
| 283 | + int ppid = getpid(); //parent pid |
| 284 | + //int pid = 0; |
| 285 | + int pid = fork(); |
| 286 | + if (pid == 0) { |
| 287 | + sem_wait(sem); |
| 288 | + sem_close(sem); |
| 289 | + sem_unlink("/gdb1_sem"); |
| 290 | + char cmdpid[256]; |
| 291 | + sprintf(cmdpid,"%d",ppid); |
| 292 | + int f = execlp("gdb","gdb","--pid",cmdpid,"--batch-silent","--command=/tmp/gdb1.gdb",(char*) 0); |
| 293 | + ASSERT(f != -1); |
| 294 | + } |
| 295 | + sem_post(sem); |
| 296 | + //wait for gdb to run |
| 297 | + int attached = 0; |
| 298 | + while (attached == 0); |
| 299 | + |
| 300 | + std::unique_ptr<AllocatorT> alloc; |
| 301 | + PoolId pool; |
| 302 | + bool quit = false; |
| 303 | + |
| 304 | + typename AllocatorT::Config config; |
| 305 | + config.setCacheSize(4 * Slab::kSize); |
| 306 | + config.enableCachePersistence("/tmp"); |
| 307 | + config.configureMemoryTiers({ |
| 308 | + MemoryTierCacheConfig::fromShm() |
| 309 | + .setRatio(1).setMemBind(std::string("0")), |
| 310 | + MemoryTierCacheConfig::fromShm() |
| 311 | + .setRatio(1).setMemBind(std::string("0")) |
| 312 | + }); |
| 313 | + |
| 314 | + alloc = std::make_unique<AllocatorT>(AllocatorT::SharedMemNew, config); |
| 315 | + ASSERT(alloc != nullptr); |
| 316 | + pool = alloc->addPool("default", alloc->getCacheMemoryStats().ramCacheSize); |
| 317 | + |
| 318 | + int i = 0; |
| 319 | + typename AllocatorT::Item* evicted; |
| 320 | + std::unique_ptr<std::thread> t; |
| 321 | + std::unique_ptr<std::thread> r; |
| 322 | + while(!quit) { |
| 323 | + auto handle = alloc->allocate(pool, std::to_string(++i), std::string("value").size()); |
| 324 | + ASSERT(handle != nullptr); |
| 325 | + if (i == 1) { |
| 326 | + evicted = static_cast<typename AllocatorT::Item*>(handle.get()); |
| 327 | + folly::Latch latch_t(1); |
| 328 | + t = std::make_unique<std::thread>([&](){ |
| 329 | + auto handleNew = alloc->allocate(pool, std::to_string(1), std::string("new value").size()); |
| 330 | + ASSERT(handleNew != nullptr); |
| 331 | + latch_t.count_down(); |
| 332 | + //first breakpoint will be this one because |
| 333 | + //thread 1 still has more items to fill up the |
| 334 | + //cache before an evict is evicted |
| 335 | + gdb_sync1(); |
| 336 | + ASSERT(evicted->isMoving()); |
| 337 | + //need to suspend thread 1 - who is doing the eviction |
| 338 | + //gdb will do this for us |
| 339 | + folly::Latch latch(1); |
| 340 | + r = std::make_unique<std::thread>([&](){ |
| 341 | + ASSERT(evicted->isMoving()); |
| 342 | + latch.count_down(); |
| 343 | + auto handleEvict = alloc->find(std::to_string(1)); |
| 344 | + //does find block until done moving?? yes |
| 345 | + while (evicted->isMarkedForEviction()); //move will fail |
| 346 | + XDCHECK(handleEvict == nullptr) << handleEvict->toString(); |
| 347 | + ASSERT(handleEvict == nullptr); |
| 348 | + }); |
| 349 | + latch.wait(); |
| 350 | + gdb_sync2(); |
| 351 | + alloc->insertOrReplace(handleNew); |
| 352 | + ASSERT(!evicted->isAccessible()); //move failed |
| 353 | + quit = true; |
| 354 | + }); |
| 355 | + latch_t.wait(); |
| 356 | + } |
| 357 | + ASSERT_NO_THROW(alloc->insertOrReplace(handle)); |
| 358 | + } |
| 359 | + t->join(); |
| 360 | + r->join(); |
| 361 | + gdb_sync3(); |
237 | 362 | }
|
238 | 363 | };
|
239 | 364 | } // namespace tests
|
|
0 commit comments