|
50 | 50 | #include "tests/module_tests/test_task.h" |
51 | 51 | #include "tests/module_tests/thread_gate.h" |
52 | 52 | #include "tests/test_fileops.h" |
| 53 | +#include "vbucket_bgfetch_item.h" |
53 | 54 | #include "vbucket_state.h" |
54 | 55 |
|
55 | 56 | #include "../couchstore/src/internal.h" |
@@ -5359,6 +5360,83 @@ TEST_P(STParamPersistentBucketTest, FlusherMarksCleanBySeqno) { |
5359 | 5360 | EXPECT_EQ(2, it->getBySeqno()); |
5360 | 5361 | } |
5361 | 5362 |
|
| 5363 | +// @TODO move to EPBucketFullEvictionTest on merge forward to master |
| 5364 | +TEST_P(STParamPersistentBucketTest, ExpiryFindsPrepareWithSameCas) { |
| 5365 | + if (!fullEviction()) { |
| 5366 | + return; |
| 5367 | + } |
| 5368 | + setVBucketStateAndRunPersistTask( |
| 5369 | + vbid, |
| 5370 | + vbucket_state_active, |
| 5371 | + {{"topology", nlohmann::json::array({{"active", "replica"}})}}); |
| 5372 | + |
| 5373 | + // 1) Store prepare with expiry |
| 5374 | + auto key = makeStoredDocKey("a"); |
| 5375 | + using namespace cb::durability; |
| 5376 | + auto pre = makePendingItem(key, "value", Requirements{Level::Majority, {}}); |
| 5377 | + pre->setVBucketId(vbid); |
| 5378 | + pre->setExpTime(1); |
| 5379 | + |
| 5380 | + EXPECT_EQ(ENGINE_SYNC_WRITE_PENDING, store->set(*pre, cookie)); |
| 5381 | + flushVBucketToDiskIfPersistent(vbid, 1); |
| 5382 | + |
| 5383 | + auto vb = store->getVBucket(vbid); |
| 5384 | + |
| 5385 | + // 2) Seqno ack and commit the prepare |
| 5386 | + vb->seqnoAcknowledged(folly::SharedMutex::ReadHolder(vb->getStateLock()), |
| 5387 | + "replica", |
| 5388 | + 1 /*prepareSeqno*/); |
| 5389 | + vb->processResolvedSyncWrites(); |
| 5390 | + |
| 5391 | + // 3) Fudge the current snapshot so that when we warmup we scan the entire |
| 5392 | + // snapshot for prepares (i.e. incomplete disk snapshot) |
| 5393 | + vb->checkpointManager->updateCurrentSnapshot(3, 3, CheckpointType::Disk); |
| 5394 | + flushVBucketToDiskIfPersistent(vbid, 1); |
| 5395 | + |
| 5396 | + // 4) Restart and warmup |
| 5397 | + vb.reset(); |
| 5398 | + resetEngineAndWarmup(); |
| 5399 | + vb = store->getVBucket(vbid); |
| 5400 | + |
| 5401 | + { |
| 5402 | + // Verify that the prepare is there and it's "MaybeVisible" |
| 5403 | + auto ret = vb->ht.findForUpdate(key); |
| 5404 | + ASSERT_TRUE(ret.pending); |
| 5405 | + ASSERT_TRUE(ret.pending->isPreparedMaybeVisible()); |
| 5406 | + |
| 5407 | + // And that the commit is there too |
| 5408 | + ASSERT_TRUE(ret.committed); |
| 5409 | + } |
| 5410 | + |
| 5411 | + // 5) Grab the item from disk just like the compactor would |
| 5412 | + vb_bgfetch_queue_t q; |
| 5413 | + vb_bgfetch_item_ctx_t ctx; |
| 5414 | + ctx.isMetaOnly = GetMetaOnly::No; |
| 5415 | + auto diskDocKey = makeDiskDocKey("a"); |
| 5416 | + q[diskDocKey] = std::move(ctx); |
| 5417 | + store->getRWUnderlying(vbid)->getMulti(vbid, q); |
| 5418 | + EXPECT_EQ(ENGINE_SUCCESS, q[diskDocKey].value.getStatus()); |
| 5419 | + |
| 5420 | + // 6) Callback from the "compactor" with the item to try and expire it. We |
| 5421 | + // could also pretend to be the pager here. |
| 5422 | + ASSERT_EQ(0, vb->numExpiredItems); |
| 5423 | + vb->deleteExpiredItem(*q[diskDocKey].value.item, 2, ExpireBy::Compactor); |
| 5424 | + |
| 5425 | + // Item expiry cannot take place if the MaybeVisible prepare exists. |
| 5426 | + EXPECT_EQ(0, vb->numExpiredItems); |
| 5427 | + { |
| 5428 | + // Verify that the prepare is there and it's "MaybeVisible". Before the |
| 5429 | + // fix deleteExpiredItem would select and replace the prepare which is |
| 5430 | + // incorrect and causes us to have two committed items in the HashTable. |
| 5431 | + auto ret = vb->ht.findForUpdate(key); |
| 5432 | + ASSERT_TRUE(ret.pending); |
| 5433 | + ASSERT_TRUE(ret.pending->isPreparedMaybeVisible()); |
| 5434 | + |
| 5435 | + // And that the commit is there too |
| 5436 | + ASSERT_TRUE(ret.committed); |
| 5437 | + } |
| 5438 | +} |
| 5439 | + |
5362 | 5440 | INSTANTIATE_TEST_CASE_P(Persistent, |
5363 | 5441 | STParamPersistentBucketTest, |
5364 | 5442 | STParameterizedBucketTest::persistentConfigValues(), |
|
0 commit comments