@@ -2693,6 +2693,81 @@ TEST_F(ExternalSSTFileBasicTest, IngestWithTemperature) {
2693
2693
}
2694
2694
}
2695
2695
2696
+ // This tests an internal user's exact usage and expectation of the
2697
+ // IngestExternalFiles APIs to bulk load and replace files.
2698
+ TEST_F (ExternalSSTFileBasicTest,
2699
+ AtomicReplaceColumnFamilyWithIngestedVersionKey) {
2700
+ Options options = GetDefaultOptions ();
2701
+ options.create_if_missing = true ;
2702
+ options.compaction_style = CompactionStyle::kCompactionStyleUniversal ;
2703
+ options.num_levels = 7 ;
2704
+ options.disallow_memtable_writes = false ;
2705
+
2706
+ DestroyAndReopen (options);
2707
+ SstFileWriter sst_file_writer (EnvOptions (), options);
2708
+ std::string data_file_original = sst_files_dir_ + " data_original" ;
2709
+ ASSERT_OK (sst_file_writer.Open (data_file_original));
2710
+ ASSERT_OK (sst_file_writer.Put (" ukey1" , " uval1_orig" ));
2711
+ ASSERT_OK (sst_file_writer.Put (" ukey2" , " uval2_orig" ));
2712
+ ASSERT_OK (sst_file_writer.Finish ());
2713
+ ASSERT_OK (db_->IngestExternalFile (db_->DefaultColumnFamily (),
2714
+ {data_file_original},
2715
+ IngestExternalFileOptions ()));
2716
+
2717
+ ASSERT_OK (Put (" data_version" , " v_original" ));
2718
+ ASSERT_OK (Flush ());
2719
+ std::string value;
2720
+ ASSERT_OK (db_->Get (ReadOptions (), " data_version" , &value));
2721
+ ASSERT_EQ (value, " v_original" );
2722
+ ASSERT_OK (db_->Get (ReadOptions (), " ukey1" , &value));
2723
+ ASSERT_EQ (value, " uval1_orig" );
2724
+ ASSERT_OK (db_->Get (ReadOptions (), " ukey2" , &value));
2725
+ ASSERT_EQ (value, " uval2_orig" );
2726
+ // Set up a 1) data version key file on L0, and 2) a user data file on L6
2727
+ // to test the initial transitioning to use `atomic_replace_range`.
2728
+ ASSERT_EQ (" 1,0,0,0,0,0,1" , FilesPerLevel ());
2729
+
2730
+ // Test multiple cycles of replacing by atomically ingest a data file and a
2731
+ // version key file while replace the whole range in the column family.
2732
+ for (int i = 0 ; i < 10 ; i++) {
2733
+ std::string version_file_path =
2734
+ sst_files_dir_ + " version" + std::to_string (i);
2735
+ ASSERT_OK (sst_file_writer.Open (version_file_path));
2736
+ ASSERT_OK (sst_file_writer.Put (" data_version" , " v" + std::to_string (i)));
2737
+ ASSERT_OK (sst_file_writer.Finish ());
2738
+
2739
+ std::string file_path = sst_files_dir_ + std::to_string (i);
2740
+ ASSERT_OK (sst_file_writer.Open (file_path));
2741
+ ASSERT_OK (sst_file_writer.Put (" ukey1" , " uval1" + std::to_string (i)));
2742
+ ASSERT_OK (sst_file_writer.Put (" ukey2" , " uval2" + std::to_string (i)));
2743
+ ASSERT_OK (sst_file_writer.Finish ());
2744
+
2745
+ IngestExternalFileArg arg;
2746
+ arg.column_family = db_->DefaultColumnFamily ();
2747
+ arg.external_files = {version_file_path, file_path};
2748
+ arg.atomic_replace_range = {{nullptr , nullptr }};
2749
+ // Test both fail_if_not_bottomost_level: true and false
2750
+ arg.options .fail_if_not_bottommost_level = i % 2 == 0 ;
2751
+ arg.options .snapshot_consistency = false ;
2752
+ // Ingest 1) a new data version file and 2) a new user data file while erase
2753
+ // the whole column family
2754
+ Status s = db_->IngestExternalFiles ({arg});
2755
+ ASSERT_OK (s);
2756
+
2757
+ // Check ingestion result and the expected LSM shape:
2758
+ // Two files on L6, 1) a data version file 2) a user data file.
2759
+ ASSERT_OK (db_->Get (ReadOptions (), " ukey1" , &value));
2760
+ ASSERT_EQ (value, " uval1" + std::to_string (i));
2761
+ ASSERT_OK (db_->Get (ReadOptions (), " ukey2" , &value));
2762
+ ASSERT_EQ (value, " uval2" + std::to_string (i));
2763
+ ASSERT_OK (db_->Get (ReadOptions (), " data_version" , &value));
2764
+ ASSERT_EQ (value, " v" + std::to_string (i));
2765
+ ASSERT_EQ (" 0,0,0,0,0,0,2" , FilesPerLevel ());
2766
+ }
2767
+
2768
+ Close ();
2769
+ }
2770
+
2696
2771
TEST_F (ExternalSSTFileBasicTest, FailIfNotBottommostLevelAndDisallowMemtable) {
2697
2772
for (bool disallow_memtable : {false , true }) {
2698
2773
Options options = GetDefaultOptions ();
0 commit comments