|
52 | 52 | #include "tests/test_fileops.h" |
53 | 53 | #include "vbucket_bgfetch_item.h" |
54 | 54 | #include "vbucket_state.h" |
| 55 | +#include "warmup.h" |
55 | 56 |
|
56 | 57 | #include "../couchstore/src/internal.h" |
57 | 58 |
|
@@ -5038,6 +5039,126 @@ void STParamPersistentBucketTest::testAbortDoesNotIncrementOpsDelete( |
5038 | 5039 | EXPECT_EQ(0, vb.opsDelete); |
5039 | 5040 | } |
5040 | 5041 |
|
| 5042 | +void STParamPersistentBucketTest::testFailoverTableEntryPersistedAtWarmup( |
| 5043 | + std::function<void()> testFunction) { |
| 5044 | + // 1) Store something so we can expire it later |
| 5045 | + engine->getKVBucket()->setVBucketState(vbid, vbucket_state_active); |
| 5046 | + auto vb = engine->getKVBucket()->getVBucket(vbid); |
| 5047 | + |
| 5048 | + // Grab initialUuid for testing |
| 5049 | + auto initialUuid = vb->failovers->getLatestUUID(); |
| 5050 | + |
| 5051 | + auto key = makeStoredDocKey("key"); |
| 5052 | + store_item(vbid, key, "value", 1 /*expiryTime*/); |
| 5053 | + flushVBucketToDiskIfPersistent(vbid, 1); |
| 5054 | + EXPECT_EQ(1, vb->getHighSeqno()); |
| 5055 | + |
| 5056 | + // 2) Restart as though we had an unclean shutdown (creating a new failover |
| 5057 | + // table entry) and run the warmup up to the point of completion. |
| 5058 | + vb.reset(); |
| 5059 | + resetEngineAndEnableWarmup(); |
| 5060 | + |
| 5061 | + auto& readerQueue = *task_executor->getLpTaskQ()[READER_TASK_IDX]; |
| 5062 | + auto* warmup = engine->getKVBucket()->getWarmup(); |
| 5063 | + ASSERT_TRUE(warmup); |
| 5064 | + |
| 5065 | + // Warmup - load everything but don't run the complete phase which schedules |
| 5066 | + // persistence of the vBucket state (new failover entry) |
| 5067 | + while (warmup->getWarmupState() != WarmupState::State::Done) { |
| 5068 | + runNextTask(readerQueue); |
| 5069 | + } |
| 5070 | + |
| 5071 | + // 3) Test |
| 5072 | + testFunction(); |
| 5073 | + |
| 5074 | + // New high seqno |
| 5075 | + vb = engine->getKVBucket()->getVBucket(vbid); |
| 5076 | + EXPECT_EQ(2, vb->getHighSeqno()); |
| 5077 | + |
| 5078 | + // Flush the expiry |
| 5079 | + flushVBucketToDiskIfPersistent(vbid, 1); |
| 5080 | + |
| 5081 | + // Verify that the item has been expired |
| 5082 | + auto options = static_cast<get_options_t>( |
| 5083 | + QUEUE_BG_FETCH | HONOR_STATES | TRACK_REFERENCE | DELETE_TEMP | |
| 5084 | + HIDE_LOCKED_CAS | TRACK_STATISTICS); |
| 5085 | + auto gv = store->get(key, vbid, cookie, options); |
| 5086 | + |
| 5087 | + if (gv.getStatus() == ENGINE_EWOULDBLOCK) { |
| 5088 | + runBGFetcherTask(); |
| 5089 | + gv = store->get(key, vbid, cookie, options); |
| 5090 | + } |
| 5091 | + |
| 5092 | + EXPECT_EQ(ENGINE_KEY_ENOENT, gv.getStatus()); |
| 5093 | + |
| 5094 | + // Get our new uuid now |
| 5095 | + auto secondUuid = vb->failovers->getLatestUUID(); |
| 5096 | + ASSERT_NE(initialUuid, secondUuid); |
| 5097 | + |
| 5098 | + // "Complete" the warmup or the test will get stuck shutting down, we won't |
| 5099 | + // actually flush the new vb state though so we're still testing as though |
| 5100 | + // this didn't happen |
| 5101 | + runNextTask(readerQueue); |
| 5102 | + |
| 5103 | + // 4) Restart again |
| 5104 | + vb.reset(); |
| 5105 | + resetEngineAndWarmup(); |
| 5106 | + |
| 5107 | + // 5) The test - uuid should have both of the previous entries |
| 5108 | + vb = engine->getKVBucket()->getVBucket(vbid); |
| 5109 | + |
| 5110 | + auto failovers = vb->failovers->getFailoverLog(); |
| 5111 | + auto itr = std::find_if(failovers.begin(), |
| 5112 | + failovers.end(), |
| 5113 | + [&initialUuid](const auto& failoverEntry) { |
| 5114 | + return failoverEntry.uuid == initialUuid; |
| 5115 | + }); |
| 5116 | + EXPECT_NE(itr, failovers.end()); |
| 5117 | + |
| 5118 | + itr = std::find_if(failovers.begin(), |
| 5119 | + failovers.end(), |
| 5120 | + [&secondUuid](const auto& failoverEntry) { |
| 5121 | + return failoverEntry.uuid == secondUuid; |
| 5122 | + }); |
| 5123 | + EXPECT_NE(itr, failovers.end()); |
| 5124 | + |
| 5125 | + EXPECT_EQ(2, vb->getHighSeqno()); |
| 5126 | + gv = store->get(key, vbid, cookie, options); |
| 5127 | + |
| 5128 | + if (gv.getStatus() == ENGINE_EWOULDBLOCK) { |
| 5129 | + runBGFetcherTask(); |
| 5130 | + gv = store->get(key, vbid, cookie, options); |
| 5131 | + } |
| 5132 | +} |
| 5133 | + |
| 5134 | +TEST_P(STParamPersistentBucketTest, |
| 5135 | + TestExpiryDueToCompactionPersistsFailoverTableEntryDuringWarmup) { |
| 5136 | + testFailoverTableEntryPersistedAtWarmup([this]() { |
| 5137 | + CompactionConfig config; |
| 5138 | + engine->compactDB(vbid, config, cookie); |
| 5139 | + std::string taskDescription = |
| 5140 | + "Compact DB file " + std::to_string(vbid.get()); |
| 5141 | + runNextTask(*task_executor->getLpTaskQ()[WRITER_TASK_IDX], |
| 5142 | + taskDescription); |
| 5143 | + }); |
| 5144 | +} |
| 5145 | + |
| 5146 | +TEST_P(STParamPersistentBucketTest, |
| 5147 | + TestExpiryDueToGetPersistsFailoverTableEntryDuringWarmup) { |
| 5148 | + testFailoverTableEntryPersistedAtWarmup([this]() { |
| 5149 | + auto options = static_cast<get_options_t>( |
| 5150 | + QUEUE_BG_FETCH | HONOR_STATES | TRACK_REFERENCE | DELETE_TEMP | |
| 5151 | + HIDE_LOCKED_CAS | TRACK_STATISTICS); |
| 5152 | + auto key = makeStoredDocKey("key"); |
| 5153 | + auto gv = store->get(key, vbid, cookie, options); |
| 5154 | + |
| 5155 | + if (gv.getStatus() == ENGINE_EWOULDBLOCK) { |
| 5156 | + runBGFetcherTask(); |
| 5157 | + gv = store->get(key, vbid, cookie, options); |
| 5158 | + } |
| 5159 | + }); |
| 5160 | +} |
| 5161 | + |
5041 | 5162 | TEST_P(STParamPersistentBucketTest, AbortDoesNotIncrementOpsDelete) { |
5042 | 5163 | testAbortDoesNotIncrementOpsDelete(true /*flusherDedup*/); |
5043 | 5164 | } |
|
0 commit comments