@nxtedition/rocksdb 13.5.12 → 14.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/binding.cc +33 -2
- package/binding.gyp +2 -2
- package/chained-batch.js +9 -16
- package/deps/rocksdb/rocksdb/BUCK +18 -1
- package/deps/rocksdb/rocksdb/CMakeLists.txt +10 -3
- package/deps/rocksdb/rocksdb/Makefile +20 -9
- package/deps/rocksdb/rocksdb/cache/cache_bench_tool.cc +90 -13
- package/deps/rocksdb/rocksdb/cache/clock_cache.cc +88 -75
- package/deps/rocksdb/rocksdb/cache/clock_cache.h +44 -36
- package/deps/rocksdb/rocksdb/cache/compressed_secondary_cache.cc +184 -148
- package/deps/rocksdb/rocksdb/cache/compressed_secondary_cache.h +5 -11
- package/deps/rocksdb/rocksdb/cache/compressed_secondary_cache_test.cc +116 -47
- package/deps/rocksdb/rocksdb/cache/lru_cache_test.cc +1 -1
- package/deps/rocksdb/rocksdb/cache/secondary_cache_adapter.cc +3 -6
- package/deps/rocksdb/rocksdb/db/arena_wrapped_db_iter.h +1 -1
- package/deps/rocksdb/rocksdb/db/builder.cc +4 -2
- package/deps/rocksdb/rocksdb/db/c.cc +207 -0
- package/deps/rocksdb/rocksdb/db/c_test.c +72 -0
- package/deps/rocksdb/rocksdb/db/column_family.cc +3 -2
- package/deps/rocksdb/rocksdb/db/column_family.h +5 -0
- package/deps/rocksdb/rocksdb/db/compact_files_test.cc +4 -0
- package/deps/rocksdb/rocksdb/db/compaction/compaction.cc +2 -0
- package/deps/rocksdb/rocksdb/db/compaction/compaction_iterator.cc +51 -38
- package/deps/rocksdb/rocksdb/db/compaction/compaction_iterator.h +29 -12
- package/deps/rocksdb/rocksdb/db/compaction/compaction_iterator_test.cc +5 -10
- package/deps/rocksdb/rocksdb/db/compaction/compaction_job.cc +566 -366
- package/deps/rocksdb/rocksdb/db/compaction/compaction_job.h +131 -4
- package/deps/rocksdb/rocksdb/db/compaction/compaction_outputs.cc +1 -0
- package/deps/rocksdb/rocksdb/db/compaction/compaction_outputs.h +7 -0
- package/deps/rocksdb/rocksdb/db/compaction/compaction_picker.cc +4 -4
- package/deps/rocksdb/rocksdb/db/compaction/compaction_picker.h +13 -14
- package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_fifo.cc +12 -7
- package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_fifo.h +8 -10
- package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_test.cc +97 -76
- package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_universal.cc +11 -14
- package/deps/rocksdb/rocksdb/db/compaction/compaction_service_job.cc +1 -1
- package/deps/rocksdb/rocksdb/db/compaction/subcompaction_state.h +8 -0
- package/deps/rocksdb/rocksdb/db/compaction/tiered_compaction_test.cc +16 -3
- package/deps/rocksdb/rocksdb/db/db_basic_test.cc +1 -0
- package/deps/rocksdb/rocksdb/db/db_compaction_test.cc +448 -1
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl.cc +22 -20
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl.h +4 -1
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl_compaction_flush.cc +5 -5
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl_open.cc +7 -3
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl_secondary.cc +1 -1
- package/deps/rocksdb/rocksdb/db/db_iter.cc +104 -0
- package/deps/rocksdb/rocksdb/db/db_iter.h +4 -11
- package/deps/rocksdb/rocksdb/db/db_iterator_test.cc +331 -58
- package/deps/rocksdb/rocksdb/db/db_memtable_test.cc +129 -0
- package/deps/rocksdb/rocksdb/db/db_sst_test.cc +64 -0
- package/deps/rocksdb/rocksdb/db/db_table_properties_test.cc +40 -0
- package/deps/rocksdb/rocksdb/db/db_test2.cc +25 -15
- package/deps/rocksdb/rocksdb/db/db_test_util.cc +42 -24
- package/deps/rocksdb/rocksdb/db/db_test_util.h +29 -14
- package/deps/rocksdb/rocksdb/db/db_universal_compaction_test.cc +69 -36
- package/deps/rocksdb/rocksdb/db/db_with_timestamp_basic_test.cc +0 -1
- package/deps/rocksdb/rocksdb/db/event_helpers.cc +1 -0
- package/deps/rocksdb/rocksdb/db/experimental.cc +5 -4
- package/deps/rocksdb/rocksdb/db/external_sst_file_basic_test.cc +8 -1
- package/deps/rocksdb/rocksdb/db/external_sst_file_ingestion_job.cc +275 -79
- package/deps/rocksdb/rocksdb/db/external_sst_file_ingestion_job.h +23 -5
- package/deps/rocksdb/rocksdb/db/external_sst_file_test.cc +591 -175
- package/deps/rocksdb/rocksdb/db/flush_job.cc +3 -4
- package/deps/rocksdb/rocksdb/db/log_reader.cc +5 -2
- package/deps/rocksdb/rocksdb/db/memtable.cc +84 -35
- package/deps/rocksdb/rocksdb/db/memtable.h +39 -34
- package/deps/rocksdb/rocksdb/db/merge_helper.cc +1 -0
- package/deps/rocksdb/rocksdb/db/merge_operator.cc +1 -1
- package/deps/rocksdb/rocksdb/db/multi_scan.cc +11 -5
- package/deps/rocksdb/rocksdb/db/version_edit.cc +1 -1
- package/deps/rocksdb/rocksdb/db/version_edit.h +1 -1
- package/deps/rocksdb/rocksdb/db/version_edit_handler.cc +34 -14
- package/deps/rocksdb/rocksdb/db/version_edit_handler.h +28 -5
- package/deps/rocksdb/rocksdb/db/version_set.cc +159 -14
- package/deps/rocksdb/rocksdb/db/version_set.h +2 -0
- package/deps/rocksdb/rocksdb/db_stress_tool/CMakeLists.txt +1 -1
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_common.cc +60 -0
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_common.h +16 -1
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_compaction_service.h +75 -10
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_compression_manager.cc +28 -0
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_compression_manager.h +2 -0
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_driver.cc +31 -1
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_gflags.cc +50 -2
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_shared_state.h +57 -0
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_stat.h +0 -4
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_test_base.cc +266 -35
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_test_base.h +5 -0
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_tool.cc +0 -6
- package/deps/rocksdb/rocksdb/db_stress_tool/no_batched_ops_stress.cc +18 -2
- package/deps/rocksdb/rocksdb/env/env.cc +12 -0
- package/deps/rocksdb/rocksdb/env/env_test.cc +18 -0
- package/deps/rocksdb/rocksdb/env/file_system_tracer.cc +2 -0
- package/deps/rocksdb/rocksdb/env/fs_posix.cc +9 -5
- package/deps/rocksdb/rocksdb/env/io_posix.cc +4 -2
- package/deps/rocksdb/rocksdb/file/random_access_file_reader.cc +19 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/advanced_compression.h +33 -31
- package/deps/rocksdb/rocksdb/include/rocksdb/advanced_options.h +42 -9
- package/deps/rocksdb/rocksdb/include/rocksdb/c.h +93 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/cache.h +43 -49
- package/deps/rocksdb/rocksdb/include/rocksdb/compaction_job_stats.h +4 -3
- package/deps/rocksdb/rocksdb/include/rocksdb/compression_type.h +8 -6
- package/deps/rocksdb/rocksdb/include/rocksdb/data_structure.h +487 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/db.h +11 -12
- package/deps/rocksdb/rocksdb/include/rocksdb/env.h +135 -1
- package/deps/rocksdb/rocksdb/include/rocksdb/file_system.h +5 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/iostats_context.h +12 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/iterator.h +1 -1
- package/deps/rocksdb/rocksdb/include/rocksdb/ldb_tool.h +8 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/memtablerep.h +12 -8
- package/deps/rocksdb/rocksdb/include/rocksdb/metadata.h +3 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/multi_scan.h +19 -9
- package/deps/rocksdb/rocksdb/include/rocksdb/options.h +219 -24
- package/deps/rocksdb/rocksdb/include/rocksdb/point_lock_bench_tool.h +14 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/secondary_cache.h +2 -2
- package/deps/rocksdb/rocksdb/include/rocksdb/slice.h +1 -1
- package/deps/rocksdb/rocksdb/include/rocksdb/statistics.h +7 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/status.h +16 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/table.h +16 -4
- package/deps/rocksdb/rocksdb/include/rocksdb/table_properties.h +13 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/types.h +4 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/universal_compaction.h +0 -2
- package/deps/rocksdb/rocksdb/include/rocksdb/user_defined_index.h +45 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/utilities/cache_dump_load.h +1 -1
- package/deps/rocksdb/rocksdb/include/rocksdb/utilities/stackable_db.h +1 -1
- package/deps/rocksdb/rocksdb/include/rocksdb/utilities/transaction.h +6 -1
- package/deps/rocksdb/rocksdb/include/rocksdb/utilities/transaction_db.h +21 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/version.h +2 -2
- package/deps/rocksdb/rocksdb/memory/memory_allocator_impl.h +3 -3
- package/deps/rocksdb/rocksdb/memtable/inlineskiplist.h +77 -51
- package/deps/rocksdb/rocksdb/memtable/skiplist.h +10 -13
- package/deps/rocksdb/rocksdb/memtable/skiplistrep.cc +16 -7
- package/deps/rocksdb/rocksdb/memtable/vectorrep.cc +9 -4
- package/deps/rocksdb/rocksdb/monitoring/iostats_context.cc +2 -0
- package/deps/rocksdb/rocksdb/monitoring/statistics.cc +6 -0
- package/deps/rocksdb/rocksdb/options/cf_options.cc +13 -1
- package/deps/rocksdb/rocksdb/options/cf_options.h +6 -2
- package/deps/rocksdb/rocksdb/options/options.cc +2 -0
- package/deps/rocksdb/rocksdb/options/options_helper.cc +9 -8
- package/deps/rocksdb/rocksdb/options/options_settable_test.cc +9 -5
- package/deps/rocksdb/rocksdb/port/mmap.cc +1 -1
- package/deps/rocksdb/rocksdb/port/win/xpress_win.cc +51 -0
- package/deps/rocksdb/rocksdb/port/win/xpress_win.h +4 -0
- package/deps/rocksdb/rocksdb/src.mk +8 -2
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_builder.cc +1125 -765
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_builder.h +35 -24
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_factory.cc +29 -4
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_iterator.cc +732 -256
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_iterator.h +225 -16
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.cc +102 -26
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.h +1 -1
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader_sync_and_async.h +2 -75
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader_test.cc +433 -141
- package/deps/rocksdb/rocksdb/table/block_based/block_builder.h +2 -0
- package/deps/rocksdb/rocksdb/table/block_based/flush_block_policy.cc +17 -10
- package/deps/rocksdb/rocksdb/table/block_based/flush_block_policy_impl.h +20 -0
- package/deps/rocksdb/rocksdb/table/block_based/index_builder.cc +112 -85
- package/deps/rocksdb/rocksdb/table/block_based/index_builder.h +191 -36
- package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block.cc +2 -2
- package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block_test.cc +1 -1
- package/deps/rocksdb/rocksdb/table/block_based/user_defined_index_wrapper.h +108 -31
- package/deps/rocksdb/rocksdb/table/external_table.cc +7 -3
- package/deps/rocksdb/rocksdb/table/format.cc +6 -12
- package/deps/rocksdb/rocksdb/table/format.h +10 -0
- package/deps/rocksdb/rocksdb/table/internal_iterator.h +1 -1
- package/deps/rocksdb/rocksdb/table/iterator_wrapper.h +1 -1
- package/deps/rocksdb/rocksdb/table/merging_iterator.cc +1 -1
- package/deps/rocksdb/rocksdb/table/meta_blocks.cc +5 -0
- package/deps/rocksdb/rocksdb/table/multiget_context.h +3 -1
- package/deps/rocksdb/rocksdb/table/sst_file_dumper.cc +118 -46
- package/deps/rocksdb/rocksdb/table/sst_file_dumper.h +9 -8
- package/deps/rocksdb/rocksdb/table/table_builder.h +5 -0
- package/deps/rocksdb/rocksdb/table/table_properties.cc +16 -0
- package/deps/rocksdb/rocksdb/table/table_test.cc +1540 -155
- package/deps/rocksdb/rocksdb/test_util/testutil.h +21 -5
- package/deps/rocksdb/rocksdb/tools/db_bench_tool.cc +26 -5
- package/deps/rocksdb/rocksdb/tools/ldb.cc +1 -2
- package/deps/rocksdb/rocksdb/tools/ldb_cmd.cc +2 -0
- package/deps/rocksdb/rocksdb/tools/ldb_tool.cc +9 -3
- package/deps/rocksdb/rocksdb/tools/sst_dump_test.cc +133 -165
- package/deps/rocksdb/rocksdb/tools/sst_dump_tool.cc +173 -64
- package/deps/rocksdb/rocksdb/util/aligned_buffer.h +69 -0
- package/deps/rocksdb/rocksdb/util/atomic.h +6 -0
- package/deps/rocksdb/rocksdb/util/auto_tune_compressor.cc +29 -20
- package/deps/rocksdb/rocksdb/util/auto_tune_compressor.h +10 -6
- package/deps/rocksdb/rocksdb/util/bit_fields.h +338 -0
- package/deps/rocksdb/rocksdb/util/coding.h +3 -3
- package/deps/rocksdb/rocksdb/util/compaction_job_stats_impl.cc +2 -2
- package/deps/rocksdb/rocksdb/util/compression.cc +777 -82
- package/deps/rocksdb/rocksdb/util/compression.h +5 -0
- package/deps/rocksdb/rocksdb/util/compression_test.cc +5 -3
- package/deps/rocksdb/rocksdb/util/dynamic_bloom.cc +2 -2
- package/deps/rocksdb/rocksdb/util/dynamic_bloom.h +15 -14
- package/deps/rocksdb/rocksdb/util/interval_test.cc +102 -0
- package/deps/rocksdb/rocksdb/util/semaphore.h +164 -0
- package/deps/rocksdb/rocksdb/util/simple_mixed_compressor.cc +10 -6
- package/deps/rocksdb/rocksdb/util/simple_mixed_compressor.h +4 -2
- package/deps/rocksdb/rocksdb/util/slice_test.cc +136 -0
- package/deps/rocksdb/rocksdb/util/status.cc +1 -0
- package/deps/rocksdb/rocksdb/util/string_util.cc +2 -16
- package/deps/rocksdb/rocksdb/utilities/cache_dump_load_impl.cc +1 -1
- package/deps/rocksdb/rocksdb/utilities/cache_dump_load_impl.h +1 -1
- package/deps/rocksdb/rocksdb/utilities/fault_injection_fs.cc +7 -4
- package/deps/rocksdb/rocksdb/utilities/fault_injection_fs.h +35 -14
- package/deps/rocksdb/rocksdb/utilities/persistent_cache/hash_table_test.cc +2 -0
- package/deps/rocksdb/rocksdb/utilities/transactions/lock/lock_manager.cc +5 -2
- package/deps/rocksdb/rocksdb/utilities/transactions/lock/point/any_lock_manager_test.h +244 -0
- package/deps/rocksdb/rocksdb/utilities/transactions/lock/point/point_lock_bench.cc +18 -0
- package/deps/rocksdb/rocksdb/utilities/transactions/lock/point/point_lock_bench_tool.cc +159 -0
- package/deps/rocksdb/rocksdb/utilities/transactions/lock/point/point_lock_manager.cc +1244 -161
- package/deps/rocksdb/rocksdb/utilities/transactions/lock/point/point_lock_manager.h +66 -12
- package/deps/rocksdb/rocksdb/utilities/transactions/lock/point/point_lock_manager_stress_test.cc +103 -0
- package/deps/rocksdb/rocksdb/utilities/transactions/lock/point/point_lock_manager_test.cc +1275 -8
- package/deps/rocksdb/rocksdb/utilities/transactions/lock/point/point_lock_manager_test.h +40 -262
- package/deps/rocksdb/rocksdb/utilities/transactions/lock/point/point_lock_manager_test_common.h +78 -0
- package/deps/rocksdb/rocksdb/utilities/transactions/lock/point/point_lock_validation_test_runner.h +469 -0
- package/deps/rocksdb/rocksdb/utilities/transactions/lock/range/range_locking_test.cc +2 -6
- package/deps/rocksdb/rocksdb/utilities/transactions/pessimistic_transaction.cc +4 -0
- package/deps/rocksdb/rocksdb/utilities/transactions/pessimistic_transaction.h +9 -1
- package/deps/rocksdb/rocksdb/utilities/transactions/timestamped_snapshot_test.cc +18 -9
- package/deps/rocksdb/rocksdb/utilities/transactions/transaction_base.h +2 -0
- package/deps/rocksdb/rocksdb/utilities/transactions/transaction_db_mutex_impl.cc +2 -1
- package/deps/rocksdb/rocksdb/utilities/transactions/transaction_test.cc +72 -44
- package/deps/rocksdb/rocksdb/utilities/transactions/transaction_test.h +92 -15
- package/deps/rocksdb/rocksdb/utilities/transactions/write_committed_transaction_ts_test.cc +6 -20
- package/deps/rocksdb/rocksdb/utilities/transactions/write_prepared_transaction_test.cc +143 -112
- package/deps/rocksdb/rocksdb/utilities/transactions/write_unprepared_transaction_test.cc +23 -16
- package/index.js +3 -3
- package/package.json +1 -1
- package/prebuilds/darwin-arm64/@nxtedition+rocksdb.node +0 -0
- package/prebuilds/linux-x64/@nxtedition+rocksdb.node +0 -0
- package/util.h +38 -12
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_stat.cc +0 -17
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
#include "rocksdb/trace_record.h"
|
|
54
54
|
#include "rocksdb/unique_id.h"
|
|
55
55
|
#include "rocksdb/user_defined_index.h"
|
|
56
|
+
#include "rocksdb/utilities/object_registry.h"
|
|
56
57
|
#include "rocksdb/write_buffer_manager.h"
|
|
57
58
|
#include "table/block_based/block.h"
|
|
58
59
|
#include "table/block_based/block_based_table_builder.h"
|
|
@@ -2059,7 +2060,7 @@ TEST_P(BlockBasedTableTest, PrefetchTest) {
|
|
|
2059
2060
|
|
|
2060
2061
|
// Simple
|
|
2061
2062
|
PrefetchRange(&c, &opt, &table_options,
|
|
2062
|
-
/*
|
|
2063
|
+
/*key_begin=*/"k01", /*key_end=*/"k05",
|
|
2063
2064
|
/*keys_in_cache=*/{"k01", "k02", "k03", "k04", "k05"},
|
|
2064
2065
|
/*keys_not_in_cache=*/{"k06", "k07"});
|
|
2065
2066
|
PrefetchRange(&c, &opt, &table_options, "k01", "k01", {"k01", "k02", "k03"},
|
|
@@ -4716,8 +4717,8 @@ TEST_F(GeneralTableTest, ApproximateOffsetOfPlain) {
|
|
|
4716
4717
|
// an arbitrary slice between k04 and k05, either before or after k04a
|
|
4717
4718
|
ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04a"), 10000, 211000));
|
|
4718
4719
|
ASSERT_TRUE(Between(c.ApproximateOffsetOf("k05"), 210000, 211000));
|
|
4719
|
-
ASSERT_TRUE(Between(c.ApproximateOffsetOf("k06"), 510000,
|
|
4720
|
-
ASSERT_TRUE(Between(c.ApproximateOffsetOf("k07"), 510000,
|
|
4720
|
+
ASSERT_TRUE(Between(c.ApproximateOffsetOf("k06"), 510000, 512000));
|
|
4721
|
+
ASSERT_TRUE(Between(c.ApproximateOffsetOf("k07"), 510000, 512000));
|
|
4721
4722
|
ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"), 610000, 612000));
|
|
4722
4723
|
c.ResetTableReader();
|
|
4723
4724
|
}
|
|
@@ -6230,6 +6231,12 @@ TEST_P(BlockBasedTableTest, OutOfBoundOnNext) {
|
|
|
6230
6231
|
class ChargeCompressionDictionaryBuildingBufferTest
|
|
6231
6232
|
: public BlockBasedTableTestBase {};
|
|
6232
6233
|
TEST_F(ChargeCompressionDictionaryBuildingBufferTest, Basic) {
|
|
6234
|
+
if (GetSupportedDictCompressions().empty()) {
|
|
6235
|
+
ROCKSDB_GTEST_SKIP("No supported dict compression");
|
|
6236
|
+
return;
|
|
6237
|
+
}
|
|
6238
|
+
const auto kCompression = GetSupportedDictCompressions()[0];
|
|
6239
|
+
|
|
6233
6240
|
constexpr std::size_t kSizeDummyEntry = 256 * 1024;
|
|
6234
6241
|
constexpr std::size_t kMetaDataChargeOverhead = 10000;
|
|
6235
6242
|
constexpr std::size_t kCacheCapacity = 8 * 1024 * 1024;
|
|
@@ -6253,7 +6260,7 @@ TEST_F(ChargeCompressionDictionaryBuildingBufferTest, Basic) {
|
|
|
6253
6260
|
{CacheEntryRole::kCompressionDictionaryBuildingBuffer,
|
|
6254
6261
|
{/*.charged = */ charge_compression_dictionary_building_buffer}});
|
|
6255
6262
|
Options options;
|
|
6256
|
-
options.compression =
|
|
6263
|
+
options.compression = kCompression;
|
|
6257
6264
|
options.compression_opts.max_dict_bytes = kMaxDictBytes;
|
|
6258
6265
|
options.compression_opts.max_dict_buffer_bytes = kMaxDictBufferBytes;
|
|
6259
6266
|
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
|
@@ -6274,7 +6281,7 @@ TEST_F(ChargeCompressionDictionaryBuildingBufferTest, Basic) {
|
|
|
6274
6281
|
options.table_factory->NewTableBuilder(
|
|
6275
6282
|
TableBuilderOptions(ioptions, moptions, read_options, write_options,
|
|
6276
6283
|
ikc, &internal_tbl_prop_coll_factories,
|
|
6277
|
-
|
|
6284
|
+
kCompression, options.compression_opts,
|
|
6278
6285
|
kUnknownColumnFamily, "test_cf", -1 /* level */,
|
|
6279
6286
|
kUnknownNewestKeyTime),
|
|
6280
6287
|
file_writer.get()));
|
|
@@ -6313,6 +6320,12 @@ TEST_F(ChargeCompressionDictionaryBuildingBufferTest, Basic) {
|
|
|
6313
6320
|
|
|
6314
6321
|
TEST_F(ChargeCompressionDictionaryBuildingBufferTest,
|
|
6315
6322
|
BasicWithBufferLimitExceed) {
|
|
6323
|
+
if (GetSupportedDictCompressions().empty()) {
|
|
6324
|
+
ROCKSDB_GTEST_SKIP("No supported dict compression");
|
|
6325
|
+
return;
|
|
6326
|
+
}
|
|
6327
|
+
const auto kCompression = GetSupportedDictCompressions()[0];
|
|
6328
|
+
|
|
6316
6329
|
constexpr std::size_t kSizeDummyEntry = 256 * 1024;
|
|
6317
6330
|
constexpr std::size_t kMetaDataChargeOverhead = 10000;
|
|
6318
6331
|
constexpr std::size_t kCacheCapacity = 8 * 1024 * 1024;
|
|
@@ -6332,7 +6345,7 @@ TEST_F(ChargeCompressionDictionaryBuildingBufferTest,
|
|
|
6332
6345
|
std::make_shared<FlushBlockEveryKeyPolicyFactory>();
|
|
6333
6346
|
|
|
6334
6347
|
Options options;
|
|
6335
|
-
options.compression =
|
|
6348
|
+
options.compression = kCompression;
|
|
6336
6349
|
options.compression_opts.max_dict_bytes = kMaxDictBytes;
|
|
6337
6350
|
options.compression_opts.max_dict_buffer_bytes = kMaxDictBufferBytes;
|
|
6338
6351
|
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
|
@@ -6351,7 +6364,7 @@ TEST_F(ChargeCompressionDictionaryBuildingBufferTest,
|
|
|
6351
6364
|
const WriteOptions write_options;
|
|
6352
6365
|
std::unique_ptr<TableBuilder> builder(options.table_factory->NewTableBuilder(
|
|
6353
6366
|
TableBuilderOptions(ioptions, moptions, read_options, write_options, ikc,
|
|
6354
|
-
&internal_tbl_prop_coll_factories,
|
|
6367
|
+
&internal_tbl_prop_coll_factories, kCompression,
|
|
6355
6368
|
options.compression_opts, kUnknownColumnFamily,
|
|
6356
6369
|
"test_cf", -1 /* level */, kUnknownNewestKeyTime),
|
|
6357
6370
|
file_writer.get()));
|
|
@@ -6394,6 +6407,12 @@ TEST_F(ChargeCompressionDictionaryBuildingBufferTest,
|
|
|
6394
6407
|
}
|
|
6395
6408
|
|
|
6396
6409
|
TEST_F(ChargeCompressionDictionaryBuildingBufferTest, BasicWithCacheFull) {
|
|
6410
|
+
if (GetSupportedDictCompressions().empty()) {
|
|
6411
|
+
ROCKSDB_GTEST_SKIP("No supported dict compression");
|
|
6412
|
+
return;
|
|
6413
|
+
}
|
|
6414
|
+
const auto kCompression = GetSupportedDictCompressions()[0];
|
|
6415
|
+
|
|
6397
6416
|
constexpr std::size_t kSizeDummyEntry = 256 * 1024;
|
|
6398
6417
|
constexpr std::size_t kMetaDataChargeOverhead = 10000;
|
|
6399
6418
|
// A small kCacheCapacity is chosen so that increase cache charging for
|
|
@@ -6419,7 +6438,7 @@ TEST_F(ChargeCompressionDictionaryBuildingBufferTest, BasicWithCacheFull) {
|
|
|
6419
6438
|
std::make_shared<FlushBlockEveryKeyPolicyFactory>();
|
|
6420
6439
|
|
|
6421
6440
|
Options options;
|
|
6422
|
-
options.compression =
|
|
6441
|
+
options.compression = kCompression;
|
|
6423
6442
|
options.compression_opts.max_dict_bytes = kMaxDictBytes;
|
|
6424
6443
|
options.compression_opts.max_dict_buffer_bytes = kMaxDictBufferBytes;
|
|
6425
6444
|
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
|
@@ -6438,7 +6457,7 @@ TEST_F(ChargeCompressionDictionaryBuildingBufferTest, BasicWithCacheFull) {
|
|
|
6438
6457
|
const WriteOptions write_options;
|
|
6439
6458
|
std::unique_ptr<TableBuilder> builder(options.table_factory->NewTableBuilder(
|
|
6440
6459
|
TableBuilderOptions(ioptions, moptions, read_options, write_options, ikc,
|
|
6441
|
-
&internal_tbl_prop_coll_factories,
|
|
6460
|
+
&internal_tbl_prop_coll_factories, kCompression,
|
|
6442
6461
|
options.compression_opts, kUnknownColumnFamily,
|
|
6443
6462
|
"test_cf", -1 /* level */, kUnknownNewestKeyTime),
|
|
6444
6463
|
file_writer.get()));
|
|
@@ -7180,9 +7199,9 @@ TEST_F(ExternalTableTest, DBMultiScanTest) {
|
|
|
7180
7199
|
|
|
7181
7200
|
std::vector<std::string> key_ranges({"k03", "k10", "k25", "k50"});
|
|
7182
7201
|
ReadOptions ro;
|
|
7183
|
-
|
|
7184
|
-
|
|
7185
|
-
|
|
7202
|
+
MultiScanArgs scan_options(BytewiseComparator());
|
|
7203
|
+
scan_options.insert(key_ranges[0], key_ranges[1]);
|
|
7204
|
+
scan_options.insert(key_ranges[2], key_ranges[3]);
|
|
7186
7205
|
std::unique_ptr<MultiScan> iter = db->NewMultiScan(ro, cfh, scan_options);
|
|
7187
7206
|
try {
|
|
7188
7207
|
int idx = 0;
|
|
@@ -7209,7 +7228,10 @@ TEST_F(ExternalTableTest, DBMultiScanTest) {
|
|
|
7209
7228
|
|
|
7210
7229
|
// Test the overlapping scan case
|
|
7211
7230
|
key_ranges[1] = "k30";
|
|
7212
|
-
scan_options
|
|
7231
|
+
scan_options = MultiScanArgs(BytewiseComparator());
|
|
7232
|
+
scan_options.insert(key_ranges[0], key_ranges[1]);
|
|
7233
|
+
scan_options.insert(key_ranges[2], key_ranges[3]);
|
|
7234
|
+
|
|
7213
7235
|
iter = db->NewMultiScan(ro, cfh, scan_options);
|
|
7214
7236
|
try {
|
|
7215
7237
|
int idx = 0;
|
|
@@ -7226,8 +7248,6 @@ TEST_F(ExternalTableTest, DBMultiScanTest) {
|
|
|
7226
7248
|
} catch (MultiScanException& ex) {
|
|
7227
7249
|
// Make sure exception contains the status
|
|
7228
7250
|
ASSERT_NOK(ex.status());
|
|
7229
|
-
std::cerr << "Iterator returned status " << ex.what();
|
|
7230
|
-
abort();
|
|
7231
7251
|
} catch (std::logic_error& ex) {
|
|
7232
7252
|
std::cerr << "Iterator returned logic error " << ex.what();
|
|
7233
7253
|
abort();
|
|
@@ -7235,8 +7255,9 @@ TEST_F(ExternalTableTest, DBMultiScanTest) {
|
|
|
7235
7255
|
iter.reset();
|
|
7236
7256
|
|
|
7237
7257
|
// Test the no limit scan case
|
|
7238
|
-
scan_options
|
|
7239
|
-
scan_options
|
|
7258
|
+
scan_options = MultiScanArgs(BytewiseComparator());
|
|
7259
|
+
scan_options.insert(key_ranges[0]);
|
|
7260
|
+
scan_options.insert(key_ranges[2]);
|
|
7240
7261
|
iter = db->NewMultiScan(ro, cfh, scan_options);
|
|
7241
7262
|
try {
|
|
7242
7263
|
int idx = 0;
|
|
@@ -7255,8 +7276,6 @@ TEST_F(ExternalTableTest, DBMultiScanTest) {
|
|
|
7255
7276
|
} catch (MultiScanException& ex) {
|
|
7256
7277
|
// Make sure exception contains the status
|
|
7257
7278
|
ASSERT_NOK(ex.status());
|
|
7258
|
-
std::cerr << "Iterator returned status " << ex.what();
|
|
7259
|
-
abort();
|
|
7260
7279
|
} catch (std::logic_error& ex) {
|
|
7261
7280
|
std::cerr << "Iterator returned logic error " << ex.what();
|
|
7262
7281
|
abort();
|
|
@@ -7281,7 +7300,7 @@ TEST_F(ExternalTableTest, DBMultiScanTest) {
|
|
|
7281
7300
|
}
|
|
7282
7301
|
} catch (MultiScanException& ex) {
|
|
7283
7302
|
// Make sure exception contains the status
|
|
7284
|
-
|
|
7303
|
+
ASSERT_NOK(ex.status());
|
|
7285
7304
|
} catch (std::logic_error& ex) {
|
|
7286
7305
|
std::cerr << "Iterator returned logic error " << ex.what();
|
|
7287
7306
|
abort();
|
|
@@ -7399,7 +7418,7 @@ TEST_F(ExternalTableTest, IngestionTest) {
|
|
|
7399
7418
|
ASSERT_OK(db->Close());
|
|
7400
7419
|
}
|
|
7401
7420
|
|
|
7402
|
-
class
|
|
7421
|
+
class UserDefinedIndexTestBase : public BlockBasedTableTestBase {
|
|
7403
7422
|
public:
|
|
7404
7423
|
class CustomFlushBlockPolicy : public FlushBlockPolicy {
|
|
7405
7424
|
public:
|
|
@@ -7436,13 +7455,36 @@ class UserDefinedIndexTest : public BlockBasedTableTestBase {
|
|
|
7436
7455
|
class TestUserDefinedIndexFactory : public UserDefinedIndexFactory {
|
|
7437
7456
|
public:
|
|
7438
7457
|
const char* Name() const override { return "test_index"; }
|
|
7439
|
-
|
|
7440
|
-
|
|
7458
|
+
Status NewBuilder(
|
|
7459
|
+
const UserDefinedIndexOption& /*option*/,
|
|
7460
|
+
std::unique_ptr<UserDefinedIndexBuilder>& builder) const override {
|
|
7461
|
+
builder = std::make_unique<TestUserDefinedIndexBuilder>();
|
|
7462
|
+
return Status::OK();
|
|
7441
7463
|
}
|
|
7442
7464
|
|
|
7465
|
+
struct CustomizedMapComparator {
|
|
7466
|
+
CustomizedMapComparator(const Comparator* _comparator)
|
|
7467
|
+
: comparator(_comparator) {}
|
|
7468
|
+
const Comparator* comparator;
|
|
7469
|
+
bool operator()(const std::string& lhs, const std::string& rhs) const {
|
|
7470
|
+
return comparator->Compare(lhs, rhs) < 0;
|
|
7471
|
+
}
|
|
7472
|
+
};
|
|
7473
|
+
|
|
7474
|
+
// Deprecated API
|
|
7475
|
+
UserDefinedIndexBuilder* NewBuilder() const override { return nullptr; }
|
|
7476
|
+
|
|
7443
7477
|
std::unique_ptr<UserDefinedIndexReader> NewReader(
|
|
7444
|
-
Slice& index_block) const override {
|
|
7445
|
-
return
|
|
7478
|
+
Slice& /*index_block*/) const override {
|
|
7479
|
+
return nullptr;
|
|
7480
|
+
}
|
|
7481
|
+
|
|
7482
|
+
Status NewReader(
|
|
7483
|
+
const UserDefinedIndexOption& option, Slice& index_block,
|
|
7484
|
+
std::unique_ptr<UserDefinedIndexReader>& reader) const override {
|
|
7485
|
+
reader = std::make_unique<TestUserDefinedIndexReader>(
|
|
7486
|
+
index_block, option.comparator, this);
|
|
7487
|
+
return Status::OK();
|
|
7446
7488
|
}
|
|
7447
7489
|
|
|
7448
7490
|
uint64_t seek_error_count_ = 0;
|
|
@@ -7457,10 +7499,17 @@ class UserDefinedIndexTest : public BlockBasedTableTestBase {
|
|
|
7457
7499
|
const Slice* first_key_in_next_block,
|
|
7458
7500
|
const BlockHandle& block_handle,
|
|
7459
7501
|
std::string* separator_scratch) override {
|
|
7502
|
+
if (keys_added_ == 0) {
|
|
7503
|
+
return last_key_in_current_block;
|
|
7504
|
+
}
|
|
7505
|
+
EXPECT_EQ(last_key_in_current_block.size(), 5);
|
|
7506
|
+
if (first_key_in_next_block) {
|
|
7507
|
+
EXPECT_EQ(first_key_in_next_block->size(), 5);
|
|
7508
|
+
}
|
|
7460
7509
|
// Unused parameters
|
|
7461
|
-
(void)first_key_in_next_block;
|
|
7462
7510
|
(void)separator_scratch;
|
|
7463
7511
|
entries_added_++;
|
|
7512
|
+
index_data_[last_key_in_current_block.ToString()].clear();
|
|
7464
7513
|
// Store the block handle for each key
|
|
7465
7514
|
PutFixed64(&index_data_[last_key_in_current_block.ToString()],
|
|
7466
7515
|
block_handle.offset);
|
|
@@ -7472,13 +7521,25 @@ class UserDefinedIndexTest : public BlockBasedTableTestBase {
|
|
|
7472
7521
|
return last_key_in_current_block;
|
|
7473
7522
|
}
|
|
7474
7523
|
|
|
7475
|
-
void OnKeyAdded(const Slice&
|
|
7524
|
+
void OnKeyAdded(const Slice& key, ValueType /*value*/,
|
|
7476
7525
|
const Slice& /*value*/) override {
|
|
7526
|
+
if (key.starts_with("dummy")) {
|
|
7527
|
+
return;
|
|
7528
|
+
}
|
|
7529
|
+
EXPECT_EQ(key.size(), 5);
|
|
7477
7530
|
// Track keys added to the index
|
|
7478
7531
|
keys_added_++;
|
|
7532
|
+
// Add dummy entry
|
|
7533
|
+
PutFixed64(&index_data_[key.ToString()], 0);
|
|
7534
|
+
PutFixed64(&index_data_[key.ToString()], 0);
|
|
7535
|
+
PutFixed32(&index_data_[key.ToString()], 0);
|
|
7479
7536
|
}
|
|
7480
7537
|
|
|
7481
7538
|
Status Finish(Slice* index_contents) override {
|
|
7539
|
+
if (entries_added_ == 0) {
|
|
7540
|
+
*index_contents = Slice();
|
|
7541
|
+
return Status::OK();
|
|
7542
|
+
}
|
|
7482
7543
|
// Serialize the index data
|
|
7483
7544
|
std::string result;
|
|
7484
7545
|
for (const auto& entry : index_data_) {
|
|
@@ -7502,8 +7563,11 @@ class UserDefinedIndexTest : public BlockBasedTableTestBase {
|
|
|
7502
7563
|
class TestUserDefinedIndexReader : public UserDefinedIndexReader {
|
|
7503
7564
|
public:
|
|
7504
7565
|
explicit TestUserDefinedIndexReader(
|
|
7505
|
-
Slice& index_block, const
|
|
7506
|
-
|
|
7566
|
+
Slice& index_block, const Comparator* comparator,
|
|
7567
|
+
const TestUserDefinedIndexFactory* factory)
|
|
7568
|
+
: factory_(factory),
|
|
7569
|
+
comparator_(comparator),
|
|
7570
|
+
index_data_(CustomizedMapComparator(comparator)) {
|
|
7507
7571
|
Slice block = index_block;
|
|
7508
7572
|
while (!block.empty()) {
|
|
7509
7573
|
Slice key;
|
|
@@ -7525,9 +7589,9 @@ class UserDefinedIndexTest : public BlockBasedTableTestBase {
|
|
|
7525
7589
|
}
|
|
7526
7590
|
|
|
7527
7591
|
std::unique_ptr<UserDefinedIndexIterator> NewIterator(
|
|
7528
|
-
const ReadOptions& ro) override {
|
|
7529
|
-
return std::make_unique<TestUserDefinedIndexIterator>(
|
|
7530
|
-
|
|
7592
|
+
const ReadOptions& /*ro*/) override {
|
|
7593
|
+
return std::make_unique<TestUserDefinedIndexIterator>(
|
|
7594
|
+
index_data_, factory_, comparator_);
|
|
7531
7595
|
}
|
|
7532
7596
|
|
|
7533
7597
|
size_t ApproximateMemoryUsage() const override { return 0; }
|
|
@@ -7536,19 +7600,19 @@ class UserDefinedIndexTest : public BlockBasedTableTestBase {
|
|
|
7536
7600
|
class TestUserDefinedIndexIterator : public UserDefinedIndexIterator {
|
|
7537
7601
|
public:
|
|
7538
7602
|
TestUserDefinedIndexIterator(
|
|
7539
|
-
const ReadOptions& ro,
|
|
7540
7603
|
std::map<std::string,
|
|
7541
|
-
std::pair<UserDefinedIndexBuilder::BlockHandle, uint32_t
|
|
7542
|
-
|
|
7543
|
-
const TestUserDefinedIndexFactory* factory
|
|
7544
|
-
|
|
7545
|
-
|
|
7604
|
+
std::pair<UserDefinedIndexBuilder::BlockHandle, uint32_t>,
|
|
7605
|
+
CustomizedMapComparator>& index,
|
|
7606
|
+
const TestUserDefinedIndexFactory* factory,
|
|
7607
|
+
const Comparator* comparator)
|
|
7608
|
+
: index_(index),
|
|
7546
7609
|
iter_(index_.end()),
|
|
7547
7610
|
scan_opts_(nullptr),
|
|
7548
7611
|
num_opts_(0),
|
|
7549
7612
|
target_num_keys_(0),
|
|
7550
7613
|
seek_error_count_(factory->seek_error_count_),
|
|
7551
|
-
next_error_count_(factory->next_error_count_)
|
|
7614
|
+
next_error_count_(factory->next_error_count_),
|
|
7615
|
+
comparator_(comparator) {}
|
|
7552
7616
|
|
|
7553
7617
|
Status SeekAndGetResult(const Slice& key,
|
|
7554
7618
|
IterateResult* result) override {
|
|
@@ -7561,23 +7625,24 @@ class UserDefinedIndexTest : public BlockBasedTableTestBase {
|
|
|
7561
7625
|
return s;
|
|
7562
7626
|
}
|
|
7563
7627
|
if (scan_opts_) {
|
|
7564
|
-
|
|
7565
|
-
|
|
7566
|
-
|
|
7567
|
-
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7628
|
+
// Seeks should be in order specified in scan_opts_
|
|
7629
|
+
EXPECT_EQ(comparator_->Compare(
|
|
7630
|
+
scan_opts_[scan_idx_].range.start.value(), key),
|
|
7631
|
+
0);
|
|
7632
|
+
EXPECT_TRUE(scan_opts_[scan_idx_].property_bag.has_value());
|
|
7633
|
+
target_num_keys_ = std::stoi(scan_opts_[scan_idx_]
|
|
7634
|
+
.property_bag.value()
|
|
7635
|
+
.find("count")
|
|
7636
|
+
->second);
|
|
7637
|
+
scan_idx_++;
|
|
7574
7638
|
}
|
|
7575
7639
|
iter_ = index_.lower_bound(key.ToString());
|
|
7576
|
-
if (iter_ != index_.end()) {
|
|
7640
|
+
if ((iter_ != index_.end()) && IsInbound()) {
|
|
7641
|
+
AdvanceToNextIndexEntry();
|
|
7577
7642
|
result->bound_check_result = IterBoundCheck::kInbound;
|
|
7578
7643
|
result->key = Slice(iter_->first);
|
|
7579
7644
|
if (scan_opts_ && target_num_keys_ > 0 &&
|
|
7580
|
-
iter_->first
|
|
7645
|
+
comparator_->Compare(key, iter_->first) == 0) {
|
|
7581
7646
|
target_num_keys_--;
|
|
7582
7647
|
}
|
|
7583
7648
|
} else {
|
|
@@ -7596,9 +7661,10 @@ class UserDefinedIndexTest : public BlockBasedTableTestBase {
|
|
|
7596
7661
|
if (!s.ok()) {
|
|
7597
7662
|
return s;
|
|
7598
7663
|
}
|
|
7599
|
-
if (
|
|
7600
|
-
if (
|
|
7601
|
-
|
|
7664
|
+
if (scan_opts_ && scan_opts_[scan_idx_ - 1].range.limit.has_value()) {
|
|
7665
|
+
if (comparator_->Compare(
|
|
7666
|
+
iter_->first,
|
|
7667
|
+
scan_opts_[scan_idx_ - 1].range.limit.value()) >= 0) {
|
|
7602
7668
|
result->bound_check_result = IterBoundCheck::kOutOfBound;
|
|
7603
7669
|
result->key = Slice();
|
|
7604
7670
|
return Status::OK();
|
|
@@ -7610,7 +7676,8 @@ class UserDefinedIndexTest : public BlockBasedTableTestBase {
|
|
|
7610
7676
|
return Status::OK();
|
|
7611
7677
|
}
|
|
7612
7678
|
iter_++;
|
|
7613
|
-
if (iter_ != index_.end()) {
|
|
7679
|
+
if ((iter_ != index_.end()) && IsInbound()) {
|
|
7680
|
+
AdvanceToNextIndexEntry();
|
|
7614
7681
|
result->bound_check_result = IterBoundCheck::kInbound;
|
|
7615
7682
|
result->key = Slice(iter_->first);
|
|
7616
7683
|
target_num_keys_ -=
|
|
@@ -7623,6 +7690,25 @@ class UserDefinedIndexTest : public BlockBasedTableTestBase {
|
|
|
7623
7690
|
return Status::OK();
|
|
7624
7691
|
}
|
|
7625
7692
|
|
|
7693
|
+
void AdvanceToNextIndexEntry() {
|
|
7694
|
+
while (iter_->second.second == 0) {
|
|
7695
|
+
iter_++;
|
|
7696
|
+
}
|
|
7697
|
+
}
|
|
7698
|
+
|
|
7699
|
+
bool IsInbound() {
|
|
7700
|
+
if (!scan_opts_) {
|
|
7701
|
+
return true;
|
|
7702
|
+
}
|
|
7703
|
+
if (scan_opts_[scan_idx_ - 1].range.limit.has_value() &&
|
|
7704
|
+
comparator_->Compare(
|
|
7705
|
+
scan_opts_[scan_idx_ - 1].range.limit.value(),
|
|
7706
|
+
iter_->first) <= 0) {
|
|
7707
|
+
return false;
|
|
7708
|
+
}
|
|
7709
|
+
return true;
|
|
7710
|
+
}
|
|
7711
|
+
|
|
7626
7712
|
UserDefinedIndexBuilder::BlockHandle value() override {
|
|
7627
7713
|
UserDefinedIndexBuilder::BlockHandle handle{0, 0};
|
|
7628
7714
|
handle.offset = iter_->second.first.offset;
|
|
@@ -7631,16 +7717,17 @@ class UserDefinedIndexTest : public BlockBasedTableTestBase {
|
|
|
7631
7717
|
}
|
|
7632
7718
|
|
|
7633
7719
|
void Prepare(const ScanOptions scan_opts[], size_t num_opts) override {
|
|
7720
|
+
// Prepare should only be called once
|
|
7721
|
+
EXPECT_EQ(scan_opts_, nullptr);
|
|
7634
7722
|
scan_opts_ = scan_opts;
|
|
7635
7723
|
num_opts_ = num_opts;
|
|
7636
7724
|
scan_idx_ = 0;
|
|
7637
7725
|
}
|
|
7638
7726
|
|
|
7639
7727
|
private:
|
|
7640
|
-
const ReadOptions& ro_;
|
|
7641
7728
|
std::map<std::string,
|
|
7642
|
-
std::pair<UserDefinedIndexBuilder::BlockHandle, uint32_t
|
|
7643
|
-
|
|
7729
|
+
std::pair<UserDefinedIndexBuilder::BlockHandle, uint32_t>,
|
|
7730
|
+
CustomizedMapComparator>& index_;
|
|
7644
7731
|
std::map<std::string, std::pair<UserDefinedIndexBuilder::BlockHandle,
|
|
7645
7732
|
uint32_t>>::iterator iter_;
|
|
7646
7733
|
const ScanOptions* scan_opts_;
|
|
@@ -7649,18 +7736,137 @@ class UserDefinedIndexTest : public BlockBasedTableTestBase {
|
|
|
7649
7736
|
uint32_t target_num_keys_;
|
|
7650
7737
|
uint64_t seek_error_count_;
|
|
7651
7738
|
uint64_t next_error_count_;
|
|
7739
|
+
const Comparator* comparator_;
|
|
7652
7740
|
};
|
|
7653
7741
|
|
|
7654
7742
|
const TestUserDefinedIndexFactory* factory_;
|
|
7743
|
+
const Comparator* comparator_;
|
|
7655
7744
|
std::map<std::string,
|
|
7656
|
-
std::pair<UserDefinedIndexBuilder::BlockHandle, uint32_t
|
|
7745
|
+
std::pair<UserDefinedIndexBuilder::BlockHandle, uint32_t>,
|
|
7746
|
+
CustomizedMapComparator>
|
|
7657
7747
|
index_data_;
|
|
7658
7748
|
};
|
|
7659
7749
|
};
|
|
7750
|
+
|
|
7751
|
+
protected:
|
|
7752
|
+
std::vector<std::pair<std::string, std::string>> generateKVWithValue(
|
|
7753
|
+
int key_count, const std::string& value) {
|
|
7754
|
+
std::vector<std::pair<std::string, std::string>> kvs(key_count);
|
|
7755
|
+
for (int i = 0; i < key_count; i++) {
|
|
7756
|
+
std::stringstream ss;
|
|
7757
|
+
ss << std::setw(2) << std::setfill('0') << i;
|
|
7758
|
+
std::string key = "key" + ss.str();
|
|
7759
|
+
kvs[i] = std::make_pair(key, value);
|
|
7760
|
+
}
|
|
7761
|
+
if (is_reverse_comparator_) {
|
|
7762
|
+
std::reverse(kvs.begin(), kvs.end());
|
|
7763
|
+
}
|
|
7764
|
+
return kvs;
|
|
7765
|
+
}
|
|
7766
|
+
|
|
7767
|
+
std::vector<std::pair<std::string, std::string>> generateKVs(
|
|
7768
|
+
int key_count, int value_size = 0) {
|
|
7769
|
+
std::vector<std::pair<std::string, std::string>> kvs(key_count);
|
|
7770
|
+
for (int i = 0; i < key_count; i++) {
|
|
7771
|
+
std::stringstream ss;
|
|
7772
|
+
ss << std::setw(2) << std::setfill('0') << i;
|
|
7773
|
+
std::string key = "key" + ss.str();
|
|
7774
|
+
std::string value;
|
|
7775
|
+
if (value_size != 0) {
|
|
7776
|
+
value = rnd.RandomString(1024);
|
|
7777
|
+
} else {
|
|
7778
|
+
value = "value" + ss.str();
|
|
7779
|
+
}
|
|
7780
|
+
kvs[i] = std::make_pair(key, value);
|
|
7781
|
+
}
|
|
7782
|
+
if (is_reverse_comparator_) {
|
|
7783
|
+
std::reverse(kvs.begin(), kvs.end());
|
|
7784
|
+
}
|
|
7785
|
+
return kvs;
|
|
7786
|
+
}
|
|
7787
|
+
|
|
7788
|
+
void BasicTest(bool use_partitioned_index);
|
|
7789
|
+
|
|
7790
|
+
void ValidateMultiScan(
|
|
7791
|
+
std::vector<std::tuple<std::vector<std::string>, int, int>>
|
|
7792
|
+
scan_opt_validation_arg,
|
|
7793
|
+
std::unordered_map<std::string, std::string> property_bag,
|
|
7794
|
+
const ReadOptions& ro, MultiScanArgs& scan_opts,
|
|
7795
|
+
std::vector<int>& key_counts, std::unique_ptr<DB>& db,
|
|
7796
|
+
ColumnFamilyHandle* cfh) {
|
|
7797
|
+
key_counts.clear();
|
|
7798
|
+
(*scan_opts).clear();
|
|
7799
|
+
|
|
7800
|
+
if (is_reverse_comparator_) {
|
|
7801
|
+
for (auto& scan_opt_validation_range : scan_opt_validation_arg) {
|
|
7802
|
+
// reverse each range
|
|
7803
|
+
std::reverse(std::get<0>(scan_opt_validation_range).begin(),
|
|
7804
|
+
std::get<0>(scan_opt_validation_range).end());
|
|
7805
|
+
}
|
|
7806
|
+
// reverse all the ranges
|
|
7807
|
+
std::reverse(scan_opt_validation_arg.begin(),
|
|
7808
|
+
scan_opt_validation_arg.end());
|
|
7809
|
+
}
|
|
7810
|
+
|
|
7811
|
+
for (auto& scan_opt_validation_range : scan_opt_validation_arg) {
|
|
7812
|
+
scan_opts.insert(std::get<0>(scan_opt_validation_range)[0],
|
|
7813
|
+
std::get<0>(scan_opt_validation_range)[1],
|
|
7814
|
+
std::optional(property_bag));
|
|
7815
|
+
if (is_reverse_comparator_) {
|
|
7816
|
+
key_counts.push_back(std::get<2>(scan_opt_validation_range));
|
|
7817
|
+
} else {
|
|
7818
|
+
key_counts.push_back(std::get<1>(scan_opt_validation_range));
|
|
7819
|
+
}
|
|
7820
|
+
}
|
|
7821
|
+
|
|
7822
|
+
Slice ub;
|
|
7823
|
+
ReadOptions read_opts = ro;
|
|
7824
|
+
int key_count = 0;
|
|
7825
|
+
int index = 0;
|
|
7826
|
+
auto opts = scan_opts.GetScanRanges();
|
|
7827
|
+
read_opts.iterate_upper_bound = &ub;
|
|
7828
|
+
std::unique_ptr<Iterator> iter(db->NewIterator(read_opts, cfh));
|
|
7829
|
+
iter->Prepare(scan_opts);
|
|
7830
|
+
static const bool kVerbose = false;
|
|
7831
|
+
for (auto opt : opts) {
|
|
7832
|
+
ub = opt.range.limit.value();
|
|
7833
|
+
iter->Seek(opt.range.start.value());
|
|
7834
|
+
if (kVerbose) {
|
|
7835
|
+
printf("range start key %s, end key %s\n",
|
|
7836
|
+
opt.range.start.value().ToString().c_str(),
|
|
7837
|
+
opt.range.limit.value().ToString().c_str());
|
|
7838
|
+
}
|
|
7839
|
+
EXPECT_OK(iter->status());
|
|
7840
|
+
while (iter->Valid()) {
|
|
7841
|
+
if (kVerbose) {
|
|
7842
|
+
printf("found key %s\n", iter->key().ToString().c_str());
|
|
7843
|
+
}
|
|
7844
|
+
key_count++;
|
|
7845
|
+
iter->Next();
|
|
7846
|
+
}
|
|
7847
|
+
EXPECT_EQ(key_count, key_counts[index]);
|
|
7848
|
+
key_count = 0;
|
|
7849
|
+
index++;
|
|
7850
|
+
}
|
|
7851
|
+
EXPECT_OK(iter->status());
|
|
7852
|
+
}
|
|
7853
|
+
Options options_;
|
|
7854
|
+
const Comparator* comparator_;
|
|
7855
|
+
bool is_reverse_comparator_;
|
|
7856
|
+
Random rnd{301};
|
|
7660
7857
|
};
|
|
7661
7858
|
|
|
7662
|
-
|
|
7663
|
-
|
|
7859
|
+
class UserDefinedIndexTest
|
|
7860
|
+
: public UserDefinedIndexTestBase,
|
|
7861
|
+
public testing::WithParamInterface<const Comparator*> {
|
|
7862
|
+
void SetUp() override {
|
|
7863
|
+
comparator_ = GetParam();
|
|
7864
|
+
options_.comparator = comparator_;
|
|
7865
|
+
is_reverse_comparator_ = comparator_ == ReverseBytewiseComparator();
|
|
7866
|
+
}
|
|
7867
|
+
};
|
|
7868
|
+
|
|
7869
|
+
void UserDefinedIndexTestBase::BasicTest(bool use_partitioned_index) {
|
|
7664
7870
|
BlockBasedTableOptions table_options;
|
|
7665
7871
|
std::string dbname = test::PerThreadDBPath("user_defined_index_test");
|
|
7666
7872
|
std::string ingest_file = dbname + "test.sst";
|
|
@@ -7669,31 +7875,31 @@ TEST_F(UserDefinedIndexTest, BasicTest) {
|
|
|
7669
7875
|
auto user_defined_index_factory =
|
|
7670
7876
|
std::make_shared<TestUserDefinedIndexFactory>();
|
|
7671
7877
|
table_options.user_defined_index_factory = user_defined_index_factory;
|
|
7672
|
-
|
|
7878
|
+
if (use_partitioned_index) {
|
|
7879
|
+
table_options.partition_filters = true;
|
|
7880
|
+
table_options.decouple_partitioned_filters = true;
|
|
7881
|
+
table_options.index_type = BlockBasedTableOptions::kTwoLevelIndexSearch;
|
|
7882
|
+
}
|
|
7673
7883
|
// Set up custom flush block policy that flushes every 3 keys
|
|
7674
7884
|
table_options.flush_block_policy_factory =
|
|
7675
7885
|
std::make_shared<CustomFlushBlockPolicyFactory>();
|
|
7676
7886
|
|
|
7677
|
-
|
|
7887
|
+
options_.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
|
7678
7888
|
|
|
7679
7889
|
std::unique_ptr<SstFileWriter> writer;
|
|
7680
|
-
writer.reset(new SstFileWriter(EnvOptions(),
|
|
7890
|
+
writer.reset(new SstFileWriter(EnvOptions(), options_));
|
|
7681
7891
|
ASSERT_OK(writer->Open(ingest_file));
|
|
7682
7892
|
|
|
7683
|
-
|
|
7684
|
-
for (
|
|
7685
|
-
|
|
7686
|
-
ss << std::setw(2) << std::setfill('0') << i;
|
|
7687
|
-
std::string key = "key" + ss.str();
|
|
7688
|
-
std::string value = "value" + ss.str();
|
|
7689
|
-
ASSERT_OK(writer->Put(key, value));
|
|
7893
|
+
auto kvs = generateKVs(/*key_count*/ 100);
|
|
7894
|
+
for (const auto& kv : kvs) {
|
|
7895
|
+
ASSERT_OK(writer->Put(kv.first, kv.second));
|
|
7690
7896
|
}
|
|
7691
7897
|
ASSERT_OK(writer->Finish());
|
|
7692
7898
|
writer.reset();
|
|
7693
7899
|
|
|
7694
|
-
ImmutableOptions ioptions(
|
|
7695
|
-
MutableCFOptions moptions((ColumnFamilyOptions(
|
|
7696
|
-
EnvOptions eoptions(
|
|
7900
|
+
ImmutableOptions ioptions(options_);
|
|
7901
|
+
MutableCFOptions moptions((ColumnFamilyOptions(options_)));
|
|
7902
|
+
EnvOptions eoptions(options_);
|
|
7697
7903
|
TableReaderOptions toptions(
|
|
7698
7904
|
ioptions, moptions.prefix_extractor,
|
|
7699
7905
|
/*_compression_manager=*/nullptr, eoptions, ioptions.internal_comparator,
|
|
@@ -7711,7 +7917,7 @@ TEST_F(UserDefinedIndexTest, BasicTest) {
|
|
|
7711
7917
|
uint64_t file_size = 0;
|
|
7712
7918
|
std::unique_ptr<FSRandomAccessFile> file;
|
|
7713
7919
|
std::unique_ptr<RandomAccessFileReader> file_reader;
|
|
7714
|
-
const auto& fs =
|
|
7920
|
+
const auto& fs = options_.env->GetFileSystem();
|
|
7715
7921
|
ASSERT_OK(fs->GetFileSize(ingest_file, IOOptions(), &file_size, nullptr));
|
|
7716
7922
|
ASSERT_OK(fs->NewRandomAccessFile(ingest_file, eoptions, &file, nullptr));
|
|
7717
7923
|
file_reader.reset(new RandomAccessFileReader(std::move(file), ingest_file));
|
|
@@ -7728,7 +7934,7 @@ TEST_F(UserDefinedIndexTest, BasicTest) {
|
|
|
7728
7934
|
ASSERT_GE(block_handle.size(),
|
|
7729
7935
|
expected_entries); // At least this many entries
|
|
7730
7936
|
|
|
7731
|
-
std::unique_ptr<SstFileReader> reader(new SstFileReader(
|
|
7937
|
+
std::unique_ptr<SstFileReader> reader(new SstFileReader(options_));
|
|
7732
7938
|
ASSERT_OK(reader->Open(ingest_file));
|
|
7733
7939
|
|
|
7734
7940
|
ReadOptions ro;
|
|
@@ -7749,68 +7955,85 @@ TEST_F(UserDefinedIndexTest, BasicTest) {
|
|
|
7749
7955
|
iter.reset(reader->NewIterator(ro));
|
|
7750
7956
|
ASSERT_NE(iter, nullptr);
|
|
7751
7957
|
|
|
7752
|
-
// Test
|
|
7958
|
+
// Test seek specific key
|
|
7753
7959
|
key_count = 0;
|
|
7754
|
-
for (iter->Seek("
|
|
7960
|
+
for (iter->Seek("key40"); iter->Valid(); iter->Next()) {
|
|
7755
7961
|
key_count++;
|
|
7756
7962
|
}
|
|
7757
|
-
ASSERT_EQ(key_count,
|
|
7963
|
+
ASSERT_EQ(key_count, is_reverse_comparator_ ? 41 : 60);
|
|
7758
7964
|
ASSERT_OK(iter->status());
|
|
7759
7965
|
|
|
7760
|
-
|
|
7966
|
+
// Test upper bound
|
|
7967
|
+
Slice ub(is_reverse_comparator_ ? "key25" : "key75");
|
|
7761
7968
|
ro.iterate_upper_bound = &ub;
|
|
7762
7969
|
iter.reset(reader->NewIterator(ro));
|
|
7763
7970
|
ASSERT_NE(iter, nullptr);
|
|
7764
7971
|
|
|
7765
|
-
// Test
|
|
7972
|
+
// Test seek specific key with upper bound
|
|
7766
7973
|
key_count = 0;
|
|
7767
|
-
for (iter->Seek("
|
|
7974
|
+
for (iter->Seek("key40"); iter->Valid(); iter->Next()) {
|
|
7768
7975
|
key_count++;
|
|
7769
7976
|
}
|
|
7770
|
-
ASSERT_EQ(key_count,
|
|
7977
|
+
ASSERT_EQ(key_count, is_reverse_comparator_ ? 15 : 35);
|
|
7771
7978
|
ASSERT_OK(iter->status());
|
|
7772
7979
|
|
|
7773
7980
|
user_defined_index_factory->seek_error_count_ = 1;
|
|
7774
7981
|
iter.reset(reader->NewIterator(ro));
|
|
7775
7982
|
ASSERT_NE(iter, nullptr);
|
|
7776
|
-
iter->Seek("
|
|
7983
|
+
iter->Seek("key40");
|
|
7777
7984
|
ASSERT_NOK(iter->status());
|
|
7778
7985
|
|
|
7779
7986
|
user_defined_index_factory->seek_error_count_ = 0;
|
|
7780
7987
|
user_defined_index_factory->next_error_count_ = 1;
|
|
7781
7988
|
iter.reset(reader->NewIterator(ro));
|
|
7782
7989
|
ASSERT_NE(iter, nullptr);
|
|
7783
|
-
iter->Seek("key09");
|
|
7784
|
-
ASSERT_OK(iter->status());
|
|
7785
|
-
iter->Next();
|
|
7990
|
+
iter->Seek(is_reverse_comparator_ ? "key92" : "key09");
|
|
7786
7991
|
ASSERT_OK(iter->status());
|
|
7787
7992
|
iter->Next();
|
|
7788
7993
|
ASSERT_OK(iter->status());
|
|
7789
7994
|
iter->Next();
|
|
7995
|
+
if (!is_reverse_comparator_) {
|
|
7996
|
+
ASSERT_OK(iter->status());
|
|
7997
|
+
iter->Next();
|
|
7998
|
+
}
|
|
7790
7999
|
ASSERT_NOK(iter->status());
|
|
7791
8000
|
user_defined_index_factory->next_error_count_ = 0;
|
|
7792
8001
|
|
|
7793
|
-
ro.iterate_upper_bound =
|
|
8002
|
+
ro.iterate_upper_bound = &ub;
|
|
7794
8003
|
iter.reset(reader->NewIterator(ro));
|
|
7795
8004
|
ASSERT_NE(iter, nullptr);
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
|
|
8005
|
+
MultiScanArgs scan_opts(comparator_);
|
|
8006
|
+
|
|
8007
|
+
std::unordered_map<std::string, std::string> property_bag;
|
|
8008
|
+
property_bag["count"] = std::to_string(25);
|
|
8009
|
+
std::vector<std::string> boundaries = {"key10", "key50"};
|
|
8010
|
+
if (is_reverse_comparator_) {
|
|
8011
|
+
std::reverse(boundaries.begin(), boundaries.end());
|
|
8012
|
+
}
|
|
8013
|
+
|
|
8014
|
+
scan_opts.insert(boundaries[0], boundaries[1], std::optional(property_bag));
|
|
7799
8015
|
iter->Prepare(scan_opts);
|
|
7800
|
-
// Test that
|
|
8016
|
+
// Test that UDI is used to help fetch the number of keys
|
|
7801
8017
|
key_count = 0;
|
|
7802
|
-
|
|
7803
|
-
|
|
8018
|
+
ub = boundaries[1];
|
|
8019
|
+
for (iter->Seek(scan_opts.GetScanRanges()[0].range.start.value());
|
|
8020
|
+
iter->Valid(); iter->Next()) {
|
|
7804
8021
|
key_count++;
|
|
7805
8022
|
}
|
|
7806
|
-
ASSERT_GE(key_count, 25);
|
|
7807
8023
|
// The index may undercount by 2 blocks
|
|
7808
|
-
|
|
8024
|
+
ASSERT_EQ(key_count, 29);
|
|
7809
8025
|
ASSERT_OK(iter->status());
|
|
7810
8026
|
}
|
|
7811
8027
|
|
|
7812
|
-
|
|
7813
|
-
|
|
8028
|
+
TEST_P(UserDefinedIndexTest, BasicTestWithPartitionedIndex) {
|
|
8029
|
+
BasicTest(/*use_partitioned_index=*/true);
|
|
8030
|
+
}
|
|
8031
|
+
|
|
8032
|
+
TEST_P(UserDefinedIndexTest, BasicTestWithoutPartitionedIndex) {
|
|
8033
|
+
BasicTest(/*use_partitioned_index=*/false);
|
|
8034
|
+
}
|
|
8035
|
+
|
|
8036
|
+
TEST_P(UserDefinedIndexTest, InvalidArgumentTest1) {
|
|
7814
8037
|
BlockBasedTableOptions table_options;
|
|
7815
8038
|
std::string dbname = test::PerThreadDBPath("user_defined_index_test");
|
|
7816
8039
|
std::string ingest_file = dbname + "test.sst";
|
|
@@ -7824,11 +8047,11 @@ TEST_F(UserDefinedIndexTest, InvalidArgumentTest1) {
|
|
|
7824
8047
|
table_options.flush_block_policy_factory =
|
|
7825
8048
|
std::make_shared<CustomFlushBlockPolicyFactory>();
|
|
7826
8049
|
|
|
7827
|
-
|
|
7828
|
-
|
|
8050
|
+
options_.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
|
8051
|
+
options_.compression_opts.parallel_threads = 10;
|
|
7829
8052
|
|
|
7830
8053
|
std::unique_ptr<SstFileWriter> writer;
|
|
7831
|
-
writer.reset(new SstFileWriter(EnvOptions(),
|
|
8054
|
+
writer.reset(new SstFileWriter(EnvOptions(), options_));
|
|
7832
8055
|
ASSERT_OK(writer->Open(ingest_file));
|
|
7833
8056
|
|
|
7834
8057
|
std::string key = "foo";
|
|
@@ -7838,8 +8061,7 @@ TEST_F(UserDefinedIndexTest, InvalidArgumentTest1) {
|
|
|
7838
8061
|
writer.reset();
|
|
7839
8062
|
}
|
|
7840
8063
|
|
|
7841
|
-
|
|
7842
|
-
Options options;
|
|
8064
|
+
TEST_P(UserDefinedIndexTest, InvalidArgumentTest2) {
|
|
7843
8065
|
BlockBasedTableOptions table_options;
|
|
7844
8066
|
std::string dbname = test::PerThreadDBPath("user_defined_index_test");
|
|
7845
8067
|
std::string ingest_file = dbname + "test.sst";
|
|
@@ -7853,10 +8075,10 @@ TEST_F(UserDefinedIndexTest, InvalidArgumentTest2) {
|
|
|
7853
8075
|
table_options.flush_block_policy_factory =
|
|
7854
8076
|
std::make_shared<CustomFlushBlockPolicyFactory>();
|
|
7855
8077
|
|
|
7856
|
-
|
|
8078
|
+
options_.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
|
7857
8079
|
|
|
7858
8080
|
std::unique_ptr<SstFileWriter> writer;
|
|
7859
|
-
writer.reset(new SstFileWriter(EnvOptions(),
|
|
8081
|
+
writer.reset(new SstFileWriter(EnvOptions(), options_));
|
|
7860
8082
|
ASSERT_OK(writer->Open(ingest_file));
|
|
7861
8083
|
|
|
7862
8084
|
std::string key = "foo";
|
|
@@ -7866,8 +8088,7 @@ TEST_F(UserDefinedIndexTest, InvalidArgumentTest2) {
|
|
|
7866
8088
|
writer.reset();
|
|
7867
8089
|
}
|
|
7868
8090
|
|
|
7869
|
-
|
|
7870
|
-
Options options;
|
|
8091
|
+
TEST_P(UserDefinedIndexTest, IngestTest) {
|
|
7871
8092
|
BlockBasedTableOptions table_options;
|
|
7872
8093
|
std::string dbname = test::PerThreadDBPath("user_defined_index_test");
|
|
7873
8094
|
std::string ingest_file = dbname + "test.sst";
|
|
@@ -7881,30 +8102,27 @@ TEST_F(UserDefinedIndexTest, IngestTest) {
|
|
|
7881
8102
|
table_options.flush_block_policy_factory =
|
|
7882
8103
|
std::make_shared<CustomFlushBlockPolicyFactory>();
|
|
7883
8104
|
|
|
7884
|
-
|
|
8105
|
+
options_.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
|
7885
8106
|
|
|
7886
8107
|
std::unique_ptr<SstFileWriter> writer;
|
|
7887
|
-
writer.reset(new SstFileWriter(EnvOptions(),
|
|
8108
|
+
writer.reset(new SstFileWriter(EnvOptions(), options_));
|
|
7888
8109
|
ASSERT_OK(writer->Open(ingest_file));
|
|
7889
8110
|
|
|
7890
|
-
|
|
7891
|
-
for (
|
|
7892
|
-
|
|
7893
|
-
ss << std::setw(2) << std::setfill('0') << i;
|
|
7894
|
-
std::string key = "key" + ss.str();
|
|
7895
|
-
std::string value = "value" + ss.str();
|
|
7896
|
-
ASSERT_OK(writer->Put(key, value));
|
|
8111
|
+
auto kvs = generateKVs(/*key_count*/ 100);
|
|
8112
|
+
for (const auto& kv : kvs) {
|
|
8113
|
+
ASSERT_OK(writer->Put(kv.first, kv.second));
|
|
7897
8114
|
}
|
|
8115
|
+
|
|
7898
8116
|
ASSERT_OK(writer->Finish());
|
|
7899
8117
|
writer.reset();
|
|
7900
8118
|
|
|
7901
8119
|
std::unique_ptr<DB> db;
|
|
7902
|
-
|
|
7903
|
-
Status s = DB::Open(
|
|
8120
|
+
options_.create_if_missing = true;
|
|
8121
|
+
Status s = DB::Open(options_, dbname, &db);
|
|
7904
8122
|
ASSERT_OK(s);
|
|
7905
8123
|
ASSERT_TRUE(db != nullptr);
|
|
7906
8124
|
ColumnFamilyHandle* cfh = nullptr;
|
|
7907
|
-
ASSERT_OK(db->CreateColumnFamily(
|
|
8125
|
+
ASSERT_OK(db->CreateColumnFamily(options_, "new_cf", &cfh));
|
|
7908
8126
|
|
|
7909
8127
|
IngestExternalFileOptions ifo;
|
|
7910
8128
|
s = db->IngestExternalFile(cfh, {ingest_file}, ifo);
|
|
@@ -7928,55 +8146,160 @@ TEST_F(UserDefinedIndexTest, IngestTest) {
|
|
|
7928
8146
|
iter.reset(db->NewIterator(ro, cfh));
|
|
7929
8147
|
ASSERT_NE(iter, nullptr);
|
|
7930
8148
|
|
|
7931
|
-
// Test
|
|
8149
|
+
// Test seek specific key
|
|
7932
8150
|
key_count = 0;
|
|
7933
|
-
for (iter->Seek("
|
|
8151
|
+
for (iter->Seek("key40"); iter->Valid(); iter->Next()) {
|
|
7934
8152
|
key_count++;
|
|
7935
8153
|
}
|
|
7936
|
-
ASSERT_EQ(key_count,
|
|
8154
|
+
ASSERT_EQ(key_count, is_reverse_comparator_ ? 41 : 60);
|
|
7937
8155
|
ASSERT_OK(iter->status());
|
|
7938
8156
|
|
|
7939
|
-
|
|
8157
|
+
// Test upper bound
|
|
8158
|
+
Slice ub(is_reverse_comparator_ ? "key25" : "key75");
|
|
7940
8159
|
ro.iterate_upper_bound = &ub;
|
|
7941
8160
|
iter.reset(db->NewIterator(ro, cfh));
|
|
7942
8161
|
ASSERT_NE(iter, nullptr);
|
|
7943
8162
|
|
|
7944
|
-
// Test
|
|
8163
|
+
// Test seek specific key with upper bound
|
|
7945
8164
|
key_count = 0;
|
|
7946
|
-
for (iter->Seek("
|
|
8165
|
+
for (iter->Seek("key40"); iter->Valid(); iter->Next()) {
|
|
7947
8166
|
key_count++;
|
|
7948
8167
|
}
|
|
7949
|
-
ASSERT_EQ(key_count,
|
|
8168
|
+
ASSERT_EQ(key_count, is_reverse_comparator_ ? 15 : 35);
|
|
7950
8169
|
ASSERT_OK(iter->status());
|
|
8170
|
+
iter.reset();
|
|
7951
8171
|
|
|
7952
|
-
|
|
7953
|
-
|
|
8172
|
+
ASSERT_OK(db->DestroyColumnFamilyHandle(cfh));
|
|
8173
|
+
ASSERT_OK(db->Close());
|
|
8174
|
+
ASSERT_OK(DestroyDB(dbname, options_));
|
|
8175
|
+
}
|
|
8176
|
+
|
|
8177
|
+
TEST_P(UserDefinedIndexTest, EmptyRangeTest) {
|
|
8178
|
+
BlockBasedTableOptions table_options;
|
|
8179
|
+
std::string dbname = test::PerThreadDBPath("user_defined_index_test");
|
|
8180
|
+
std::string ingest_file = dbname + "test.sst";
|
|
8181
|
+
|
|
8182
|
+
// Set up the user-defined index factory
|
|
8183
|
+
auto user_defined_index_factory =
|
|
8184
|
+
std::make_shared<TestUserDefinedIndexFactory>();
|
|
8185
|
+
table_options.user_defined_index_factory = user_defined_index_factory;
|
|
8186
|
+
|
|
8187
|
+
// Set up custom flush block policy that flushes every 3 keys
|
|
8188
|
+
table_options.flush_block_policy_factory =
|
|
8189
|
+
std::make_shared<CustomFlushBlockPolicyFactory>();
|
|
8190
|
+
|
|
8191
|
+
options_.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
|
8192
|
+
|
|
8193
|
+
std::unique_ptr<SstFileWriter> writer;
|
|
8194
|
+
writer.reset(new SstFileWriter(EnvOptions(), options_));
|
|
8195
|
+
ASSERT_OK(writer->Open(ingest_file));
|
|
8196
|
+
|
|
8197
|
+
// Generate key range key0 ~ key19, key40 ~ key59, key80 ~ key99
|
|
8198
|
+
std::vector<std::pair<std::string, std::string>> kvs;
|
|
8199
|
+
bool skip = false;
|
|
8200
|
+
for (int i = 0; i < 100; i++) {
|
|
8201
|
+
if (i > 0 && i % 20 == 0) {
|
|
8202
|
+
skip = !skip;
|
|
8203
|
+
}
|
|
8204
|
+
if (skip) {
|
|
8205
|
+
continue;
|
|
8206
|
+
}
|
|
8207
|
+
std::stringstream ss;
|
|
8208
|
+
ss << std::setw(2) << std::setfill('0') << i;
|
|
8209
|
+
std::string key = "key" + ss.str();
|
|
8210
|
+
std::string value = "value" + ss.str();
|
|
8211
|
+
kvs.emplace_back(key, value);
|
|
8212
|
+
}
|
|
8213
|
+
|
|
8214
|
+
if (is_reverse_comparator_) {
|
|
8215
|
+
std::reverse(kvs.begin(), kvs.end());
|
|
8216
|
+
}
|
|
8217
|
+
|
|
8218
|
+
for (const auto& kv : kvs) {
|
|
8219
|
+
ASSERT_OK(writer->Put(kv.first, kv.second));
|
|
8220
|
+
}
|
|
8221
|
+
ASSERT_OK(writer->Finish());
|
|
8222
|
+
writer.reset();
|
|
8223
|
+
|
|
8224
|
+
std::unique_ptr<DB> db;
|
|
8225
|
+
options_.create_if_missing = true;
|
|
8226
|
+
Status s = DB::Open(options_, dbname, &db);
|
|
8227
|
+
ASSERT_OK(s);
|
|
8228
|
+
ASSERT_TRUE(db != nullptr);
|
|
8229
|
+
ColumnFamilyHandle* cfh = nullptr;
|
|
8230
|
+
ASSERT_OK(db->CreateColumnFamily(options_, "new_cf", &cfh));
|
|
8231
|
+
|
|
8232
|
+
IngestExternalFileOptions ifo;
|
|
8233
|
+
s = db->IngestExternalFile(cfh, {ingest_file}, ifo);
|
|
8234
|
+
ASSERT_OK(s);
|
|
8235
|
+
|
|
8236
|
+
ReadOptions ro;
|
|
8237
|
+
std::unique_ptr<Iterator> iter(db->NewIterator(ro, cfh));
|
|
7954
8238
|
ASSERT_NE(iter, nullptr);
|
|
7955
|
-
|
|
7956
|
-
|
|
7957
|
-
scan_opts[0].property_bag.emplace().emplace("count", std::to_string(25));
|
|
7958
|
-
iter->Prepare(scan_opts);
|
|
8239
|
+
ASSERT_OK(iter->status());
|
|
8240
|
+
|
|
7959
8241
|
// Test that we can read all the keys
|
|
7960
|
-
key_count = 0;
|
|
7961
|
-
for (iter->
|
|
7962
|
-
iter->Next()) {
|
|
8242
|
+
int key_count = 0;
|
|
8243
|
+
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
|
|
7963
8244
|
key_count++;
|
|
7964
8245
|
}
|
|
7965
|
-
|
|
7966
|
-
// The index may undercount by 2 blocks
|
|
7967
|
-
ASSERT_LE(key_count, 30);
|
|
8246
|
+
ASSERT_EQ(key_count, 60);
|
|
7968
8247
|
ASSERT_OK(iter->status());
|
|
7969
8248
|
iter.reset();
|
|
7970
8249
|
|
|
8250
|
+
ro.table_index_factory = user_defined_index_factory.get();
|
|
8251
|
+
std::vector<int> key_counts;
|
|
8252
|
+
MultiScanArgs scan_opts(options_.comparator);
|
|
8253
|
+
std::unordered_map<std::string, std::string> property_bag;
|
|
8254
|
+
property_bag["count"] = std::to_string(5);
|
|
8255
|
+
|
|
8256
|
+
ValidateMultiScan({{{"key25", "key30"}, 0, 0},
|
|
8257
|
+
{{"key33", "key37"}, 0, 0},
|
|
8258
|
+
// Non-empty scan with range greater than count
|
|
8259
|
+
// In the key42:key56 range, we might read an additional
|
|
8260
|
+
// block worth of keys due to the boundaries (5 + 3)
|
|
8261
|
+
{{"key42", "key56"}, 8, 7},
|
|
8262
|
+
// Empty scan succeeding a non-empty one
|
|
8263
|
+
{{"key65", "key70"}, 0, 0},
|
|
8264
|
+
// A non-empty scan with range smaller than count
|
|
8265
|
+
{{"key85", "key87"}, 2, 2},
|
|
8266
|
+
// Scan range completely outside the DB
|
|
8267
|
+
{{"key991", "key999"}, 0, 0}},
|
|
8268
|
+
property_bag, ro, scan_opts, key_counts, db, cfh);
|
|
8269
|
+
|
|
8270
|
+
// Scans that overlap with part of key range, with overlap less than count
|
|
8271
|
+
ValidateMultiScan({{{"key18", "key25"}, 2, 1}, {{"key38", "key43"}, 3, 4}},
|
|
8272
|
+
property_bag, ro, scan_opts, key_counts, db, cfh);
|
|
8273
|
+
|
|
8274
|
+
// Scans that overlap with part of key range, with overlap same as count
|
|
8275
|
+
ValidateMultiScan({{{"key15", "key26"}, 5, 4}, {{"key38", "key46"}, 6, 7}},
|
|
8276
|
+
property_bag, ro, scan_opts, key_counts, db, cfh);
|
|
8277
|
+
|
|
8278
|
+
// Scans that overlap with part of key range, with overlap greater than count
|
|
8279
|
+
ValidateMultiScan({{{"key10", "key26"}, 8, 8},
|
|
8280
|
+
// Cross block boundary
|
|
8281
|
+
{{"key38", "key49"}, 7, 9}},
|
|
8282
|
+
property_bag, ro, scan_opts, key_counts, db, cfh);
|
|
8283
|
+
|
|
8284
|
+
// Scan bigger than one contiguous range of keys, with overlap greater than
|
|
8285
|
+
// count
|
|
8286
|
+
ValidateMultiScan({{{"key75", "key991"}, 8, 9}}, property_bag, ro, scan_opts,
|
|
8287
|
+
key_counts, db, cfh);
|
|
8288
|
+
|
|
8289
|
+
// Scan bigger than one contiguous range of keys, with overlap less than count
|
|
8290
|
+
property_bag["count"] = std::to_string(25);
|
|
8291
|
+
ValidateMultiScan({{{"key75", "key991"}, 20, 20}}, property_bag, ro,
|
|
8292
|
+
scan_opts, key_counts, db, cfh);
|
|
8293
|
+
|
|
7971
8294
|
ASSERT_OK(db->DestroyColumnFamilyHandle(cfh));
|
|
7972
8295
|
ASSERT_OK(db->Close());
|
|
7973
|
-
ASSERT_OK(DestroyDB(dbname,
|
|
8296
|
+
ASSERT_OK(DestroyDB(dbname, options_));
|
|
7974
8297
|
}
|
|
7975
8298
|
|
|
7976
8299
|
// Verify that external file ingestion fails if we try to ingest an SST file
|
|
7977
8300
|
// without the UDI and a UDI factory is configured in BlockBasedTableOptions
|
|
7978
|
-
|
|
7979
|
-
|
|
8301
|
+
// and fail_if_no_udi_on_open is true in BlockBasedTableOptions.
|
|
8302
|
+
TEST_P(UserDefinedIndexTest, IngestFailTest) {
|
|
7980
8303
|
BlockBasedTableOptions table_options;
|
|
7981
8304
|
std::string dbname = test::PerThreadDBPath("user_defined_index_test");
|
|
7982
8305
|
std::string ingest_file = dbname + "test.sst";
|
|
@@ -7985,19 +8308,15 @@ TEST_F(UserDefinedIndexTest, IngestFailTest) {
|
|
|
7985
8308
|
table_options.flush_block_policy_factory =
|
|
7986
8309
|
std::make_shared<CustomFlushBlockPolicyFactory>();
|
|
7987
8310
|
|
|
7988
|
-
|
|
8311
|
+
options_.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
|
7989
8312
|
|
|
7990
8313
|
std::unique_ptr<SstFileWriter> writer;
|
|
7991
|
-
writer.reset(new SstFileWriter(EnvOptions(),
|
|
8314
|
+
writer.reset(new SstFileWriter(EnvOptions(), options_));
|
|
7992
8315
|
ASSERT_OK(writer->Open(ingest_file));
|
|
7993
8316
|
|
|
7994
|
-
|
|
7995
|
-
for (
|
|
7996
|
-
|
|
7997
|
-
ss << std::setw(2) << std::setfill('0') << i;
|
|
7998
|
-
std::string key = "key" + ss.str();
|
|
7999
|
-
std::string value = "value" + ss.str();
|
|
8000
|
-
ASSERT_OK(writer->Put(key, value));
|
|
8317
|
+
auto kvs = generateKVs(/*key_count*/ 100);
|
|
8318
|
+
for (const auto& kv : kvs) {
|
|
8319
|
+
ASSERT_OK(writer->Put(kv.first, kv.second));
|
|
8001
8320
|
}
|
|
8002
8321
|
ASSERT_OK(writer->Finish());
|
|
8003
8322
|
writer.reset();
|
|
@@ -8006,24 +8325,1090 @@ TEST_F(UserDefinedIndexTest, IngestFailTest) {
|
|
|
8006
8325
|
auto user_defined_index_factory =
|
|
8007
8326
|
std::make_shared<TestUserDefinedIndexFactory>();
|
|
8008
8327
|
table_options.user_defined_index_factory = user_defined_index_factory;
|
|
8009
|
-
|
|
8328
|
+
table_options.fail_if_no_udi_on_open = true;
|
|
8329
|
+
options_.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
|
8010
8330
|
|
|
8011
8331
|
std::unique_ptr<DB> db;
|
|
8012
|
-
|
|
8013
|
-
Status s = DB::Open(
|
|
8332
|
+
options_.create_if_missing = true;
|
|
8333
|
+
Status s = DB::Open(options_, dbname, &db);
|
|
8014
8334
|
ASSERT_OK(s);
|
|
8015
8335
|
ASSERT_TRUE(db != nullptr);
|
|
8016
8336
|
ColumnFamilyHandle* cfh = nullptr;
|
|
8017
|
-
ASSERT_OK(db->CreateColumnFamily(
|
|
8337
|
+
ASSERT_OK(db->CreateColumnFamily(options_, "new_cf", &cfh));
|
|
8018
8338
|
|
|
8019
8339
|
IngestExternalFileOptions ifo;
|
|
8020
8340
|
s = db->IngestExternalFile(cfh, {ingest_file}, ifo);
|
|
8021
8341
|
ASSERT_NOK(s);
|
|
8022
8342
|
|
|
8343
|
+
ASSERT_OK(db->SetOptions(
|
|
8344
|
+
cfh, {{"block_based_table_factory", "{fail_if_no_udi_on_open=false;}"}}));
|
|
8345
|
+
s = db->IngestExternalFile(cfh, {ingest_file}, ifo);
|
|
8346
|
+
ASSERT_OK(s);
|
|
8347
|
+
|
|
8023
8348
|
ASSERT_OK(db->DestroyColumnFamilyHandle(cfh));
|
|
8024
8349
|
ASSERT_OK(db->Close());
|
|
8025
|
-
ASSERT_OK(DestroyDB(dbname,
|
|
8350
|
+
ASSERT_OK(DestroyDB(dbname, options_));
|
|
8351
|
+
}
|
|
8352
|
+
|
|
8353
|
+
TEST_P(UserDefinedIndexTest, IngestEmptyUDI) {
|
|
8354
|
+
BlockBasedTableOptions table_options;
|
|
8355
|
+
std::string dbname = test::PerThreadDBPath("user_defined_index_test");
|
|
8356
|
+
std::string ingest_file = dbname + "test.sst";
|
|
8357
|
+
std::string ingest_file2 = dbname + "dummy.sst";
|
|
8358
|
+
|
|
8359
|
+
// Set up the user-defined index factory
|
|
8360
|
+
auto user_defined_index_factory =
|
|
8361
|
+
std::make_shared<TestUserDefinedIndexFactory>();
|
|
8362
|
+
table_options.user_defined_index_factory = user_defined_index_factory;
|
|
8363
|
+
// Set up custom flush block policy that flushes every 3 keys
|
|
8364
|
+
table_options.flush_block_policy_factory =
|
|
8365
|
+
std::make_shared<CustomFlushBlockPolicyFactory>();
|
|
8366
|
+
|
|
8367
|
+
options_.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
|
8368
|
+
|
|
8369
|
+
std::unique_ptr<SstFileWriter> writer;
|
|
8370
|
+
writer.reset(new SstFileWriter(EnvOptions(), options_));
|
|
8371
|
+
ASSERT_OK(writer->Open(ingest_file));
|
|
8372
|
+
|
|
8373
|
+
auto kvs = generateKVs(/*key_count*/ 100);
|
|
8374
|
+
for (const auto& kv : kvs) {
|
|
8375
|
+
ASSERT_OK(writer->Put(kv.first, kv.second));
|
|
8376
|
+
}
|
|
8377
|
+
ASSERT_OK(writer->Finish());
|
|
8378
|
+
writer.reset();
|
|
8379
|
+
writer.reset(new SstFileWriter(EnvOptions(), options_));
|
|
8380
|
+
ASSERT_OK(writer->Open(ingest_file2));
|
|
8381
|
+
ASSERT_OK(writer->Put("dummy", "val"));
|
|
8382
|
+
ASSERT_OK(writer->Finish());
|
|
8383
|
+
writer.reset();
|
|
8384
|
+
|
|
8385
|
+
table_options.fail_if_no_udi_on_open = true;
|
|
8386
|
+
options_.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
|
8387
|
+
|
|
8388
|
+
std::unique_ptr<DB> db;
|
|
8389
|
+
options_.create_if_missing = true;
|
|
8390
|
+
Status s = DB::Open(options_, dbname, &db);
|
|
8391
|
+
ASSERT_OK(s);
|
|
8392
|
+
ASSERT_TRUE(db != nullptr);
|
|
8393
|
+
ColumnFamilyHandle* cfh = nullptr;
|
|
8394
|
+
ASSERT_OK(db->CreateColumnFamily(options_, "new_cf", &cfh));
|
|
8395
|
+
|
|
8396
|
+
std::vector<IngestExternalFileArg> ifa;
|
|
8397
|
+
ifa.emplace_back();
|
|
8398
|
+
ifa[0].column_family = cfh;
|
|
8399
|
+
ifa[0].external_files.emplace_back(ingest_file);
|
|
8400
|
+
ifa[0].external_files.emplace_back(ingest_file2);
|
|
8401
|
+
s = db->IngestExternalFiles(ifa);
|
|
8402
|
+
ASSERT_OK(s);
|
|
8403
|
+
|
|
8404
|
+
ASSERT_OK(db->DestroyColumnFamilyHandle(cfh));
|
|
8405
|
+
ASSERT_OK(db->Close());
|
|
8406
|
+
ASSERT_OK(DestroyDB(dbname, options_));
|
|
8026
8407
|
}
|
|
8408
|
+
|
|
8409
|
+
TEST_P(UserDefinedIndexTest, MultiScanFailureTest) {
|
|
8410
|
+
BlockBasedTableOptions table_options;
|
|
8411
|
+
std::string dbname = test::PerThreadDBPath("user_defined_index_test");
|
|
8412
|
+
std::string ingest_file = dbname + "test.sst";
|
|
8413
|
+
|
|
8414
|
+
// Set up the user-defined index factory
|
|
8415
|
+
auto user_defined_index_factory =
|
|
8416
|
+
std::make_shared<TestUserDefinedIndexFactory>();
|
|
8417
|
+
table_options.user_defined_index_factory = user_defined_index_factory;
|
|
8418
|
+
|
|
8419
|
+
// Set up custom flush block policy that flushes every 3 keys
|
|
8420
|
+
table_options.flush_block_policy_factory =
|
|
8421
|
+
std::make_shared<CustomFlushBlockPolicyFactory>();
|
|
8422
|
+
|
|
8423
|
+
options_.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
|
8424
|
+
|
|
8425
|
+
std::unique_ptr<SstFileWriter> writer;
|
|
8426
|
+
writer.reset(new SstFileWriter(EnvOptions(), options_));
|
|
8427
|
+
ASSERT_OK(writer->Open(ingest_file));
|
|
8428
|
+
|
|
8429
|
+
// Use bigger value, so that prefetch size limit will be effective
|
|
8430
|
+
auto kvs = generateKVs(/*key_count*/ 100, /* value_size */ 1024);
|
|
8431
|
+
for (const auto& kv : kvs) {
|
|
8432
|
+
ASSERT_OK(writer->Put(kv.first, kv.second));
|
|
8433
|
+
}
|
|
8434
|
+
ASSERT_OK(writer->Finish());
|
|
8435
|
+
writer.reset();
|
|
8436
|
+
|
|
8437
|
+
std::unique_ptr<DB> db;
|
|
8438
|
+
options_.create_if_missing = true;
|
|
8439
|
+
Status s = DB::Open(options_, dbname, &db);
|
|
8440
|
+
ASSERT_OK(s);
|
|
8441
|
+
ASSERT_TRUE(db != nullptr);
|
|
8442
|
+
ColumnFamilyHandle* cfh = nullptr;
|
|
8443
|
+
ASSERT_OK(db->CreateColumnFamily(options_, "new_cf", &cfh));
|
|
8444
|
+
|
|
8445
|
+
IngestExternalFileOptions ifo;
|
|
8446
|
+
s = db->IngestExternalFile(cfh, {ingest_file}, ifo);
|
|
8447
|
+
ASSERT_OK(s);
|
|
8448
|
+
|
|
8449
|
+
std::vector<std::string> key_ranges({"key03", "key05", "key12", "key14"});
|
|
8450
|
+
ReadOptions ro;
|
|
8451
|
+
ro.table_index_factory = user_defined_index_factory.get();
|
|
8452
|
+
Slice ub;
|
|
8453
|
+
ro.iterate_upper_bound = &ub;
|
|
8454
|
+
std::unordered_map<std::string, std::string> property_bag;
|
|
8455
|
+
property_bag["count"] = std::to_string(5);
|
|
8456
|
+
MultiScanArgs scan_options(comparator_);
|
|
8457
|
+
if (is_reverse_comparator_) {
|
|
8458
|
+
std::reverse(key_ranges.begin(), key_ranges.end());
|
|
8459
|
+
}
|
|
8460
|
+
scan_options.insert(key_ranges[0], key_ranges[1], property_bag);
|
|
8461
|
+
scan_options.insert(key_ranges[2], key_ranges[3], property_bag);
|
|
8462
|
+
scan_options.max_prefetch_size = 3500;
|
|
8463
|
+
std::unique_ptr<Iterator> iter(db->NewIterator(ro, cfh));
|
|
8464
|
+
ASSERT_NE(iter, nullptr);
|
|
8465
|
+
iter->Prepare(scan_options);
|
|
8466
|
+
int count = 0;
|
|
8467
|
+
ub = key_ranges[1];
|
|
8468
|
+
iter->Seek(key_ranges[0]);
|
|
8469
|
+
while (iter->status().ok() && iter->Valid()) {
|
|
8470
|
+
ASSERT_GE(comparator_->Compare(iter->key(), key_ranges[0]), 0);
|
|
8471
|
+
ASSERT_LT(comparator_->Compare(iter->key(), key_ranges[1]), 0);
|
|
8472
|
+
count++;
|
|
8473
|
+
iter->Next();
|
|
8474
|
+
}
|
|
8475
|
+
ASSERT_OK(iter->status()) << iter->status().ToString();
|
|
8476
|
+
ASSERT_EQ(count, 2);
|
|
8477
|
+
|
|
8478
|
+
ub = key_ranges[3];
|
|
8479
|
+
iter->Seek(key_ranges[2]);
|
|
8480
|
+
// This should fail due to reaching max_prefetch_size limit
|
|
8481
|
+
ASSERT_EQ(iter->status(), Status::Incomplete());
|
|
8482
|
+
iter.reset();
|
|
8483
|
+
|
|
8484
|
+
// Empty range multiscan error
|
|
8485
|
+
iter.reset(db->NewIterator(ro, cfh));
|
|
8486
|
+
scan_options = MultiScanArgs(comparator_);
|
|
8487
|
+
iter->Prepare(scan_options);
|
|
8488
|
+
ASSERT_EQ(iter->status(), Status::InvalidArgument("Empty MultiScanArgs"));
|
|
8489
|
+
|
|
8490
|
+
// Check no seek key error
|
|
8491
|
+
iter.reset(db->NewIterator(ro, cfh));
|
|
8492
|
+
scan_options = MultiScanArgs(comparator_);
|
|
8493
|
+
scan_options.insert(key_ranges[0], key_ranges[2], property_bag);
|
|
8494
|
+
iter->Prepare(scan_options);
|
|
8495
|
+
iter->SeekToFirst();
|
|
8496
|
+
ASSERT_EQ(iter->status(),
|
|
8497
|
+
Status::InvalidArgument("No seek key for MultiScan"));
|
|
8498
|
+
|
|
8499
|
+
// Seek is not allowed to seen a key that is not following the prepare order
|
|
8500
|
+
iter.reset(db->NewIterator(ro, cfh));
|
|
8501
|
+
ASSERT_NE(iter, nullptr);
|
|
8502
|
+
scan_options.max_prefetch_size = 0;
|
|
8503
|
+
iter->Prepare(scan_options);
|
|
8504
|
+
ub = key_ranges[3];
|
|
8505
|
+
iter->Seek(key_ranges[2]);
|
|
8506
|
+
ASSERT_EQ(
|
|
8507
|
+
iter->status(),
|
|
8508
|
+
Status::InvalidArgument(
|
|
8509
|
+
"Seek target does not match the start of the next prepared range at "
|
|
8510
|
+
"index 0"));
|
|
8511
|
+
ASSERT_FALSE(iter->Valid());
|
|
8512
|
+
iter.reset();
|
|
8513
|
+
|
|
8514
|
+
// limit is equal to start error
|
|
8515
|
+
iter.reset(db->NewIterator(ro, cfh));
|
|
8516
|
+
ASSERT_NE(iter, nullptr);
|
|
8517
|
+
(*scan_options).clear();
|
|
8518
|
+
scan_options.insert(key_ranges[0], key_ranges[0], property_bag);
|
|
8519
|
+
iter->Prepare(scan_options);
|
|
8520
|
+
ASSERT_EQ(iter->status(),
|
|
8521
|
+
Status::InvalidArgument(
|
|
8522
|
+
"Scan start key is large or equal than limit at index 0"));
|
|
8523
|
+
iter.reset();
|
|
8524
|
+
|
|
8525
|
+
// overlapping ranges error
|
|
8526
|
+
iter.reset(db->NewIterator(ro, cfh));
|
|
8527
|
+
ASSERT_NE(iter, nullptr);
|
|
8528
|
+
(*scan_options).clear();
|
|
8529
|
+
scan_options.insert(key_ranges[0], key_ranges[2], property_bag);
|
|
8530
|
+
scan_options.insert(key_ranges[1], key_ranges[3], property_bag);
|
|
8531
|
+
iter->Prepare(scan_options);
|
|
8532
|
+
ASSERT_EQ(iter->status(),
|
|
8533
|
+
Status::InvalidArgument("Overlapping ranges at index 1"));
|
|
8534
|
+
iter.reset();
|
|
8535
|
+
|
|
8536
|
+
// Validate an error is returned if upper bound is not set to the same value
|
|
8537
|
+
// as limit
|
|
8538
|
+
iter.reset(db->NewIterator(ro, cfh));
|
|
8539
|
+
scan_options = MultiScanArgs(comparator_);
|
|
8540
|
+
scan_options.insert(key_ranges[0], key_ranges[1], property_bag);
|
|
8541
|
+
iter->Prepare(scan_options);
|
|
8542
|
+
ub = "";
|
|
8543
|
+
iter->Seek(key_ranges[0]);
|
|
8544
|
+
ASSERT_EQ(iter->status(),
|
|
8545
|
+
Status::InvalidArgument(
|
|
8546
|
+
"Upper bound is not set to the same limit value of the next "
|
|
8547
|
+
"prepared range at index 0"));
|
|
8548
|
+
ASSERT_FALSE(iter->Valid());
|
|
8549
|
+
|
|
8550
|
+
// Validate an error is returned when seek more keys than prepared
|
|
8551
|
+
iter.reset(db->NewIterator(ro, cfh));
|
|
8552
|
+
scan_options = MultiScanArgs(comparator_);
|
|
8553
|
+
scan_options.insert(key_ranges[0], key_ranges[1], property_bag);
|
|
8554
|
+
iter->Prepare(scan_options);
|
|
8555
|
+
ub = key_ranges[1];
|
|
8556
|
+
iter->Seek(key_ranges[0]);
|
|
8557
|
+
ASSERT_OK(iter->status());
|
|
8558
|
+
ASSERT_TRUE(iter->Valid());
|
|
8559
|
+
iter->Seek(key_ranges[2]);
|
|
8560
|
+
ASSERT_EQ(iter->status(),
|
|
8561
|
+
Status::InvalidArgument(
|
|
8562
|
+
"Seek called after exhausting all of the scan ranges"));
|
|
8563
|
+
ASSERT_FALSE(iter->Valid());
|
|
8564
|
+
iter.reset();
|
|
8565
|
+
|
|
8566
|
+
// Check error is returned if upper bound is not set and limit is set
|
|
8567
|
+
ro.iterate_upper_bound = nullptr;
|
|
8568
|
+
iter.reset(db->NewIterator(ro, cfh));
|
|
8569
|
+
scan_options = MultiScanArgs(comparator_);
|
|
8570
|
+
scan_options.insert(key_ranges[0], key_ranges[1], property_bag);
|
|
8571
|
+
iter->Prepare(scan_options);
|
|
8572
|
+
iter->Seek(key_ranges[0]);
|
|
8573
|
+
ASSERT_EQ(iter->status(),
|
|
8574
|
+
Status::InvalidArgument(
|
|
8575
|
+
"Upper bound is not set to the same limit value of the next "
|
|
8576
|
+
"prepared range at index 0"));
|
|
8577
|
+
ASSERT_FALSE(iter->Valid());
|
|
8578
|
+
iter.reset();
|
|
8579
|
+
|
|
8580
|
+
// Upper bound is allowed to be empty, if limit is not set
|
|
8581
|
+
ro.iterate_upper_bound = nullptr;
|
|
8582
|
+
iter.reset(db->NewIterator(ro, cfh));
|
|
8583
|
+
scan_options = MultiScanArgs(comparator_);
|
|
8584
|
+
scan_options.insert(key_ranges[0], property_bag);
|
|
8585
|
+
iter->Prepare(scan_options);
|
|
8586
|
+
iter->Seek(key_ranges[0]);
|
|
8587
|
+
ASSERT_OK(iter->status());
|
|
8588
|
+
ASSERT_TRUE(iter->Valid());
|
|
8589
|
+
iter.reset();
|
|
8590
|
+
|
|
8591
|
+
ASSERT_OK(db->DestroyColumnFamilyHandle(cfh));
|
|
8592
|
+
ASSERT_OK(db->Close());
|
|
8593
|
+
ASSERT_OK(DestroyDB(dbname, options_));
|
|
8594
|
+
}
|
|
8595
|
+
|
|
8596
|
+
TEST_P(UserDefinedIndexTest, ConfigTest) {
|
|
8597
|
+
BlockBasedTableOptions table_options;
|
|
8598
|
+
std::string dbname = test::PerThreadDBPath("user_defined_index_test");
|
|
8599
|
+
std::string ingest_file = dbname + "test.sst";
|
|
8600
|
+
|
|
8601
|
+
// Set up the user-defined index factory
|
|
8602
|
+
auto user_defined_index_factory =
|
|
8603
|
+
std::make_shared<TestUserDefinedIndexFactory>();
|
|
8604
|
+
table_options.user_defined_index_factory = user_defined_index_factory;
|
|
8605
|
+
|
|
8606
|
+
// Set up custom flush block policy that flushes every 3 keys
|
|
8607
|
+
table_options.flush_block_policy_factory =
|
|
8608
|
+
std::make_shared<CustomFlushBlockPolicyFactory>();
|
|
8609
|
+
|
|
8610
|
+
options_.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
|
8611
|
+
|
|
8612
|
+
std::unique_ptr<SstFileWriter> writer;
|
|
8613
|
+
writer.reset(new SstFileWriter(EnvOptions(), options_));
|
|
8614
|
+
ASSERT_OK(writer->Open(ingest_file));
|
|
8615
|
+
|
|
8616
|
+
auto kvs = generateKVs(/*key_count*/ 100);
|
|
8617
|
+
for (const auto& kv : kvs) {
|
|
8618
|
+
ASSERT_OK(writer->Put(kv.first, kv.second));
|
|
8619
|
+
}
|
|
8620
|
+
ASSERT_OK(writer->Finish());
|
|
8621
|
+
writer.reset();
|
|
8622
|
+
|
|
8623
|
+
table_options.user_defined_index_factory.reset();
|
|
8624
|
+
options_.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
|
8625
|
+
// Set up the user-defined index factory
|
|
8626
|
+
ObjectLibrary::Default().get()->AddFactory<UserDefinedIndexFactory>(
|
|
8627
|
+
"test_index", [](const std::string& /* uri */,
|
|
8628
|
+
std::unique_ptr<UserDefinedIndexFactory>* guard,
|
|
8629
|
+
std::string* /* errmsg */) {
|
|
8630
|
+
auto factory = new TestUserDefinedIndexFactory();
|
|
8631
|
+
guard->reset(factory);
|
|
8632
|
+
return guard->get();
|
|
8633
|
+
});
|
|
8634
|
+
ASSERT_OK(GetColumnFamilyOptionsFromString(
|
|
8635
|
+
ConfigOptions(), options_,
|
|
8636
|
+
"block_based_table_factory={user_defined_index_factory=test_index;}",
|
|
8637
|
+
&options_));
|
|
8638
|
+
|
|
8639
|
+
std::unique_ptr<DB> db;
|
|
8640
|
+
options_.create_if_missing = true;
|
|
8641
|
+
Status s = DB::Open(options_, dbname, &db);
|
|
8642
|
+
ASSERT_OK(s);
|
|
8643
|
+
ASSERT_TRUE(db != nullptr);
|
|
8644
|
+
ColumnFamilyHandle* cfh = nullptr;
|
|
8645
|
+
ASSERT_OK(db->CreateColumnFamily(options_, "new_cf", &cfh));
|
|
8646
|
+
|
|
8647
|
+
IngestExternalFileOptions ifo;
|
|
8648
|
+
s = db->IngestExternalFile(cfh, {ingest_file}, ifo);
|
|
8649
|
+
ASSERT_OK(s);
|
|
8650
|
+
|
|
8651
|
+
ReadOptions ro;
|
|
8652
|
+
Slice ub;
|
|
8653
|
+
ro.iterate_upper_bound = &ub;
|
|
8654
|
+
ro.table_index_factory = user_defined_index_factory.get();
|
|
8655
|
+
std::unique_ptr<Iterator> iter(db->NewIterator(ro, cfh));
|
|
8656
|
+
ASSERT_NE(iter, nullptr);
|
|
8657
|
+
MultiScanArgs scan_opts(options_.comparator);
|
|
8658
|
+
std::unordered_map<std::string, std::string> property_bag;
|
|
8659
|
+
property_bag["count"] = std::to_string(25);
|
|
8660
|
+
|
|
8661
|
+
std::vector<std::string> boundaries = {"key10", "key50"};
|
|
8662
|
+
if (is_reverse_comparator_) {
|
|
8663
|
+
std::reverse(boundaries.begin(), boundaries.end());
|
|
8664
|
+
}
|
|
8665
|
+
|
|
8666
|
+
scan_opts.insert(boundaries[0], boundaries[1], std::optional(property_bag));
|
|
8667
|
+
iter->Prepare(scan_opts);
|
|
8668
|
+
// Test that UDI is used to help fetch the number of keys
|
|
8669
|
+
ub = boundaries[1];
|
|
8670
|
+
int key_count = 0;
|
|
8671
|
+
for (iter->Seek(scan_opts.GetScanRanges()[0].range.start.value());
|
|
8672
|
+
iter->Valid(); iter->Next()) {
|
|
8673
|
+
key_count++;
|
|
8674
|
+
}
|
|
8675
|
+
// Number of blocks prepared is based on UDI, it would be slightly higher than
|
|
8676
|
+
// the limit
|
|
8677
|
+
// The index may undercount by 2 blocks
|
|
8678
|
+
ASSERT_EQ(key_count, 29);
|
|
8679
|
+
ASSERT_OK(iter->status());
|
|
8680
|
+
iter.reset();
|
|
8681
|
+
|
|
8682
|
+
ASSERT_OK(db->DestroyColumnFamilyHandle(cfh));
|
|
8683
|
+
ASSERT_OK(db->Close());
|
|
8684
|
+
ASSERT_OK(DestroyDB(dbname, options_));
|
|
8685
|
+
}
|
|
8686
|
+
|
|
8687
|
+
TEST_P(UserDefinedIndexTest, RangeDelete) {
|
|
8688
|
+
BlockBasedTableOptions table_options;
|
|
8689
|
+
options_.num_levels = 50;
|
|
8690
|
+
options_.compaction_style = kCompactionStyleUniversal;
|
|
8691
|
+
options_.disable_auto_compactions = true;
|
|
8692
|
+
std::string dbname = test::PerThreadDBPath("user_defined_index_test");
|
|
8693
|
+
std::string ingest_file = dbname + "test.sst";
|
|
8694
|
+
|
|
8695
|
+
// Set up the user-defined index factory
|
|
8696
|
+
auto user_defined_index_factory =
|
|
8697
|
+
std::make_shared<TestUserDefinedIndexFactory>();
|
|
8698
|
+
table_options.user_defined_index_factory = user_defined_index_factory;
|
|
8699
|
+
|
|
8700
|
+
// Set up custom flush block policy that flushes every 3 keys
|
|
8701
|
+
table_options.flush_block_policy_factory =
|
|
8702
|
+
std::make_shared<CustomFlushBlockPolicyFactory>();
|
|
8703
|
+
|
|
8704
|
+
options_.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
|
8705
|
+
|
|
8706
|
+
auto create_ingestion_data_file = [&](const std::string& filename) {
|
|
8707
|
+
std::unique_ptr<SstFileWriter> writer;
|
|
8708
|
+
writer.reset(new SstFileWriter(EnvOptions(), options_));
|
|
8709
|
+
ASSERT_OK(writer->Open(filename));
|
|
8710
|
+
auto kvs = generateKVs(100);
|
|
8711
|
+
|
|
8712
|
+
for (const auto& kv : kvs) {
|
|
8713
|
+
ASSERT_OK(writer->Put(kv.first, kv.second));
|
|
8714
|
+
}
|
|
8715
|
+
ASSERT_OK(writer->Finish());
|
|
8716
|
+
writer.reset();
|
|
8717
|
+
};
|
|
8718
|
+
|
|
8719
|
+
// Create first ingestion file with data
|
|
8720
|
+
create_ingestion_data_file(ingest_file + "_0");
|
|
8721
|
+
|
|
8722
|
+
// Create second ingestion file with range delete only that covers the first
|
|
8723
|
+
// file to delete all of its keys.
|
|
8724
|
+
{
|
|
8725
|
+
std::unique_ptr<SstFileWriter> writer;
|
|
8726
|
+
writer.reset(new SstFileWriter(EnvOptions(), options_));
|
|
8727
|
+
ASSERT_OK(writer->Open(ingest_file + "_1"));
|
|
8728
|
+
if (is_reverse_comparator_) {
|
|
8729
|
+
ASSERT_OK(writer->DeleteRange("keyz", "key"));
|
|
8730
|
+
} else {
|
|
8731
|
+
ASSERT_OK(writer->DeleteRange("key", "keyz"));
|
|
8732
|
+
}
|
|
8733
|
+
ASSERT_OK(writer->Finish());
|
|
8734
|
+
writer.reset();
|
|
8735
|
+
}
|
|
8736
|
+
|
|
8737
|
+
// Create the second ingestion file with data
|
|
8738
|
+
create_ingestion_data_file(ingest_file + "_2");
|
|
8739
|
+
|
|
8740
|
+
std::unique_ptr<DB> db;
|
|
8741
|
+
options_.create_if_missing = true;
|
|
8742
|
+
Status s = DB::Open(options_, dbname, &db);
|
|
8743
|
+
ASSERT_OK(s);
|
|
8744
|
+
ASSERT_TRUE(db != nullptr);
|
|
8745
|
+
ColumnFamilyHandle* cfh = nullptr;
|
|
8746
|
+
ASSERT_OK(db->CreateColumnFamily(options_, "new_cf", &cfh));
|
|
8747
|
+
|
|
8748
|
+
IngestExternalFileOptions ifo;
|
|
8749
|
+
// ingest first data file key00~key99
|
|
8750
|
+
s = db->IngestExternalFile(cfh, {ingest_file + "_0"}, ifo);
|
|
8751
|
+
ASSERT_OK(s);
|
|
8752
|
+
// ingest delete range (key-keyz) and new data file (key00-key99) together
|
|
8753
|
+
s = db->IngestExternalFile(cfh, {ingest_file + "_1", ingest_file + "_2"},
|
|
8754
|
+
ifo);
|
|
8755
|
+
ASSERT_OK(s);
|
|
8756
|
+
|
|
8757
|
+
std::vector<Slice> range = {
|
|
8758
|
+
Slice("key10"),
|
|
8759
|
+
Slice("key25"),
|
|
8760
|
+
Slice("key80"),
|
|
8761
|
+
Slice("key95"),
|
|
8762
|
+
};
|
|
8763
|
+
|
|
8764
|
+
if (is_reverse_comparator_) {
|
|
8765
|
+
std::reverse(range.begin(), range.end());
|
|
8766
|
+
}
|
|
8767
|
+
|
|
8768
|
+
Slice ub("");
|
|
8769
|
+
ReadOptions ro;
|
|
8770
|
+
ro.iterate_upper_bound = &ub;
|
|
8771
|
+
std::unique_ptr<Iterator> iter(db->NewIterator(ro, cfh));
|
|
8772
|
+
ASSERT_NE(iter, nullptr);
|
|
8773
|
+
|
|
8774
|
+
MultiScanArgs scan_opts(options_.comparator);
|
|
8775
|
+
std::unordered_map<std::string, std::string> property_bag;
|
|
8776
|
+
property_bag["count"] = std::to_string(9);
|
|
8777
|
+
|
|
8778
|
+
std::vector<std::vector<char>> decoded_ranges;
|
|
8779
|
+
for (size_t i = 0; i < range.size() / 2; i++) {
|
|
8780
|
+
scan_opts.insert(range[i * 2], range[i * 2 + 1],
|
|
8781
|
+
std::optional(property_bag));
|
|
8782
|
+
}
|
|
8783
|
+
iter->Prepare(scan_opts);
|
|
8784
|
+
|
|
8785
|
+
for (size_t i = 0; i < range.size() / 2; i++) {
|
|
8786
|
+
// Update upper bound before each seek
|
|
8787
|
+
ub = range[2 * i + 1];
|
|
8788
|
+
auto key_count = 0;
|
|
8789
|
+
for (iter->Seek(range[i * 2]); iter->Valid(); iter->Next()) {
|
|
8790
|
+
key_count++;
|
|
8791
|
+
}
|
|
8792
|
+
ASSERT_OK(iter->status());
|
|
8793
|
+
ASSERT_EQ(key_count, 15);
|
|
8794
|
+
}
|
|
8795
|
+
|
|
8796
|
+
iter.reset();
|
|
8797
|
+
|
|
8798
|
+
ASSERT_OK(db->DestroyColumnFamilyHandle(cfh));
|
|
8799
|
+
ASSERT_OK(db->Close());
|
|
8800
|
+
ASSERT_OK(DestroyDB(dbname, options_));
|
|
8801
|
+
}
|
|
8802
|
+
|
|
8803
|
+
TEST_P(UserDefinedIndexTest, QueryCrossTwoFiles) {
|
|
8804
|
+
BlockBasedTableOptions table_options;
|
|
8805
|
+
options_.num_levels = 50;
|
|
8806
|
+
options_.compaction_style = kCompactionStyleUniversal;
|
|
8807
|
+
options_.disable_auto_compactions = true;
|
|
8808
|
+
options_.sst_partitioner_factory = NewSstPartitionerFixedPrefixFactory(4);
|
|
8809
|
+
std::string dbname = test::PerThreadDBPath("user_defined_index_test");
|
|
8810
|
+
std::string ingest_file = dbname + "test.sst";
|
|
8811
|
+
|
|
8812
|
+
// Set up the user-defined index factory
|
|
8813
|
+
auto user_defined_index_factory =
|
|
8814
|
+
std::make_shared<TestUserDefinedIndexFactory>();
|
|
8815
|
+
table_options.user_defined_index_factory = user_defined_index_factory;
|
|
8816
|
+
|
|
8817
|
+
// Set up custom flush block policy that flushes every 3 keys
|
|
8818
|
+
table_options.flush_block_policy_factory =
|
|
8819
|
+
std::make_shared<CustomFlushBlockPolicyFactory>();
|
|
8820
|
+
|
|
8821
|
+
options_.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
|
8822
|
+
|
|
8823
|
+
auto create_ingestion_data_file = [&](const std::string& filename,
|
|
8824
|
+
const std::string& value) {
|
|
8825
|
+
std::unique_ptr<SstFileWriter> writer;
|
|
8826
|
+
writer.reset(new SstFileWriter(EnvOptions(), options_));
|
|
8827
|
+
ASSERT_OK(writer->Open(filename));
|
|
8828
|
+
auto kvs = generateKVWithValue(100, value);
|
|
8829
|
+
|
|
8830
|
+
for (const auto& kv : kvs) {
|
|
8831
|
+
ASSERT_OK(writer->Put(kv.first, kv.second));
|
|
8832
|
+
}
|
|
8833
|
+
ASSERT_OK(writer->Finish());
|
|
8834
|
+
writer.reset();
|
|
8835
|
+
};
|
|
8836
|
+
|
|
8837
|
+
// Create first ingestion file with data
|
|
8838
|
+
create_ingestion_data_file(ingest_file + "_0", "old");
|
|
8839
|
+
|
|
8840
|
+
std::unique_ptr<DB> db;
|
|
8841
|
+
options_.create_if_missing = true;
|
|
8842
|
+
Status s = DB::Open(options_, dbname, &db);
|
|
8843
|
+
ASSERT_OK(s);
|
|
8844
|
+
ASSERT_TRUE(db != nullptr);
|
|
8845
|
+
ColumnFamilyHandle* cfh = nullptr;
|
|
8846
|
+
ASSERT_OK(db->CreateColumnFamily(options_, "new_cf", &cfh));
|
|
8847
|
+
|
|
8848
|
+
IngestExternalFileOptions ifo;
|
|
8849
|
+
// ingest data file key00~key99
|
|
8850
|
+
s = db->IngestExternalFile(cfh, {ingest_file + "_0"}, ifo);
|
|
8851
|
+
ASSERT_OK(s);
|
|
8852
|
+
|
|
8853
|
+
// Compact the file with SST partitioner, so that files are split into
|
|
8854
|
+
// multiple ones
|
|
8855
|
+
s = db->CompactRange(
|
|
8856
|
+
{.exclusive_manual_compaction = true,
|
|
8857
|
+
.bottommost_level_compaction = BottommostLevelCompaction::kForce},
|
|
8858
|
+
cfh, nullptr, nullptr);
|
|
8859
|
+
ASSERT_OK(s);
|
|
8860
|
+
|
|
8861
|
+
std::vector<Slice> range = {
|
|
8862
|
+
// Each range span across 2 files
|
|
8863
|
+
Slice("key16"),
|
|
8864
|
+
Slice("key24"),
|
|
8865
|
+
Slice("key26"),
|
|
8866
|
+
Slice("key34"),
|
|
8867
|
+
};
|
|
8868
|
+
|
|
8869
|
+
if (is_reverse_comparator_) {
|
|
8870
|
+
std::reverse(range.begin(), range.end());
|
|
8871
|
+
}
|
|
8872
|
+
|
|
8873
|
+
Slice ub("");
|
|
8874
|
+
ReadOptions ro;
|
|
8875
|
+
ro.iterate_upper_bound = &ub;
|
|
8876
|
+
std::unique_ptr<Iterator> iter(db->NewIterator(ro, cfh));
|
|
8877
|
+
ASSERT_NE(iter, nullptr);
|
|
8878
|
+
|
|
8879
|
+
MultiScanArgs scan_opts(options_.comparator);
|
|
8880
|
+
std::unordered_map<std::string, std::string> property_bag;
|
|
8881
|
+
auto read_key_per_range_limit = 2;
|
|
8882
|
+
property_bag["count"] = std::to_string(read_key_per_range_limit);
|
|
8883
|
+
|
|
8884
|
+
for (size_t i = 0; i < range.size() / 2; i++) {
|
|
8885
|
+
scan_opts.insert(range[i * 2], range[i * 2 + 1],
|
|
8886
|
+
std::optional(property_bag));
|
|
8887
|
+
}
|
|
8888
|
+
iter->Prepare(scan_opts);
|
|
8889
|
+
|
|
8890
|
+
for (size_t i = 0; i < range.size() / 2; i++) {
|
|
8891
|
+
// Update upper bound before each seek
|
|
8892
|
+
ub = range[2 * i + 1];
|
|
8893
|
+
auto key_count = 0;
|
|
8894
|
+
for (iter->Seek(range[i * 2]); iter->Valid(); iter->Next()) {
|
|
8895
|
+
key_count++;
|
|
8896
|
+
ASSERT_EQ(iter->value(), "old");
|
|
8897
|
+
if (key_count >= read_key_per_range_limit) {
|
|
8898
|
+
break;
|
|
8899
|
+
}
|
|
8900
|
+
}
|
|
8901
|
+
ASSERT_OK(iter->status());
|
|
8902
|
+
ASSERT_EQ(key_count, read_key_per_range_limit);
|
|
8903
|
+
}
|
|
8904
|
+
|
|
8905
|
+
// Create another ingestion file with range delete only that covers the first
|
|
8906
|
+
// file to delete all of its keys.
|
|
8907
|
+
{
|
|
8908
|
+
std::unique_ptr<SstFileWriter> writer;
|
|
8909
|
+
writer.reset(new SstFileWriter(EnvOptions(), options_));
|
|
8910
|
+
ASSERT_OK(writer->Open(ingest_file + "_1"));
|
|
8911
|
+
if (is_reverse_comparator_) {
|
|
8912
|
+
ASSERT_OK(writer->DeleteRange("keyz", "key"));
|
|
8913
|
+
} else {
|
|
8914
|
+
ASSERT_OK(writer->DeleteRange("key", "keyz"));
|
|
8915
|
+
}
|
|
8916
|
+
ASSERT_OK(writer->Finish());
|
|
8917
|
+
writer.reset();
|
|
8918
|
+
}
|
|
8919
|
+
s = db->IngestExternalFile(cfh, {ingest_file + "_1"}, ifo);
|
|
8920
|
+
ASSERT_OK(s);
|
|
8921
|
+
|
|
8922
|
+
// ingest new data
|
|
8923
|
+
create_ingestion_data_file(ingest_file + "_2", "new");
|
|
8924
|
+
s = db->IngestExternalFile(cfh, {ingest_file + "_2"}, ifo);
|
|
8925
|
+
ASSERT_OK(s);
|
|
8926
|
+
|
|
8927
|
+
iter.reset(db->NewIterator(ro, cfh));
|
|
8928
|
+
ASSERT_NE(iter, nullptr);
|
|
8929
|
+
ASSERT_OK(iter->status());
|
|
8930
|
+
|
|
8931
|
+
iter->Prepare(scan_opts);
|
|
8932
|
+
|
|
8933
|
+
for (size_t i = 0; i < range.size() / 2; i++) {
|
|
8934
|
+
// Update upper bound before each seek
|
|
8935
|
+
ub = range[2 * i + 1];
|
|
8936
|
+
auto key_count = 0;
|
|
8937
|
+
for (iter->Seek(range[i * 2]); iter->Valid(); iter->Next()) {
|
|
8938
|
+
key_count++;
|
|
8939
|
+
ASSERT_EQ(iter->value(), "new");
|
|
8940
|
+
if (key_count >= read_key_per_range_limit) {
|
|
8941
|
+
break;
|
|
8942
|
+
}
|
|
8943
|
+
}
|
|
8944
|
+
ASSERT_OK(iter->status());
|
|
8945
|
+
ASSERT_EQ(key_count, read_key_per_range_limit);
|
|
8946
|
+
}
|
|
8947
|
+
|
|
8948
|
+
iter.reset();
|
|
8949
|
+
|
|
8950
|
+
ASSERT_OK(db->DestroyColumnFamilyHandle(cfh));
|
|
8951
|
+
ASSERT_OK(db->Close());
|
|
8952
|
+
ASSERT_OK(DestroyDB(dbname, options_));
|
|
8953
|
+
}
|
|
8954
|
+
|
|
8955
|
+
INSTANTIATE_TEST_CASE_P(UserDefinedIndexTest, UserDefinedIndexTest,
|
|
8956
|
+
::testing::Values(BytewiseComparator(),
|
|
8957
|
+
ReverseBytewiseComparator()));
|
|
8958
|
+
|
|
8959
|
+
struct UserDefinedIndexStressTestParam {
|
|
8960
|
+
const Comparator* comparator;
|
|
8961
|
+
bool enable_udi;
|
|
8962
|
+
bool enable_compaction_with_sst_partitioner;
|
|
8963
|
+
|
|
8964
|
+
using UserDefinedIndexStressTestTuple =
|
|
8965
|
+
std::tuple<const Comparator*, bool, bool>;
|
|
8966
|
+
|
|
8967
|
+
UserDefinedIndexStressTestParam(const UserDefinedIndexStressTestTuple& tuple)
|
|
8968
|
+
: comparator(std::get<0>(tuple)),
|
|
8969
|
+
enable_udi(std::get<1>(tuple)),
|
|
8970
|
+
enable_compaction_with_sst_partitioner(std::get<2>(tuple)) {}
|
|
8971
|
+
};
|
|
8972
|
+
|
|
8973
|
+
std::ostream& operator<<(std::ostream& os,
|
|
8974
|
+
const UserDefinedIndexStressTestParam& param) {
|
|
8975
|
+
return os << "UserDefinedIndexStressTestParam{comparator="
|
|
8976
|
+
<< (param.comparator ? param.comparator->Name() : "nullptr")
|
|
8977
|
+
<< ", enable_udi=" << param.enable_udi
|
|
8978
|
+
<< ", enable_compaction_with_sst_partitioner="
|
|
8979
|
+
<< param.enable_compaction_with_sst_partitioner << "}";
|
|
8980
|
+
}
|
|
8981
|
+
|
|
8982
|
+
constexpr auto kVerbose = false;
|
|
8983
|
+
|
|
8984
|
+
struct DataRange {
|
|
8985
|
+
size_t start; // inclusive
|
|
8986
|
+
size_t end; // exclusive
|
|
8987
|
+
std::string value;
|
|
8988
|
+
bool is_range_delete;
|
|
8989
|
+
bool skipped;
|
|
8990
|
+
size_t scan_key_count_limit;
|
|
8991
|
+
std::string start_key;
|
|
8992
|
+
std::string end_key;
|
|
8993
|
+
|
|
8994
|
+
// print the range in human readable format
|
|
8995
|
+
std::string ToString() const {
|
|
8996
|
+
std::ostringstream oss;
|
|
8997
|
+
oss << "[" << start << ", " << end << "), value: " << value
|
|
8998
|
+
<< ", is_range_delete: " << is_range_delete << ", skipped: " << skipped
|
|
8999
|
+
<< ", scan_key_count_limit: " << scan_key_count_limit
|
|
9000
|
+
<< ", start_key: " << start_key << ", end_key: " << end_key;
|
|
9001
|
+
return oss.str();
|
|
9002
|
+
}
|
|
9003
|
+
};
|
|
9004
|
+
class UserDefinedIndexStressTest
|
|
9005
|
+
: public UserDefinedIndexTestBase,
|
|
9006
|
+
public testing::WithParamInterface<
|
|
9007
|
+
UserDefinedIndexStressTestParam::UserDefinedIndexStressTestTuple> {
|
|
9008
|
+
public:
|
|
9009
|
+
void SetUp() override {
|
|
9010
|
+
rand_seed_ = static_cast<uint32_t>(
|
|
9011
|
+
std::chrono::duration_cast<std::chrono::nanoseconds>(
|
|
9012
|
+
std::chrono::system_clock::now().time_since_epoch())
|
|
9013
|
+
.count());
|
|
9014
|
+
|
|
9015
|
+
std::cout << "Random seed: " << rand_seed_ << std::endl;
|
|
9016
|
+
|
|
9017
|
+
rnd = Random(rand_seed_);
|
|
9018
|
+
UserDefinedIndexStressTestParam param = GetParam();
|
|
9019
|
+
comparator_ = param.comparator;
|
|
9020
|
+
enable_udi_ = param.enable_udi;
|
|
9021
|
+
enable_compaction_with_sst_partitioner_ =
|
|
9022
|
+
param.enable_compaction_with_sst_partitioner;
|
|
9023
|
+
options_.comparator = comparator_;
|
|
9024
|
+
is_reverse_comparator_ = comparator_ == ReverseBytewiseComparator();
|
|
9025
|
+
options_.compaction_style = kCompactionStyleUniversal;
|
|
9026
|
+
|
|
9027
|
+
// Set up custom flush block policy that flushes every 3 keys
|
|
9028
|
+
table_options_.flush_block_policy_factory =
|
|
9029
|
+
std::make_shared<CustomFlushBlockPolicyFactory>();
|
|
9030
|
+
|
|
9031
|
+
options_.table_factory.reset(NewBlockBasedTableFactory(table_options_));
|
|
9032
|
+
}
|
|
9033
|
+
|
|
9034
|
+
void TearDown() override {
|
|
9035
|
+
ASSERT_OK(db_->DestroyColumnFamilyHandle(ingest_cfh_));
|
|
9036
|
+
ASSERT_OK(db_->DestroyColumnFamilyHandle(regular_cfh_));
|
|
9037
|
+
|
|
9038
|
+
ASSERT_OK(db_->Close());
|
|
9039
|
+
ASSERT_OK(DestroyDB(dbname_, options_));
|
|
9040
|
+
}
|
|
9041
|
+
|
|
9042
|
+
protected:
|
|
9043
|
+
static constexpr auto kKeyRange = 100;
|
|
9044
|
+
bool enable_udi_{};
|
|
9045
|
+
bool enable_compaction_with_sst_partitioner_{};
|
|
9046
|
+
uint32_t rand_seed_{};
|
|
9047
|
+
std::shared_ptr<UserDefinedIndexFactory> user_defined_index_factory_;
|
|
9048
|
+
BlockBasedTableOptions table_options_;
|
|
9049
|
+
const Comparator* comparator_{};
|
|
9050
|
+
bool is_reverse_comparator_{};
|
|
9051
|
+
Random rnd{0};
|
|
9052
|
+
ColumnFamilyHandle* ingest_cfh_ = nullptr;
|
|
9053
|
+
ColumnFamilyHandle* regular_cfh_ = nullptr;
|
|
9054
|
+
std::unique_ptr<DB> db_;
|
|
9055
|
+
std::vector<std::vector<DataRange>> ranges_in_levels_;
|
|
9056
|
+
std::string dbname_;
|
|
9057
|
+
|
|
9058
|
+
void SetupDB(const std::string& dbname) {
|
|
9059
|
+
options_.create_if_missing = true;
|
|
9060
|
+
options_.disable_auto_compactions = true;
|
|
9061
|
+
Status s = DB::Open(options_, dbname, &db_);
|
|
9062
|
+
ASSERT_OK(s);
|
|
9063
|
+
ASSERT_TRUE(db_ != nullptr);
|
|
9064
|
+
if (enable_compaction_with_sst_partitioner_) {
|
|
9065
|
+
// Use a SST partitioner to create multiple files, use the first 4 bytes
|
|
9066
|
+
// of key to partition the file, The key is formatted with 2 digit
|
|
9067
|
+
// following "key" string, e.g. key01, key99
|
|
9068
|
+
options_.sst_partitioner_factory = NewSstPartitionerFixedPrefixFactory(4);
|
|
9069
|
+
}
|
|
9070
|
+
|
|
9071
|
+
ASSERT_OK(db_->CreateColumnFamily(options_, "regular_cf", ®ular_cfh_));
|
|
9072
|
+
|
|
9073
|
+
if (enable_udi_) {
|
|
9074
|
+
// Set up the user-defined index factory
|
|
9075
|
+
user_defined_index_factory_ =
|
|
9076
|
+
std::make_shared<TestUserDefinedIndexFactory>();
|
|
9077
|
+
table_options_.user_defined_index_factory = user_defined_index_factory_;
|
|
9078
|
+
}
|
|
9079
|
+
|
|
9080
|
+
options_.table_factory.reset(NewBlockBasedTableFactory(table_options_));
|
|
9081
|
+
ASSERT_OK(db_->CreateColumnFamily(options_, "ingest_cf", &ingest_cfh_));
|
|
9082
|
+
}
|
|
9083
|
+
|
|
9084
|
+
template <typename T>
|
|
9085
|
+
std::string FormatKey(T i) {
|
|
9086
|
+
std::stringstream ss;
|
|
9087
|
+
ss << std::setw(2) << std::setfill('0') << i;
|
|
9088
|
+
return "key" + ss.str();
|
|
9089
|
+
}
|
|
9090
|
+
|
|
9091
|
+
std::vector<DataRange> GenerateKeyRanges(size_t range_count,
|
|
9092
|
+
int skip_range_count,
|
|
9093
|
+
const std::string& value) {
|
|
9094
|
+
std::set<size_t> boundaries;
|
|
9095
|
+
// generate n + 1 number of unique boundaries to form n contiguoes ranges
|
|
9096
|
+
while (boundaries.size() < range_count + 1) {
|
|
9097
|
+
boundaries.insert(rnd.Uniform(kKeyRange));
|
|
9098
|
+
}
|
|
9099
|
+
std::vector<size_t> sorted_boundaries(boundaries.begin(), boundaries.end());
|
|
9100
|
+
if (is_reverse_comparator_) {
|
|
9101
|
+
std::reverse(sorted_boundaries.begin(), sorted_boundaries.end());
|
|
9102
|
+
}
|
|
9103
|
+
auto ranges = std::vector<DataRange>();
|
|
9104
|
+
std::optional<size_t> prev_bound;
|
|
9105
|
+
for (auto it = sorted_boundaries.begin(); it != sorted_boundaries.end();
|
|
9106
|
+
it++) {
|
|
9107
|
+
if (prev_bound.has_value()) {
|
|
9108
|
+
ranges.push_back({.start = prev_bound.value(),
|
|
9109
|
+
.end = *it,
|
|
9110
|
+
.value = value,
|
|
9111
|
+
.is_range_delete = rnd.OneIn(6),
|
|
9112
|
+
.skipped = false,
|
|
9113
|
+
.scan_key_count_limit = rnd.Uniform(10) + 1,
|
|
9114
|
+
.start_key = FormatKey(prev_bound.value()),
|
|
9115
|
+
.end_key = FormatKey(*it)});
|
|
9116
|
+
}
|
|
9117
|
+
prev_bound = *it;
|
|
9118
|
+
}
|
|
9119
|
+
// skipped some of them
|
|
9120
|
+
for (int j = 0; j < skip_range_count; j++) {
|
|
9121
|
+
ranges[rnd.Uniform(static_cast<uint32_t>(range_count))].skipped = true;
|
|
9122
|
+
}
|
|
9123
|
+
|
|
9124
|
+
if (kVerbose) {
|
|
9125
|
+
for (auto const& range : ranges) {
|
|
9126
|
+
std::cout << range.ToString() << std::endl;
|
|
9127
|
+
}
|
|
9128
|
+
}
|
|
9129
|
+
|
|
9130
|
+
return ranges;
|
|
9131
|
+
}
|
|
9132
|
+
|
|
9133
|
+
void CreateSstFileWithRanges(const std::string& ingest_file,
|
|
9134
|
+
const DataRange& range) {
|
|
9135
|
+
std::unique_ptr<SstFileWriter> writer =
|
|
9136
|
+
std::make_unique<SstFileWriter>(EnvOptions(), options_);
|
|
9137
|
+
ASSERT_OK(writer->Open(ingest_file));
|
|
9138
|
+
|
|
9139
|
+
assert(range.start != range.end);
|
|
9140
|
+
|
|
9141
|
+
if (range.is_range_delete) {
|
|
9142
|
+
ASSERT_OK(writer->DeleteRange(range.start_key, range.end_key));
|
|
9143
|
+
} else {
|
|
9144
|
+
for (size_t i = range.start; i != range.end;) {
|
|
9145
|
+
auto key = FormatKey(i);
|
|
9146
|
+
range.start < range.end ? i++ : i--;
|
|
9147
|
+
ASSERT_OK(writer->Put(key, range.value));
|
|
9148
|
+
}
|
|
9149
|
+
}
|
|
9150
|
+
ASSERT_OK(writer->Finish()) << range.ToString();
|
|
9151
|
+
}
|
|
9152
|
+
|
|
9153
|
+
void RangeScan(std::unique_ptr<Iterator>& iter,
|
|
9154
|
+
const std::vector<DataRange>& ranges, Slice& upper_bound,
|
|
9155
|
+
std::vector<std::pair<std::string, std::string>>& result,
|
|
9156
|
+
bool use_multi_scan) {
|
|
9157
|
+
ASSERT_NE(iter, nullptr);
|
|
9158
|
+
ASSERT_OK(iter->status());
|
|
9159
|
+
ASSERT_TRUE(!ranges.empty());
|
|
9160
|
+
|
|
9161
|
+
MultiScanArgs scan_opts(options_.comparator);
|
|
9162
|
+
std::unordered_map<std::string, std::string> property_bag;
|
|
9163
|
+
if (use_multi_scan) {
|
|
9164
|
+
for (auto const& range : ranges) {
|
|
9165
|
+
if (range.skipped) {
|
|
9166
|
+
continue;
|
|
9167
|
+
}
|
|
9168
|
+
property_bag["count"] = std::to_string(range.scan_key_count_limit);
|
|
9169
|
+
scan_opts.insert(range.start_key, range.end_key, property_bag);
|
|
9170
|
+
// print range start end key
|
|
9171
|
+
if (kVerbose) {
|
|
9172
|
+
std::cout << "range start " << range.start_key << " end "
|
|
9173
|
+
<< range.end_key << std::endl;
|
|
9174
|
+
}
|
|
9175
|
+
}
|
|
9176
|
+
iter->Prepare(scan_opts);
|
|
9177
|
+
ASSERT_OK(iter->status());
|
|
9178
|
+
}
|
|
9179
|
+
|
|
9180
|
+
for (auto const& range : ranges) {
|
|
9181
|
+
if (range.skipped) {
|
|
9182
|
+
continue;
|
|
9183
|
+
}
|
|
9184
|
+
size_t scan_key_count = 0;
|
|
9185
|
+
if (kVerbose) {
|
|
9186
|
+
std::cout << "seek key " << range.start_key << std::endl;
|
|
9187
|
+
}
|
|
9188
|
+
upper_bound = range.end_key;
|
|
9189
|
+
for (iter->Seek(range.start_key);
|
|
9190
|
+
iter->Valid() && scan_key_count < range.scan_key_count_limit;
|
|
9191
|
+
iter->Next()) {
|
|
9192
|
+
if (kVerbose) {
|
|
9193
|
+
std::cout << "key " << iter->key().ToString() << " value "
|
|
9194
|
+
<< iter->value().ToString() << std::endl;
|
|
9195
|
+
}
|
|
9196
|
+
result.emplace_back(iter->key().ToString(), iter->value().ToString());
|
|
9197
|
+
scan_key_count++;
|
|
9198
|
+
}
|
|
9199
|
+
ASSERT_OK(iter->status());
|
|
9200
|
+
}
|
|
9201
|
+
}
|
|
9202
|
+
|
|
9203
|
+
void AddDataToRegularCF() {
|
|
9204
|
+
for (auto const& ranges_in_level : ranges_in_levels_) {
|
|
9205
|
+
for (auto const& range : ranges_in_level) {
|
|
9206
|
+
if (!range.skipped) {
|
|
9207
|
+
for (auto i = range.start; i != range.end;
|
|
9208
|
+
range.start < range.end ? i++ : i--) {
|
|
9209
|
+
if (range.is_range_delete) {
|
|
9210
|
+
ASSERT_OK(
|
|
9211
|
+
db_->Delete(WriteOptions(), regular_cfh_, FormatKey(i)));
|
|
9212
|
+
} else {
|
|
9213
|
+
ASSERT_OK(db_->Put(WriteOptions(), regular_cfh_, FormatKey(i),
|
|
9214
|
+
range.value));
|
|
9215
|
+
}
|
|
9216
|
+
}
|
|
9217
|
+
}
|
|
9218
|
+
}
|
|
9219
|
+
}
|
|
9220
|
+
ASSERT_OK(db_->Flush(FlushOptions(), regular_cfh_));
|
|
9221
|
+
}
|
|
9222
|
+
|
|
9223
|
+
void ValidateQueryResult() {
|
|
9224
|
+
// Query both CF with same range scan and validate result are same
|
|
9225
|
+
for (auto i = 0; i < 200; i++) {
|
|
9226
|
+
if (kVerbose) {
|
|
9227
|
+
std::cout << "iteration " << i << std::endl;
|
|
9228
|
+
}
|
|
9229
|
+
// randomly generate 1 to 3 ranges
|
|
9230
|
+
auto ranges = GenerateKeyRanges(rnd.Uniform(3) + 4, 2, "");
|
|
9231
|
+
|
|
9232
|
+
// Query regular CF
|
|
9233
|
+
std::vector<std::pair<std::string, std::string>> expected_result;
|
|
9234
|
+
Slice upper_bound("");
|
|
9235
|
+
ReadOptions ro;
|
|
9236
|
+
ro.iterate_upper_bound = &upper_bound;
|
|
9237
|
+
|
|
9238
|
+
std::unique_ptr<Iterator> iter(db_->NewIterator(ro, regular_cfh_));
|
|
9239
|
+
ASSERT_NO_FATAL_FAILURE(
|
|
9240
|
+
RangeScan(iter, ranges, upper_bound, expected_result, false));
|
|
9241
|
+
ASSERT_OK(iter->status());
|
|
9242
|
+
|
|
9243
|
+
// Query ingest CF
|
|
9244
|
+
iter.reset(db_->NewIterator(ro, ingest_cfh_));
|
|
9245
|
+
std::vector<std::pair<std::string, std::string>> ingest_cf_result;
|
|
9246
|
+
ASSERT_NO_FATAL_FAILURE(
|
|
9247
|
+
RangeScan(iter, ranges, upper_bound, ingest_cf_result, false));
|
|
9248
|
+
|
|
9249
|
+
ASSERT_EQ(expected_result, ingest_cf_result);
|
|
9250
|
+
ASSERT_OK(iter->status());
|
|
9251
|
+
|
|
9252
|
+
// Query ingest CF with UDI if it is enabled
|
|
9253
|
+
if (enable_udi_) {
|
|
9254
|
+
ro.table_index_factory = user_defined_index_factory_.get();
|
|
9255
|
+
}
|
|
9256
|
+
|
|
9257
|
+
iter.reset(db_->NewIterator(ro, ingest_cfh_));
|
|
9258
|
+
std::vector<std::pair<std::string, std::string>>
|
|
9259
|
+
ingest_cf_multi_scan_result;
|
|
9260
|
+
ASSERT_NO_FATAL_FAILURE(RangeScan(iter, ranges, upper_bound,
|
|
9261
|
+
ingest_cf_multi_scan_result, true));
|
|
9262
|
+
ASSERT_EQ(expected_result, ingest_cf_multi_scan_result);
|
|
9263
|
+
ASSERT_OK(iter->status());
|
|
9264
|
+
}
|
|
9265
|
+
}
|
|
9266
|
+
|
|
9267
|
+
void IngestFilesInOneLevel(const std::vector<DataRange>& ranges_in_level,
|
|
9268
|
+
const std::string& ingest_file_name_prefix,
|
|
9269
|
+
size_t& ingest_file_count,
|
|
9270
|
+
const IngestExternalFileOptions& ifo) {
|
|
9271
|
+
std::vector<std::string> ingest_files;
|
|
9272
|
+
// Generate SST file and bulk load them one level at a time
|
|
9273
|
+
for (auto const& range : ranges_in_level) {
|
|
9274
|
+
if (!range.skipped) {
|
|
9275
|
+
ASSERT_NO_FATAL_FAILURE(CreateSstFileWithRanges(
|
|
9276
|
+
ingest_file_name_prefix + std::to_string(ingest_file_count),
|
|
9277
|
+
range));
|
|
9278
|
+
ingest_files.push_back(ingest_file_name_prefix +
|
|
9279
|
+
std::to_string(ingest_file_count));
|
|
9280
|
+
ingest_file_count++;
|
|
9281
|
+
}
|
|
9282
|
+
}
|
|
9283
|
+
|
|
9284
|
+
ASSERT_OK(db_->IngestExternalFile(ingest_cfh_, ingest_files, ifo));
|
|
9285
|
+
}
|
|
9286
|
+
|
|
9287
|
+
void IngestDataToCF() {
|
|
9288
|
+
IngestExternalFileOptions ifo;
|
|
9289
|
+
ifo.snapshot_consistency = false;
|
|
9290
|
+
auto ingest_file_name_prefix = dbname_ + "ingest_file_";
|
|
9291
|
+
size_t ingest_file_count = 0;
|
|
9292
|
+
for (auto const& ranges_in_level : ranges_in_levels_) {
|
|
9293
|
+
ASSERT_NO_FATAL_FAILURE(IngestFilesInOneLevel(
|
|
9294
|
+
ranges_in_level, ingest_file_name_prefix, ingest_file_count, ifo));
|
|
9295
|
+
}
|
|
9296
|
+
|
|
9297
|
+
ASSERT_GE(ingest_file_count, 0);
|
|
9298
|
+
}
|
|
9299
|
+
|
|
9300
|
+
void CompactIngestedCF() {
|
|
9301
|
+
auto s = db_->CompactRange(
|
|
9302
|
+
{.exclusive_manual_compaction = true,
|
|
9303
|
+
.bottommost_level_compaction = BottommostLevelCompaction::kForce},
|
|
9304
|
+
ingest_cfh_, nullptr, nullptr);
|
|
9305
|
+
ASSERT_OK(s);
|
|
9306
|
+
}
|
|
9307
|
+
};
|
|
9308
|
+
|
|
9309
|
+
// TODO(xingbo)
|
|
9310
|
+
// This test is disabled due to following test case condition:
|
|
9311
|
+
// level n: delete range 4-6
|
|
9312
|
+
// level n+1: data range 0-------10
|
|
9313
|
+
// query: 3-9, count=2.
|
|
9314
|
+
// Becuase query count == 2, level n+1 would only prepare 3-5. but since 4-6
|
|
9315
|
+
// got deleted in the upper level, they are not returned, so only 3 is
|
|
9316
|
+
// returned. Meantime the query should have return [3, 6]
|
|
9317
|
+
// One way to fix this is by preparing more data blocks once prepared blocks are
|
|
9318
|
+
// exhausted, but upper bound is not reached yet.
|
|
9319
|
+
// This requires following changes:
|
|
9320
|
+
// 1. Fix out of bound flag in block table iterator. Only set it if the key is
|
|
9321
|
+
// larger than the upper bound.
|
|
9322
|
+
// 2. Refactor the prepared block single dimension vector into 2 dimension of
|
|
9323
|
+
// vectors, so that more blocks could be prepared if needed.
|
|
9324
|
+
TEST_P(UserDefinedIndexStressTest, DISABLED_PartialDeleteRange) {
|
|
9325
|
+
// Create 2 column families. One use normal put/del, the other uses sst
|
|
9326
|
+
// ingest Randomly generate multiple non overlapping range for multiple
|
|
9327
|
+
// levels Range scan same range between the 2 CF and validate the result is
|
|
9328
|
+
// same
|
|
9329
|
+
SCOPED_TRACE("Start with random seed: " + std::to_string(rand_seed_));
|
|
9330
|
+
dbname_ =
|
|
9331
|
+
test::PerThreadDBPath("UserDefinedIndexStressTest_PartialDeleteRange");
|
|
9332
|
+
SCOPED_TRACE("dbname: " + dbname_);
|
|
9333
|
+
ASSERT_NO_FATAL_FAILURE(SetupDB(dbname_));
|
|
9334
|
+
|
|
9335
|
+
for (int i = 0; i < 5; i++) {
|
|
9336
|
+
ranges_in_levels_.push_back(
|
|
9337
|
+
GenerateKeyRanges(rnd.Uniform(3) + 4, 2,
|
|
9338
|
+
"L" + std::to_string(options_.num_levels - 1 - i)));
|
|
9339
|
+
}
|
|
9340
|
+
|
|
9341
|
+
ASSERT_NO_FATAL_FAILURE(IngestDataToCF());
|
|
9342
|
+
|
|
9343
|
+
if (enable_compaction_with_sst_partitioner_) {
|
|
9344
|
+
ASSERT_NO_FATAL_FAILURE(CompactIngestedCF());
|
|
9345
|
+
}
|
|
9346
|
+
|
|
9347
|
+
ASSERT_NO_FATAL_FAILURE(AddDataToRegularCF());
|
|
9348
|
+
|
|
9349
|
+
ASSERT_NO_FATAL_FAILURE(ValidateQueryResult());
|
|
9350
|
+
}
|
|
9351
|
+
|
|
9352
|
+
TEST_P(UserDefinedIndexStressTest, DeleteRange) {
|
|
9353
|
+
// Create 2 column families. One use normal put/del, the other uses sst
|
|
9354
|
+
// ingest.
|
|
9355
|
+
// Test the case where there are 3 levels, the middle level is a delete range
|
|
9356
|
+
// file that span across the entire key space.
|
|
9357
|
+
// Range scan same range between the 2 CF and validate the result is same
|
|
9358
|
+
SCOPED_TRACE("Start with random seed: " + std::to_string(rand_seed_));
|
|
9359
|
+
dbname_ = test::PerThreadDBPath("UserDefinedIndexStressTest_DeleteRange");
|
|
9360
|
+
SCOPED_TRACE("dbname: " + dbname_);
|
|
9361
|
+
ASSERT_NO_FATAL_FAILURE(SetupDB(dbname_));
|
|
9362
|
+
|
|
9363
|
+
// Test 3 levels.
|
|
9364
|
+
// bottom level is normal data files.
|
|
9365
|
+
ranges_in_levels_.push_back(GenerateKeyRanges(rnd.Uniform(3) + 4, 2, "L6"));
|
|
9366
|
+
// middle level delete range between each level
|
|
9367
|
+
if (is_reverse_comparator_) {
|
|
9368
|
+
ranges_in_levels_.push_back({{.start = 100,
|
|
9369
|
+
.end = 0,
|
|
9370
|
+
.is_range_delete = true,
|
|
9371
|
+
.skipped = false,
|
|
9372
|
+
.start_key = "keyz",
|
|
9373
|
+
.end_key = "key"}});
|
|
9374
|
+
} else {
|
|
9375
|
+
ranges_in_levels_.push_back({{.start = 0,
|
|
9376
|
+
.end = 100,
|
|
9377
|
+
.is_range_delete = true,
|
|
9378
|
+
.skipped = false,
|
|
9379
|
+
.start_key = "key",
|
|
9380
|
+
.end_key = "keyz"}});
|
|
9381
|
+
}
|
|
9382
|
+
// Top level is normal data files
|
|
9383
|
+
ranges_in_levels_.push_back(GenerateKeyRanges(rnd.Uniform(3) + 4, 2, "L4"));
|
|
9384
|
+
|
|
9385
|
+
IngestExternalFileOptions ifo;
|
|
9386
|
+
ifo.snapshot_consistency = false;
|
|
9387
|
+
auto ingest_file_name_prefix = dbname_ + "ingest_file_";
|
|
9388
|
+
size_t ingest_file_count = 0;
|
|
9389
|
+
auto first_level = true;
|
|
9390
|
+
for (auto const& ranges_in_level : ranges_in_levels_) {
|
|
9391
|
+
ASSERT_NO_FATAL_FAILURE(IngestFilesInOneLevel(
|
|
9392
|
+
ranges_in_level, ingest_file_name_prefix, ingest_file_count, ifo));
|
|
9393
|
+
if (first_level) {
|
|
9394
|
+
first_level = false;
|
|
9395
|
+
if (enable_compaction_with_sst_partitioner_) {
|
|
9396
|
+
// When compaction is enabled, do a compaction at the first level
|
|
9397
|
+
ASSERT_NO_FATAL_FAILURE(CompactIngestedCF());
|
|
9398
|
+
}
|
|
9399
|
+
}
|
|
9400
|
+
}
|
|
9401
|
+
|
|
9402
|
+
ASSERT_NO_FATAL_FAILURE(AddDataToRegularCF());
|
|
9403
|
+
|
|
9404
|
+
ASSERT_NO_FATAL_FAILURE(ValidateQueryResult());
|
|
9405
|
+
}
|
|
9406
|
+
|
|
9407
|
+
INSTANTIATE_TEST_CASE_P(
|
|
9408
|
+
UserDefinedIndexStressTest, UserDefinedIndexStressTest,
|
|
9409
|
+
testing::Combine(testing::Values(BytewiseComparator(),
|
|
9410
|
+
ReverseBytewiseComparator()),
|
|
9411
|
+
testing::Bool(), testing::Bool()));
|
|
8027
9412
|
} // namespace ROCKSDB_NAMESPACE
|
|
8028
9413
|
|
|
8029
9414
|
int main(int argc, char** argv) {
|