|
14 | 14 | #include "checkpoint_manager.h" |
15 | 15 | #include "checkpoint_utils.h" |
16 | 16 | #include "collections/collections_test_helpers.h" |
| 17 | +#include "collections/events_generated.h" |
17 | 18 | #include "collections/vbucket_manifest_handles.h" |
18 | 19 | #include "dcp/backfill_disk.h" |
19 | 20 | #include "dcp/response.h" |
@@ -5242,45 +5243,177 @@ INSTANTIATE_TEST_SUITE_P(Persistent, |
5242 | 5243 | STParameterizedBucketTest::magmaConfigValues(), |
5243 | 5244 | STParameterizedBucketTest::PrintToStringParamName); |
5244 | 5245 |
|
5245 | | -TEST_P(CDCPassiveStreamTest, HistorySnapshotReceived) { |
5246 | | - // Replica receives Snap{1, 3, Disk|History}, with 1->3 mutations of the |
5247 | | - // same key. |
5248 | | - // The test verifies that replica is resilient to duplicates in the disk |
5249 | | - // snapshot and that duplicates are successfully queued into the same |
5250 | | - // checkpoint. |
| 5246 | +void CDCPassiveStreamTest::SetUp() { |
| 5247 | + // Note: Checkpoint removal isn't under test at all here. |
| 5248 | + // Eager checkpoint removal, default prod setting in Neo and post-Neo. |
| 5249 | + // That helps in cleaning up the CheckpointManager during the test and |
| 5250 | + // we won't need to fix the testsuite when merging into the master |
| 5251 | + // branch. |
| 5252 | + if (!config_string.empty()) { |
| 5253 | + config_string += ";"; |
| 5254 | + } |
| 5255 | + config_string += "checkpoint_removal_mode=eager"; |
| 5256 | + |
| 5257 | + STPassiveStreamPersistentTest::SetUp(); |
| 5258 | +} |
| 5259 | + |
| 5260 | +void CDCPassiveStreamTest::createHistoricalCollection(uint64_t snapStart, |
| 5261 | + uint64_t snapEnd) { |
| 5262 | + const uint32_t opaque = 1; |
| 5263 | + ASSERT_EQ(cb::engine_errc::success, |
| 5264 | + consumer->snapshotMarker( |
| 5265 | + opaque, |
| 5266 | + vbid, |
| 5267 | + snapStart, |
| 5268 | + snapEnd, |
| 5269 | + MARKER_FLAG_DISK | MARKER_FLAG_CHK | MARKER_FLAG_HISTORY, |
| 5270 | + {0}, |
| 5271 | + {})); |
| 5272 | + |
| 5273 | + flatbuffers::FlatBufferBuilder fb; |
| 5274 | + Collections::ManifestUid manifestUid; |
| 5275 | + const auto collection = CollectionEntry::historical; |
| 5276 | + auto fbPayload = Collections::VB::CreateCollection( |
| 5277 | + fb, |
| 5278 | + manifestUid, |
| 5279 | + uint32_t(ScopeEntry::defaultS.getId()), |
| 5280 | + uint32_t(collection.getId()), |
| 5281 | + false, |
| 5282 | + 0, |
| 5283 | + fb.CreateString(collection.name.data(), collection.name.size()), |
| 5284 | + true /*history*/); |
| 5285 | + fb.Finish(fbPayload); |
| 5286 | + ASSERT_EQ(cb::engine_errc::success, |
| 5287 | + consumer->systemEvent( |
| 5288 | + 1 /*opaque*/, |
| 5289 | + vbid, |
| 5290 | + mcbp::systemevent::id::CreateCollection, |
| 5291 | + 1, |
| 5292 | + mcbp::systemevent::version::version2, |
| 5293 | + {reinterpret_cast<const uint8_t*>(collection.name.data()), |
| 5294 | + collection.name.size()}, |
| 5295 | + {fb.GetBufferPointer(), fb.GetSize()})); |
5251 | 5296 |
|
5252 | 5297 | const auto& vb = *store->getVBucket(vbid); |
5253 | | - ASSERT_EQ(0, vb.getHighSeqno()); |
5254 | | - const auto& manager = *vb.checkpointManager; |
| 5298 | + ASSERT_EQ(0, vb.getNumTotalItems()); |
| 5299 | + ASSERT_EQ(1, vb.getHighSeqno()); |
| 5300 | + auto& manager = *vb.checkpointManager; |
| 5301 | + ASSERT_EQ(1, manager.getNumCheckpoints()); |
| 5302 | + ASSERT_EQ(1, manager.getNumOpenChkItems()); |
| 5303 | + ASSERT_EQ(CheckpointType::InitialDisk, manager.getOpenCheckpointType()); |
| 5304 | + ASSERT_EQ(CheckpointHistorical::Yes, manager.getOpenCheckpointHistorical()); |
| 5305 | + flush_vbucket_to_disk(vbid, 1); |
| 5306 | +} |
| 5307 | + |
| 5308 | +/* |
| 5309 | + * HistorySnapshotReceived tests verify (on different scenarios) that: |
| 5310 | + * - replica stream is resilient to duplicates on disk snapshot |
| 5311 | + * - duplicates are queued in checkpoint (ie, not deduplicated) |
| 5312 | + * - duplicates are persisted on disk (again, not deduplicated) |
| 5313 | + * - stats (eg item-count) are updated correctly |
| 5314 | + */ |
| 5315 | + |
| 5316 | +TEST_P(CDCPassiveStreamTest, HistorySnapshotReceived_Disk) { |
| 5317 | + // Replica receives Snap{start, end, Disk|History}, with start->end |
| 5318 | + // mutations for the same key. |
| 5319 | + |
| 5320 | + createHistoricalCollection(1, 1); |
| 5321 | + |
| 5322 | + // Clear CM |
| 5323 | + const auto& vb = *store->getVBucket(vbid); |
| 5324 | + const auto initialHighSeqno = vb.getHighSeqno(); |
| 5325 | + ASSERT_EQ(1, initialHighSeqno); |
| 5326 | + auto& manager = *vb.checkpointManager; |
| 5327 | + manager.createNewCheckpoint(true); |
5255 | 5328 | ASSERT_EQ(1, manager.getNumCheckpoints()); |
5256 | 5329 | ASSERT_EQ(0, manager.getNumOpenChkItems()); |
5257 | 5330 |
|
5258 | | - const uint32_t opaque = 0; |
| 5331 | + const uint32_t opaque = 1; |
5259 | 5332 | SnapshotMarker snapshotMarker( |
5260 | 5333 | opaque, |
5261 | 5334 | vbid, |
5262 | | - 1 /*start*/, |
5263 | | - 3 /*end*/, |
| 5335 | + initialHighSeqno + 1 /*start*/, |
| 5336 | + initialHighSeqno + 3 /*end*/, |
5264 | 5337 | MARKER_FLAG_CHK | MARKER_FLAG_DISK | MARKER_FLAG_HISTORY, |
5265 | 5338 | std::optional<uint64_t>(0), /*HCS*/ |
5266 | 5339 | {}, /*maxVisibleSeqno*/ |
5267 | 5340 | {}, /*timestamp*/ |
5268 | 5341 | {} /*streamId*/); |
5269 | 5342 | stream->processMarker(&snapshotMarker); |
| 5343 | + ASSERT_EQ(1, manager.getNumCheckpoints()); |
| 5344 | + ASSERT_EQ(0, manager.getNumOpenChkItems()); |
| 5345 | + ASSERT_EQ(CheckpointType::Disk, manager.getOpenCheckpointType()); |
| 5346 | + ASSERT_EQ(CheckpointHistorical::Yes, manager.getOpenCheckpointHistorical()); |
| 5347 | + |
| 5348 | + const auto collection = CollectionEntry::historical; |
| 5349 | + const std::string key("key"); |
| 5350 | + const std::string value("value"); |
| 5351 | + const size_t numItems = 3; |
| 5352 | + for (size_t seqno = initialHighSeqno + 1; |
| 5353 | + seqno <= initialHighSeqno + numItems; |
| 5354 | + ++seqno) { |
| 5355 | + EXPECT_EQ( |
| 5356 | + cb::engine_errc::success, |
| 5357 | + stream->messageReceived(makeMutationConsumerMessage( |
| 5358 | + opaque, seqno, vbid, value, key, collection.getId()))); |
| 5359 | + } |
| 5360 | + |
| 5361 | + EXPECT_EQ(initialHighSeqno + numItems, vb.getHighSeqno()); |
5270 | 5362 | EXPECT_EQ(1, manager.getNumCheckpoints()); |
5271 | | - EXPECT_EQ(0, manager.getNumOpenChkItems()); |
| 5363 | + EXPECT_EQ(numItems, manager.getNumOpenChkItems()); |
| 5364 | + |
| 5365 | + // All duplicates persisted |
| 5366 | + flush_vbucket_to_disk(vbid, numItems); |
| 5367 | + |
| 5368 | + // Item count doesn't account for historical revisions |
| 5369 | + EXPECT_EQ(1, vb.getNumTotalItems()); |
| 5370 | +} |
| 5371 | + |
| 5372 | +TEST_P(CDCPassiveStreamTest, HistorySnapshotReceived_InitialDisk) { |
| 5373 | + // Replica receives Snap{start, end, InitialDisk|History}, with start->end |
| 5374 | + // mutations for the same key. |
5272 | 5375 |
|
| 5376 | + createHistoricalCollection(1, 10); |
| 5377 | + |
| 5378 | + const auto& vb = *store->getVBucket(vbid); |
| 5379 | + const auto initialHighSeqno = vb.getHighSeqno(); |
| 5380 | + ASSERT_EQ(1, initialHighSeqno); |
| 5381 | + auto& manager = *vb.checkpointManager; |
| 5382 | + ASSERT_EQ(1, manager.getNumCheckpoints()); |
| 5383 | + ASSERT_EQ(1, manager.getNumOpenChkItems()); |
| 5384 | + |
| 5385 | + // Historical items received within the same snapshot |
| 5386 | + const auto collection = CollectionEntry::historical; |
5273 | 5387 | const std::string key("key"); |
5274 | 5388 | const std::string value("value"); |
5275 | | - for (size_t seqno = 1; seqno <= 3; ++seqno) { |
| 5389 | + const size_t numItems = 3; |
| 5390 | + for (size_t seqno = initialHighSeqno + 1; |
| 5391 | + seqno <= initialHighSeqno + numItems; |
| 5392 | + ++seqno) { |
5276 | 5393 | EXPECT_EQ(cb::engine_errc::success, |
5277 | | - stream->messageReceived(makeMutationConsumerMessage( |
5278 | | - seqno, vbid, value, opaque, key))); |
| 5394 | + stream->messageReceived( |
| 5395 | + makeMutationConsumerMessage(1 /*opaque*/, |
| 5396 | + seqno, |
| 5397 | + vbid, |
| 5398 | + value, |
| 5399 | + key, |
| 5400 | + collection.getId()))); |
5279 | 5401 | } |
5280 | 5402 |
|
5281 | | - EXPECT_EQ(3, vb.getHighSeqno()); |
| 5403 | + // Important: In this scenario historical mutations are queued into the |
| 5404 | + // Initial disk checkpoint |
| 5405 | + ASSERT_EQ(CheckpointType::InitialDisk, manager.getOpenCheckpointType()); |
| 5406 | + ASSERT_EQ(CheckpointHistorical::Yes, manager.getOpenCheckpointHistorical()); |
| 5407 | + |
| 5408 | + EXPECT_EQ(initialHighSeqno + numItems, vb.getHighSeqno()); |
5282 | 5409 | EXPECT_EQ(1, manager.getNumCheckpoints()); |
5283 | | - EXPECT_EQ(3, manager.getNumOpenChkItems()); |
| 5410 | + EXPECT_EQ(initialHighSeqno + numItems, manager.getNumOpenChkItems()); |
| 5411 | + |
| 5412 | + // All duplicates persisted |
| 5413 | + flush_vbucket_to_disk(vbid, numItems); |
| 5414 | + |
| 5415 | + // Item count doesn't account for historical revisions |
| 5416 | + EXPECT_EQ(1, vb.getNumTotalItems()); |
5284 | 5417 | } |
5285 | 5418 |
|
5286 | 5419 | INSTANTIATE_TEST_SUITE_P(Persistent, |
|
0 commit comments