1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
6 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
7 // Use of this source code is governed by a BSD-style license that can be
8 // found in the LICENSE file. See the AUTHORS file for names of contributors.
13 #include <unordered_map>
15 #include "cache/lru_cache.h"
16 #include "cache/sharded_cache.h"
17 #include "options/options_helper.h"
18 #include "options/options_parser.h"
19 #include "port/port.h"
20 #include "rocksdb/cache.h"
21 #include "rocksdb/convenience.h"
22 #include "rocksdb/file_checksum.h"
23 #include "rocksdb/memtablerep.h"
24 #include "rocksdb/utilities/leveldb_options.h"
25 #include "rocksdb/utilities/object_registry.h"
26 #include "rocksdb/utilities/options_type.h"
27 #include "table/block_based/filter_policy_internal.h"
28 #include "test_util/testharness.h"
29 #include "test_util/testutil.h"
30 #include "util/random.h"
31 #include "util/stderr_logger.h"
32 #include "util/string_util.h"
33 #include "utilities/merge_operators/bytesxor.h"
34 #include "utilities/merge_operators/sortlist.h"
35 #include "utilities/merge_operators/string_append/stringappend.h"
36 #include "utilities/merge_operators/string_append/stringappend2.h"
39 bool FLAGS_enable_print
= false;
41 #include "util/gflags_compat.h"
42 using GFLAGS_NAMESPACE::ParseCommandLineFlags
;
43 DEFINE_bool(enable_print
, false, "Print options generated to console.");
46 namespace ROCKSDB_NAMESPACE
{
48 class OptionsTest
: public testing::Test
{};
50 class UnregisteredTableFactory
: public TableFactory
{
52 UnregisteredTableFactory() {}
53 const char* Name() const override
{ return "Unregistered"; }
54 using TableFactory::NewTableReader
;
55 Status
NewTableReader(const ReadOptions
&, const TableReaderOptions
&,
56 std::unique_ptr
<RandomAccessFileReader
>&&, uint64_t,
57 std::unique_ptr
<TableReader
>*, bool) const override
{
58 return Status::NotSupported();
60 TableBuilder
* NewTableBuilder(const TableBuilderOptions
&,
61 WritableFileWriter
*) const override
{
66 #ifndef ROCKSDB_LITE // GetOptionsFromMap is not supported in ROCKSDB_LITE
67 TEST_F(OptionsTest
, GetOptionsFromMapTest
) {
68 std::unordered_map
<std::string
, std::string
> cf_options_map
= {
69 {"write_buffer_size", "1"},
70 {"max_write_buffer_number", "2"},
71 {"min_write_buffer_number_to_merge", "3"},
72 {"max_write_buffer_number_to_maintain", "99"},
73 {"max_write_buffer_size_to_maintain", "-99999"},
74 {"compression", "kSnappyCompression"},
75 {"compression_per_level",
84 "kZSTDNotFinalCompression"},
85 {"bottommost_compression", "kLZ4Compression"},
86 {"bottommost_compression_opts", "5:6:7:8:10:true"},
87 {"compression_opts", "4:5:6:7:8:2:true:100:false"},
89 {"level0_file_num_compaction_trigger", "8"},
90 {"level0_slowdown_writes_trigger", "9"},
91 {"level0_stop_writes_trigger", "10"},
92 {"target_file_size_base", "12"},
93 {"target_file_size_multiplier", "13"},
94 {"max_bytes_for_level_base", "14"},
95 {"level_compaction_dynamic_level_bytes", "true"},
96 {"max_bytes_for_level_multiplier", "15.0"},
97 {"max_bytes_for_level_multiplier_additional", "16:17:18"},
98 {"max_compaction_bytes", "21"},
99 {"hard_pending_compaction_bytes_limit", "211"},
100 {"arena_block_size", "22"},
101 {"disable_auto_compactions", "true"},
102 {"compaction_style", "kCompactionStyleLevel"},
103 {"compaction_pri", "kOldestSmallestSeqFirst"},
104 {"verify_checksums_in_compaction", "false"},
105 {"compaction_options_fifo", "23"},
106 {"max_sequential_skip_in_iterations", "24"},
107 {"inplace_update_support", "true"},
108 {"report_bg_io_stats", "true"},
109 {"compaction_measure_io_stats", "false"},
110 {"purge_redundant_kvs_while_flush", "false"},
111 {"inplace_update_num_locks", "25"},
112 {"memtable_prefix_bloom_size_ratio", "0.26"},
113 {"memtable_whole_key_filtering", "true"},
114 {"memtable_huge_page_size", "28"},
115 {"bloom_locality", "29"},
116 {"max_successive_merges", "30"},
117 {"min_partial_merge_operands", "31"},
118 {"prefix_extractor", "fixed:31"},
119 {"experimental_mempurge_threshold", "0.003"},
120 {"optimize_filters_for_hits", "true"},
121 {"enable_blob_files", "true"},
122 {"min_blob_size", "1K"},
123 {"blob_file_size", "1G"},
124 {"blob_compression_type", "kZSTD"},
125 {"enable_blob_garbage_collection", "true"},
126 {"blob_garbage_collection_age_cutoff", "0.5"},
127 {"blob_garbage_collection_force_threshold", "0.75"},
128 {"blob_compaction_readahead_size", "256K"},
129 {"blob_file_starting_level", "1"},
130 {"prepopulate_blob_cache", "kDisable"},
131 {"last_level_temperature", "kWarm"},
134 std::unordered_map
<std::string
, std::string
> db_options_map
= {
135 {"create_if_missing", "false"},
136 {"create_missing_column_families", "true"},
137 {"error_if_exists", "false"},
138 {"paranoid_checks", "true"},
139 {"track_and_verify_wals_in_manifest", "true"},
140 {"verify_sst_unique_id_in_manifest", "true"},
141 {"max_open_files", "32"},
142 {"max_total_wal_size", "33"},
143 {"use_fsync", "true"},
144 {"db_log_dir", "/db_log_dir"},
145 {"wal_dir", "/wal_dir"},
146 {"delete_obsolete_files_period_micros", "34"},
147 {"max_background_compactions", "35"},
148 {"max_background_flushes", "36"},
149 {"max_log_file_size", "37"},
150 {"log_file_time_to_roll", "38"},
151 {"keep_log_file_num", "39"},
152 {"recycle_log_file_num", "5"},
153 {"max_manifest_file_size", "40"},
154 {"table_cache_numshardbits", "41"},
155 {"WAL_ttl_seconds", "43"},
156 {"WAL_size_limit_MB", "44"},
157 {"manifest_preallocation_size", "45"},
158 {"allow_mmap_reads", "true"},
159 {"allow_mmap_writes", "false"},
160 {"use_direct_reads", "false"},
161 {"use_direct_io_for_flush_and_compaction", "false"},
162 {"is_fd_close_on_exec", "true"},
163 {"skip_log_error_on_recovery", "false"},
164 {"stats_dump_period_sec", "46"},
165 {"stats_persist_period_sec", "57"},
166 {"persist_stats_to_disk", "false"},
167 {"stats_history_buffer_size", "69"},
168 {"advise_random_on_open", "true"},
169 {"use_adaptive_mutex", "false"},
170 {"compaction_readahead_size", "100"},
171 {"random_access_max_buffer_size", "3145728"},
172 {"writable_file_max_buffer_size", "314159"},
173 {"bytes_per_sync", "47"},
174 {"wal_bytes_per_sync", "48"},
175 {"strict_bytes_per_sync", "true"},
176 {"preserve_deletes", "false"},
179 ColumnFamilyOptions base_cf_opt
;
180 ColumnFamilyOptions new_cf_opt
;
181 ConfigOptions exact
, loose
;
182 exact
.input_strings_escaped
= false;
183 exact
.ignore_unknown_options
= false;
184 exact
.sanity_level
= ConfigOptions::kSanityLevelExactMatch
;
185 loose
.sanity_level
= ConfigOptions::kSanityLevelLooselyCompatible
;
187 loose
.input_strings_escaped
= false;
188 loose
.ignore_unknown_options
= true;
189 ASSERT_OK(GetColumnFamilyOptionsFromMap(exact
, base_cf_opt
, cf_options_map
,
191 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 1U);
192 ASSERT_EQ(new_cf_opt
.max_write_buffer_number
, 2);
193 ASSERT_EQ(new_cf_opt
.min_write_buffer_number_to_merge
, 3);
194 ASSERT_EQ(new_cf_opt
.max_write_buffer_number_to_maintain
, 99);
195 ASSERT_EQ(new_cf_opt
.max_write_buffer_size_to_maintain
, -99999);
196 ASSERT_EQ(new_cf_opt
.compression
, kSnappyCompression
);
197 ASSERT_EQ(new_cf_opt
.compression_per_level
.size(), 9U);
198 ASSERT_EQ(new_cf_opt
.compression_per_level
[0], kNoCompression
);
199 ASSERT_EQ(new_cf_opt
.compression_per_level
[1], kSnappyCompression
);
200 ASSERT_EQ(new_cf_opt
.compression_per_level
[2], kZlibCompression
);
201 ASSERT_EQ(new_cf_opt
.compression_per_level
[3], kBZip2Compression
);
202 ASSERT_EQ(new_cf_opt
.compression_per_level
[4], kLZ4Compression
);
203 ASSERT_EQ(new_cf_opt
.compression_per_level
[5], kLZ4HCCompression
);
204 ASSERT_EQ(new_cf_opt
.compression_per_level
[6], kXpressCompression
);
205 ASSERT_EQ(new_cf_opt
.compression_per_level
[7], kZSTD
);
206 ASSERT_EQ(new_cf_opt
.compression_per_level
[8], kZSTDNotFinalCompression
);
207 ASSERT_EQ(new_cf_opt
.compression_opts
.window_bits
, 4);
208 ASSERT_EQ(new_cf_opt
.compression_opts
.level
, 5);
209 ASSERT_EQ(new_cf_opt
.compression_opts
.strategy
, 6);
210 ASSERT_EQ(new_cf_opt
.compression_opts
.max_dict_bytes
, 7u);
211 ASSERT_EQ(new_cf_opt
.compression_opts
.zstd_max_train_bytes
, 8u);
212 ASSERT_EQ(new_cf_opt
.compression_opts
.parallel_threads
, 2u);
213 ASSERT_EQ(new_cf_opt
.compression_opts
.enabled
, true);
214 ASSERT_EQ(new_cf_opt
.compression_opts
.max_dict_buffer_bytes
, 100u);
215 ASSERT_EQ(new_cf_opt
.compression_opts
.use_zstd_dict_trainer
, false);
216 ASSERT_EQ(new_cf_opt
.bottommost_compression
, kLZ4Compression
);
217 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.window_bits
, 5);
218 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.level
, 6);
219 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.strategy
, 7);
220 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.max_dict_bytes
, 8u);
221 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.zstd_max_train_bytes
, 10u);
222 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.parallel_threads
,
223 CompressionOptions().parallel_threads
);
224 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.enabled
, true);
225 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.use_zstd_dict_trainer
,
226 CompressionOptions().use_zstd_dict_trainer
);
227 ASSERT_EQ(new_cf_opt
.num_levels
, 8);
228 ASSERT_EQ(new_cf_opt
.level0_file_num_compaction_trigger
, 8);
229 ASSERT_EQ(new_cf_opt
.level0_slowdown_writes_trigger
, 9);
230 ASSERT_EQ(new_cf_opt
.level0_stop_writes_trigger
, 10);
231 ASSERT_EQ(new_cf_opt
.target_file_size_base
, static_cast<uint64_t>(12));
232 ASSERT_EQ(new_cf_opt
.target_file_size_multiplier
, 13);
233 ASSERT_EQ(new_cf_opt
.max_bytes_for_level_base
, 14U);
234 ASSERT_EQ(new_cf_opt
.level_compaction_dynamic_level_bytes
, true);
235 ASSERT_EQ(new_cf_opt
.max_bytes_for_level_multiplier
, 15.0);
236 ASSERT_EQ(new_cf_opt
.max_bytes_for_level_multiplier_additional
.size(), 3U);
237 ASSERT_EQ(new_cf_opt
.max_bytes_for_level_multiplier_additional
[0], 16);
238 ASSERT_EQ(new_cf_opt
.max_bytes_for_level_multiplier_additional
[1], 17);
239 ASSERT_EQ(new_cf_opt
.max_bytes_for_level_multiplier_additional
[2], 18);
240 ASSERT_EQ(new_cf_opt
.max_compaction_bytes
, 21);
241 ASSERT_EQ(new_cf_opt
.hard_pending_compaction_bytes_limit
, 211);
242 ASSERT_EQ(new_cf_opt
.arena_block_size
, 22U);
243 ASSERT_EQ(new_cf_opt
.disable_auto_compactions
, true);
244 ASSERT_EQ(new_cf_opt
.compaction_style
, kCompactionStyleLevel
);
245 ASSERT_EQ(new_cf_opt
.compaction_pri
, kOldestSmallestSeqFirst
);
246 ASSERT_EQ(new_cf_opt
.compaction_options_fifo
.max_table_files_size
,
247 static_cast<uint64_t>(23));
248 ASSERT_EQ(new_cf_opt
.max_sequential_skip_in_iterations
,
249 static_cast<uint64_t>(24));
250 ASSERT_EQ(new_cf_opt
.inplace_update_support
, true);
251 ASSERT_EQ(new_cf_opt
.inplace_update_num_locks
, 25U);
252 ASSERT_EQ(new_cf_opt
.memtable_prefix_bloom_size_ratio
, 0.26);
253 ASSERT_EQ(new_cf_opt
.memtable_whole_key_filtering
, true);
254 ASSERT_EQ(new_cf_opt
.memtable_huge_page_size
, 28U);
255 ASSERT_EQ(new_cf_opt
.bloom_locality
, 29U);
256 ASSERT_EQ(new_cf_opt
.max_successive_merges
, 30U);
257 ASSERT_TRUE(new_cf_opt
.prefix_extractor
!= nullptr);
258 ASSERT_EQ(new_cf_opt
.optimize_filters_for_hits
, true);
259 ASSERT_EQ(new_cf_opt
.prefix_extractor
->AsString(), "rocksdb.FixedPrefix.31");
260 ASSERT_EQ(new_cf_opt
.experimental_mempurge_threshold
, 0.003);
261 ASSERT_EQ(new_cf_opt
.enable_blob_files
, true);
262 ASSERT_EQ(new_cf_opt
.min_blob_size
, 1ULL << 10);
263 ASSERT_EQ(new_cf_opt
.blob_file_size
, 1ULL << 30);
264 ASSERT_EQ(new_cf_opt
.blob_compression_type
, kZSTD
);
265 ASSERT_EQ(new_cf_opt
.enable_blob_garbage_collection
, true);
266 ASSERT_EQ(new_cf_opt
.blob_garbage_collection_age_cutoff
, 0.5);
267 ASSERT_EQ(new_cf_opt
.blob_garbage_collection_force_threshold
, 0.75);
268 ASSERT_EQ(new_cf_opt
.blob_compaction_readahead_size
, 262144);
269 ASSERT_EQ(new_cf_opt
.blob_file_starting_level
, 1);
270 ASSERT_EQ(new_cf_opt
.prepopulate_blob_cache
, PrepopulateBlobCache::kDisable
);
271 ASSERT_EQ(new_cf_opt
.last_level_temperature
, Temperature::kWarm
);
272 ASSERT_EQ(new_cf_opt
.bottommost_temperature
, Temperature::kWarm
);
274 cf_options_map
["write_buffer_size"] = "hello";
275 ASSERT_NOK(GetColumnFamilyOptionsFromMap(exact
, base_cf_opt
, cf_options_map
,
278 RocksDBOptionsParser::VerifyCFOptions(exact
, base_cf_opt
, new_cf_opt
));
280 cf_options_map
["write_buffer_size"] = "1";
281 ASSERT_OK(GetColumnFamilyOptionsFromMap(exact
, base_cf_opt
, cf_options_map
,
284 cf_options_map
["unknown_option"] = "1";
285 ASSERT_NOK(GetColumnFamilyOptionsFromMap(exact
, base_cf_opt
, cf_options_map
,
288 RocksDBOptionsParser::VerifyCFOptions(exact
, base_cf_opt
, new_cf_opt
));
290 // ignore_unknown_options=true;input_strings_escaped=false
291 ASSERT_OK(GetColumnFamilyOptionsFromMap(loose
, base_cf_opt
, cf_options_map
,
294 RocksDBOptionsParser::VerifyCFOptions(loose
, base_cf_opt
, new_cf_opt
));
296 RocksDBOptionsParser::VerifyCFOptions(exact
, base_cf_opt
, new_cf_opt
));
298 DBOptions base_db_opt
;
299 DBOptions new_db_opt
;
301 GetDBOptionsFromMap(exact
, base_db_opt
, db_options_map
, &new_db_opt
));
302 ASSERT_EQ(new_db_opt
.create_if_missing
, false);
303 ASSERT_EQ(new_db_opt
.create_missing_column_families
, true);
304 ASSERT_EQ(new_db_opt
.error_if_exists
, false);
305 ASSERT_EQ(new_db_opt
.paranoid_checks
, true);
306 ASSERT_EQ(new_db_opt
.track_and_verify_wals_in_manifest
, true);
307 ASSERT_EQ(new_db_opt
.verify_sst_unique_id_in_manifest
, true);
308 ASSERT_EQ(new_db_opt
.max_open_files
, 32);
309 ASSERT_EQ(new_db_opt
.max_total_wal_size
, static_cast<uint64_t>(33));
310 ASSERT_EQ(new_db_opt
.use_fsync
, true);
311 ASSERT_EQ(new_db_opt
.db_log_dir
, "/db_log_dir");
312 ASSERT_EQ(new_db_opt
.wal_dir
, "/wal_dir");
313 ASSERT_EQ(new_db_opt
.delete_obsolete_files_period_micros
,
314 static_cast<uint64_t>(34));
315 ASSERT_EQ(new_db_opt
.max_background_compactions
, 35);
316 ASSERT_EQ(new_db_opt
.max_background_flushes
, 36);
317 ASSERT_EQ(new_db_opt
.max_log_file_size
, 37U);
318 ASSERT_EQ(new_db_opt
.log_file_time_to_roll
, 38U);
319 ASSERT_EQ(new_db_opt
.keep_log_file_num
, 39U);
320 ASSERT_EQ(new_db_opt
.recycle_log_file_num
, 5U);
321 ASSERT_EQ(new_db_opt
.max_manifest_file_size
, static_cast<uint64_t>(40));
322 ASSERT_EQ(new_db_opt
.table_cache_numshardbits
, 41);
323 ASSERT_EQ(new_db_opt
.WAL_ttl_seconds
, static_cast<uint64_t>(43));
324 ASSERT_EQ(new_db_opt
.WAL_size_limit_MB
, static_cast<uint64_t>(44));
325 ASSERT_EQ(new_db_opt
.manifest_preallocation_size
, 45U);
326 ASSERT_EQ(new_db_opt
.allow_mmap_reads
, true);
327 ASSERT_EQ(new_db_opt
.allow_mmap_writes
, false);
328 ASSERT_EQ(new_db_opt
.use_direct_reads
, false);
329 ASSERT_EQ(new_db_opt
.use_direct_io_for_flush_and_compaction
, false);
330 ASSERT_EQ(new_db_opt
.is_fd_close_on_exec
, true);
331 ASSERT_EQ(new_db_opt
.stats_dump_period_sec
, 46U);
332 ASSERT_EQ(new_db_opt
.stats_persist_period_sec
, 57U);
333 ASSERT_EQ(new_db_opt
.persist_stats_to_disk
, false);
334 ASSERT_EQ(new_db_opt
.stats_history_buffer_size
, 69U);
335 ASSERT_EQ(new_db_opt
.advise_random_on_open
, true);
336 ASSERT_EQ(new_db_opt
.use_adaptive_mutex
, false);
337 ASSERT_EQ(new_db_opt
.compaction_readahead_size
, 100);
338 ASSERT_EQ(new_db_opt
.random_access_max_buffer_size
, 3145728);
339 ASSERT_EQ(new_db_opt
.writable_file_max_buffer_size
, 314159);
340 ASSERT_EQ(new_db_opt
.bytes_per_sync
, static_cast<uint64_t>(47));
341 ASSERT_EQ(new_db_opt
.wal_bytes_per_sync
, static_cast<uint64_t>(48));
342 ASSERT_EQ(new_db_opt
.strict_bytes_per_sync
, true);
344 db_options_map
["max_open_files"] = "hello";
346 GetDBOptionsFromMap(exact
, base_db_opt
, db_options_map
, &new_db_opt
);
348 ASSERT_TRUE(s
.IsInvalidArgument());
351 RocksDBOptionsParser::VerifyDBOptions(exact
, base_db_opt
, new_db_opt
));
353 RocksDBOptionsParser::VerifyDBOptions(loose
, base_db_opt
, new_db_opt
));
355 // unknow options should fail parsing without ignore_unknown_options = true
356 db_options_map
["unknown_db_option"] = "1";
357 s
= GetDBOptionsFromMap(exact
, base_db_opt
, db_options_map
, &new_db_opt
);
359 ASSERT_TRUE(s
.IsInvalidArgument());
361 RocksDBOptionsParser::VerifyDBOptions(exact
, base_db_opt
, new_db_opt
));
364 GetDBOptionsFromMap(loose
, base_db_opt
, db_options_map
, &new_db_opt
));
366 RocksDBOptionsParser::VerifyDBOptions(loose
, base_db_opt
, new_db_opt
));
368 RocksDBOptionsParser::VerifyDBOptions(exact
, base_db_opt
, new_db_opt
));
370 #endif // !ROCKSDB_LITE
372 #ifndef ROCKSDB_LITE // GetColumnFamilyOptionsFromString is not supported in
374 TEST_F(OptionsTest
, GetColumnFamilyOptionsFromStringTest
) {
375 ColumnFamilyOptions base_cf_opt
;
376 ColumnFamilyOptions new_cf_opt
;
377 ConfigOptions config_options
;
378 config_options
.input_strings_escaped
= false;
379 config_options
.ignore_unknown_options
= false;
381 base_cf_opt
.table_factory
.reset();
382 ASSERT_OK(GetColumnFamilyOptionsFromString(config_options
, base_cf_opt
, "",
384 ASSERT_OK(GetColumnFamilyOptionsFromString(
385 config_options
, base_cf_opt
, "write_buffer_size=5", &new_cf_opt
));
386 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 5U);
387 ASSERT_TRUE(new_cf_opt
.table_factory
== nullptr);
388 ASSERT_OK(GetColumnFamilyOptionsFromString(
389 config_options
, base_cf_opt
, "write_buffer_size=6;", &new_cf_opt
));
390 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 6U);
391 ASSERT_OK(GetColumnFamilyOptionsFromString(
392 config_options
, base_cf_opt
, " write_buffer_size = 7 ", &new_cf_opt
));
393 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 7U);
394 ASSERT_OK(GetColumnFamilyOptionsFromString(
395 config_options
, base_cf_opt
, " write_buffer_size = 8 ; ", &new_cf_opt
));
396 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 8U);
397 ASSERT_OK(GetColumnFamilyOptionsFromString(
398 config_options
, base_cf_opt
,
399 "write_buffer_size=9;max_write_buffer_number=10", &new_cf_opt
));
400 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 9U);
401 ASSERT_EQ(new_cf_opt
.max_write_buffer_number
, 10);
402 ASSERT_OK(GetColumnFamilyOptionsFromString(
403 config_options
, base_cf_opt
,
404 "write_buffer_size=11; max_write_buffer_number = 12 ;", &new_cf_opt
));
405 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 11U);
406 ASSERT_EQ(new_cf_opt
.max_write_buffer_number
, 12);
407 // Wrong name "max_write_buffer_number_"
408 ASSERT_NOK(GetColumnFamilyOptionsFromString(
409 config_options
, base_cf_opt
,
410 "write_buffer_size=13;max_write_buffer_number_=14;", &new_cf_opt
));
411 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options
, base_cf_opt
,
414 // Comparator from object registry
415 std::string kCompName
= "reverse_comp";
416 ObjectLibrary::Default()->AddFactory
<const Comparator
>(
418 [](const std::string
& /*name*/,
419 std::unique_ptr
<const Comparator
>* /*guard*/,
420 std::string
* /* errmsg */) { return ReverseBytewiseComparator(); });
422 ASSERT_OK(GetColumnFamilyOptionsFromString(config_options
, base_cf_opt
,
423 "comparator=" + kCompName
+ ";",
425 ASSERT_EQ(new_cf_opt
.comparator
, ReverseBytewiseComparator());
427 // MergeOperator from object registry
428 std::unique_ptr
<BytesXOROperator
> bxo(new BytesXOROperator());
429 std::string kMoName
= bxo
->Name();
431 ASSERT_OK(GetColumnFamilyOptionsFromString(config_options
, base_cf_opt
,
432 "merge_operator=" + kMoName
+ ";",
434 ASSERT_EQ(kMoName
, std::string(new_cf_opt
.merge_operator
->Name()));
436 // Wrong key/value pair
437 Status s
= GetColumnFamilyOptionsFromString(
438 config_options
, base_cf_opt
,
439 "write_buffer_size=13;max_write_buffer_number;", &new_cf_opt
);
441 ASSERT_TRUE(s
.IsInvalidArgument());
443 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options
, base_cf_opt
,
446 // Error Parsing value
447 s
= GetColumnFamilyOptionsFromString(
448 config_options
, base_cf_opt
,
449 "write_buffer_size=13;max_write_buffer_number=;", &new_cf_opt
);
451 ASSERT_TRUE(s
.IsInvalidArgument());
452 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options
, base_cf_opt
,
455 // Missing option name
456 s
= GetColumnFamilyOptionsFromString(
457 config_options
, base_cf_opt
, "write_buffer_size=13; =100;", &new_cf_opt
);
459 ASSERT_TRUE(s
.IsInvalidArgument());
460 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options
, base_cf_opt
,
463 const uint64_t kilo
= 1024UL;
464 const uint64_t mega
= 1024 * kilo
;
465 const uint64_t giga
= 1024 * mega
;
466 const uint64_t tera
= 1024 * giga
;
469 ASSERT_OK(GetColumnFamilyOptionsFromString(
470 config_options
, base_cf_opt
, "max_write_buffer_number=15K", &new_cf_opt
));
471 ASSERT_EQ(new_cf_opt
.max_write_buffer_number
, 15 * kilo
);
473 ASSERT_OK(GetColumnFamilyOptionsFromString(
474 config_options
, base_cf_opt
,
475 "max_write_buffer_number=16m;inplace_update_num_locks=17M", &new_cf_opt
));
476 ASSERT_EQ(new_cf_opt
.max_write_buffer_number
, 16 * mega
);
477 ASSERT_EQ(new_cf_opt
.inplace_update_num_locks
, 17u * mega
);
479 ASSERT_OK(GetColumnFamilyOptionsFromString(
480 config_options
, base_cf_opt
,
481 "write_buffer_size=18g;prefix_extractor=capped:8;"
482 "arena_block_size=19G",
485 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 18 * giga
);
486 ASSERT_EQ(new_cf_opt
.arena_block_size
, 19 * giga
);
487 ASSERT_TRUE(new_cf_opt
.prefix_extractor
.get() != nullptr);
488 ASSERT_EQ(new_cf_opt
.prefix_extractor
->AsString(), "rocksdb.CappedPrefix.8");
491 ASSERT_OK(GetColumnFamilyOptionsFromString(
492 config_options
, base_cf_opt
, "write_buffer_size=20t;arena_block_size=21T",
494 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 20 * tera
);
495 ASSERT_EQ(new_cf_opt
.arena_block_size
, 21 * tera
);
497 // Nested block based table options
499 ASSERT_OK(GetColumnFamilyOptionsFromString(
500 config_options
, base_cf_opt
,
501 "write_buffer_size=10;max_write_buffer_number=16;"
502 "block_based_table_factory={};arena_block_size=1024",
504 ASSERT_TRUE(new_cf_opt
.table_factory
!= nullptr);
506 ASSERT_OK(GetColumnFamilyOptionsFromString(
507 config_options
, base_cf_opt
,
508 "write_buffer_size=10;max_write_buffer_number=16;"
509 "block_based_table_factory={block_cache=1M;block_size=4;};"
510 "arena_block_size=1024",
512 ASSERT_TRUE(new_cf_opt
.table_factory
!= nullptr);
514 ASSERT_OK(GetColumnFamilyOptionsFromString(
515 config_options
, base_cf_opt
,
516 "write_buffer_size=10;max_write_buffer_number=16;"
517 "block_based_table_factory={block_cache=1M;block_size=4;}",
519 ASSERT_TRUE(new_cf_opt
.table_factory
!= nullptr);
520 // Mismatch curly braces
521 ASSERT_NOK(GetColumnFamilyOptionsFromString(
522 config_options
, base_cf_opt
,
523 "write_buffer_size=10;max_write_buffer_number=16;"
524 "block_based_table_factory={{{block_size=4;};"
525 "arena_block_size=1024",
527 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options
, base_cf_opt
,
530 // Unexpected chars after closing curly brace
531 ASSERT_NOK(GetColumnFamilyOptionsFromString(
532 config_options
, base_cf_opt
,
533 "write_buffer_size=10;max_write_buffer_number=16;"
534 "block_based_table_factory={block_size=4;}};"
535 "arena_block_size=1024",
537 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options
, base_cf_opt
,
540 ASSERT_NOK(GetColumnFamilyOptionsFromString(
541 config_options
, base_cf_opt
,
542 "write_buffer_size=10;max_write_buffer_number=16;"
543 "block_based_table_factory={block_size=4;}xdfa;"
544 "arena_block_size=1024",
546 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options
, base_cf_opt
,
549 ASSERT_NOK(GetColumnFamilyOptionsFromString(
550 config_options
, base_cf_opt
,
551 "write_buffer_size=10;max_write_buffer_number=16;"
552 "block_based_table_factory={block_size=4;}xdfa",
554 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options
, base_cf_opt
,
557 // Invalid block based table option
558 ASSERT_NOK(GetColumnFamilyOptionsFromString(
559 config_options
, base_cf_opt
,
560 "write_buffer_size=10;max_write_buffer_number=16;"
561 "block_based_table_factory={xx_block_size=4;}",
563 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options
, base_cf_opt
,
566 ASSERT_OK(GetColumnFamilyOptionsFromString(config_options
, base_cf_opt
,
567 "optimize_filters_for_hits=true",
569 ASSERT_OK(GetColumnFamilyOptionsFromString(config_options
, base_cf_opt
,
570 "optimize_filters_for_hits=false",
573 ASSERT_NOK(GetColumnFamilyOptionsFromString(config_options
, base_cf_opt
,
574 "optimize_filters_for_hits=junk",
576 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options
, base_cf_opt
,
579 // Nested plain table options
581 ASSERT_OK(GetColumnFamilyOptionsFromString(
582 config_options
, base_cf_opt
,
583 "write_buffer_size=10;max_write_buffer_number=16;"
584 "plain_table_factory={};arena_block_size=1024",
586 ASSERT_TRUE(new_cf_opt
.table_factory
!= nullptr);
587 ASSERT_EQ(std::string(new_cf_opt
.table_factory
->Name()), "PlainTable");
589 ASSERT_OK(GetColumnFamilyOptionsFromString(
590 config_options
, base_cf_opt
,
591 "write_buffer_size=10;max_write_buffer_number=16;"
592 "plain_table_factory={user_key_len=66;bloom_bits_per_key=20;};"
593 "arena_block_size=1024",
595 ASSERT_TRUE(new_cf_opt
.table_factory
!= nullptr);
596 ASSERT_EQ(std::string(new_cf_opt
.table_factory
->Name()), "PlainTable");
599 ASSERT_OK(GetColumnFamilyOptionsFromString(
600 config_options
, base_cf_opt
,
601 "write_buffer_size=10;max_write_buffer_number=16;"
602 "memtable=skip_list:10;arena_block_size=1024",
604 ASSERT_TRUE(new_cf_opt
.memtable_factory
!= nullptr);
605 ASSERT_EQ(std::string(new_cf_opt
.memtable_factory
->Name()), "SkipListFactory");
606 ASSERT_TRUE(new_cf_opt
.memtable_factory
->IsInstanceOf("SkipListFactory"));
609 ASSERT_OK(GetColumnFamilyOptionsFromString(
610 config_options
, base_cf_opt
,
611 "blob_cache={capacity=1M;num_shard_bits=4;"
612 "strict_capacity_limit=true;high_pri_pool_ratio=0.5;};",
614 ASSERT_NE(new_cf_opt
.blob_cache
, nullptr);
615 ASSERT_EQ(new_cf_opt
.blob_cache
->GetCapacity(), 1024UL * 1024UL);
616 ASSERT_EQ(static_cast<ShardedCacheBase
*>(new_cf_opt
.blob_cache
.get())
619 ASSERT_EQ(new_cf_opt
.blob_cache
->HasStrictCapacityLimit(), true);
620 ASSERT_EQ(static_cast<LRUCache
*>(new_cf_opt
.blob_cache
.get())
621 ->GetHighPriPoolRatio(),
625 TEST_F(OptionsTest
, CompressionOptionsFromString
) {
626 ColumnFamilyOptions base_cf_opt
;
627 ColumnFamilyOptions new_cf_opt
;
628 ConfigOptions config_options
;
629 std::string opts_str
;
630 config_options
.ignore_unknown_options
= false;
631 CompressionOptions dflt
;
632 // Test with some optional values removed....
634 GetColumnFamilyOptionsFromString(config_options
, ColumnFamilyOptions(),
635 "compression_opts=3:4:5; "
636 "bottommost_compression_opts=4:5:6:7",
638 ASSERT_EQ(base_cf_opt
.compression_opts
.window_bits
, 3);
639 ASSERT_EQ(base_cf_opt
.compression_opts
.level
, 4);
640 ASSERT_EQ(base_cf_opt
.compression_opts
.strategy
, 5);
641 ASSERT_EQ(base_cf_opt
.compression_opts
.max_dict_bytes
, dflt
.max_dict_bytes
);
642 ASSERT_EQ(base_cf_opt
.compression_opts
.zstd_max_train_bytes
,
643 dflt
.zstd_max_train_bytes
);
644 ASSERT_EQ(base_cf_opt
.compression_opts
.parallel_threads
,
645 dflt
.parallel_threads
);
646 ASSERT_EQ(base_cf_opt
.compression_opts
.enabled
, dflt
.enabled
);
647 ASSERT_EQ(base_cf_opt
.compression_opts
.use_zstd_dict_trainer
,
648 dflt
.use_zstd_dict_trainer
);
649 ASSERT_EQ(base_cf_opt
.bottommost_compression_opts
.window_bits
, 4);
650 ASSERT_EQ(base_cf_opt
.bottommost_compression_opts
.level
, 5);
651 ASSERT_EQ(base_cf_opt
.bottommost_compression_opts
.strategy
, 6);
652 ASSERT_EQ(base_cf_opt
.bottommost_compression_opts
.max_dict_bytes
, 7u);
653 ASSERT_EQ(base_cf_opt
.bottommost_compression_opts
.zstd_max_train_bytes
,
654 dflt
.zstd_max_train_bytes
);
655 ASSERT_EQ(base_cf_opt
.bottommost_compression_opts
.parallel_threads
,
656 dflt
.parallel_threads
);
657 ASSERT_EQ(base_cf_opt
.bottommost_compression_opts
.enabled
, dflt
.enabled
);
658 ASSERT_EQ(base_cf_opt
.bottommost_compression_opts
.use_zstd_dict_trainer
,
659 dflt
.use_zstd_dict_trainer
);
661 ASSERT_OK(GetColumnFamilyOptionsFromString(
662 config_options
, ColumnFamilyOptions(),
663 "compression_opts=4:5:6:7:8:9:true:10:false; "
664 "bottommost_compression_opts=5:6:7:8:9:false",
666 ASSERT_EQ(base_cf_opt
.compression_opts
.window_bits
, 4);
667 ASSERT_EQ(base_cf_opt
.compression_opts
.level
, 5);
668 ASSERT_EQ(base_cf_opt
.compression_opts
.strategy
, 6);
669 ASSERT_EQ(base_cf_opt
.compression_opts
.max_dict_bytes
, 7u);
670 ASSERT_EQ(base_cf_opt
.compression_opts
.zstd_max_train_bytes
, 8u);
671 ASSERT_EQ(base_cf_opt
.compression_opts
.parallel_threads
, 9u);
672 ASSERT_EQ(base_cf_opt
.compression_opts
.enabled
, true);
673 ASSERT_EQ(base_cf_opt
.compression_opts
.max_dict_buffer_bytes
, 10u);
674 ASSERT_EQ(base_cf_opt
.compression_opts
.use_zstd_dict_trainer
, false);
675 ASSERT_EQ(base_cf_opt
.bottommost_compression_opts
.window_bits
, 5);
676 ASSERT_EQ(base_cf_opt
.bottommost_compression_opts
.level
, 6);
677 ASSERT_EQ(base_cf_opt
.bottommost_compression_opts
.strategy
, 7);
678 ASSERT_EQ(base_cf_opt
.bottommost_compression_opts
.max_dict_bytes
, 8u);
679 ASSERT_EQ(base_cf_opt
.bottommost_compression_opts
.zstd_max_train_bytes
, 9u);
680 ASSERT_EQ(base_cf_opt
.bottommost_compression_opts
.parallel_threads
,
681 dflt
.parallel_threads
);
682 ASSERT_EQ(base_cf_opt
.bottommost_compression_opts
.enabled
, false);
683 ASSERT_EQ(base_cf_opt
.bottommost_compression_opts
.use_zstd_dict_trainer
,
684 dflt
.use_zstd_dict_trainer
);
687 GetStringFromColumnFamilyOptions(config_options
, base_cf_opt
, &opts_str
));
688 ASSERT_OK(GetColumnFamilyOptionsFromString(
689 config_options
, ColumnFamilyOptions(), opts_str
, &new_cf_opt
));
690 ASSERT_EQ(new_cf_opt
.compression_opts
.window_bits
, 4);
691 ASSERT_EQ(new_cf_opt
.compression_opts
.level
, 5);
692 ASSERT_EQ(new_cf_opt
.compression_opts
.strategy
, 6);
693 ASSERT_EQ(new_cf_opt
.compression_opts
.max_dict_bytes
, 7u);
694 ASSERT_EQ(new_cf_opt
.compression_opts
.zstd_max_train_bytes
, 8u);
695 ASSERT_EQ(new_cf_opt
.compression_opts
.parallel_threads
, 9u);
696 ASSERT_EQ(new_cf_opt
.compression_opts
.enabled
, true);
697 ASSERT_EQ(base_cf_opt
.compression_opts
.max_dict_buffer_bytes
, 10u);
698 ASSERT_EQ(base_cf_opt
.compression_opts
.use_zstd_dict_trainer
, false);
699 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.window_bits
, 5);
700 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.level
, 6);
701 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.strategy
, 7);
702 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.max_dict_bytes
, 8u);
703 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.zstd_max_train_bytes
, 9u);
704 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.parallel_threads
,
705 dflt
.parallel_threads
);
706 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.enabled
, false);
707 ASSERT_EQ(base_cf_opt
.bottommost_compression_opts
.use_zstd_dict_trainer
,
708 dflt
.use_zstd_dict_trainer
);
710 // Test as struct values
711 ASSERT_OK(GetColumnFamilyOptionsFromString(
712 config_options
, ColumnFamilyOptions(),
713 "compression_opts={window_bits=5; level=6; strategy=7; max_dict_bytes=8;"
714 "zstd_max_train_bytes=9;parallel_threads=10;enabled=true;use_zstd_dict_"
716 "bottommost_compression_opts={window_bits=4; level=5; strategy=6;"
717 " max_dict_bytes=7;zstd_max_train_bytes=8;parallel_threads=9;"
718 "enabled=false;use_zstd_dict_trainer=true}; ",
720 ASSERT_EQ(new_cf_opt
.compression_opts
.window_bits
, 5);
721 ASSERT_EQ(new_cf_opt
.compression_opts
.level
, 6);
722 ASSERT_EQ(new_cf_opt
.compression_opts
.strategy
, 7);
723 ASSERT_EQ(new_cf_opt
.compression_opts
.max_dict_bytes
, 8u);
724 ASSERT_EQ(new_cf_opt
.compression_opts
.zstd_max_train_bytes
, 9u);
725 ASSERT_EQ(new_cf_opt
.compression_opts
.parallel_threads
, 10u);
726 ASSERT_EQ(new_cf_opt
.compression_opts
.enabled
, true);
727 ASSERT_EQ(new_cf_opt
.compression_opts
.use_zstd_dict_trainer
, false);
728 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.window_bits
, 4);
729 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.level
, 5);
730 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.strategy
, 6);
731 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.max_dict_bytes
, 7u);
732 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.zstd_max_train_bytes
, 8u);
733 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.parallel_threads
, 9u);
734 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.enabled
, false);
735 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.use_zstd_dict_trainer
, true);
737 ASSERT_OK(GetColumnFamilyOptionsFromString(
738 config_options
, base_cf_opt
,
739 "compression_opts={window_bits=4; strategy=5;};"
740 "bottommost_compression_opts={level=6; strategy=7;}",
742 ASSERT_EQ(new_cf_opt
.compression_opts
.window_bits
, 4);
743 ASSERT_EQ(new_cf_opt
.compression_opts
.strategy
, 5);
744 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.level
, 6);
745 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.strategy
, 7);
747 ASSERT_EQ(new_cf_opt
.compression_opts
.level
,
748 base_cf_opt
.compression_opts
.level
);
749 ASSERT_EQ(new_cf_opt
.compression_opts
.max_dict_bytes
,
750 base_cf_opt
.compression_opts
.max_dict_bytes
);
751 ASSERT_EQ(new_cf_opt
.compression_opts
.zstd_max_train_bytes
,
752 base_cf_opt
.compression_opts
.zstd_max_train_bytes
);
753 ASSERT_EQ(new_cf_opt
.compression_opts
.parallel_threads
,
754 base_cf_opt
.compression_opts
.parallel_threads
);
755 ASSERT_EQ(new_cf_opt
.compression_opts
.enabled
,
756 base_cf_opt
.compression_opts
.enabled
);
757 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.window_bits
,
758 base_cf_opt
.bottommost_compression_opts
.window_bits
);
759 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.max_dict_bytes
,
760 base_cf_opt
.bottommost_compression_opts
.max_dict_bytes
);
761 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.zstd_max_train_bytes
,
762 base_cf_opt
.bottommost_compression_opts
.zstd_max_train_bytes
);
763 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.parallel_threads
,
764 base_cf_opt
.bottommost_compression_opts
.parallel_threads
);
765 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.enabled
,
766 base_cf_opt
.bottommost_compression_opts
.enabled
);
767 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.use_zstd_dict_trainer
,
768 base_cf_opt
.bottommost_compression_opts
.use_zstd_dict_trainer
);
770 // Test a few individual struct values
771 ASSERT_OK(GetColumnFamilyOptionsFromString(
772 config_options
, base_cf_opt
,
773 "compression_opts.enabled=false; "
774 "bottommost_compression_opts.enabled=true; ",
776 ASSERT_EQ(new_cf_opt
.compression_opts
.enabled
, false);
777 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.enabled
, true);
779 // Now test some illegal values
780 ConfigOptions ignore
;
781 ignore
.ignore_unknown_options
= true;
782 ASSERT_NOK(GetColumnFamilyOptionsFromString(
783 config_options
, ColumnFamilyOptions(),
784 "compression_opts=5:6:7:8:9:x:false", &base_cf_opt
));
785 ASSERT_OK(GetColumnFamilyOptionsFromString(
786 ignore
, ColumnFamilyOptions(), "compression_opts=5:6:7:8:9:x:false",
788 ASSERT_OK(GetColumnFamilyOptionsFromString(
789 config_options
, ColumnFamilyOptions(),
790 "compression_opts=1:2:3:4:5:6:true:8", &base_cf_opt
));
791 ASSERT_OK(GetColumnFamilyOptionsFromString(
792 ignore
, ColumnFamilyOptions(), "compression_opts=1:2:3:4:5:6:true:8",
794 ASSERT_NOK(GetColumnFamilyOptionsFromString(
795 config_options
, ColumnFamilyOptions(),
796 "compression_opts=1:2:3:4:5:6:true:8:9", &base_cf_opt
));
797 ASSERT_OK(GetColumnFamilyOptionsFromString(
798 ignore
, ColumnFamilyOptions(), "compression_opts=1:2:3:4:5:6:true:8:9",
800 ASSERT_NOK(GetColumnFamilyOptionsFromString(
801 config_options
, ColumnFamilyOptions(), "compression_opts={unknown=bad;}",
803 ASSERT_OK(GetColumnFamilyOptionsFromString(ignore
, ColumnFamilyOptions(),
804 "compression_opts={unknown=bad;}",
806 ASSERT_NOK(GetColumnFamilyOptionsFromString(
807 config_options
, ColumnFamilyOptions(), "compression_opts.unknown=bad",
809 ASSERT_OK(GetColumnFamilyOptionsFromString(ignore
, ColumnFamilyOptions(),
810 "compression_opts.unknown=bad",
814 TEST_F(OptionsTest
, OldInterfaceTest
) {
815 ColumnFamilyOptions base_cf_opt
;
816 ColumnFamilyOptions new_cf_opt
;
819 ASSERT_OK(GetColumnFamilyOptionsFromString(
821 "write_buffer_size=18;prefix_extractor=capped:8;"
822 "arena_block_size=19",
825 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 18);
826 ASSERT_EQ(new_cf_opt
.arena_block_size
, 19);
827 ASSERT_TRUE(new_cf_opt
.prefix_extractor
.get() != nullptr);
829 // And with a bad option
830 ASSERT_NOK(GetColumnFamilyOptionsFromString(
832 "write_buffer_size=10;max_write_buffer_number=16;"
833 "block_based_table_factory={xx_block_size=4;}",
836 RocksDBOptionsParser::VerifyCFOptions(exact
, base_cf_opt
, new_cf_opt
));
838 std::unordered_map
<std::string
, std::string
> cf_options_map
= {
839 {"write_buffer_size", "1"},
840 {"max_write_buffer_number", "2"},
841 {"min_write_buffer_number_to_merge", "3"},
844 GetColumnFamilyOptionsFromMap(base_cf_opt
, cf_options_map
, &new_cf_opt
));
845 cf_options_map
["unknown_option"] = "1";
847 GetColumnFamilyOptionsFromMap(base_cf_opt
, cf_options_map
, &new_cf_opt
));
849 RocksDBOptionsParser::VerifyCFOptions(exact
, base_cf_opt
, new_cf_opt
));
850 ASSERT_OK(GetColumnFamilyOptionsFromMap(base_cf_opt
, cf_options_map
,
851 &new_cf_opt
, true, true));
853 DBOptions base_db_opt
;
854 DBOptions new_db_opt
;
855 std::unordered_map
<std::string
, std::string
> db_options_map
= {
856 {"create_if_missing", "false"},
857 {"create_missing_column_families", "true"},
858 {"error_if_exists", "false"},
859 {"paranoid_checks", "true"},
860 {"track_and_verify_wals_in_manifest", "true"},
861 {"verify_sst_unique_id_in_manifest", "true"},
862 {"max_open_files", "32"},
864 ASSERT_OK(GetDBOptionsFromMap(base_db_opt
, db_options_map
, &new_db_opt
));
865 ASSERT_EQ(new_db_opt
.create_if_missing
, false);
866 ASSERT_EQ(new_db_opt
.create_missing_column_families
, true);
867 ASSERT_EQ(new_db_opt
.error_if_exists
, false);
868 ASSERT_EQ(new_db_opt
.paranoid_checks
, true);
869 ASSERT_EQ(new_db_opt
.track_and_verify_wals_in_manifest
, true);
870 ASSERT_EQ(new_db_opt
.verify_sst_unique_id_in_manifest
, true);
871 ASSERT_EQ(new_db_opt
.max_open_files
, 32);
872 db_options_map
["unknown_option"] = "1";
873 Status s
= GetDBOptionsFromMap(base_db_opt
, db_options_map
, &new_db_opt
);
875 ASSERT_TRUE(s
.IsInvalidArgument());
878 RocksDBOptionsParser::VerifyDBOptions(exact
, base_db_opt
, new_db_opt
));
879 ASSERT_OK(GetDBOptionsFromMap(base_db_opt
, db_options_map
, &new_db_opt
, true,
881 ASSERT_OK(GetDBOptionsFromString(
883 "create_if_missing=false;error_if_exists=false;max_open_files=42;",
885 ASSERT_EQ(new_db_opt
.create_if_missing
, false);
886 ASSERT_EQ(new_db_opt
.error_if_exists
, false);
887 ASSERT_EQ(new_db_opt
.max_open_files
, 42);
888 s
= GetDBOptionsFromString(
890 "create_if_missing=false;error_if_exists=false;max_open_files=42;"
894 ASSERT_TRUE(s
.IsInvalidArgument());
896 RocksDBOptionsParser::VerifyDBOptions(exact
, base_db_opt
, new_db_opt
));
899 #endif // !ROCKSDB_LITE
901 #ifndef ROCKSDB_LITE // GetBlockBasedTableOptionsFromString is not supported
902 TEST_F(OptionsTest
, GetBlockBasedTableOptionsFromString
) {
903 BlockBasedTableOptions table_opt
;
904 BlockBasedTableOptions new_opt
;
905 ConfigOptions config_options
;
906 config_options
.input_strings_escaped
= false;
907 config_options
.ignore_unknown_options
= false;
908 config_options
.ignore_unsupported_options
= false;
910 // make sure default values are overwritten by something else
911 ASSERT_OK(GetBlockBasedTableOptionsFromString(
912 config_options
, table_opt
,
913 "cache_index_and_filter_blocks=1;index_type=kHashSearch;"
915 "block_cache=1M;block_cache_compressed=1k;block_size=1024;"
916 "block_size_deviation=8;block_restart_interval=4;"
917 "format_version=5;whole_key_filtering=1;"
918 "filter_policy=bloomfilter:4.567:false;detect_filter_construct_"
920 // A bug caused read_amp_bytes_per_bit to be a large integer in OPTIONS
921 // file generated by 6.10 to 6.14. Though bug is fixed in these releases,
922 // we need to handle the case of loading OPTIONS file generated before the
924 "read_amp_bytes_per_bit=17179869185;",
926 ASSERT_TRUE(new_opt
.cache_index_and_filter_blocks
);
927 ASSERT_EQ(new_opt
.index_type
, BlockBasedTableOptions::kHashSearch
);
928 ASSERT_EQ(new_opt
.checksum
, ChecksumType::kxxHash
);
929 ASSERT_TRUE(new_opt
.block_cache
!= nullptr);
930 ASSERT_EQ(new_opt
.block_cache
->GetCapacity(), 1024UL*1024UL);
931 ASSERT_TRUE(new_opt
.block_cache_compressed
!= nullptr);
932 ASSERT_EQ(new_opt
.block_cache_compressed
->GetCapacity(), 1024UL);
933 ASSERT_EQ(new_opt
.block_size
, 1024UL);
934 ASSERT_EQ(new_opt
.block_size_deviation
, 8);
935 ASSERT_EQ(new_opt
.block_restart_interval
, 4);
936 ASSERT_EQ(new_opt
.format_version
, 5U);
937 ASSERT_EQ(new_opt
.whole_key_filtering
, true);
938 ASSERT_EQ(new_opt
.detect_filter_construct_corruption
, true);
939 ASSERT_TRUE(new_opt
.filter_policy
!= nullptr);
940 auto bfp
= new_opt
.filter_policy
->CheckedCast
<BloomFilterPolicy
>();
941 ASSERT_NE(bfp
, nullptr);
942 EXPECT_EQ(bfp
->GetMillibitsPerKey(), 4567);
943 EXPECT_EQ(bfp
->GetWholeBitsPerKey(), 5);
944 // Verify that only the lower 32bits are stored in
945 // new_opt.read_amp_bytes_per_bit.
946 EXPECT_EQ(1U, new_opt
.read_amp_bytes_per_bit
);
949 Status s
= GetBlockBasedTableOptionsFromString(
950 config_options
, table_opt
,
951 "cache_index_and_filter_blocks=1;index_type=kBinarySearch;"
955 ASSERT_TRUE(s
.IsInvalidArgument());
956 ASSERT_EQ(static_cast<bool>(table_opt
.cache_index_and_filter_blocks
),
957 new_opt
.cache_index_and_filter_blocks
);
958 ASSERT_EQ(table_opt
.index_type
, new_opt
.index_type
);
960 // unrecognized index type
961 s
= GetBlockBasedTableOptionsFromString(
962 config_options
, table_opt
,
963 "cache_index_and_filter_blocks=1;index_type=kBinarySearchXX", &new_opt
);
965 ASSERT_TRUE(s
.IsInvalidArgument());
966 ASSERT_EQ(table_opt
.cache_index_and_filter_blocks
,
967 new_opt
.cache_index_and_filter_blocks
);
968 ASSERT_EQ(table_opt
.index_type
, new_opt
.index_type
);
970 // unrecognized checksum type
971 ASSERT_NOK(GetBlockBasedTableOptionsFromString(
972 config_options
, table_opt
,
973 "cache_index_and_filter_blocks=1;checksum=kxxHashXX", &new_opt
));
974 ASSERT_EQ(table_opt
.cache_index_and_filter_blocks
,
975 new_opt
.cache_index_and_filter_blocks
);
976 ASSERT_EQ(table_opt
.index_type
, new_opt
.index_type
);
978 // unrecognized filter policy name
979 s
= GetBlockBasedTableOptionsFromString(config_options
, table_opt
,
980 "filter_policy=bloomfilterxx:4:true",
983 ASSERT_TRUE(s
.IsInvalidArgument());
985 // missing bits per key
986 s
= GetBlockBasedTableOptionsFromString(
987 config_options
, table_opt
, "filter_policy=bloomfilter", &new_opt
);
989 ASSERT_TRUE(s
.IsInvalidArgument());
991 // Used to be rejected, now accepted
992 ASSERT_OK(GetBlockBasedTableOptionsFromString(
993 config_options
, table_opt
, "filter_policy=bloomfilter:4", &new_opt
));
994 bfp
= dynamic_cast<const BloomFilterPolicy
*>(new_opt
.filter_policy
.get());
995 EXPECT_EQ(bfp
->GetMillibitsPerKey(), 4000);
996 EXPECT_EQ(bfp
->GetWholeBitsPerKey(), 4);
998 // use_block_based_builder=true now ignored in public API (same as false)
999 ASSERT_OK(GetBlockBasedTableOptionsFromString(
1000 config_options
, table_opt
, "filter_policy=bloomfilter:4:true", &new_opt
));
1001 bfp
= dynamic_cast<const BloomFilterPolicy
*>(new_opt
.filter_policy
.get());
1002 EXPECT_EQ(bfp
->GetMillibitsPerKey(), 4000);
1003 EXPECT_EQ(bfp
->GetWholeBitsPerKey(), 4);
1005 // Test configuring using other internal names
1006 ASSERT_OK(GetBlockBasedTableOptionsFromString(
1007 config_options
, table_opt
,
1008 "filter_policy=rocksdb.internal.LegacyBloomFilter:3", &new_opt
));
1010 dynamic_cast<const BuiltinFilterPolicy
*>(new_opt
.filter_policy
.get());
1011 EXPECT_EQ(builtin
->GetId(), "rocksdb.internal.LegacyBloomFilter:3");
1013 ASSERT_OK(GetBlockBasedTableOptionsFromString(
1014 config_options
, table_opt
,
1015 "filter_policy=rocksdb.internal.FastLocalBloomFilter:1.234", &new_opt
));
1017 dynamic_cast<const BuiltinFilterPolicy
*>(new_opt
.filter_policy
.get());
1018 EXPECT_EQ(builtin
->GetId(), "rocksdb.internal.FastLocalBloomFilter:1.234");
1020 ASSERT_OK(GetBlockBasedTableOptionsFromString(
1021 config_options
, table_opt
,
1022 "filter_policy=rocksdb.internal.Standard128RibbonFilter:1.234",
1025 dynamic_cast<const BuiltinFilterPolicy
*>(new_opt
.filter_policy
.get());
1026 EXPECT_EQ(builtin
->GetId(), "rocksdb.internal.Standard128RibbonFilter:1.234");
1028 // Ribbon filter policy (no Bloom hybrid)
1029 ASSERT_OK(GetBlockBasedTableOptionsFromString(
1030 config_options
, table_opt
, "filter_policy=ribbonfilter:5.678:-1;",
1032 ASSERT_TRUE(new_opt
.filter_policy
!= nullptr);
1034 dynamic_cast<const RibbonFilterPolicy
*>(new_opt
.filter_policy
.get());
1035 EXPECT_EQ(rfp
->GetMillibitsPerKey(), 5678);
1036 EXPECT_EQ(rfp
->GetBloomBeforeLevel(), -1);
1038 // Ribbon filter policy (default Bloom hybrid)
1039 ASSERT_OK(GetBlockBasedTableOptionsFromString(
1040 config_options
, table_opt
, "filter_policy=ribbonfilter:6.789;",
1042 ASSERT_TRUE(new_opt
.filter_policy
!= nullptr);
1043 rfp
= dynamic_cast<const RibbonFilterPolicy
*>(new_opt
.filter_policy
.get());
1044 EXPECT_EQ(rfp
->GetMillibitsPerKey(), 6789);
1045 EXPECT_EQ(rfp
->GetBloomBeforeLevel(), 0);
1047 // Ribbon filter policy (custom Bloom hybrid)
1048 ASSERT_OK(GetBlockBasedTableOptionsFromString(
1049 config_options
, table_opt
, "filter_policy=ribbonfilter:6.789:5;",
1051 ASSERT_TRUE(new_opt
.filter_policy
!= nullptr);
1052 rfp
= dynamic_cast<const RibbonFilterPolicy
*>(new_opt
.filter_policy
.get());
1053 EXPECT_EQ(rfp
->GetMillibitsPerKey(), 6789);
1054 EXPECT_EQ(rfp
->GetBloomBeforeLevel(), 5);
1056 // Check block cache options are overwritten when specified
1057 // in new format as a struct.
1058 ASSERT_OK(GetBlockBasedTableOptionsFromString(
1059 config_options
, table_opt
,
1060 "block_cache={capacity=1M;num_shard_bits=4;"
1061 "strict_capacity_limit=true;high_pri_pool_ratio=0.5;};"
1062 "block_cache_compressed={capacity=1M;num_shard_bits=4;"
1063 "strict_capacity_limit=true;high_pri_pool_ratio=0.5;}",
1065 ASSERT_TRUE(new_opt
.block_cache
!= nullptr);
1066 ASSERT_EQ(new_opt
.block_cache
->GetCapacity(), 1024UL*1024UL);
1067 ASSERT_EQ(std::dynamic_pointer_cast
<ShardedCacheBase
>(new_opt
.block_cache
)
1068 ->GetNumShardBits(),
1070 ASSERT_EQ(new_opt
.block_cache
->HasStrictCapacityLimit(), true);
1071 ASSERT_EQ(std::dynamic_pointer_cast
<LRUCache
>(
1072 new_opt
.block_cache
)->GetHighPriPoolRatio(), 0.5);
1073 ASSERT_TRUE(new_opt
.block_cache_compressed
!= nullptr);
1074 ASSERT_EQ(new_opt
.block_cache_compressed
->GetCapacity(), 1024UL*1024UL);
1075 ASSERT_EQ(std::dynamic_pointer_cast
<ShardedCacheBase
>(
1076 new_opt
.block_cache_compressed
)
1077 ->GetNumShardBits(),
1079 ASSERT_EQ(new_opt
.block_cache_compressed
->HasStrictCapacityLimit(), true);
1080 ASSERT_EQ(std::dynamic_pointer_cast
<LRUCache
>(
1081 new_opt
.block_cache_compressed
)->GetHighPriPoolRatio(),
1084 // Set only block cache capacity. Check other values are
1085 // reset to default values.
1086 ASSERT_OK(GetBlockBasedTableOptionsFromString(
1087 config_options
, table_opt
,
1088 "block_cache={capacity=2M};"
1089 "block_cache_compressed={capacity=2M}",
1091 ASSERT_TRUE(new_opt
.block_cache
!= nullptr);
1092 ASSERT_EQ(new_opt
.block_cache
->GetCapacity(), 2*1024UL*1024UL);
1094 ASSERT_EQ(std::dynamic_pointer_cast
<ShardedCacheBase
>(new_opt
.block_cache
)
1095 ->GetNumShardBits(),
1096 GetDefaultCacheShardBits(new_opt
.block_cache
->GetCapacity()));
1097 ASSERT_EQ(new_opt
.block_cache
->HasStrictCapacityLimit(), false);
1098 ASSERT_EQ(std::dynamic_pointer_cast
<LRUCache
>(new_opt
.block_cache
)
1099 ->GetHighPriPoolRatio(),
1101 ASSERT_TRUE(new_opt
.block_cache_compressed
!= nullptr);
1102 ASSERT_EQ(new_opt
.block_cache_compressed
->GetCapacity(), 2*1024UL*1024UL);
1105 std::dynamic_pointer_cast
<ShardedCacheBase
>(
1106 new_opt
.block_cache_compressed
)
1107 ->GetNumShardBits(),
1108 GetDefaultCacheShardBits(new_opt
.block_cache_compressed
->GetCapacity()));
1109 ASSERT_EQ(new_opt
.block_cache_compressed
->HasStrictCapacityLimit(), false);
1110 ASSERT_EQ(std::dynamic_pointer_cast
<LRUCache
>(new_opt
.block_cache_compressed
)
1111 ->GetHighPriPoolRatio(),
1114 // Set couple of block cache options.
1115 ASSERT_OK(GetBlockBasedTableOptionsFromString(
1116 config_options
, table_opt
,
1117 "block_cache={num_shard_bits=5;high_pri_pool_ratio=0.5;};"
1118 "block_cache_compressed={num_shard_bits=5;"
1119 "high_pri_pool_ratio=0.0;}",
1121 ASSERT_EQ(new_opt
.block_cache
->GetCapacity(), 0);
1122 ASSERT_EQ(std::dynamic_pointer_cast
<ShardedCacheBase
>(new_opt
.block_cache
)
1123 ->GetNumShardBits(),
1125 ASSERT_EQ(new_opt
.block_cache
->HasStrictCapacityLimit(), false);
1126 ASSERT_EQ(std::dynamic_pointer_cast
<LRUCache
>(
1127 new_opt
.block_cache
)->GetHighPriPoolRatio(), 0.5);
1128 ASSERT_TRUE(new_opt
.block_cache_compressed
!= nullptr);
1129 ASSERT_EQ(new_opt
.block_cache_compressed
->GetCapacity(), 0);
1130 ASSERT_EQ(std::dynamic_pointer_cast
<ShardedCacheBase
>(
1131 new_opt
.block_cache_compressed
)
1132 ->GetNumShardBits(),
1134 ASSERT_EQ(new_opt
.block_cache_compressed
->HasStrictCapacityLimit(), false);
1135 ASSERT_EQ(std::dynamic_pointer_cast
<LRUCache
>(new_opt
.block_cache_compressed
)
1136 ->GetHighPriPoolRatio(),
1139 // Set couple of block cache options.
1140 ASSERT_OK(GetBlockBasedTableOptionsFromString(
1141 config_options
, table_opt
,
1142 "block_cache={capacity=1M;num_shard_bits=4;"
1143 "strict_capacity_limit=true;};"
1144 "block_cache_compressed={capacity=1M;num_shard_bits=4;"
1145 "strict_capacity_limit=true;}",
1147 ASSERT_TRUE(new_opt
.block_cache
!= nullptr);
1148 ASSERT_EQ(new_opt
.block_cache
->GetCapacity(), 1024UL*1024UL);
1149 ASSERT_EQ(std::dynamic_pointer_cast
<ShardedCacheBase
>(new_opt
.block_cache
)
1150 ->GetNumShardBits(),
1152 ASSERT_EQ(new_opt
.block_cache
->HasStrictCapacityLimit(), true);
1153 ASSERT_EQ(std::dynamic_pointer_cast
<LRUCache
>(new_opt
.block_cache
)
1154 ->GetHighPriPoolRatio(),
1156 ASSERT_TRUE(new_opt
.block_cache_compressed
!= nullptr);
1157 ASSERT_EQ(new_opt
.block_cache_compressed
->GetCapacity(), 1024UL*1024UL);
1158 ASSERT_EQ(std::dynamic_pointer_cast
<ShardedCacheBase
>(
1159 new_opt
.block_cache_compressed
)
1160 ->GetNumShardBits(),
1162 ASSERT_EQ(new_opt
.block_cache_compressed
->HasStrictCapacityLimit(), true);
1163 ASSERT_EQ(std::dynamic_pointer_cast
<LRUCache
>(new_opt
.block_cache_compressed
)
1164 ->GetHighPriPoolRatio(),
1167 ASSERT_OK(GetBlockBasedTableOptionsFromString(
1168 config_options
, table_opt
, "filter_policy=rocksdb.BloomFilter:1.234",
1170 ASSERT_TRUE(new_opt
.filter_policy
!= nullptr);
1172 new_opt
.filter_policy
->IsInstanceOf(BloomFilterPolicy::kClassName()));
1174 new_opt
.filter_policy
->IsInstanceOf(BloomFilterPolicy::kNickName()));
1176 // Ribbon filter policy alternative name
1177 ASSERT_OK(GetBlockBasedTableOptionsFromString(
1178 config_options
, table_opt
, "filter_policy=rocksdb.RibbonFilter:6.789:5;",
1180 ASSERT_TRUE(new_opt
.filter_policy
!= nullptr);
1182 new_opt
.filter_policy
->IsInstanceOf(RibbonFilterPolicy::kClassName()));
1184 new_opt
.filter_policy
->IsInstanceOf(RibbonFilterPolicy::kNickName()));
1186 #endif // !ROCKSDB_LITE
1189 #ifndef ROCKSDB_LITE // GetPlainTableOptionsFromString is not supported
1190 TEST_F(OptionsTest
, GetPlainTableOptionsFromString
) {
1191 PlainTableOptions table_opt
;
1192 PlainTableOptions new_opt
;
1193 ConfigOptions config_options
;
1194 config_options
.input_strings_escaped
= false;
1195 config_options
.ignore_unknown_options
= false;
1196 // make sure default values are overwritten by something else
1197 ASSERT_OK(GetPlainTableOptionsFromString(
1198 config_options
, table_opt
,
1199 "user_key_len=66;bloom_bits_per_key=20;hash_table_ratio=0.5;"
1200 "index_sparseness=8;huge_page_tlb_size=4;encoding_type=kPrefix;"
1201 "full_scan_mode=true;store_index_in_file=true",
1203 ASSERT_EQ(new_opt
.user_key_len
, 66u);
1204 ASSERT_EQ(new_opt
.bloom_bits_per_key
, 20);
1205 ASSERT_EQ(new_opt
.hash_table_ratio
, 0.5);
1206 ASSERT_EQ(new_opt
.index_sparseness
, 8);
1207 ASSERT_EQ(new_opt
.huge_page_tlb_size
, 4);
1208 ASSERT_EQ(new_opt
.encoding_type
, EncodingType::kPrefix
);
1209 ASSERT_TRUE(new_opt
.full_scan_mode
);
1210 ASSERT_TRUE(new_opt
.store_index_in_file
);
1213 Status s
= GetPlainTableOptionsFromString(
1214 config_options
, table_opt
,
1215 "user_key_len=66;bloom_bits_per_key=20;hash_table_ratio=0.5;"
1219 ASSERT_TRUE(s
.IsInvalidArgument());
1221 // unrecognized EncodingType
1222 s
= GetPlainTableOptionsFromString(
1223 config_options
, table_opt
,
1224 "user_key_len=66;bloom_bits_per_key=20;hash_table_ratio=0.5;"
1225 "encoding_type=kPrefixXX",
1228 ASSERT_TRUE(s
.IsInvalidArgument());
1230 #endif // !ROCKSDB_LITE
1232 #ifndef ROCKSDB_LITE // GetMemTableRepFactoryFromString is not supported
1233 TEST_F(OptionsTest
, GetMemTableRepFactoryFromString
) {
1234 std::unique_ptr
<MemTableRepFactory
> new_mem_factory
= nullptr;
1236 ASSERT_OK(GetMemTableRepFactoryFromString("skip_list", &new_mem_factory
));
1237 ASSERT_OK(GetMemTableRepFactoryFromString("skip_list:16", &new_mem_factory
));
1238 ASSERT_STREQ(new_mem_factory
->Name(), "SkipListFactory");
1239 ASSERT_NOK(GetMemTableRepFactoryFromString("skip_list:16:invalid_opt",
1242 ASSERT_OK(GetMemTableRepFactoryFromString("prefix_hash", &new_mem_factory
));
1243 ASSERT_OK(GetMemTableRepFactoryFromString("prefix_hash:1000",
1245 ASSERT_STREQ(new_mem_factory
->Name(), "HashSkipListRepFactory");
1246 ASSERT_NOK(GetMemTableRepFactoryFromString("prefix_hash:1000:invalid_opt",
1249 ASSERT_OK(GetMemTableRepFactoryFromString("hash_linkedlist",
1251 ASSERT_OK(GetMemTableRepFactoryFromString("hash_linkedlist:1000",
1253 ASSERT_EQ(std::string(new_mem_factory
->Name()), "HashLinkListRepFactory");
1254 ASSERT_NOK(GetMemTableRepFactoryFromString("hash_linkedlist:1000:invalid_opt",
1257 ASSERT_OK(GetMemTableRepFactoryFromString("vector", &new_mem_factory
));
1258 ASSERT_OK(GetMemTableRepFactoryFromString("vector:1024", &new_mem_factory
));
1259 ASSERT_EQ(std::string(new_mem_factory
->Name()), "VectorRepFactory");
1260 ASSERT_NOK(GetMemTableRepFactoryFromString("vector:1024:invalid_opt",
1263 ASSERT_NOK(GetMemTableRepFactoryFromString("cuckoo", &new_mem_factory
));
1264 // CuckooHash memtable is already removed.
1265 ASSERT_NOK(GetMemTableRepFactoryFromString("cuckoo:1024", &new_mem_factory
));
1267 ASSERT_NOK(GetMemTableRepFactoryFromString("bad_factory", &new_mem_factory
));
1269 #endif // !ROCKSDB_LITE
1271 TEST_F(OptionsTest
, MemTableRepFactoryCreateFromString
) {
1272 std::unique_ptr
<MemTableRepFactory
> new_mem_factory
= nullptr;
1273 ConfigOptions config_options
;
1274 config_options
.ignore_unsupported_options
= false;
1275 config_options
.ignore_unknown_options
= false;
1277 ASSERT_OK(MemTableRepFactory::CreateFromString(config_options
, "skip_list",
1279 ASSERT_OK(MemTableRepFactory::CreateFromString(config_options
, "skip_list:16",
1281 ASSERT_STREQ(new_mem_factory
->Name(), "SkipListFactory");
1282 ASSERT_TRUE(new_mem_factory
->IsInstanceOf("skip_list"));
1283 ASSERT_TRUE(new_mem_factory
->IsInstanceOf("SkipListFactory"));
1284 ASSERT_NOK(MemTableRepFactory::CreateFromString(
1285 config_options
, "skip_list:16:invalid_opt", &new_mem_factory
));
1287 ASSERT_NOK(MemTableRepFactory::CreateFromString(
1288 config_options
, "invalid_opt=10", &new_mem_factory
));
1291 ASSERT_OK(MemTableRepFactory::CreateFromString(config_options
, "",
1293 ASSERT_EQ(new_mem_factory
, nullptr);
1294 ASSERT_NOK(MemTableRepFactory::CreateFromString(
1295 config_options
, "invalid_opt=10", &new_mem_factory
));
1297 #ifndef ROCKSDB_LITE
1298 ASSERT_OK(MemTableRepFactory::CreateFromString(
1299 config_options
, "id=skip_list; lookahead=32", &new_mem_factory
));
1300 ASSERT_OK(MemTableRepFactory::CreateFromString(config_options
, "prefix_hash",
1302 ASSERT_OK(MemTableRepFactory::CreateFromString(
1303 config_options
, "prefix_hash:1000", &new_mem_factory
));
1304 ASSERT_STREQ(new_mem_factory
->Name(), "HashSkipListRepFactory");
1305 ASSERT_TRUE(new_mem_factory
->IsInstanceOf("prefix_hash"));
1306 ASSERT_TRUE(new_mem_factory
->IsInstanceOf("HashSkipListRepFactory"));
1307 ASSERT_NOK(MemTableRepFactory::CreateFromString(
1308 config_options
, "prefix_hash:1000:invalid_opt", &new_mem_factory
));
1309 ASSERT_OK(MemTableRepFactory::CreateFromString(
1311 "id=prefix_hash; bucket_count=32; skiplist_height=64; "
1312 "branching_factor=16",
1314 ASSERT_NOK(MemTableRepFactory::CreateFromString(
1316 "id=prefix_hash; bucket_count=32; skiplist_height=64; "
1317 "branching_factor=16; invalid=unknown",
1320 ASSERT_OK(MemTableRepFactory::CreateFromString(
1321 config_options
, "hash_linkedlist", &new_mem_factory
));
1322 ASSERT_OK(MemTableRepFactory::CreateFromString(
1323 config_options
, "hash_linkedlist:1000", &new_mem_factory
));
1324 ASSERT_STREQ(new_mem_factory
->Name(), "HashLinkListRepFactory");
1325 ASSERT_TRUE(new_mem_factory
->IsInstanceOf("hash_linkedlist"));
1326 ASSERT_TRUE(new_mem_factory
->IsInstanceOf("HashLinkListRepFactory"));
1327 ASSERT_NOK(MemTableRepFactory::CreateFromString(
1328 config_options
, "hash_linkedlist:1000:invalid_opt", &new_mem_factory
));
1329 ASSERT_OK(MemTableRepFactory::CreateFromString(
1331 "id=hash_linkedlist; bucket_count=32; threshold=64; huge_page_size=16; "
1332 "logging_threshold=12; log_when_flash=true",
1334 ASSERT_NOK(MemTableRepFactory::CreateFromString(
1336 "id=hash_linkedlist; bucket_count=32; threshold=64; huge_page_size=16; "
1337 "logging_threshold=12; log_when_flash=true; invalid=unknown",
1340 ASSERT_OK(MemTableRepFactory::CreateFromString(config_options
, "vector",
1342 ASSERT_OK(MemTableRepFactory::CreateFromString(config_options
, "vector:1024",
1344 ASSERT_STREQ(new_mem_factory
->Name(), "VectorRepFactory");
1345 ASSERT_TRUE(new_mem_factory
->IsInstanceOf("vector"));
1346 ASSERT_TRUE(new_mem_factory
->IsInstanceOf("VectorRepFactory"));
1347 ASSERT_NOK(MemTableRepFactory::CreateFromString(
1348 config_options
, "vector:1024:invalid_opt", &new_mem_factory
));
1349 ASSERT_OK(MemTableRepFactory::CreateFromString(
1350 config_options
, "id=vector; count=42", &new_mem_factory
));
1351 ASSERT_NOK(MemTableRepFactory::CreateFromString(
1352 config_options
, "id=vector; invalid=unknown", &new_mem_factory
));
1353 #endif // ROCKSDB_LITE
1354 ASSERT_NOK(MemTableRepFactory::CreateFromString(config_options
, "cuckoo",
1356 // CuckooHash memtable is already removed.
1357 ASSERT_NOK(MemTableRepFactory::CreateFromString(config_options
, "cuckoo:1024",
1360 ASSERT_NOK(MemTableRepFactory::CreateFromString(config_options
, "bad_factory",
1364 #ifndef ROCKSDB_LITE // GetOptionsFromString is not supported in RocksDB Lite
1365 class CustomEnv
: public EnvWrapper
{
1367 explicit CustomEnv(Env
* _target
) : EnvWrapper(_target
) {}
1368 static const char* kClassName() { return "CustomEnv"; }
1369 const char* Name() const override
{ return kClassName(); }
1372 TEST_F(OptionsTest
, GetOptionsFromStringTest
) {
1373 Options base_options
, new_options
;
1374 ConfigOptions config_options
;
1375 config_options
.input_strings_escaped
= false;
1376 config_options
.ignore_unknown_options
= false;
1378 base_options
.write_buffer_size
= 20;
1379 base_options
.min_write_buffer_number_to_merge
= 15;
1380 BlockBasedTableOptions block_based_table_options
;
1381 block_based_table_options
.cache_index_and_filter_blocks
= true;
1382 base_options
.table_factory
.reset(
1383 NewBlockBasedTableFactory(block_based_table_options
));
1385 // Register an Env with object registry.
1386 ObjectLibrary::Default()->AddFactory
<Env
>(
1387 CustomEnv::kClassName(),
1388 [](const std::string
& /*name*/, std::unique_ptr
<Env
>* /*env_guard*/,
1389 std::string
* /* errmsg */) {
1390 static CustomEnv
env(Env::Default());
1394 ASSERT_OK(GetOptionsFromString(
1395 config_options
, base_options
,
1396 "write_buffer_size=10;max_write_buffer_number=16;"
1397 "block_based_table_factory={block_cache=1M;block_size=4;};"
1398 "compression_opts=4:5:6;create_if_missing=true;max_open_files=1;"
1399 "bottommost_compression_opts=5:6:7;create_if_missing=true;max_open_files="
1401 "rate_limiter_bytes_per_sec=1024;env=CustomEnv",
1404 ASSERT_EQ(new_options
.compression_opts
.window_bits
, 4);
1405 ASSERT_EQ(new_options
.compression_opts
.level
, 5);
1406 ASSERT_EQ(new_options
.compression_opts
.strategy
, 6);
1407 ASSERT_EQ(new_options
.compression_opts
.max_dict_bytes
, 0u);
1408 ASSERT_EQ(new_options
.compression_opts
.zstd_max_train_bytes
, 0u);
1409 ASSERT_EQ(new_options
.compression_opts
.parallel_threads
, 1u);
1410 ASSERT_EQ(new_options
.compression_opts
.enabled
, false);
1411 ASSERT_EQ(new_options
.compression_opts
.use_zstd_dict_trainer
, true);
1412 ASSERT_EQ(new_options
.bottommost_compression
, kDisableCompressionOption
);
1413 ASSERT_EQ(new_options
.bottommost_compression_opts
.window_bits
, 5);
1414 ASSERT_EQ(new_options
.bottommost_compression_opts
.level
, 6);
1415 ASSERT_EQ(new_options
.bottommost_compression_opts
.strategy
, 7);
1416 ASSERT_EQ(new_options
.bottommost_compression_opts
.max_dict_bytes
, 0u);
1417 ASSERT_EQ(new_options
.bottommost_compression_opts
.zstd_max_train_bytes
, 0u);
1418 ASSERT_EQ(new_options
.bottommost_compression_opts
.parallel_threads
, 1u);
1419 ASSERT_EQ(new_options
.bottommost_compression_opts
.enabled
, false);
1420 ASSERT_EQ(new_options
.bottommost_compression_opts
.use_zstd_dict_trainer
,
1422 ASSERT_EQ(new_options
.write_buffer_size
, 10U);
1423 ASSERT_EQ(new_options
.max_write_buffer_number
, 16);
1424 const auto new_bbto
=
1425 new_options
.table_factory
->GetOptions
<BlockBasedTableOptions
>();
1426 ASSERT_NE(new_bbto
, nullptr);
1427 ASSERT_EQ(new_bbto
->block_cache
->GetCapacity(), 1U << 20);
1428 ASSERT_EQ(new_bbto
->block_size
, 4U);
1429 // don't overwrite block based table options
1430 ASSERT_TRUE(new_bbto
->cache_index_and_filter_blocks
);
1432 ASSERT_EQ(new_options
.create_if_missing
, true);
1433 ASSERT_EQ(new_options
.max_open_files
, 1);
1434 ASSERT_TRUE(new_options
.rate_limiter
.get() != nullptr);
1435 Env
* newEnv
= new_options
.env
;
1436 ASSERT_OK(Env::LoadEnv(CustomEnv::kClassName(), &newEnv
));
1437 ASSERT_EQ(newEnv
, new_options
.env
);
1439 config_options
.ignore_unknown_options
= false;
1440 // Test a bad value for a DBOption returns a failure
1441 base_options
.dump_malloc_stats
= false;
1442 base_options
.write_buffer_size
= 1024;
1443 Options bad_options
= new_options
;
1444 Status s
= GetOptionsFromString(config_options
, base_options
,
1445 "create_if_missing=XX;dump_malloc_stats=true",
1448 ASSERT_TRUE(s
.IsInvalidArgument());
1449 ASSERT_EQ(bad_options
.dump_malloc_stats
, false);
1451 bad_options
= new_options
;
1452 s
= GetOptionsFromString(config_options
, base_options
,
1453 "write_buffer_size=XX;dump_malloc_stats=true",
1456 ASSERT_TRUE(s
.IsInvalidArgument());
1458 ASSERT_EQ(bad_options
.dump_malloc_stats
, false);
1460 // Test a bad value for a TableFactory Option returns a failure
1461 bad_options
= new_options
;
1462 s
= GetOptionsFromString(config_options
, base_options
,
1463 "write_buffer_size=16;dump_malloc_stats=true"
1464 "block_based_table_factory={block_size=XX;};",
1466 ASSERT_TRUE(s
.IsInvalidArgument());
1467 ASSERT_EQ(bad_options
.dump_malloc_stats
, false);
1468 ASSERT_EQ(bad_options
.write_buffer_size
, 1024);
1470 config_options
.ignore_unknown_options
= true;
1471 ASSERT_OK(GetOptionsFromString(config_options
, base_options
,
1472 "create_if_missing=XX;dump_malloc_stats=true;"
1473 "write_buffer_size=XX;"
1474 "block_based_table_factory={block_size=XX;};",
1476 ASSERT_EQ(bad_options
.create_if_missing
, base_options
.create_if_missing
);
1477 ASSERT_EQ(bad_options
.dump_malloc_stats
, true);
1478 ASSERT_EQ(bad_options
.write_buffer_size
, base_options
.write_buffer_size
);
1480 // Test the old interface
1481 ASSERT_OK(GetOptionsFromString(
1483 "write_buffer_size=22;max_write_buffer_number=33;max_open_files=44;",
1485 ASSERT_EQ(new_options
.write_buffer_size
, 22U);
1486 ASSERT_EQ(new_options
.max_write_buffer_number
, 33);
1487 ASSERT_EQ(new_options
.max_open_files
, 44);
1490 TEST_F(OptionsTest
, DBOptionsSerialization
) {
1491 Options base_options
, new_options
;
1493 ConfigOptions config_options
;
1494 config_options
.input_strings_escaped
= false;
1495 config_options
.ignore_unknown_options
= false;
1497 // Phase 1: Make big change in base_options
1498 test::RandomInitDBOptions(&base_options
, &rnd
);
1500 // Phase 2: obtain a string from base_option
1501 std::string base_options_file_content
;
1502 ASSERT_OK(GetStringFromDBOptions(config_options
, base_options
,
1503 &base_options_file_content
));
1505 // Phase 3: Set new_options from the derived string and expect
1506 // new_options == base_options
1507 ASSERT_OK(GetDBOptionsFromString(config_options
, DBOptions(),
1508 base_options_file_content
, &new_options
));
1509 ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(config_options
, base_options
,
1513 TEST_F(OptionsTest
, OptionsComposeDecompose
) {
1514 // build an Options from DBOptions + CFOptions, then decompose it to verify
1515 // we get same constituent options.
1516 DBOptions base_db_opts
;
1517 ColumnFamilyOptions base_cf_opts
;
1519 config_options
; // Use default for ignore(false) and check (exact)
1520 config_options
.input_strings_escaped
= false;
1523 test::RandomInitDBOptions(&base_db_opts
, &rnd
);
1524 test::RandomInitCFOptions(&base_cf_opts
, base_db_opts
, &rnd
);
1526 Options
base_opts(base_db_opts
, base_cf_opts
);
1527 DBOptions
new_db_opts(base_opts
);
1528 ColumnFamilyOptions
new_cf_opts(base_opts
);
1530 ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(config_options
, base_db_opts
,
1532 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options
, base_cf_opts
,
1534 delete new_cf_opts
.compaction_filter
;
1537 TEST_F(OptionsTest
, DBOptionsComposeImmutable
) {
1538 // Build a DBOptions from an Immutable/Mutable one and verify that
1539 // we get same constituent options.
1540 ConfigOptions config_options
;
1542 DBOptions base_opts
, new_opts
;
1543 test::RandomInitDBOptions(&base_opts
, &rnd
);
1544 MutableDBOptions
m_opts(base_opts
);
1545 ImmutableDBOptions
i_opts(base_opts
);
1546 new_opts
= BuildDBOptions(i_opts
, m_opts
);
1547 ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(config_options
, base_opts
,
1551 TEST_F(OptionsTest
, GetMutableDBOptions
) {
1553 DBOptions base_opts
;
1554 std::string opts_str
;
1555 std::unordered_map
<std::string
, std::string
> opts_map
;
1556 ConfigOptions config_options
;
1558 test::RandomInitDBOptions(&base_opts
, &rnd
);
1559 ImmutableDBOptions
i_opts(base_opts
);
1560 MutableDBOptions
m_opts(base_opts
);
1561 MutableDBOptions new_opts
;
1562 ASSERT_OK(GetStringFromMutableDBOptions(config_options
, m_opts
, &opts_str
));
1563 ASSERT_OK(StringToMap(opts_str
, &opts_map
));
1564 ASSERT_OK(GetMutableDBOptionsFromStrings(m_opts
, opts_map
, &new_opts
));
1565 ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(
1566 config_options
, base_opts
, BuildDBOptions(i_opts
, new_opts
)));
1569 TEST_F(OptionsTest
, CFOptionsComposeImmutable
) {
1570 // Build a DBOptions from an Immutable/Mutable one and verify that
1571 // we get same constituent options.
1572 ConfigOptions config_options
;
1574 ColumnFamilyOptions base_opts
, new_opts
;
1575 DBOptions dummy
; // Needed to create ImmutableCFOptions
1576 test::RandomInitCFOptions(&base_opts
, dummy
, &rnd
);
1577 MutableCFOptions
m_opts(base_opts
);
1578 ImmutableCFOptions
i_opts(base_opts
);
1579 UpdateColumnFamilyOptions(i_opts
, &new_opts
);
1580 UpdateColumnFamilyOptions(m_opts
, &new_opts
);
1581 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options
, base_opts
,
1583 delete new_opts
.compaction_filter
;
1586 TEST_F(OptionsTest
, GetMutableCFOptions
) {
1588 ColumnFamilyOptions base
, copy
;
1589 std::string opts_str
;
1590 std::unordered_map
<std::string
, std::string
> opts_map
;
1591 ConfigOptions config_options
;
1592 DBOptions dummy
; // Needed to create ImmutableCFOptions
1594 test::RandomInitCFOptions(&base
, dummy
, &rnd
);
1595 ColumnFamilyOptions result
;
1596 MutableCFOptions
m_opts(base
), new_opts
;
1598 ASSERT_OK(GetStringFromMutableCFOptions(config_options
, m_opts
, &opts_str
));
1599 ASSERT_OK(StringToMap(opts_str
, &opts_map
));
1600 ASSERT_OK(GetMutableOptionsFromStrings(m_opts
, opts_map
, nullptr, &new_opts
));
1601 UpdateColumnFamilyOptions(ImmutableCFOptions(base
), ©
);
1602 UpdateColumnFamilyOptions(new_opts
, ©
);
1604 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options
, base
, copy
));
1605 delete copy
.compaction_filter
;
1608 TEST_F(OptionsTest
, ColumnFamilyOptionsSerialization
) {
1610 ColumnFamilyOptions base_opt
, new_opt
;
1612 ConfigOptions config_options
;
1613 config_options
.input_strings_escaped
= false;
1615 // Phase 1: randomly assign base_opt
1616 // custom type options
1617 test::RandomInitCFOptions(&base_opt
, options
, &rnd
);
1619 // Phase 2: obtain a string from base_opt
1620 std::string base_options_file_content
;
1621 ASSERT_OK(GetStringFromColumnFamilyOptions(config_options
, base_opt
,
1622 &base_options_file_content
));
1624 // Phase 3: Set new_opt from the derived string and expect
1625 // new_opt == base_opt
1627 GetColumnFamilyOptionsFromString(config_options
, ColumnFamilyOptions(),
1628 base_options_file_content
, &new_opt
));
1630 RocksDBOptionsParser::VerifyCFOptions(config_options
, base_opt
, new_opt
));
1631 if (base_opt
.compaction_filter
) {
1632 delete base_opt
.compaction_filter
;
1636 TEST_F(OptionsTest
, CheckBlockBasedTableOptions
) {
1637 ColumnFamilyOptions cf_opts
;
1639 ConfigOptions config_opts
;
1641 ASSERT_OK(GetColumnFamilyOptionsFromString(
1642 config_opts
, cf_opts
, "prefix_extractor=capped:8", &cf_opts
));
1643 ASSERT_OK(TableFactory::CreateFromString(config_opts
, "BlockBasedTable",
1644 &cf_opts
.table_factory
));
1645 ASSERT_NE(cf_opts
.table_factory
.get(), nullptr);
1646 ASSERT_TRUE(cf_opts
.table_factory
->IsInstanceOf(
1647 TableFactory::kBlockBasedTableName()));
1648 auto bbto
= cf_opts
.table_factory
->GetOptions
<BlockBasedTableOptions
>();
1649 ASSERT_OK(cf_opts
.table_factory
->ConfigureFromString(
1651 "block_cache={capacity=1M;num_shard_bits=4;};"
1652 "block_size_deviation=101;"
1653 "block_restart_interval=0;"
1654 "index_block_restart_interval=5;"
1655 "partition_filters=true;"
1656 "index_type=kHashSearch;"
1657 "no_block_cache=1;"));
1658 ASSERT_NE(bbto
, nullptr);
1659 ASSERT_EQ(bbto
->block_cache
.get(), nullptr);
1660 ASSERT_EQ(bbto
->block_size_deviation
, 0);
1661 ASSERT_EQ(bbto
->block_restart_interval
, 1);
1662 ASSERT_EQ(bbto
->index_block_restart_interval
, 1);
1663 ASSERT_FALSE(bbto
->partition_filters
);
1664 ASSERT_OK(TableFactory::CreateFromString(config_opts
, "BlockBasedTable",
1665 &cf_opts
.table_factory
));
1666 bbto
= cf_opts
.table_factory
->GetOptions
<BlockBasedTableOptions
>();
1668 ASSERT_OK(cf_opts
.table_factory
->ConfigureFromString(config_opts
,
1669 "no_block_cache=0;"));
1670 ASSERT_NE(bbto
->block_cache
.get(), nullptr);
1671 ASSERT_OK(cf_opts
.table_factory
->ValidateOptions(db_opts
, cf_opts
));
1674 TEST_F(OptionsTest
, MutableTableOptions
) {
1675 ConfigOptions config_options
;
1676 std::shared_ptr
<TableFactory
> bbtf
;
1677 bbtf
.reset(NewBlockBasedTableFactory());
1678 auto bbto
= bbtf
->GetOptions
<BlockBasedTableOptions
>();
1679 ASSERT_NE(bbto
, nullptr);
1680 ASSERT_OK(bbtf
->ConfigureOption(config_options
, "block_align", "true"));
1681 ASSERT_OK(bbtf
->ConfigureOption(config_options
, "block_size", "1024"));
1682 ASSERT_EQ(bbto
->block_align
, true);
1683 ASSERT_EQ(bbto
->block_size
, 1024);
1684 ASSERT_OK(bbtf
->PrepareOptions(config_options
));
1685 config_options
.mutable_options_only
= true;
1686 ASSERT_OK(bbtf
->ConfigureOption(config_options
, "block_size", "1024"));
1687 ASSERT_EQ(bbto
->block_align
, true);
1688 ASSERT_NOK(bbtf
->ConfigureOption(config_options
, "block_align", "false"));
1689 ASSERT_OK(bbtf
->ConfigureOption(config_options
, "block_size", "2048"));
1690 ASSERT_EQ(bbto
->block_align
, true);
1691 ASSERT_EQ(bbto
->block_size
, 2048);
1693 ColumnFamilyOptions cf_opts
;
1694 cf_opts
.table_factory
= bbtf
;
1695 ASSERT_NOK(GetColumnFamilyOptionsFromString(
1696 config_options
, cf_opts
, "block_based_table_factory.block_align=false",
1698 ASSERT_OK(GetColumnFamilyOptionsFromString(
1699 config_options
, cf_opts
, "block_based_table_factory.block_size=8192",
1701 ASSERT_EQ(bbto
->block_align
, true);
1702 ASSERT_EQ(bbto
->block_size
, 8192);
1705 TEST_F(OptionsTest
, MutableCFOptions
) {
1706 ConfigOptions config_options
;
1707 ColumnFamilyOptions cf_opts
;
1709 ASSERT_OK(GetColumnFamilyOptionsFromString(
1710 config_options
, cf_opts
,
1711 "paranoid_file_checks=true; block_based_table_factory.block_align=false; "
1712 "block_based_table_factory.block_size=8192;",
1714 ASSERT_TRUE(cf_opts
.paranoid_file_checks
);
1715 ASSERT_NE(cf_opts
.table_factory
.get(), nullptr);
1716 const auto bbto
= cf_opts
.table_factory
->GetOptions
<BlockBasedTableOptions
>();
1717 ASSERT_NE(bbto
, nullptr);
1718 ASSERT_EQ(bbto
->block_size
, 8192);
1719 ASSERT_EQ(bbto
->block_align
, false);
1720 std::unordered_map
<std::string
, std::string
> unused_opts
;
1721 ASSERT_OK(GetColumnFamilyOptionsFromMap(
1722 config_options
, cf_opts
, {{"paranoid_file_checks", "false"}}, &cf_opts
));
1723 ASSERT_EQ(cf_opts
.paranoid_file_checks
, false);
1725 ASSERT_OK(GetColumnFamilyOptionsFromMap(
1726 config_options
, cf_opts
,
1727 {{"block_based_table_factory.block_size", "16384"}}, &cf_opts
));
1728 ASSERT_EQ(bbto
, cf_opts
.table_factory
->GetOptions
<BlockBasedTableOptions
>());
1729 ASSERT_EQ(bbto
->block_size
, 16384);
1731 config_options
.mutable_options_only
= true;
1732 // Force consistency checks is not mutable
1733 ASSERT_NOK(GetColumnFamilyOptionsFromMap(
1734 config_options
, cf_opts
, {{"force_consistency_checks", "true"}},
1737 // Attempt to change the table. It is not mutable, so this should fail and
1738 // leave the original intact
1739 ASSERT_NOK(GetColumnFamilyOptionsFromMap(
1740 config_options
, cf_opts
, {{"table_factory", "PlainTable"}}, &cf_opts
));
1741 ASSERT_NOK(GetColumnFamilyOptionsFromMap(
1742 config_options
, cf_opts
, {{"table_factory.id", "PlainTable"}}, &cf_opts
));
1743 ASSERT_NE(cf_opts
.table_factory
.get(), nullptr);
1744 ASSERT_EQ(bbto
, cf_opts
.table_factory
->GetOptions
<BlockBasedTableOptions
>());
1746 // Change the block size. Should update the value in the current table
1747 ASSERT_OK(GetColumnFamilyOptionsFromMap(
1748 config_options
, cf_opts
,
1749 {{"block_based_table_factory.block_size", "8192"}}, &cf_opts
));
1750 ASSERT_EQ(bbto
, cf_opts
.table_factory
->GetOptions
<BlockBasedTableOptions
>());
1751 ASSERT_EQ(bbto
->block_size
, 8192);
1753 // Attempt to turn off block cache fails, as this option is not mutable
1754 ASSERT_NOK(GetColumnFamilyOptionsFromMap(
1755 config_options
, cf_opts
,
1756 {{"block_based_table_factory.no_block_cache", "true"}}, &cf_opts
));
1757 ASSERT_EQ(bbto
, cf_opts
.table_factory
->GetOptions
<BlockBasedTableOptions
>());
1759 // Attempt to change the block size via a config string/map. Should update
1760 // the current value
1761 ASSERT_OK(GetColumnFamilyOptionsFromMap(
1762 config_options
, cf_opts
,
1763 {{"block_based_table_factory", "{block_size=32768}"}}, &cf_opts
));
1764 ASSERT_EQ(bbto
, cf_opts
.table_factory
->GetOptions
<BlockBasedTableOptions
>());
1765 ASSERT_EQ(bbto
->block_size
, 32768);
1767 // Attempt to change the block size and no cache through the map. Should
1768 // fail, leaving the old values intact
1769 ASSERT_NOK(GetColumnFamilyOptionsFromMap(
1770 config_options
, cf_opts
,
1771 {{"block_based_table_factory",
1772 "{block_size=16384; no_block_cache=true}"}},
1774 ASSERT_EQ(bbto
, cf_opts
.table_factory
->GetOptions
<BlockBasedTableOptions
>());
1775 ASSERT_EQ(bbto
->block_size
, 32768);
1778 #endif // !ROCKSDB_LITE
1781 const std::string
& opts_str
,
1782 std::unordered_map
<std::string
, std::string
>* opts_map
);
1784 #ifndef ROCKSDB_LITE // StringToMap is not supported in ROCKSDB_LITE
1785 TEST_F(OptionsTest
, StringToMapTest
) {
1786 std::unordered_map
<std::string
, std::string
> opts_map
;
1788 ASSERT_OK(StringToMap("k1=v1;k2=v2;k3=v3", &opts_map
));
1789 ASSERT_EQ(opts_map
["k1"], "v1");
1790 ASSERT_EQ(opts_map
["k2"], "v2");
1791 ASSERT_EQ(opts_map
["k3"], "v3");
1794 ASSERT_OK(StringToMap("k1==v1;k2=v2=;", &opts_map
));
1795 ASSERT_EQ(opts_map
["k1"], "=v1");
1796 ASSERT_EQ(opts_map
["k2"], "v2=");
1797 // Overwrriten option
1799 ASSERT_OK(StringToMap("k1=v1;k1=v2;k3=v3", &opts_map
));
1800 ASSERT_EQ(opts_map
["k1"], "v2");
1801 ASSERT_EQ(opts_map
["k3"], "v3");
1804 ASSERT_OK(StringToMap("k1=v1;k2=;k3=v3;k4=", &opts_map
));
1805 ASSERT_EQ(opts_map
["k1"], "v1");
1806 ASSERT_TRUE(opts_map
.find("k2") != opts_map
.end());
1807 ASSERT_EQ(opts_map
["k2"], "");
1808 ASSERT_EQ(opts_map
["k3"], "v3");
1809 ASSERT_TRUE(opts_map
.find("k4") != opts_map
.end());
1810 ASSERT_EQ(opts_map
["k4"], "");
1812 ASSERT_OK(StringToMap("k1=v1;k2=;k3=v3;k4= ", &opts_map
));
1813 ASSERT_EQ(opts_map
["k1"], "v1");
1814 ASSERT_TRUE(opts_map
.find("k2") != opts_map
.end());
1815 ASSERT_EQ(opts_map
["k2"], "");
1816 ASSERT_EQ(opts_map
["k3"], "v3");
1817 ASSERT_TRUE(opts_map
.find("k4") != opts_map
.end());
1818 ASSERT_EQ(opts_map
["k4"], "");
1820 ASSERT_OK(StringToMap("k1=v1;k2=;k3=", &opts_map
));
1821 ASSERT_EQ(opts_map
["k1"], "v1");
1822 ASSERT_TRUE(opts_map
.find("k2") != opts_map
.end());
1823 ASSERT_EQ(opts_map
["k2"], "");
1824 ASSERT_TRUE(opts_map
.find("k3") != opts_map
.end());
1825 ASSERT_EQ(opts_map
["k3"], "");
1827 ASSERT_OK(StringToMap("k1=v1;k2=;k3=;", &opts_map
));
1828 ASSERT_EQ(opts_map
["k1"], "v1");
1829 ASSERT_TRUE(opts_map
.find("k2") != opts_map
.end());
1830 ASSERT_EQ(opts_map
["k2"], "");
1831 ASSERT_TRUE(opts_map
.find("k3") != opts_map
.end());
1832 ASSERT_EQ(opts_map
["k3"], "");
1833 // Regular nested options
1835 ASSERT_OK(StringToMap("k1=v1;k2={nk1=nv1;nk2=nv2};k3=v3", &opts_map
));
1836 ASSERT_EQ(opts_map
["k1"], "v1");
1837 ASSERT_EQ(opts_map
["k2"], "nk1=nv1;nk2=nv2");
1838 ASSERT_EQ(opts_map
["k3"], "v3");
1839 // Multi-level nested options
1841 ASSERT_OK(StringToMap("k1=v1;k2={nk1=nv1;nk2={nnk1=nnk2}};"
1842 "k3={nk1={nnk1={nnnk1=nnnv1;nnnk2;nnnv2}}};k4=v4",
1844 ASSERT_EQ(opts_map
["k1"], "v1");
1845 ASSERT_EQ(opts_map
["k2"], "nk1=nv1;nk2={nnk1=nnk2}");
1846 ASSERT_EQ(opts_map
["k3"], "nk1={nnk1={nnnk1=nnnv1;nnnk2;nnnv2}}");
1847 ASSERT_EQ(opts_map
["k4"], "v4");
1848 // Garbage inside curly braces
1850 ASSERT_OK(StringToMap("k1=v1;k2={dfad=};k3={=};k4=v4",
1852 ASSERT_EQ(opts_map
["k1"], "v1");
1853 ASSERT_EQ(opts_map
["k2"], "dfad=");
1854 ASSERT_EQ(opts_map
["k3"], "=");
1855 ASSERT_EQ(opts_map
["k4"], "v4");
1856 // Empty nested options
1858 ASSERT_OK(StringToMap("k1=v1;k2={};", &opts_map
));
1859 ASSERT_EQ(opts_map
["k1"], "v1");
1860 ASSERT_EQ(opts_map
["k2"], "");
1862 ASSERT_OK(StringToMap("k1=v1;k2={{{{}}}{}{}};", &opts_map
));
1863 ASSERT_EQ(opts_map
["k1"], "v1");
1864 ASSERT_EQ(opts_map
["k2"], "{{{}}}{}{}");
1865 // With random spaces
1867 ASSERT_OK(StringToMap(" k1 = v1 ; k2= {nk1=nv1; nk2={nnk1=nnk2}} ; "
1868 "k3={ { } }; k4= v4 ",
1870 ASSERT_EQ(opts_map
["k1"], "v1");
1871 ASSERT_EQ(opts_map
["k2"], "nk1=nv1; nk2={nnk1=nnk2}");
1872 ASSERT_EQ(opts_map
["k3"], "{ }");
1873 ASSERT_EQ(opts_map
["k4"], "v4");
1876 ASSERT_NOK(StringToMap("k1=v1;k2=v2;=", &opts_map
));
1877 ASSERT_NOK(StringToMap("=v1;k2=v2", &opts_map
));
1878 ASSERT_NOK(StringToMap("k1=v1;k2v2;", &opts_map
));
1879 ASSERT_NOK(StringToMap("k1=v1;k2=v2;fadfa", &opts_map
));
1880 ASSERT_NOK(StringToMap("k1=v1;k2=v2;;", &opts_map
));
1881 // Mismatch curly braces
1882 ASSERT_NOK(StringToMap("k1=v1;k2={;k3=v3", &opts_map
));
1883 ASSERT_NOK(StringToMap("k1=v1;k2={{};k3=v3", &opts_map
));
1884 ASSERT_NOK(StringToMap("k1=v1;k2={}};k3=v3", &opts_map
));
1885 ASSERT_NOK(StringToMap("k1=v1;k2={{}{}}};k3=v3", &opts_map
));
1886 // However this is valid!
1888 ASSERT_OK(StringToMap("k1=v1;k2=};k3=v3", &opts_map
));
1889 ASSERT_EQ(opts_map
["k1"], "v1");
1890 ASSERT_EQ(opts_map
["k2"], "}");
1891 ASSERT_EQ(opts_map
["k3"], "v3");
1893 // Invalid chars after closing curly brace
1894 ASSERT_NOK(StringToMap("k1=v1;k2={{}}{};k3=v3", &opts_map
));
1895 ASSERT_NOK(StringToMap("k1=v1;k2={{}}cfda;k3=v3", &opts_map
));
1896 ASSERT_NOK(StringToMap("k1=v1;k2={{}} cfda;k3=v3", &opts_map
));
1897 ASSERT_NOK(StringToMap("k1=v1;k2={{}} cfda", &opts_map
));
1898 ASSERT_NOK(StringToMap("k1=v1;k2={{}}{}", &opts_map
));
1899 ASSERT_NOK(StringToMap("k1=v1;k2={{dfdl}adfa}{}", &opts_map
));
1901 #endif // ROCKSDB_LITE
1903 #ifndef ROCKSDB_LITE // StringToMap is not supported in ROCKSDB_LITE
1904 TEST_F(OptionsTest
, StringToMapRandomTest
) {
1905 std::unordered_map
<std::string
, std::string
> opts_map
;
1906 // Make sure segfault is not hit by semi-random strings
1908 std::vector
<std::string
> bases
= {
1909 "a={aa={};tt={xxx={}}};c=defff",
1910 "a={aa={};tt={xxx={}}};c=defff;d={{}yxx{}3{xx}}",
1911 "abc={{}{}{}{{{}}}{{}{}{}{}{}{}{}"};
1913 for (std::string base
: bases
) {
1914 for (int rand_seed
= 301; rand_seed
< 401; rand_seed
++) {
1915 Random
rnd(rand_seed
);
1916 for (int attempt
= 0; attempt
< 10; attempt
++) {
1917 std::string str
= base
;
1918 // Replace random position to space
1919 size_t pos
= static_cast<size_t>(
1920 rnd
.Uniform(static_cast<int>(base
.size())));
1922 Status s
= StringToMap(str
, &opts_map
);
1923 ASSERT_TRUE(s
.ok() || s
.IsInvalidArgument());
1929 // Random Construct a string
1930 std::vector
<char> chars
= {'{', '}', ' ', '=', ';', 'c'};
1931 for (int rand_seed
= 301; rand_seed
< 1301; rand_seed
++) {
1932 Random
rnd(rand_seed
);
1933 int len
= rnd
.Uniform(30);
1934 std::string str
= "";
1935 for (int attempt
= 0; attempt
< len
; attempt
++) {
1936 // Add a random character
1937 size_t pos
= static_cast<size_t>(
1938 rnd
.Uniform(static_cast<int>(chars
.size())));
1939 str
.append(1, chars
[pos
]);
1941 Status s
= StringToMap(str
, &opts_map
);
1942 ASSERT_TRUE(s
.ok() || s
.IsInvalidArgument());
1943 s
= StringToMap("name=" + str
, &opts_map
);
1944 ASSERT_TRUE(s
.ok() || s
.IsInvalidArgument());
1949 TEST_F(OptionsTest
, GetStringFromCompressionType
) {
1952 ASSERT_OK(GetStringFromCompressionType(&res
, kNoCompression
));
1953 ASSERT_EQ(res
, "kNoCompression");
1955 ASSERT_OK(GetStringFromCompressionType(&res
, kSnappyCompression
));
1956 ASSERT_EQ(res
, "kSnappyCompression");
1958 ASSERT_OK(GetStringFromCompressionType(&res
, kDisableCompressionOption
));
1959 ASSERT_EQ(res
, "kDisableCompressionOption");
1961 ASSERT_OK(GetStringFromCompressionType(&res
, kLZ4Compression
));
1962 ASSERT_EQ(res
, "kLZ4Compression");
1964 ASSERT_OK(GetStringFromCompressionType(&res
, kZlibCompression
));
1965 ASSERT_EQ(res
, "kZlibCompression");
1968 GetStringFromCompressionType(&res
, static_cast<CompressionType
>(-10)));
1971 TEST_F(OptionsTest
, OnlyMutableDBOptions
) {
1972 std::string opt_str
;
1974 ConfigOptions cfg_opts
;
1977 std::unordered_set
<std::string
> m_names
;
1978 std::unordered_set
<std::string
> a_names
;
1980 test::RandomInitDBOptions(&db_opts
, &rnd
);
1981 auto db_config
= DBOptionsAsConfigurable(db_opts
);
1983 // Get all of the DB Option names (mutable or not)
1984 ASSERT_OK(db_config
->GetOptionNames(cfg_opts
, &a_names
));
1986 // Get only the mutable options from db_opts and set those in mdb_opts
1987 cfg_opts
.mutable_options_only
= true;
1989 // Get only the Mutable DB Option names
1990 ASSERT_OK(db_config
->GetOptionNames(cfg_opts
, &m_names
));
1991 ASSERT_OK(GetStringFromDBOptions(cfg_opts
, db_opts
, &opt_str
));
1992 ASSERT_OK(GetDBOptionsFromString(cfg_opts
, mdb_opts
, opt_str
, &mdb_opts
));
1993 std::string mismatch
;
1994 // Comparing only the mutable options, the two are equivalent
1995 auto mdb_config
= DBOptionsAsConfigurable(mdb_opts
);
1996 ASSERT_TRUE(mdb_config
->AreEquivalent(cfg_opts
, db_config
.get(), &mismatch
));
1997 ASSERT_TRUE(db_config
->AreEquivalent(cfg_opts
, mdb_config
.get(), &mismatch
));
1999 ASSERT_GT(a_names
.size(), m_names
.size());
2000 for (const auto& n
: m_names
) {
2002 ASSERT_OK(mdb_config
->GetOption(cfg_opts
, n
, &m
));
2003 ASSERT_OK(db_config
->GetOption(cfg_opts
, n
, &d
));
2007 cfg_opts
.mutable_options_only
= false;
2008 // Comparing all of the options, the two are not equivalent
2009 ASSERT_FALSE(mdb_config
->AreEquivalent(cfg_opts
, db_config
.get(), &mismatch
));
2010 ASSERT_FALSE(db_config
->AreEquivalent(cfg_opts
, mdb_config
.get(), &mismatch
));
2012 // Make sure there are only mutable options being configured
2013 ASSERT_OK(GetDBOptionsFromString(cfg_opts
, DBOptions(), opt_str
, &db_opts
));
2016 TEST_F(OptionsTest
, OnlyMutableCFOptions
) {
2017 std::string opt_str
;
2019 ConfigOptions cfg_opts
;
2021 ColumnFamilyOptions mcf_opts
;
2022 ColumnFamilyOptions cf_opts
;
2023 std::unordered_set
<std::string
> m_names
;
2024 std::unordered_set
<std::string
> a_names
;
2026 test::RandomInitCFOptions(&cf_opts
, db_opts
, &rnd
);
2027 cf_opts
.comparator
= ReverseBytewiseComparator();
2028 auto cf_config
= CFOptionsAsConfigurable(cf_opts
);
2030 // Get all of the CF Option names (mutable or not)
2031 ASSERT_OK(cf_config
->GetOptionNames(cfg_opts
, &a_names
));
2033 // Get only the mutable options from cf_opts and set those in mcf_opts
2034 cfg_opts
.mutable_options_only
= true;
2035 // Get only the Mutable CF Option names
2036 ASSERT_OK(cf_config
->GetOptionNames(cfg_opts
, &m_names
));
2037 ASSERT_OK(GetStringFromColumnFamilyOptions(cfg_opts
, cf_opts
, &opt_str
));
2039 GetColumnFamilyOptionsFromString(cfg_opts
, mcf_opts
, opt_str
, &mcf_opts
));
2040 std::string mismatch
;
2042 auto mcf_config
= CFOptionsAsConfigurable(mcf_opts
);
2043 // Comparing only the mutable options, the two are equivalent
2044 ASSERT_TRUE(mcf_config
->AreEquivalent(cfg_opts
, cf_config
.get(), &mismatch
));
2045 ASSERT_TRUE(cf_config
->AreEquivalent(cfg_opts
, mcf_config
.get(), &mismatch
));
2047 ASSERT_GT(a_names
.size(), m_names
.size());
2048 for (const auto& n
: m_names
) {
2050 ASSERT_OK(mcf_config
->GetOption(cfg_opts
, n
, &m
));
2051 ASSERT_OK(cf_config
->GetOption(cfg_opts
, n
, &d
));
2055 cfg_opts
.mutable_options_only
= false;
2056 // Comparing all of the options, the two are not equivalent
2057 ASSERT_FALSE(mcf_config
->AreEquivalent(cfg_opts
, cf_config
.get(), &mismatch
));
2058 ASSERT_FALSE(cf_config
->AreEquivalent(cfg_opts
, mcf_config
.get(), &mismatch
));
2059 delete cf_opts
.compaction_filter
;
2061 // Make sure the options string contains only mutable options
2062 ASSERT_OK(GetColumnFamilyOptionsFromString(cfg_opts
, ColumnFamilyOptions(),
2063 opt_str
, &cf_opts
));
2064 delete cf_opts
.compaction_filter
;
2067 TEST_F(OptionsTest
, SstPartitionerTest
) {
2068 ConfigOptions cfg_opts
;
2069 ColumnFamilyOptions cf_opts
, new_opt
;
2070 std::string opts_str
, mismatch
;
2072 ASSERT_OK(SstPartitionerFactory::CreateFromString(
2073 cfg_opts
, SstPartitionerFixedPrefixFactory::kClassName(),
2074 &cf_opts
.sst_partitioner_factory
));
2075 ASSERT_NE(cf_opts
.sst_partitioner_factory
, nullptr);
2076 ASSERT_STREQ(cf_opts
.sst_partitioner_factory
->Name(),
2077 SstPartitionerFixedPrefixFactory::kClassName());
2078 ASSERT_NOK(GetColumnFamilyOptionsFromString(
2079 cfg_opts
, ColumnFamilyOptions(),
2080 std::string("sst_partitioner_factory={id=") +
2081 SstPartitionerFixedPrefixFactory::kClassName() + "; unknown=10;}",
2083 ASSERT_OK(GetColumnFamilyOptionsFromString(
2084 cfg_opts
, ColumnFamilyOptions(),
2085 std::string("sst_partitioner_factory={id=") +
2086 SstPartitionerFixedPrefixFactory::kClassName() + "; length=10;}",
2088 ASSERT_NE(cf_opts
.sst_partitioner_factory
, nullptr);
2089 ASSERT_STREQ(cf_opts
.sst_partitioner_factory
->Name(),
2090 SstPartitionerFixedPrefixFactory::kClassName());
2091 ASSERT_OK(GetStringFromColumnFamilyOptions(cfg_opts
, cf_opts
, &opts_str
));
2093 GetColumnFamilyOptionsFromString(cfg_opts
, cf_opts
, opts_str
, &new_opt
));
2094 ASSERT_NE(new_opt
.sst_partitioner_factory
, nullptr);
2095 ASSERT_STREQ(new_opt
.sst_partitioner_factory
->Name(),
2096 SstPartitionerFixedPrefixFactory::kClassName());
2097 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(cfg_opts
, cf_opts
, new_opt
));
2098 ASSERT_TRUE(cf_opts
.sst_partitioner_factory
->AreEquivalent(
2099 cfg_opts
, new_opt
.sst_partitioner_factory
.get(), &mismatch
));
2102 TEST_F(OptionsTest
, FileChecksumGenFactoryTest
) {
2103 ConfigOptions cfg_opts
;
2104 DBOptions db_opts
, new_opt
;
2105 std::string opts_str
, mismatch
;
2106 auto factory
= GetFileChecksumGenCrc32cFactory();
2108 cfg_opts
.ignore_unsupported_options
= false;
2110 ASSERT_OK(GetStringFromDBOptions(cfg_opts
, db_opts
, &opts_str
));
2111 ASSERT_OK(GetDBOptionsFromString(cfg_opts
, db_opts
, opts_str
, &new_opt
));
2113 ASSERT_NE(factory
, nullptr);
2114 ASSERT_OK(FileChecksumGenFactory::CreateFromString(
2115 cfg_opts
, factory
->Name(), &db_opts
.file_checksum_gen_factory
));
2116 ASSERT_NE(db_opts
.file_checksum_gen_factory
, nullptr);
2117 ASSERT_STREQ(db_opts
.file_checksum_gen_factory
->Name(), factory
->Name());
2118 ASSERT_NOK(GetDBOptionsFromString(
2119 cfg_opts
, DBOptions(), "file_checksum_gen_factory=unknown", &db_opts
));
2120 ASSERT_OK(GetDBOptionsFromString(
2121 cfg_opts
, DBOptions(),
2122 std::string("file_checksum_gen_factory=") + factory
->Name(), &db_opts
));
2123 ASSERT_NE(db_opts
.file_checksum_gen_factory
, nullptr);
2124 ASSERT_STREQ(db_opts
.file_checksum_gen_factory
->Name(), factory
->Name());
2126 ASSERT_OK(GetStringFromDBOptions(cfg_opts
, db_opts
, &opts_str
));
2127 ASSERT_OK(GetDBOptionsFromString(cfg_opts
, db_opts
, opts_str
, &new_opt
));
2128 ASSERT_NE(new_opt
.file_checksum_gen_factory
, nullptr);
2129 ASSERT_STREQ(new_opt
.file_checksum_gen_factory
->Name(), factory
->Name());
2130 ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(cfg_opts
, db_opts
, new_opt
));
2131 ASSERT_TRUE(factory
->AreEquivalent(
2132 cfg_opts
, new_opt
.file_checksum_gen_factory
.get(), &mismatch
));
2133 ASSERT_TRUE(db_opts
.file_checksum_gen_factory
->AreEquivalent(
2134 cfg_opts
, new_opt
.file_checksum_gen_factory
.get(), &mismatch
));
2137 class TestTablePropertiesCollectorFactory
2138 : public TablePropertiesCollectorFactory
{
2143 explicit TestTablePropertiesCollectorFactory(const std::string
& id
)
2145 TablePropertiesCollector
* CreateTablePropertiesCollector(
2146 TablePropertiesCollectorFactory::Context
/*context*/) override
{
2149 static const char* kClassName() { return "TestCollector"; }
2150 const char* Name() const override
{ return kClassName(); }
2151 std::string
GetId() const override
{
2152 return std::string(kClassName()) + ":" + id_
;
2156 TEST_F(OptionsTest
, OptionTablePropertiesTest
) {
2157 ConfigOptions cfg_opts
;
2158 ColumnFamilyOptions orig
, copy
;
2159 orig
.table_properties_collector_factories
.push_back(
2160 std::make_shared
<TestTablePropertiesCollectorFactory
>("1"));
2161 orig
.table_properties_collector_factories
.push_back(
2162 std::make_shared
<TestTablePropertiesCollectorFactory
>("2"));
2164 // Push two TablePropertiesCollectorFactories then create a new
2165 // ColumnFamilyOptions based on those settings. The copy should
2166 // have no properties but still match the original
2167 std::string opts_str
;
2168 ASSERT_OK(GetStringFromColumnFamilyOptions(cfg_opts
, orig
, &opts_str
));
2169 ASSERT_OK(GetColumnFamilyOptionsFromString(cfg_opts
, orig
, opts_str
, ©
));
2170 ASSERT_EQ(copy
.table_properties_collector_factories
.size(), 0);
2171 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(cfg_opts
, orig
, copy
));
2173 // Now register a TablePropertiesCollectorFactory
2174 // Repeat the experiment. The copy should have the same
2175 // properties as the original
2176 cfg_opts
.registry
->AddLibrary("collector")
2177 ->AddFactory
<TablePropertiesCollectorFactory
>(
2178 ObjectLibrary::PatternEntry(
2179 TestTablePropertiesCollectorFactory::kClassName(), false)
2181 [](const std::string
& name
,
2182 std::unique_ptr
<TablePropertiesCollectorFactory
>* guard
,
2183 std::string
* /* errmsg */) {
2184 std::string id
= name
.substr(
2185 strlen(TestTablePropertiesCollectorFactory::kClassName()) + 1);
2186 guard
->reset(new TestTablePropertiesCollectorFactory(id
));
2187 return guard
->get();
2190 ASSERT_OK(GetColumnFamilyOptionsFromString(cfg_opts
, orig
, opts_str
, ©
));
2191 ASSERT_EQ(copy
.table_properties_collector_factories
.size(), 2);
2192 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(cfg_opts
, orig
, copy
));
2194 #endif // !ROCKSDB_LITE
2196 TEST_F(OptionsTest
, ConvertOptionsTest
) {
2197 LevelDBOptions leveldb_opt
;
2198 Options converted_opt
= ConvertOptions(leveldb_opt
);
2200 ASSERT_EQ(converted_opt
.create_if_missing
, leveldb_opt
.create_if_missing
);
2201 ASSERT_EQ(converted_opt
.error_if_exists
, leveldb_opt
.error_if_exists
);
2202 ASSERT_EQ(converted_opt
.paranoid_checks
, leveldb_opt
.paranoid_checks
);
2203 ASSERT_EQ(converted_opt
.env
, leveldb_opt
.env
);
2204 ASSERT_EQ(converted_opt
.info_log
.get(), leveldb_opt
.info_log
);
2205 ASSERT_EQ(converted_opt
.write_buffer_size
, leveldb_opt
.write_buffer_size
);
2206 ASSERT_EQ(converted_opt
.max_open_files
, leveldb_opt
.max_open_files
);
2207 ASSERT_EQ(converted_opt
.compression
, leveldb_opt
.compression
);
2209 std::shared_ptr
<TableFactory
> table_factory
= converted_opt
.table_factory
;
2210 const auto table_opt
= table_factory
->GetOptions
<BlockBasedTableOptions
>();
2211 ASSERT_NE(table_opt
, nullptr);
2213 ASSERT_EQ(table_opt
->block_cache
->GetCapacity(), 8UL << 20);
2214 ASSERT_EQ(table_opt
->block_size
, leveldb_opt
.block_size
);
2215 ASSERT_EQ(table_opt
->block_restart_interval
,
2216 leveldb_opt
.block_restart_interval
);
2217 ASSERT_EQ(table_opt
->filter_policy
.get(), leveldb_opt
.filter_policy
);
2219 #ifndef ROCKSDB_LITE
2220 class TestEventListener
: public EventListener
{
2225 explicit TestEventListener(const std::string
& id
) : id_("Test" + id
) {}
2226 const char* Name() const override
{ return id_
.c_str(); }
2229 static std::unordered_map
<std::string
, OptionTypeInfo
>
2230 test_listener_option_info
= {
2232 {0, OptionType::kString
, OptionVerificationType::kNormal
,
2233 OptionTypeFlags::kNone
}},
2237 class TestConfigEventListener
: public TestEventListener
{
2242 explicit TestConfigEventListener(const std::string
& id
)
2243 : TestEventListener("Config" + id
) {
2245 RegisterOptions("Test", &s_
, &test_listener_option_info
);
2249 static int RegisterTestEventListener(ObjectLibrary
& library
,
2250 const std::string
& arg
) {
2251 library
.AddFactory
<EventListener
>(
2253 [](const std::string
& name
, std::unique_ptr
<EventListener
>* guard
,
2254 std::string
* /* errmsg */) {
2255 guard
->reset(new TestEventListener(name
.substr(4)));
2256 return guard
->get();
2258 library
.AddFactory
<EventListener
>(
2260 [](const std::string
& name
, std::unique_ptr
<EventListener
>* guard
,
2261 std::string
* /* errmsg */) {
2262 guard
->reset(new TestConfigEventListener(name
.substr(10)));
2263 return guard
->get();
2267 TEST_F(OptionsTest
, OptionsListenerTest
) {
2268 DBOptions orig
, copy
;
2269 orig
.listeners
.push_back(std::make_shared
<TestEventListener
>("1"));
2270 orig
.listeners
.push_back(std::make_shared
<TestEventListener
>("2"));
2271 orig
.listeners
.push_back(std::make_shared
<TestEventListener
>(""));
2272 orig
.listeners
.push_back(std::make_shared
<TestConfigEventListener
>("1"));
2273 orig
.listeners
.push_back(std::make_shared
<TestConfigEventListener
>("2"));
2274 orig
.listeners
.push_back(std::make_shared
<TestConfigEventListener
>(""));
2275 ConfigOptions
config_opts(orig
);
2276 config_opts
.registry
->AddLibrary("listener", RegisterTestEventListener
, "1");
2277 std::string opts_str
;
2278 ASSERT_OK(GetStringFromDBOptions(config_opts
, orig
, &opts_str
));
2279 ASSERT_OK(GetDBOptionsFromString(config_opts
, orig
, opts_str
, ©
));
2280 ASSERT_OK(GetStringFromDBOptions(config_opts
, copy
, &opts_str
));
2282 copy
.listeners
.size(),
2283 2); // The Test{Config}1 Listeners could be loaded but not the others
2284 ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(config_opts
, orig
, copy
));
2286 #endif // ROCKSDB_LITE
2288 #ifndef ROCKSDB_LITE
2289 const static std::string kCustomEnvName
= "Custom";
2290 const static std::string kCustomEnvProp
= "env=" + kCustomEnvName
;
2292 static int RegisterCustomEnv(ObjectLibrary
& library
, const std::string
& arg
) {
2293 library
.AddFactory
<Env
>(
2294 arg
, [](const std::string
& /*name*/, std::unique_ptr
<Env
>* /*env_guard*/,
2295 std::string
* /* errmsg */) {
2296 static CustomEnv
env(Env::Default());
2302 // This test suite tests the old APIs into the Configure options methods.
2303 // Once those APIs are officially deprecated, this test suite can be deleted.
2304 class OptionsOldApiTest
: public testing::Test
{};
2306 TEST_F(OptionsOldApiTest
, GetOptionsFromMapTest
) {
2307 std::unordered_map
<std::string
, std::string
> cf_options_map
= {
2308 {"write_buffer_size", "1"},
2309 {"max_write_buffer_number", "2"},
2310 {"min_write_buffer_number_to_merge", "3"},
2311 {"max_write_buffer_number_to_maintain", "99"},
2312 {"max_write_buffer_size_to_maintain", "-99999"},
2313 {"compression", "kSnappyCompression"},
2314 {"compression_per_level",
2316 "kSnappyCompression:"
2318 "kBZip2Compression:"
2320 "kLZ4HCCompression:"
2321 "kXpressCompression:"
2323 "kZSTDNotFinalCompression"},
2324 {"bottommost_compression", "kLZ4Compression"},
2325 {"bottommost_compression_opts", "5:6:7:8:9:true"},
2326 {"compression_opts", "4:5:6:7:8:9:true:10:false"},
2327 {"num_levels", "8"},
2328 {"level0_file_num_compaction_trigger", "8"},
2329 {"level0_slowdown_writes_trigger", "9"},
2330 {"level0_stop_writes_trigger", "10"},
2331 {"target_file_size_base", "12"},
2332 {"target_file_size_multiplier", "13"},
2333 {"max_bytes_for_level_base", "14"},
2334 {"level_compaction_dynamic_level_bytes", "true"},
2335 {"level_compaction_dynamic_file_size", "true"},
2336 {"max_bytes_for_level_multiplier", "15.0"},
2337 {"max_bytes_for_level_multiplier_additional", "16:17:18"},
2338 {"max_compaction_bytes", "21"},
2339 {"soft_rate_limit", "1.1"},
2340 {"hard_rate_limit", "2.1"},
2341 {"rate_limit_delay_max_milliseconds", "100"},
2342 {"hard_pending_compaction_bytes_limit", "211"},
2343 {"arena_block_size", "22"},
2344 {"disable_auto_compactions", "true"},
2345 {"compaction_style", "kCompactionStyleLevel"},
2346 {"compaction_pri", "kOldestSmallestSeqFirst"},
2347 {"verify_checksums_in_compaction", "false"},
2348 {"compaction_options_fifo", "23"},
2349 {"max_sequential_skip_in_iterations", "24"},
2350 {"inplace_update_support", "true"},
2351 {"report_bg_io_stats", "true"},
2352 {"compaction_measure_io_stats", "false"},
2353 {"purge_redundant_kvs_while_flush", "false"},
2354 {"inplace_update_num_locks", "25"},
2355 {"memtable_prefix_bloom_size_ratio", "0.26"},
2356 {"memtable_whole_key_filtering", "true"},
2357 {"memtable_huge_page_size", "28"},
2358 {"bloom_locality", "29"},
2359 {"max_successive_merges", "30"},
2360 {"min_partial_merge_operands", "31"},
2361 {"prefix_extractor", "fixed:31"},
2362 {"experimental_mempurge_threshold", "0.003"},
2363 {"optimize_filters_for_hits", "true"},
2364 {"enable_blob_files", "true"},
2365 {"min_blob_size", "1K"},
2366 {"blob_file_size", "1G"},
2367 {"blob_compression_type", "kZSTD"},
2368 {"enable_blob_garbage_collection", "true"},
2369 {"blob_garbage_collection_age_cutoff", "0.5"},
2370 {"blob_garbage_collection_force_threshold", "0.75"},
2371 {"blob_compaction_readahead_size", "256K"},
2372 {"blob_file_starting_level", "1"},
2373 {"prepopulate_blob_cache", "kDisable"},
2374 {"last_level_temperature", "kWarm"},
2377 std::unordered_map
<std::string
, std::string
> db_options_map
= {
2378 {"create_if_missing", "false"},
2379 {"create_missing_column_families", "true"},
2380 {"error_if_exists", "false"},
2381 {"paranoid_checks", "true"},
2382 {"track_and_verify_wals_in_manifest", "true"},
2383 {"verify_sst_unique_id_in_manifest", "true"},
2384 {"max_open_files", "32"},
2385 {"max_total_wal_size", "33"},
2386 {"use_fsync", "true"},
2387 {"db_log_dir", "/db_log_dir"},
2388 {"wal_dir", "/wal_dir"},
2389 {"delete_obsolete_files_period_micros", "34"},
2390 {"max_background_compactions", "35"},
2391 {"max_background_flushes", "36"},
2392 {"max_log_file_size", "37"},
2393 {"log_file_time_to_roll", "38"},
2394 {"keep_log_file_num", "39"},
2395 {"recycle_log_file_num", "5"},
2396 {"max_manifest_file_size", "40"},
2397 {"table_cache_numshardbits", "41"},
2398 {"WAL_ttl_seconds", "43"},
2399 {"WAL_size_limit_MB", "44"},
2400 {"manifest_preallocation_size", "45"},
2401 {"allow_mmap_reads", "true"},
2402 {"allow_mmap_writes", "false"},
2403 {"use_direct_reads", "false"},
2404 {"use_direct_io_for_flush_and_compaction", "false"},
2405 {"is_fd_close_on_exec", "true"},
2406 {"skip_log_error_on_recovery", "false"},
2407 {"stats_dump_period_sec", "46"},
2408 {"stats_persist_period_sec", "57"},
2409 {"persist_stats_to_disk", "false"},
2410 {"stats_history_buffer_size", "69"},
2411 {"advise_random_on_open", "true"},
2412 {"use_adaptive_mutex", "false"},
2413 {"compaction_readahead_size", "100"},
2414 {"random_access_max_buffer_size", "3145728"},
2415 {"writable_file_max_buffer_size", "314159"},
2416 {"bytes_per_sync", "47"},
2417 {"wal_bytes_per_sync", "48"},
2418 {"strict_bytes_per_sync", "true"},
2419 {"preserve_deletes", "false"},
2422 ColumnFamilyOptions base_cf_opt
;
2423 ColumnFamilyOptions new_cf_opt
;
2424 ASSERT_OK(GetColumnFamilyOptionsFromMap(
2425 base_cf_opt
, cf_options_map
, &new_cf_opt
));
2426 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 1U);
2427 ASSERT_EQ(new_cf_opt
.max_write_buffer_number
, 2);
2428 ASSERT_EQ(new_cf_opt
.min_write_buffer_number_to_merge
, 3);
2429 ASSERT_EQ(new_cf_opt
.max_write_buffer_number_to_maintain
, 99);
2430 ASSERT_EQ(new_cf_opt
.max_write_buffer_size_to_maintain
, -99999);
2431 ASSERT_EQ(new_cf_opt
.compression
, kSnappyCompression
);
2432 ASSERT_EQ(new_cf_opt
.compression_per_level
.size(), 9U);
2433 ASSERT_EQ(new_cf_opt
.compression_per_level
[0], kNoCompression
);
2434 ASSERT_EQ(new_cf_opt
.compression_per_level
[1], kSnappyCompression
);
2435 ASSERT_EQ(new_cf_opt
.compression_per_level
[2], kZlibCompression
);
2436 ASSERT_EQ(new_cf_opt
.compression_per_level
[3], kBZip2Compression
);
2437 ASSERT_EQ(new_cf_opt
.compression_per_level
[4], kLZ4Compression
);
2438 ASSERT_EQ(new_cf_opt
.compression_per_level
[5], kLZ4HCCompression
);
2439 ASSERT_EQ(new_cf_opt
.compression_per_level
[6], kXpressCompression
);
2440 ASSERT_EQ(new_cf_opt
.compression_per_level
[7], kZSTD
);
2441 ASSERT_EQ(new_cf_opt
.compression_per_level
[8], kZSTDNotFinalCompression
);
2442 ASSERT_EQ(new_cf_opt
.compression_opts
.window_bits
, 4);
2443 ASSERT_EQ(new_cf_opt
.compression_opts
.level
, 5);
2444 ASSERT_EQ(new_cf_opt
.compression_opts
.strategy
, 6);
2445 ASSERT_EQ(new_cf_opt
.compression_opts
.max_dict_bytes
, 7u);
2446 ASSERT_EQ(new_cf_opt
.compression_opts
.zstd_max_train_bytes
, 8u);
2447 ASSERT_EQ(new_cf_opt
.compression_opts
.parallel_threads
, 9u);
2448 ASSERT_EQ(new_cf_opt
.compression_opts
.enabled
, true);
2449 ASSERT_EQ(new_cf_opt
.compression_opts
.max_dict_buffer_bytes
, 10u);
2450 ASSERT_EQ(new_cf_opt
.compression_opts
.use_zstd_dict_trainer
, false);
2451 ASSERT_EQ(new_cf_opt
.bottommost_compression
, kLZ4Compression
);
2452 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.window_bits
, 5);
2453 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.level
, 6);
2454 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.strategy
, 7);
2455 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.max_dict_bytes
, 8u);
2456 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.zstd_max_train_bytes
, 9u);
2457 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.parallel_threads
,
2458 CompressionOptions().parallel_threads
);
2459 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.enabled
, true);
2460 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.max_dict_buffer_bytes
,
2461 CompressionOptions().max_dict_buffer_bytes
);
2462 ASSERT_EQ(new_cf_opt
.bottommost_compression_opts
.use_zstd_dict_trainer
,
2463 CompressionOptions().use_zstd_dict_trainer
);
2464 ASSERT_EQ(new_cf_opt
.num_levels
, 8);
2465 ASSERT_EQ(new_cf_opt
.level0_file_num_compaction_trigger
, 8);
2466 ASSERT_EQ(new_cf_opt
.level0_slowdown_writes_trigger
, 9);
2467 ASSERT_EQ(new_cf_opt
.level0_stop_writes_trigger
, 10);
2468 ASSERT_EQ(new_cf_opt
.target_file_size_base
, static_cast<uint64_t>(12));
2469 ASSERT_EQ(new_cf_opt
.target_file_size_multiplier
, 13);
2470 ASSERT_EQ(new_cf_opt
.max_bytes_for_level_base
, 14U);
2471 ASSERT_EQ(new_cf_opt
.level_compaction_dynamic_level_bytes
, true);
2472 ASSERT_EQ(new_cf_opt
.level_compaction_dynamic_file_size
, true);
2473 ASSERT_EQ(new_cf_opt
.max_bytes_for_level_multiplier
, 15.0);
2474 ASSERT_EQ(new_cf_opt
.max_bytes_for_level_multiplier_additional
.size(), 3U);
2475 ASSERT_EQ(new_cf_opt
.max_bytes_for_level_multiplier_additional
[0], 16);
2476 ASSERT_EQ(new_cf_opt
.max_bytes_for_level_multiplier_additional
[1], 17);
2477 ASSERT_EQ(new_cf_opt
.max_bytes_for_level_multiplier_additional
[2], 18);
2478 ASSERT_EQ(new_cf_opt
.max_compaction_bytes
, 21);
2479 ASSERT_EQ(new_cf_opt
.hard_pending_compaction_bytes_limit
, 211);
2480 ASSERT_EQ(new_cf_opt
.arena_block_size
, 22U);
2481 ASSERT_EQ(new_cf_opt
.disable_auto_compactions
, true);
2482 ASSERT_EQ(new_cf_opt
.compaction_style
, kCompactionStyleLevel
);
2483 ASSERT_EQ(new_cf_opt
.compaction_pri
, kOldestSmallestSeqFirst
);
2484 ASSERT_EQ(new_cf_opt
.compaction_options_fifo
.max_table_files_size
,
2485 static_cast<uint64_t>(23));
2486 ASSERT_EQ(new_cf_opt
.max_sequential_skip_in_iterations
,
2487 static_cast<uint64_t>(24));
2488 ASSERT_EQ(new_cf_opt
.inplace_update_support
, true);
2489 ASSERT_EQ(new_cf_opt
.inplace_update_num_locks
, 25U);
2490 ASSERT_EQ(new_cf_opt
.memtable_prefix_bloom_size_ratio
, 0.26);
2491 ASSERT_EQ(new_cf_opt
.memtable_whole_key_filtering
, true);
2492 ASSERT_EQ(new_cf_opt
.memtable_huge_page_size
, 28U);
2493 ASSERT_EQ(new_cf_opt
.bloom_locality
, 29U);
2494 ASSERT_EQ(new_cf_opt
.max_successive_merges
, 30U);
2495 ASSERT_TRUE(new_cf_opt
.prefix_extractor
!= nullptr);
2496 ASSERT_EQ(new_cf_opt
.optimize_filters_for_hits
, true);
2497 ASSERT_EQ(new_cf_opt
.prefix_extractor
->AsString(), "rocksdb.FixedPrefix.31");
2498 ASSERT_EQ(new_cf_opt
.experimental_mempurge_threshold
, 0.003);
2499 ASSERT_EQ(new_cf_opt
.enable_blob_files
, true);
2500 ASSERT_EQ(new_cf_opt
.min_blob_size
, 1ULL << 10);
2501 ASSERT_EQ(new_cf_opt
.blob_file_size
, 1ULL << 30);
2502 ASSERT_EQ(new_cf_opt
.blob_compression_type
, kZSTD
);
2503 ASSERT_EQ(new_cf_opt
.enable_blob_garbage_collection
, true);
2504 ASSERT_EQ(new_cf_opt
.blob_garbage_collection_age_cutoff
, 0.5);
2505 ASSERT_EQ(new_cf_opt
.blob_garbage_collection_force_threshold
, 0.75);
2506 ASSERT_EQ(new_cf_opt
.blob_compaction_readahead_size
, 262144);
2507 ASSERT_EQ(new_cf_opt
.blob_file_starting_level
, 1);
2508 ASSERT_EQ(new_cf_opt
.prepopulate_blob_cache
, PrepopulateBlobCache::kDisable
);
2509 ASSERT_EQ(new_cf_opt
.last_level_temperature
, Temperature::kWarm
);
2510 ASSERT_EQ(new_cf_opt
.bottommost_temperature
, Temperature::kWarm
);
2512 cf_options_map
["write_buffer_size"] = "hello";
2513 ASSERT_NOK(GetColumnFamilyOptionsFromMap(
2514 base_cf_opt
, cf_options_map
, &new_cf_opt
));
2515 ConfigOptions exact
, loose
;
2516 exact
.sanity_level
= ConfigOptions::kSanityLevelExactMatch
;
2517 loose
.sanity_level
= ConfigOptions::kSanityLevelLooselyCompatible
;
2519 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(exact
, base_cf_opt
, new_cf_opt
));
2521 cf_options_map
["write_buffer_size"] = "1";
2522 ASSERT_OK(GetColumnFamilyOptionsFromMap(
2523 base_cf_opt
, cf_options_map
, &new_cf_opt
));
2525 cf_options_map
["unknown_option"] = "1";
2526 ASSERT_NOK(GetColumnFamilyOptionsFromMap(
2527 base_cf_opt
, cf_options_map
, &new_cf_opt
));
2528 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(exact
, base_cf_opt
, new_cf_opt
));
2530 ASSERT_OK(GetColumnFamilyOptionsFromMap(base_cf_opt
, cf_options_map
,
2532 false, /* input_strings_escaped */
2533 true /* ignore_unknown_options */));
2534 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
2535 loose
, base_cf_opt
, new_cf_opt
, nullptr /* new_opt_map */));
2536 ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
2537 exact
/* default for VerifyCFOptions */, base_cf_opt
, new_cf_opt
, nullptr));
2539 DBOptions base_db_opt
;
2540 DBOptions new_db_opt
;
2541 ASSERT_OK(GetDBOptionsFromMap(base_db_opt
, db_options_map
, &new_db_opt
));
2542 ASSERT_EQ(new_db_opt
.create_if_missing
, false);
2543 ASSERT_EQ(new_db_opt
.create_missing_column_families
, true);
2544 ASSERT_EQ(new_db_opt
.error_if_exists
, false);
2545 ASSERT_EQ(new_db_opt
.paranoid_checks
, true);
2546 ASSERT_EQ(new_db_opt
.track_and_verify_wals_in_manifest
, true);
2547 ASSERT_EQ(new_db_opt
.max_open_files
, 32);
2548 ASSERT_EQ(new_db_opt
.max_total_wal_size
, static_cast<uint64_t>(33));
2549 ASSERT_EQ(new_db_opt
.use_fsync
, true);
2550 ASSERT_EQ(new_db_opt
.db_log_dir
, "/db_log_dir");
2551 ASSERT_EQ(new_db_opt
.wal_dir
, "/wal_dir");
2552 ASSERT_EQ(new_db_opt
.delete_obsolete_files_period_micros
,
2553 static_cast<uint64_t>(34));
2554 ASSERT_EQ(new_db_opt
.max_background_compactions
, 35);
2555 ASSERT_EQ(new_db_opt
.max_background_flushes
, 36);
2556 ASSERT_EQ(new_db_opt
.max_log_file_size
, 37U);
2557 ASSERT_EQ(new_db_opt
.log_file_time_to_roll
, 38U);
2558 ASSERT_EQ(new_db_opt
.keep_log_file_num
, 39U);
2559 ASSERT_EQ(new_db_opt
.recycle_log_file_num
, 5U);
2560 ASSERT_EQ(new_db_opt
.max_manifest_file_size
, static_cast<uint64_t>(40));
2561 ASSERT_EQ(new_db_opt
.table_cache_numshardbits
, 41);
2562 ASSERT_EQ(new_db_opt
.WAL_ttl_seconds
, static_cast<uint64_t>(43));
2563 ASSERT_EQ(new_db_opt
.WAL_size_limit_MB
, static_cast<uint64_t>(44));
2564 ASSERT_EQ(new_db_opt
.manifest_preallocation_size
, 45U);
2565 ASSERT_EQ(new_db_opt
.allow_mmap_reads
, true);
2566 ASSERT_EQ(new_db_opt
.allow_mmap_writes
, false);
2567 ASSERT_EQ(new_db_opt
.use_direct_reads
, false);
2568 ASSERT_EQ(new_db_opt
.use_direct_io_for_flush_and_compaction
, false);
2569 ASSERT_EQ(new_db_opt
.is_fd_close_on_exec
, true);
2570 ASSERT_EQ(new_db_opt
.stats_dump_period_sec
, 46U);
2571 ASSERT_EQ(new_db_opt
.stats_persist_period_sec
, 57U);
2572 ASSERT_EQ(new_db_opt
.persist_stats_to_disk
, false);
2573 ASSERT_EQ(new_db_opt
.stats_history_buffer_size
, 69U);
2574 ASSERT_EQ(new_db_opt
.advise_random_on_open
, true);
2575 ASSERT_EQ(new_db_opt
.use_adaptive_mutex
, false);
2576 ASSERT_EQ(new_db_opt
.compaction_readahead_size
, 100);
2577 ASSERT_EQ(new_db_opt
.random_access_max_buffer_size
, 3145728);
2578 ASSERT_EQ(new_db_opt
.writable_file_max_buffer_size
, 314159);
2579 ASSERT_EQ(new_db_opt
.bytes_per_sync
, static_cast<uint64_t>(47));
2580 ASSERT_EQ(new_db_opt
.wal_bytes_per_sync
, static_cast<uint64_t>(48));
2581 ASSERT_EQ(new_db_opt
.strict_bytes_per_sync
, true);
2583 db_options_map
["max_open_files"] = "hello";
2584 ASSERT_NOK(GetDBOptionsFromMap(base_db_opt
, db_options_map
, &new_db_opt
));
2585 ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(exact
, base_db_opt
, new_db_opt
));
2586 ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(loose
, base_db_opt
, new_db_opt
));
2588 // unknow options should fail parsing without ignore_unknown_options = true
2589 db_options_map
["unknown_db_option"] = "1";
2590 ASSERT_NOK(GetDBOptionsFromMap(base_db_opt
, db_options_map
, &new_db_opt
));
2591 ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(exact
, base_db_opt
, new_db_opt
));
2593 ASSERT_OK(GetDBOptionsFromMap(base_db_opt
, db_options_map
, &new_db_opt
,
2594 false, /* input_strings_escaped */
2595 true /* ignore_unknown_options */));
2596 ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(loose
, base_db_opt
, new_db_opt
));
2597 ASSERT_NOK(RocksDBOptionsParser::VerifyDBOptions(exact
, base_db_opt
, new_db_opt
));
2600 TEST_F(OptionsOldApiTest
, GetColumnFamilyOptionsFromStringTest
) {
2601 ColumnFamilyOptions base_cf_opt
;
2602 ColumnFamilyOptions new_cf_opt
;
2603 base_cf_opt
.table_factory
.reset();
2604 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
, "", &new_cf_opt
));
2605 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2606 "write_buffer_size=5", &new_cf_opt
));
2607 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 5U);
2608 ASSERT_TRUE(new_cf_opt
.table_factory
== nullptr);
2609 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2610 "write_buffer_size=6;", &new_cf_opt
));
2611 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 6U);
2612 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2613 " write_buffer_size = 7 ", &new_cf_opt
));
2614 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 7U);
2615 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2616 " write_buffer_size = 8 ; ", &new_cf_opt
));
2617 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 8U);
2618 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2619 "write_buffer_size=9;max_write_buffer_number=10", &new_cf_opt
));
2620 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 9U);
2621 ASSERT_EQ(new_cf_opt
.max_write_buffer_number
, 10);
2622 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2623 "write_buffer_size=11; max_write_buffer_number = 12 ;",
2625 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 11U);
2626 ASSERT_EQ(new_cf_opt
.max_write_buffer_number
, 12);
2627 // Wrong name "max_write_buffer_number_"
2628 ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2629 "write_buffer_size=13;max_write_buffer_number_=14;",
2631 ConfigOptions exact
;
2632 exact
.sanity_level
= ConfigOptions::kSanityLevelExactMatch
;
2633 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(exact
, base_cf_opt
, new_cf_opt
));
2635 // Comparator from object registry
2636 std::string kCompName
= "reverse_comp";
2637 ObjectLibrary::Default()->AddFactory
<const Comparator
>(
2639 [](const std::string
& /*name*/,
2640 std::unique_ptr
<const Comparator
>* /*guard*/,
2641 std::string
* /* errmsg */) { return ReverseBytewiseComparator(); });
2643 ASSERT_OK(GetColumnFamilyOptionsFromString(
2644 base_cf_opt
, "comparator=" + kCompName
+ ";", &new_cf_opt
));
2645 ASSERT_EQ(new_cf_opt
.comparator
, ReverseBytewiseComparator());
2647 // MergeOperator from object registry
2648 std::unique_ptr
<BytesXOROperator
> bxo(new BytesXOROperator());
2649 std::string kMoName
= bxo
->Name();
2650 ASSERT_OK(GetColumnFamilyOptionsFromString(
2651 base_cf_opt
, "merge_operator=" + kMoName
+ ";", &new_cf_opt
));
2652 ASSERT_EQ(kMoName
, std::string(new_cf_opt
.merge_operator
->Name()));
2654 // Wrong key/value pair
2655 ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2656 "write_buffer_size=13;max_write_buffer_number;", &new_cf_opt
));
2657 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(exact
, base_cf_opt
, new_cf_opt
));
2659 // Error Paring value
2660 ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2661 "write_buffer_size=13;max_write_buffer_number=;", &new_cf_opt
));
2662 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(exact
, base_cf_opt
, new_cf_opt
));
2664 // Missing option name
2665 ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2666 "write_buffer_size=13; =100;", &new_cf_opt
));
2667 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(exact
, base_cf_opt
, new_cf_opt
));
2669 const uint64_t kilo
= 1024UL;
2670 const uint64_t mega
= 1024 * kilo
;
2671 const uint64_t giga
= 1024 * mega
;
2672 const uint64_t tera
= 1024 * giga
;
2675 ASSERT_OK(GetColumnFamilyOptionsFromString(
2676 base_cf_opt
, "max_write_buffer_number=15K", &new_cf_opt
));
2677 ASSERT_EQ(new_cf_opt
.max_write_buffer_number
, 15 * kilo
);
2679 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2680 "max_write_buffer_number=16m;inplace_update_num_locks=17M",
2682 ASSERT_EQ(new_cf_opt
.max_write_buffer_number
, 16 * mega
);
2683 ASSERT_EQ(new_cf_opt
.inplace_update_num_locks
, 17u * mega
);
2685 ASSERT_OK(GetColumnFamilyOptionsFromString(
2687 "write_buffer_size=18g;prefix_extractor=capped:8;"
2688 "arena_block_size=19G",
2691 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 18 * giga
);
2692 ASSERT_EQ(new_cf_opt
.arena_block_size
, 19 * giga
);
2693 ASSERT_TRUE(new_cf_opt
.prefix_extractor
.get() != nullptr);
2694 ASSERT_EQ(new_cf_opt
.prefix_extractor
->AsString(), "rocksdb.CappedPrefix.8");
2697 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2698 "write_buffer_size=20t;arena_block_size=21T", &new_cf_opt
));
2699 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 20 * tera
);
2700 ASSERT_EQ(new_cf_opt
.arena_block_size
, 21 * tera
);
2702 // Nested block based table options
2704 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2705 "write_buffer_size=10;max_write_buffer_number=16;"
2706 "block_based_table_factory={};arena_block_size=1024",
2708 ASSERT_TRUE(new_cf_opt
.table_factory
!= nullptr);
2710 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2711 "write_buffer_size=10;max_write_buffer_number=16;"
2712 "block_based_table_factory={block_cache=1M;block_size=4;};"
2713 "arena_block_size=1024",
2715 ASSERT_TRUE(new_cf_opt
.table_factory
!= nullptr);
2717 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2718 "write_buffer_size=10;max_write_buffer_number=16;"
2719 "block_based_table_factory={block_cache=1M;block_size=4;}",
2721 ASSERT_TRUE(new_cf_opt
.table_factory
!= nullptr);
2722 // Mismatch curly braces
2723 ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2724 "write_buffer_size=10;max_write_buffer_number=16;"
2725 "block_based_table_factory={{{block_size=4;};"
2726 "arena_block_size=1024",
2728 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(exact
, base_cf_opt
, new_cf_opt
));
2730 // Unexpected chars after closing curly brace
2731 ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2732 "write_buffer_size=10;max_write_buffer_number=16;"
2733 "block_based_table_factory={block_size=4;}};"
2734 "arena_block_size=1024",
2736 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(exact
, base_cf_opt
, new_cf_opt
));
2738 ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2739 "write_buffer_size=10;max_write_buffer_number=16;"
2740 "block_based_table_factory={block_size=4;}xdfa;"
2741 "arena_block_size=1024",
2743 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(exact
, base_cf_opt
, new_cf_opt
));
2745 ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2746 "write_buffer_size=10;max_write_buffer_number=16;"
2747 "block_based_table_factory={block_size=4;}xdfa",
2749 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(exact
, base_cf_opt
, new_cf_opt
));
2751 // Invalid block based table option
2752 ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2753 "write_buffer_size=10;max_write_buffer_number=16;"
2754 "block_based_table_factory={xx_block_size=4;}",
2756 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(exact
, base_cf_opt
, new_cf_opt
));
2758 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2759 "optimize_filters_for_hits=true",
2761 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2762 "optimize_filters_for_hits=false",
2765 ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2766 "optimize_filters_for_hits=junk",
2768 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(exact
, base_cf_opt
, new_cf_opt
));
2770 // Nested plain table options
2772 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2773 "write_buffer_size=10;max_write_buffer_number=16;"
2774 "plain_table_factory={};arena_block_size=1024",
2776 ASSERT_TRUE(new_cf_opt
.table_factory
!= nullptr);
2777 ASSERT_EQ(std::string(new_cf_opt
.table_factory
->Name()), "PlainTable");
2779 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2780 "write_buffer_size=10;max_write_buffer_number=16;"
2781 "plain_table_factory={user_key_len=66;bloom_bits_per_key=20;};"
2782 "arena_block_size=1024",
2784 ASSERT_TRUE(new_cf_opt
.table_factory
!= nullptr);
2785 ASSERT_EQ(std::string(new_cf_opt
.table_factory
->Name()), "PlainTable");
2788 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
2789 "write_buffer_size=10;max_write_buffer_number=16;"
2790 "memtable=skip_list:10;arena_block_size=1024",
2792 ASSERT_TRUE(new_cf_opt
.memtable_factory
!= nullptr);
2793 ASSERT_TRUE(new_cf_opt
.memtable_factory
->IsInstanceOf("SkipListFactory"));
2796 ASSERT_OK(GetColumnFamilyOptionsFromString(
2798 "blob_cache={capacity=1M;num_shard_bits=4;"
2799 "strict_capacity_limit=true;high_pri_pool_ratio=0.5;};",
2801 ASSERT_NE(new_cf_opt
.blob_cache
, nullptr);
2802 ASSERT_EQ(new_cf_opt
.blob_cache
->GetCapacity(), 1024UL * 1024UL);
2803 ASSERT_EQ(static_cast<ShardedCacheBase
*>(new_cf_opt
.blob_cache
.get())
2804 ->GetNumShardBits(),
2806 ASSERT_EQ(new_cf_opt
.blob_cache
->HasStrictCapacityLimit(), true);
2807 ASSERT_EQ(static_cast<LRUCache
*>(new_cf_opt
.blob_cache
.get())
2808 ->GetHighPriPoolRatio(),
2812 TEST_F(OptionsTest
, SliceTransformCreateFromString
) {
2813 std::shared_ptr
<const SliceTransform
> transform
= nullptr;
2814 ConfigOptions config_options
;
2815 config_options
.ignore_unsupported_options
= false;
2816 config_options
.ignore_unknown_options
= false;
2819 SliceTransform::CreateFromString(config_options
, "fixed:31", &transform
));
2820 ASSERT_NE(transform
, nullptr);
2821 ASSERT_FALSE(transform
->IsInstanceOf("capped"));
2822 ASSERT_TRUE(transform
->IsInstanceOf("fixed"));
2823 ASSERT_TRUE(transform
->IsInstanceOf("rocksdb.FixedPrefix"));
2824 ASSERT_EQ(transform
->GetId(), "rocksdb.FixedPrefix.31");
2825 ASSERT_OK(SliceTransform::CreateFromString(
2826 config_options
, "rocksdb.FixedPrefix.42", &transform
));
2827 ASSERT_NE(transform
, nullptr);
2828 ASSERT_EQ(transform
->GetId(), "rocksdb.FixedPrefix.42");
2830 ASSERT_OK(SliceTransform::CreateFromString(config_options
, "capped:16",
2832 ASSERT_NE(transform
, nullptr);
2833 ASSERT_FALSE(transform
->IsInstanceOf("fixed"));
2834 ASSERT_TRUE(transform
->IsInstanceOf("capped"));
2835 ASSERT_TRUE(transform
->IsInstanceOf("rocksdb.CappedPrefix"));
2836 ASSERT_EQ(transform
->GetId(), "rocksdb.CappedPrefix.16");
2837 ASSERT_OK(SliceTransform::CreateFromString(
2838 config_options
, "rocksdb.CappedPrefix.42", &transform
));
2839 ASSERT_NE(transform
, nullptr);
2840 ASSERT_EQ(transform
->GetId(), "rocksdb.CappedPrefix.42");
2842 ASSERT_OK(SliceTransform::CreateFromString(config_options
, "rocksdb.Noop",
2844 ASSERT_NE(transform
, nullptr);
2846 ASSERT_NOK(SliceTransform::CreateFromString(config_options
,
2847 "fixed:21:invalid", &transform
));
2848 ASSERT_NOK(SliceTransform::CreateFromString(config_options
,
2849 "capped:21:invalid", &transform
));
2851 SliceTransform::CreateFromString(config_options
, "fixed", &transform
));
2853 SliceTransform::CreateFromString(config_options
, "capped", &transform
));
2855 SliceTransform::CreateFromString(config_options
, "fixed:", &transform
));
2857 SliceTransform::CreateFromString(config_options
, "capped:", &transform
));
2858 ASSERT_NOK(SliceTransform::CreateFromString(
2859 config_options
, "rocksdb.FixedPrefix:42", &transform
));
2860 ASSERT_NOK(SliceTransform::CreateFromString(
2861 config_options
, "rocksdb.CappedPrefix:42", &transform
));
2862 ASSERT_NOK(SliceTransform::CreateFromString(
2863 config_options
, "rocksdb.FixedPrefix", &transform
));
2864 ASSERT_NOK(SliceTransform::CreateFromString(
2865 config_options
, "rocksdb.CappedPrefix", &transform
));
2866 ASSERT_NOK(SliceTransform::CreateFromString(
2867 config_options
, "rocksdb.FixedPrefix.", &transform
));
2868 ASSERT_NOK(SliceTransform::CreateFromString(
2869 config_options
, "rocksdb.CappedPrefix.", &transform
));
2871 SliceTransform::CreateFromString(config_options
, "invalid", &transform
));
2873 #ifndef ROCKSDB_LITE
2874 ASSERT_OK(SliceTransform::CreateFromString(
2875 config_options
, "rocksdb.CappedPrefix.11", &transform
));
2876 ASSERT_NE(transform
, nullptr);
2877 ASSERT_EQ(transform
->GetId(), "rocksdb.CappedPrefix.11");
2878 ASSERT_TRUE(transform
->IsInstanceOf("capped"));
2879 ASSERT_TRUE(transform
->IsInstanceOf("capped:11"));
2880 ASSERT_TRUE(transform
->IsInstanceOf("rocksdb.CappedPrefix"));
2881 ASSERT_TRUE(transform
->IsInstanceOf("rocksdb.CappedPrefix.11"));
2882 ASSERT_FALSE(transform
->IsInstanceOf("fixed"));
2883 ASSERT_FALSE(transform
->IsInstanceOf("fixed:11"));
2884 ASSERT_FALSE(transform
->IsInstanceOf("rocksdb.FixedPrefix"));
2885 ASSERT_FALSE(transform
->IsInstanceOf("rocksdb.FixedPrefix.11"));
2887 ASSERT_OK(SliceTransform::CreateFromString(
2888 config_options
, "rocksdb.FixedPrefix.11", &transform
));
2889 ASSERT_TRUE(transform
->IsInstanceOf("fixed"));
2890 ASSERT_TRUE(transform
->IsInstanceOf("fixed:11"));
2891 ASSERT_TRUE(transform
->IsInstanceOf("rocksdb.FixedPrefix"));
2892 ASSERT_TRUE(transform
->IsInstanceOf("rocksdb.FixedPrefix.11"));
2893 ASSERT_FALSE(transform
->IsInstanceOf("capped"));
2894 ASSERT_FALSE(transform
->IsInstanceOf("capped:11"));
2895 ASSERT_FALSE(transform
->IsInstanceOf("rocksdb.CappedPrefix"));
2896 ASSERT_FALSE(transform
->IsInstanceOf("rocksdb.CappedPrefix.11"));
2897 #endif // ROCKSDB_LITE
2900 TEST_F(OptionsOldApiTest
, GetBlockBasedTableOptionsFromString
) {
2901 BlockBasedTableOptions table_opt
;
2902 BlockBasedTableOptions new_opt
;
2903 // make sure default values are overwritten by something else
2904 ASSERT_OK(GetBlockBasedTableOptionsFromString(
2906 "cache_index_and_filter_blocks=1;index_type=kHashSearch;"
2907 "checksum=kxxHash;no_block_cache=1;"
2908 "block_cache=1M;block_cache_compressed=1k;block_size=1024;"
2909 "block_size_deviation=8;block_restart_interval=4;"
2910 "format_version=5;whole_key_filtering=1;"
2911 "filter_policy=bloomfilter:4.567:false;",
2913 ASSERT_TRUE(new_opt
.cache_index_and_filter_blocks
);
2914 ASSERT_EQ(new_opt
.index_type
, BlockBasedTableOptions::kHashSearch
);
2915 ASSERT_EQ(new_opt
.checksum
, ChecksumType::kxxHash
);
2916 ASSERT_TRUE(new_opt
.no_block_cache
);
2917 ASSERT_TRUE(new_opt
.block_cache
!= nullptr);
2918 ASSERT_EQ(new_opt
.block_cache
->GetCapacity(), 1024UL*1024UL);
2919 ASSERT_TRUE(new_opt
.block_cache_compressed
!= nullptr);
2920 ASSERT_EQ(new_opt
.block_cache_compressed
->GetCapacity(), 1024UL);
2921 ASSERT_EQ(new_opt
.block_size
, 1024UL);
2922 ASSERT_EQ(new_opt
.block_size_deviation
, 8);
2923 ASSERT_EQ(new_opt
.block_restart_interval
, 4);
2924 ASSERT_EQ(new_opt
.format_version
, 5U);
2925 ASSERT_EQ(new_opt
.whole_key_filtering
, true);
2926 ASSERT_TRUE(new_opt
.filter_policy
!= nullptr);
2927 const BloomFilterPolicy
* bfp
=
2928 dynamic_cast<const BloomFilterPolicy
*>(new_opt
.filter_policy
.get());
2929 EXPECT_EQ(bfp
->GetMillibitsPerKey(), 4567);
2930 EXPECT_EQ(bfp
->GetWholeBitsPerKey(), 5);
2933 ASSERT_NOK(GetBlockBasedTableOptionsFromString(table_opt
,
2934 "cache_index_and_filter_blocks=1;index_type=kBinarySearch;"
2937 ASSERT_EQ(static_cast<bool>(table_opt
.cache_index_and_filter_blocks
),
2938 new_opt
.cache_index_and_filter_blocks
);
2939 ASSERT_EQ(table_opt
.index_type
, new_opt
.index_type
);
2941 // unrecognized index type
2942 ASSERT_NOK(GetBlockBasedTableOptionsFromString(table_opt
,
2943 "cache_index_and_filter_blocks=1;index_type=kBinarySearchXX",
2945 ASSERT_EQ(table_opt
.cache_index_and_filter_blocks
,
2946 new_opt
.cache_index_and_filter_blocks
);
2947 ASSERT_EQ(table_opt
.index_type
, new_opt
.index_type
);
2949 // unrecognized checksum type
2950 ASSERT_NOK(GetBlockBasedTableOptionsFromString(table_opt
,
2951 "cache_index_and_filter_blocks=1;checksum=kxxHashXX",
2953 ASSERT_EQ(table_opt
.cache_index_and_filter_blocks
,
2954 new_opt
.cache_index_and_filter_blocks
);
2955 ASSERT_EQ(table_opt
.index_type
, new_opt
.index_type
);
2957 // unrecognized filter policy name
2958 ASSERT_NOK(GetBlockBasedTableOptionsFromString(table_opt
,
2959 "cache_index_and_filter_blocks=1;"
2960 "filter_policy=bloomfilterxx:4:true",
2962 ASSERT_EQ(table_opt
.cache_index_and_filter_blocks
,
2963 new_opt
.cache_index_and_filter_blocks
);
2964 ASSERT_EQ(table_opt
.filter_policy
, new_opt
.filter_policy
);
2966 // Used to be rejected, now accepted
2967 ASSERT_OK(GetBlockBasedTableOptionsFromString(
2968 table_opt
, "filter_policy=bloomfilter:4", &new_opt
));
2969 bfp
= dynamic_cast<const BloomFilterPolicy
*>(new_opt
.filter_policy
.get());
2970 EXPECT_EQ(bfp
->GetMillibitsPerKey(), 4000);
2971 EXPECT_EQ(bfp
->GetWholeBitsPerKey(), 4);
2973 // Check block cache options are overwritten when specified
2974 // in new format as a struct.
2975 ASSERT_OK(GetBlockBasedTableOptionsFromString(table_opt
,
2976 "block_cache={capacity=1M;num_shard_bits=4;"
2977 "strict_capacity_limit=true;high_pri_pool_ratio=0.5;};"
2978 "block_cache_compressed={capacity=1M;num_shard_bits=4;"
2979 "strict_capacity_limit=true;high_pri_pool_ratio=0.5;}",
2981 ASSERT_TRUE(new_opt
.block_cache
!= nullptr);
2982 ASSERT_EQ(new_opt
.block_cache
->GetCapacity(), 1024UL*1024UL);
2983 ASSERT_EQ(std::dynamic_pointer_cast
<ShardedCacheBase
>(new_opt
.block_cache
)
2984 ->GetNumShardBits(),
2986 ASSERT_EQ(new_opt
.block_cache
->HasStrictCapacityLimit(), true);
2987 ASSERT_EQ(std::dynamic_pointer_cast
<LRUCache
>(
2988 new_opt
.block_cache
)->GetHighPriPoolRatio(), 0.5);
2989 ASSERT_TRUE(new_opt
.block_cache_compressed
!= nullptr);
2990 ASSERT_EQ(new_opt
.block_cache_compressed
->GetCapacity(), 1024UL*1024UL);
2991 ASSERT_EQ(std::dynamic_pointer_cast
<ShardedCacheBase
>(
2992 new_opt
.block_cache_compressed
)
2993 ->GetNumShardBits(),
2995 ASSERT_EQ(new_opt
.block_cache_compressed
->HasStrictCapacityLimit(), true);
2996 ASSERT_EQ(std::dynamic_pointer_cast
<LRUCache
>(
2997 new_opt
.block_cache_compressed
)->GetHighPriPoolRatio(),
3000 // Set only block cache capacity. Check other values are
3001 // reset to default values.
3002 ASSERT_OK(GetBlockBasedTableOptionsFromString(table_opt
,
3003 "block_cache={capacity=2M};"
3004 "block_cache_compressed={capacity=2M}",
3006 ASSERT_TRUE(new_opt
.block_cache
!= nullptr);
3007 ASSERT_EQ(new_opt
.block_cache
->GetCapacity(), 2*1024UL*1024UL);
3009 ASSERT_EQ(std::dynamic_pointer_cast
<ShardedCacheBase
>(new_opt
.block_cache
)
3010 ->GetNumShardBits(),
3011 GetDefaultCacheShardBits(new_opt
.block_cache
->GetCapacity()));
3012 ASSERT_EQ(new_opt
.block_cache
->HasStrictCapacityLimit(), false);
3013 ASSERT_EQ(std::dynamic_pointer_cast
<LRUCache
>(new_opt
.block_cache
)
3014 ->GetHighPriPoolRatio(),
3016 ASSERT_TRUE(new_opt
.block_cache_compressed
!= nullptr);
3017 ASSERT_EQ(new_opt
.block_cache_compressed
->GetCapacity(), 2*1024UL*1024UL);
3020 std::dynamic_pointer_cast
<ShardedCacheBase
>(
3021 new_opt
.block_cache_compressed
)
3022 ->GetNumShardBits(),
3023 GetDefaultCacheShardBits(new_opt
.block_cache_compressed
->GetCapacity()));
3024 ASSERT_EQ(new_opt
.block_cache_compressed
->HasStrictCapacityLimit(), false);
3025 ASSERT_EQ(std::dynamic_pointer_cast
<LRUCache
>(new_opt
.block_cache_compressed
)
3026 ->GetHighPriPoolRatio(),
3029 // Set couple of block cache options.
3030 ASSERT_OK(GetBlockBasedTableOptionsFromString(
3032 "block_cache={num_shard_bits=5;high_pri_pool_ratio=0.5;};"
3033 "block_cache_compressed={num_shard_bits=5;"
3034 "high_pri_pool_ratio=0.0;}",
3036 ASSERT_EQ(new_opt
.block_cache
->GetCapacity(), 0);
3037 ASSERT_EQ(std::dynamic_pointer_cast
<ShardedCacheBase
>(new_opt
.block_cache
)
3038 ->GetNumShardBits(),
3040 ASSERT_EQ(new_opt
.block_cache
->HasStrictCapacityLimit(), false);
3041 ASSERT_EQ(std::dynamic_pointer_cast
<LRUCache
>(
3042 new_opt
.block_cache
)->GetHighPriPoolRatio(), 0.5);
3043 ASSERT_TRUE(new_opt
.block_cache_compressed
!= nullptr);
3044 ASSERT_EQ(new_opt
.block_cache_compressed
->GetCapacity(), 0);
3045 ASSERT_EQ(std::dynamic_pointer_cast
<ShardedCacheBase
>(
3046 new_opt
.block_cache_compressed
)
3047 ->GetNumShardBits(),
3049 ASSERT_EQ(new_opt
.block_cache_compressed
->HasStrictCapacityLimit(), false);
3050 ASSERT_EQ(std::dynamic_pointer_cast
<LRUCache
>(new_opt
.block_cache_compressed
)
3051 ->GetHighPriPoolRatio(),
3054 // Set couple of block cache options.
3055 ASSERT_OK(GetBlockBasedTableOptionsFromString(table_opt
,
3056 "block_cache={capacity=1M;num_shard_bits=4;"
3057 "strict_capacity_limit=true;};"
3058 "block_cache_compressed={capacity=1M;num_shard_bits=4;"
3059 "strict_capacity_limit=true;}",
3061 ASSERT_TRUE(new_opt
.block_cache
!= nullptr);
3062 ASSERT_EQ(new_opt
.block_cache
->GetCapacity(), 1024UL*1024UL);
3063 ASSERT_EQ(std::dynamic_pointer_cast
<ShardedCacheBase
>(new_opt
.block_cache
)
3064 ->GetNumShardBits(),
3066 ASSERT_EQ(new_opt
.block_cache
->HasStrictCapacityLimit(), true);
3067 ASSERT_EQ(std::dynamic_pointer_cast
<LRUCache
>(new_opt
.block_cache
)
3068 ->GetHighPriPoolRatio(),
3070 ASSERT_TRUE(new_opt
.block_cache_compressed
!= nullptr);
3071 ASSERT_EQ(new_opt
.block_cache_compressed
->GetCapacity(), 1024UL*1024UL);
3072 ASSERT_EQ(std::dynamic_pointer_cast
<ShardedCacheBase
>(
3073 new_opt
.block_cache_compressed
)
3074 ->GetNumShardBits(),
3076 ASSERT_EQ(new_opt
.block_cache_compressed
->HasStrictCapacityLimit(), true);
3077 ASSERT_EQ(std::dynamic_pointer_cast
<LRUCache
>(new_opt
.block_cache_compressed
)
3078 ->GetHighPriPoolRatio(),
3082 TEST_F(OptionsOldApiTest
, GetPlainTableOptionsFromString
) {
3083 PlainTableOptions table_opt
;
3084 PlainTableOptions new_opt
;
3085 // make sure default values are overwritten by something else
3086 ASSERT_OK(GetPlainTableOptionsFromString(table_opt
,
3087 "user_key_len=66;bloom_bits_per_key=20;hash_table_ratio=0.5;"
3088 "index_sparseness=8;huge_page_tlb_size=4;encoding_type=kPrefix;"
3089 "full_scan_mode=true;store_index_in_file=true",
3091 ASSERT_EQ(new_opt
.user_key_len
, 66u);
3092 ASSERT_EQ(new_opt
.bloom_bits_per_key
, 20);
3093 ASSERT_EQ(new_opt
.hash_table_ratio
, 0.5);
3094 ASSERT_EQ(new_opt
.index_sparseness
, 8);
3095 ASSERT_EQ(new_opt
.huge_page_tlb_size
, 4);
3096 ASSERT_EQ(new_opt
.encoding_type
, EncodingType::kPrefix
);
3097 ASSERT_TRUE(new_opt
.full_scan_mode
);
3098 ASSERT_TRUE(new_opt
.store_index_in_file
);
3100 std::unordered_map
<std::string
, std::string
> opt_map
;
3101 ASSERT_OK(StringToMap(
3102 "user_key_len=55;bloom_bits_per_key=10;huge_page_tlb_size=8;", &opt_map
));
3103 ASSERT_OK(GetPlainTableOptionsFromMap(table_opt
, opt_map
, &new_opt
));
3104 ASSERT_EQ(new_opt
.user_key_len
, 55u);
3105 ASSERT_EQ(new_opt
.bloom_bits_per_key
, 10);
3106 ASSERT_EQ(new_opt
.huge_page_tlb_size
, 8);
3109 ASSERT_NOK(GetPlainTableOptionsFromString(table_opt
,
3110 "user_key_len=66;bloom_bits_per_key=20;hash_table_ratio=0.5;"
3114 // unrecognized EncodingType
3115 ASSERT_NOK(GetPlainTableOptionsFromString(table_opt
,
3116 "user_key_len=66;bloom_bits_per_key=20;hash_table_ratio=0.5;"
3117 "encoding_type=kPrefixXX",
3121 TEST_F(OptionsOldApiTest
, GetOptionsFromStringTest
) {
3122 Options base_options
, new_options
;
3123 base_options
.write_buffer_size
= 20;
3124 base_options
.min_write_buffer_number_to_merge
= 15;
3125 BlockBasedTableOptions block_based_table_options
;
3126 block_based_table_options
.cache_index_and_filter_blocks
= true;
3127 base_options
.table_factory
.reset(
3128 NewBlockBasedTableFactory(block_based_table_options
));
3130 // Register an Env with object registry.
3131 ObjectLibrary::Default()->AddFactory
<Env
>(
3133 [](const std::string
& /*name*/, std::unique_ptr
<Env
>* /*env_guard*/,
3134 std::string
* /* errmsg */) {
3135 static CustomEnv
env(Env::Default());
3139 ASSERT_OK(GetOptionsFromString(
3141 "write_buffer_size=10;max_write_buffer_number=16;"
3142 "block_based_table_factory={block_cache=1M;block_size=4;};"
3143 "compression_opts=4:5:6;create_if_missing=true;max_open_files=1;"
3144 "bottommost_compression_opts=5:6:7;create_if_missing=true;max_open_files="
3146 "rate_limiter_bytes_per_sec=1024;env=CustomEnvDefault",
3149 ASSERT_EQ(new_options
.compression_opts
.window_bits
, 4);
3150 ASSERT_EQ(new_options
.compression_opts
.level
, 5);
3151 ASSERT_EQ(new_options
.compression_opts
.strategy
, 6);
3152 ASSERT_EQ(new_options
.compression_opts
.max_dict_bytes
, 0u);
3153 ASSERT_EQ(new_options
.compression_opts
.zstd_max_train_bytes
, 0u);
3154 ASSERT_EQ(new_options
.compression_opts
.parallel_threads
, 1u);
3155 ASSERT_EQ(new_options
.compression_opts
.enabled
, false);
3156 ASSERT_EQ(new_options
.compression_opts
.use_zstd_dict_trainer
, true);
3157 ASSERT_EQ(new_options
.bottommost_compression
, kDisableCompressionOption
);
3158 ASSERT_EQ(new_options
.bottommost_compression_opts
.window_bits
, 5);
3159 ASSERT_EQ(new_options
.bottommost_compression_opts
.level
, 6);
3160 ASSERT_EQ(new_options
.bottommost_compression_opts
.strategy
, 7);
3161 ASSERT_EQ(new_options
.bottommost_compression_opts
.max_dict_bytes
, 0u);
3162 ASSERT_EQ(new_options
.bottommost_compression_opts
.zstd_max_train_bytes
, 0u);
3163 ASSERT_EQ(new_options
.bottommost_compression_opts
.parallel_threads
, 1u);
3164 ASSERT_EQ(new_options
.bottommost_compression_opts
.enabled
, false);
3165 ASSERT_EQ(new_options
.bottommost_compression_opts
.use_zstd_dict_trainer
,
3167 ASSERT_EQ(new_options
.write_buffer_size
, 10U);
3168 ASSERT_EQ(new_options
.max_write_buffer_number
, 16);
3170 auto new_block_based_table_options
=
3171 new_options
.table_factory
->GetOptions
<BlockBasedTableOptions
>();
3172 ASSERT_NE(new_block_based_table_options
, nullptr);
3173 ASSERT_EQ(new_block_based_table_options
->block_cache
->GetCapacity(),
3175 ASSERT_EQ(new_block_based_table_options
->block_size
, 4U);
3176 // don't overwrite block based table options
3177 ASSERT_TRUE(new_block_based_table_options
->cache_index_and_filter_blocks
);
3179 ASSERT_EQ(new_options
.create_if_missing
, true);
3180 ASSERT_EQ(new_options
.max_open_files
, 1);
3181 ASSERT_TRUE(new_options
.rate_limiter
.get() != nullptr);
3182 Env
* newEnv
= new_options
.env
;
3183 ASSERT_OK(Env::LoadEnv("CustomEnvDefault", &newEnv
));
3184 ASSERT_EQ(newEnv
, new_options
.env
);
3187 TEST_F(OptionsOldApiTest
, DBOptionsSerialization
) {
3188 Options base_options
, new_options
;
3191 // Phase 1: Make big change in base_options
3192 test::RandomInitDBOptions(&base_options
, &rnd
);
3194 // Phase 2: obtain a string from base_option
3195 std::string base_options_file_content
;
3196 ASSERT_OK(GetStringFromDBOptions(&base_options_file_content
, base_options
));
3198 // Phase 3: Set new_options from the derived string and expect
3199 // new_options == base_options
3200 ASSERT_OK(GetDBOptionsFromString(DBOptions(), base_options_file_content
,
3202 ConfigOptions config_options
;
3203 ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(config_options
, base_options
, new_options
));
3206 TEST_F(OptionsOldApiTest
, ColumnFamilyOptionsSerialization
) {
3208 ColumnFamilyOptions base_opt
, new_opt
;
3210 // Phase 1: randomly assign base_opt
3211 // custom type options
3212 test::RandomInitCFOptions(&base_opt
, options
, &rnd
);
3214 // Phase 2: obtain a string from base_opt
3215 std::string base_options_file_content
;
3217 GetStringFromColumnFamilyOptions(&base_options_file_content
, base_opt
));
3219 // Phase 3: Set new_opt from the derived string and expect
3220 // new_opt == base_opt
3221 ASSERT_OK(GetColumnFamilyOptionsFromString(
3222 ColumnFamilyOptions(), base_options_file_content
, &new_opt
));
3223 ConfigOptions config_options
;
3224 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options
, base_opt
, new_opt
));
3225 if (base_opt
.compaction_filter
) {
3226 delete base_opt
.compaction_filter
;
3229 #endif // !ROCKSDB_LITE
3231 #ifndef ROCKSDB_LITE
3232 class OptionsParserTest
: public testing::Test
{
3234 OptionsParserTest() { fs_
.reset(new test::StringFS(FileSystem::Default())); }
3237 std::shared_ptr
<test::StringFS
> fs_
;
3240 TEST_F(OptionsParserTest
, Comment
) {
3242 db_opt
.max_open_files
= 12345;
3243 db_opt
.max_background_flushes
= 301;
3244 db_opt
.max_total_wal_size
= 1024;
3245 ColumnFamilyOptions cf_opt
;
3247 std::string options_file_content
=
3248 "# This is a testing option string.\n"
3249 "# Currently we only support \"#\" styled comment.\n"
3252 " rocksdb_version=3.14.0\n"
3253 " options_file_version=1\n"
3255 " # note that we don't support space around \"=\"\n"
3256 " max_open_files=12345;\n"
3257 " max_background_flushes=301 # comment after a statement is fine\n"
3258 " # max_background_flushes=1000 # this line would be ignored\n"
3259 " # max_background_compactions=2000 # so does this one\n"
3260 " max_total_wal_size=1024 # keep_log_file_num=1000\n"
3261 "[CFOptions \"default\"] # column family must be specified\n"
3262 " # in the correct order\n"
3263 " # if a section is blank, we will use the default\n";
3265 const std::string kTestFileName
= "test-rocksdb-options.ini";
3266 ASSERT_OK(fs_
->WriteToNewFile(kTestFileName
, options_file_content
));
3267 RocksDBOptionsParser parser
;
3269 parser
.Parse(kTestFileName
, fs_
.get(), false, 4096 /* readahead_size */));
3271 ConfigOptions exact
;
3272 exact
.input_strings_escaped
= false;
3273 exact
.sanity_level
= ConfigOptions::kSanityLevelExactMatch
;
3275 RocksDBOptionsParser::VerifyDBOptions(exact
, *parser
.db_opt(), db_opt
));
3276 ASSERT_EQ(parser
.NumColumnFamilies(), 1U);
3277 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
3278 exact
, *parser
.GetCFOptions("default"), cf_opt
));
3281 TEST_F(OptionsParserTest
, ExtraSpace
) {
3282 std::string options_file_content
=
3283 "# This is a testing option string.\n"
3284 "# Currently we only support \"#\" styled comment.\n"
3287 " rocksdb_version = 3.14.0 \n"
3288 " options_file_version=1 # some comment\n"
3289 "[DBOptions ] # some comment\n"
3290 "max_open_files=12345 \n"
3291 " max_background_flushes = 301 \n"
3292 " max_total_wal_size = 1024 # keep_log_file_num=1000\n"
3293 " [CFOptions \"default\" ]\n"
3294 " # if a section is blank, we will use the default\n";
3296 const std::string kTestFileName
= "test-rocksdb-options.ini";
3297 ASSERT_OK(fs_
->WriteToNewFile(kTestFileName
, options_file_content
));
3298 RocksDBOptionsParser parser
;
3300 parser
.Parse(kTestFileName
, fs_
.get(), false, 4096 /* readahead_size */));
3303 TEST_F(OptionsParserTest
, MissingDBOptions
) {
3304 std::string options_file_content
=
3305 "# This is a testing option string.\n"
3306 "# Currently we only support \"#\" styled comment.\n"
3309 " rocksdb_version=3.14.0\n"
3310 " options_file_version=1\n"
3311 "[CFOptions \"default\"]\n"
3312 " # if a section is blank, we will use the default\n";
3314 const std::string kTestFileName
= "test-rocksdb-options.ini";
3315 ASSERT_OK(fs_
->WriteToNewFile(kTestFileName
, options_file_content
));
3316 RocksDBOptionsParser parser
;
3318 parser
.Parse(kTestFileName
, fs_
.get(), false, 4096 /* readahead_size */));
3322 TEST_F(OptionsParserTest
, DoubleDBOptions
) {
3324 db_opt
.max_open_files
= 12345;
3325 db_opt
.max_background_flushes
= 301;
3326 db_opt
.max_total_wal_size
= 1024;
3327 ColumnFamilyOptions cf_opt
;
3329 std::string options_file_content
=
3330 "# This is a testing option string.\n"
3331 "# Currently we only support \"#\" styled comment.\n"
3334 " rocksdb_version=3.14.0\n"
3335 " options_file_version=1\n"
3337 " max_open_files=12345\n"
3338 " max_background_flushes=301\n"
3339 " max_total_wal_size=1024 # keep_log_file_num=1000\n"
3341 "[CFOptions \"default\"]\n"
3342 " # if a section is blank, we will use the default\n";
3344 const std::string kTestFileName
= "test-rocksdb-options.ini";
3345 ASSERT_OK(fs_
->WriteToNewFile(kTestFileName
, options_file_content
));
3346 RocksDBOptionsParser parser
;
3348 parser
.Parse(kTestFileName
, fs_
.get(), false, 4096 /* readahead_size */));
3351 TEST_F(OptionsParserTest
, NoDefaultCFOptions
) {
3353 db_opt
.max_open_files
= 12345;
3354 db_opt
.max_background_flushes
= 301;
3355 db_opt
.max_total_wal_size
= 1024;
3356 ColumnFamilyOptions cf_opt
;
3358 std::string options_file_content
=
3359 "# This is a testing option string.\n"
3360 "# Currently we only support \"#\" styled comment.\n"
3363 " rocksdb_version=3.14.0\n"
3364 " options_file_version=1\n"
3366 " max_open_files=12345\n"
3367 " max_background_flushes=301\n"
3368 " max_total_wal_size=1024 # keep_log_file_num=1000\n"
3369 "[CFOptions \"something_else\"]\n"
3370 " # if a section is blank, we will use the default\n";
3372 const std::string kTestFileName
= "test-rocksdb-options.ini";
3373 ASSERT_OK(fs_
->WriteToNewFile(kTestFileName
, options_file_content
));
3374 RocksDBOptionsParser parser
;
3376 parser
.Parse(kTestFileName
, fs_
.get(), false, 4096 /* readahead_size */));
3379 TEST_F(OptionsParserTest
, DefaultCFOptionsMustBeTheFirst
) {
3381 db_opt
.max_open_files
= 12345;
3382 db_opt
.max_background_flushes
= 301;
3383 db_opt
.max_total_wal_size
= 1024;
3384 ColumnFamilyOptions cf_opt
;
3386 std::string options_file_content
=
3387 "# This is a testing option string.\n"
3388 "# Currently we only support \"#\" styled comment.\n"
3391 " rocksdb_version=3.14.0\n"
3392 " options_file_version=1\n"
3394 " max_open_files=12345\n"
3395 " max_background_flushes=301\n"
3396 " max_total_wal_size=1024 # keep_log_file_num=1000\n"
3397 "[CFOptions \"something_else\"]\n"
3398 " # if a section is blank, we will use the default\n"
3399 "[CFOptions \"default\"]\n"
3400 " # if a section is blank, we will use the default\n";
3402 const std::string kTestFileName
= "test-rocksdb-options.ini";
3403 ASSERT_OK(fs_
->WriteToNewFile(kTestFileName
, options_file_content
));
3404 RocksDBOptionsParser parser
;
3406 parser
.Parse(kTestFileName
, fs_
.get(), false, 4096 /* readahead_size */));
3409 TEST_F(OptionsParserTest
, DuplicateCFOptions
) {
3411 db_opt
.max_open_files
= 12345;
3412 db_opt
.max_background_flushes
= 301;
3413 db_opt
.max_total_wal_size
= 1024;
3414 ColumnFamilyOptions cf_opt
;
3416 std::string options_file_content
=
3417 "# This is a testing option string.\n"
3418 "# Currently we only support \"#\" styled comment.\n"
3421 " rocksdb_version=3.14.0\n"
3422 " options_file_version=1\n"
3424 " max_open_files=12345\n"
3425 " max_background_flushes=301\n"
3426 " max_total_wal_size=1024 # keep_log_file_num=1000\n"
3427 "[CFOptions \"default\"]\n"
3428 "[CFOptions \"something_else\"]\n"
3429 "[CFOptions \"something_else\"]\n";
3431 const std::string kTestFileName
= "test-rocksdb-options.ini";
3432 ASSERT_OK(fs_
->WriteToNewFile(kTestFileName
, options_file_content
));
3433 RocksDBOptionsParser parser
;
3435 parser
.Parse(kTestFileName
, fs_
.get(), false, 4096 /* readahead_size */));
3438 TEST_F(OptionsParserTest
, IgnoreUnknownOptions
) {
3439 for (int case_id
= 0; case_id
< 5; case_id
++) {
3441 db_opt
.max_open_files
= 12345;
3442 db_opt
.max_background_flushes
= 301;
3443 db_opt
.max_total_wal_size
= 1024;
3444 ColumnFamilyOptions cf_opt
;
3446 std::string version_string
;
3447 bool should_ignore
= true;
3450 should_ignore
= false;
3451 version_string
= std::to_string(ROCKSDB_MAJOR
) + "." +
3452 std::to_string(ROCKSDB_MINOR
) + ".0";
3453 } else if (case_id
== 1) {
3454 // higher minor version
3455 should_ignore
= true;
3456 version_string
= std::to_string(ROCKSDB_MAJOR
) + "." +
3457 std::to_string(ROCKSDB_MINOR
+ 1) + ".0";
3458 } else if (case_id
== 2) {
3459 // higher major version.
3460 should_ignore
= true;
3461 version_string
= std::to_string(ROCKSDB_MAJOR
+ 1) + ".0.0";
3462 } else if (case_id
== 3) {
3463 // lower minor version
3464 #if ROCKSDB_MINOR == 0
3467 version_string
= std::to_string(ROCKSDB_MAJOR
) + "." +
3468 std::to_string(ROCKSDB_MINOR
- 1) + ".0";
3469 should_ignore
= false;
3472 // lower major version
3473 should_ignore
= false;
3474 version_string
= std::to_string(ROCKSDB_MAJOR
- 1) + "." +
3475 std::to_string(ROCKSDB_MINOR
) + ".0";
3478 std::string options_file_content
=
3479 "# This is a testing option string.\n"
3480 "# Currently we only support \"#\" styled comment.\n"
3483 " rocksdb_version=" +
3486 " options_file_version=1\n"
3488 " max_open_files=12345\n"
3489 " max_background_flushes=301\n"
3490 " max_total_wal_size=1024 # keep_log_file_num=1000\n"
3491 " unknown_db_option1=321\n"
3492 " unknown_db_option2=false\n"
3493 "[CFOptions \"default\"]\n"
3494 " unknown_cf_option1=hello\n"
3495 "[CFOptions \"something_else\"]\n"
3496 " unknown_cf_option2=world\n"
3497 " # if a section is blank, we will use the default\n";
3499 const std::string kTestFileName
= "test-rocksdb-options.ini";
3500 auto s
= fs_
->FileExists(kTestFileName
, IOOptions(), nullptr);
3501 ASSERT_TRUE(s
.ok() || s
.IsNotFound());
3503 ASSERT_OK(fs_
->DeleteFile(kTestFileName
, IOOptions(), nullptr));
3505 ASSERT_OK(fs_
->WriteToNewFile(kTestFileName
, options_file_content
));
3506 RocksDBOptionsParser parser
;
3507 ASSERT_NOK(parser
.Parse(kTestFileName
, fs_
.get(), false,
3508 4096 /* readahead_size */));
3509 if (should_ignore
) {
3510 ASSERT_OK(parser
.Parse(kTestFileName
, fs_
.get(),
3511 true /* ignore_unknown_options */,
3512 4096 /* readahead_size */));
3514 ASSERT_NOK(parser
.Parse(kTestFileName
, fs_
.get(),
3515 true /* ignore_unknown_options */,
3516 4096 /* readahead_size */));
3521 TEST_F(OptionsParserTest
, ParseVersion
) {
3523 db_opt
.max_open_files
= 12345;
3524 db_opt
.max_background_flushes
= 301;
3525 db_opt
.max_total_wal_size
= 1024;
3526 ColumnFamilyOptions cf_opt
;
3528 std::string file_template
=
3529 "# This is a testing option string.\n"
3530 "# Currently we only support \"#\" styled comment.\n"
3533 " rocksdb_version=3.13.1\n"
3534 " options_file_version=%s\n"
3536 "[CFOptions \"default\"]\n";
3537 const int kLength
= 1000;
3538 char buffer
[kLength
];
3539 RocksDBOptionsParser parser
;
3541 const std::vector
<std::string
> invalid_versions
= {
3542 "a.b.c", "3.2.2b", "3.-12", "3. 1", // only digits and dots are allowed
3544 "1.2.3" // can only contains at most one dot.
3545 "0", // options_file_version must be at least one
3547 ".", ".1.2", // must have at least one digit before each dot
3548 "1.2.", "1.", "2.34."}; // must have at least one digit after each dot
3549 for (auto iv
: invalid_versions
) {
3550 snprintf(buffer
, kLength
- 1, file_template
.c_str(), iv
.c_str());
3553 ASSERT_OK(fs_
->WriteToNewFile(iv
, buffer
));
3554 ASSERT_NOK(parser
.Parse(iv
, fs_
.get(), false, 0 /* readahead_size */));
3557 const std::vector
<std::string
> valid_versions
= {
3558 "1.232", "100", "3.12", "1", "12.3 ", " 1.25 "};
3559 for (auto vv
: valid_versions
) {
3560 snprintf(buffer
, kLength
- 1, file_template
.c_str(), vv
.c_str());
3562 ASSERT_OK(fs_
->WriteToNewFile(vv
, buffer
));
3563 ASSERT_OK(parser
.Parse(vv
, fs_
.get(), false, 0 /* readahead_size */));
3567 void VerifyCFPointerTypedOptions(
3568 ColumnFamilyOptions
* base_cf_opt
, const ColumnFamilyOptions
* new_cf_opt
,
3569 const std::unordered_map
<std::string
, std::string
>* new_cf_opt_map
) {
3570 std::string name_buffer
;
3571 ConfigOptions config_options
;
3572 config_options
.input_strings_escaped
= false;
3573 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options
, *base_cf_opt
,
3574 *new_cf_opt
, new_cf_opt_map
));
3576 // change the name of merge operator back-and-forth
3578 auto* merge_operator
= base_cf_opt
->merge_operator
3579 ->CheckedCast
<test::ChanglingMergeOperator
>();
3580 if (merge_operator
!= nullptr) {
3581 name_buffer
= merge_operator
->Name();
3582 // change the name and expect non-ok status
3583 merge_operator
->SetName("some-other-name");
3584 ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
3585 config_options
, *base_cf_opt
, *new_cf_opt
, new_cf_opt_map
));
3586 // change the name back and expect ok status
3587 merge_operator
->SetName(name_buffer
);
3588 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
3589 config_options
, *base_cf_opt
, *new_cf_opt
, new_cf_opt_map
));
3593 // change the name of the compaction filter factory back-and-forth
3595 auto* compaction_filter_factory
=
3596 base_cf_opt
->compaction_filter_factory
3597 ->CheckedCast
<test::ChanglingCompactionFilterFactory
>();
3598 if (compaction_filter_factory
!= nullptr) {
3599 name_buffer
= compaction_filter_factory
->Name();
3600 // change the name and expect non-ok status
3601 compaction_filter_factory
->SetName("some-other-name");
3602 ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
3603 config_options
, *base_cf_opt
, *new_cf_opt
, new_cf_opt_map
));
3604 // change the name back and expect ok status
3605 compaction_filter_factory
->SetName(name_buffer
);
3606 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
3607 config_options
, *base_cf_opt
, *new_cf_opt
, new_cf_opt_map
));
3611 // test by setting compaction_filter to nullptr
3613 auto* tmp_compaction_filter
= base_cf_opt
->compaction_filter
;
3614 if (tmp_compaction_filter
!= nullptr) {
3615 base_cf_opt
->compaction_filter
= nullptr;
3616 // set compaction_filter to nullptr and expect non-ok status
3617 ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
3618 config_options
, *base_cf_opt
, *new_cf_opt
, new_cf_opt_map
));
3619 // set the value back and expect ok status
3620 base_cf_opt
->compaction_filter
= tmp_compaction_filter
;
3621 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
3622 config_options
, *base_cf_opt
, *new_cf_opt
, new_cf_opt_map
));
3626 // test by setting table_factory to nullptr
3628 auto tmp_table_factory
= base_cf_opt
->table_factory
;
3629 if (tmp_table_factory
!= nullptr) {
3630 base_cf_opt
->table_factory
.reset();
3631 // set table_factory to nullptr and expect non-ok status
3632 ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
3633 config_options
, *base_cf_opt
, *new_cf_opt
, new_cf_opt_map
));
3634 // set the value back and expect ok status
3635 base_cf_opt
->table_factory
= tmp_table_factory
;
3636 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
3637 config_options
, *base_cf_opt
, *new_cf_opt
, new_cf_opt_map
));
3641 // test by setting memtable_factory to nullptr
3643 auto tmp_memtable_factory
= base_cf_opt
->memtable_factory
;
3644 if (tmp_memtable_factory
!= nullptr) {
3645 base_cf_opt
->memtable_factory
.reset();
3646 // set memtable_factory to nullptr and expect non-ok status
3647 ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
3648 config_options
, *base_cf_opt
, *new_cf_opt
, new_cf_opt_map
));
3649 // set the value back and expect ok status
3650 base_cf_opt
->memtable_factory
= tmp_memtable_factory
;
3651 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
3652 config_options
, *base_cf_opt
, *new_cf_opt
, new_cf_opt_map
));
3657 TEST_F(OptionsParserTest
, Readahead
) {
3658 DBOptions base_db_opt
;
3659 std::vector
<ColumnFamilyOptions
> base_cf_opts
;
3660 base_cf_opts
.emplace_back();
3661 base_cf_opts
.emplace_back();
3663 std::string one_mb_string
= std::string(1024 * 1024, 'x');
3664 std::vector
<std::string
> cf_names
= {"default", one_mb_string
};
3665 const std::string kOptionsFileName
= "test-persisted-options.ini";
3667 ASSERT_OK(PersistRocksDBOptions(base_db_opt
, cf_names
, base_cf_opts
,
3668 kOptionsFileName
, fs_
.get()));
3670 uint64_t file_size
= 0;
3672 fs_
->GetFileSize(kOptionsFileName
, IOOptions(), &file_size
, nullptr));
3673 assert(file_size
> 0);
3675 RocksDBOptionsParser parser
;
3677 fs_
->num_seq_file_read_
= 0;
3678 size_t readahead_size
= 128 * 1024;
3680 ASSERT_OK(parser
.Parse(kOptionsFileName
, fs_
.get(), false, readahead_size
));
3681 ASSERT_EQ(fs_
->num_seq_file_read_
.load(),
3682 (file_size
- 1) / readahead_size
+ 1);
3684 fs_
->num_seq_file_read_
.store(0);
3685 readahead_size
= 1024 * 1024;
3686 ASSERT_OK(parser
.Parse(kOptionsFileName
, fs_
.get(), false, readahead_size
));
3687 ASSERT_EQ(fs_
->num_seq_file_read_
.load(),
3688 (file_size
- 1) / readahead_size
+ 1);
3690 // Tiny readahead. 8 KB is read each time.
3691 fs_
->num_seq_file_read_
.store(0);
3693 parser
.Parse(kOptionsFileName
, fs_
.get(), false, 1 /* readahead_size */));
3694 ASSERT_GE(fs_
->num_seq_file_read_
.load(), file_size
/ (8 * 1024));
3695 ASSERT_LT(fs_
->num_seq_file_read_
.load(), file_size
/ (8 * 1024) * 2);
3697 // Disable readahead means 512KB readahead.
3698 fs_
->num_seq_file_read_
.store(0);
3700 parser
.Parse(kOptionsFileName
, fs_
.get(), false, 0 /* readahead_size */));
3701 ASSERT_GE(fs_
->num_seq_file_read_
.load(), (file_size
- 1) / (512 * 1024) + 1);
3704 TEST_F(OptionsParserTest
, DumpAndParse
) {
3705 DBOptions base_db_opt
;
3706 std::vector
<ColumnFamilyOptions
> base_cf_opts
;
3707 std::vector
<std::string
> cf_names
= {"default", "cf1", "cf2", "cf3",
3709 "p\\i\\k\\a\\chu\\\\\\",
3710 "###rocksdb#1-testcf#2###"};
3711 const int num_cf
= static_cast<int>(cf_names
.size());
3713 test::RandomInitDBOptions(&base_db_opt
, &rnd
);
3714 base_db_opt
.db_log_dir
+= "/#odd #but #could #happen #path #/\\\\#OMG";
3716 BlockBasedTableOptions special_bbto
;
3717 special_bbto
.cache_index_and_filter_blocks
= true;
3718 special_bbto
.block_size
= 999999;
3720 for (int c
= 0; c
< num_cf
; ++c
) {
3721 ColumnFamilyOptions cf_opt
;
3722 Random
cf_rnd(0xFB + c
);
3723 test::RandomInitCFOptions(&cf_opt
, base_db_opt
, &cf_rnd
);
3725 cf_opt
.prefix_extractor
.reset(test::RandomSliceTransform(&rnd
, c
));
3728 cf_opt
.table_factory
.reset(test::RandomTableFactory(&rnd
, c
));
3729 } else if (c
== 4) {
3730 cf_opt
.table_factory
.reset(NewBlockBasedTableFactory(special_bbto
));
3731 } else if (c
== 5) {
3732 // A table factory that doesn't support deserialization should be
3734 cf_opt
.table_factory
.reset(new UnregisteredTableFactory());
3736 base_cf_opts
.emplace_back(cf_opt
);
3739 const std::string kOptionsFileName
= "test-persisted-options.ini";
3740 // Use default for escaped(true), unknown(false) and check (exact)
3741 ConfigOptions config_options
;
3742 ASSERT_OK(PersistRocksDBOptions(base_db_opt
, cf_names
, base_cf_opts
,
3743 kOptionsFileName
, fs_
.get()));
3745 RocksDBOptionsParser parser
;
3746 ASSERT_OK(parser
.Parse(config_options
, kOptionsFileName
, fs_
.get()));
3748 // Make sure block-based table factory options was deserialized correctly
3749 std::shared_ptr
<TableFactory
> ttf
= (*parser
.cf_opts())[4].table_factory
;
3750 ASSERT_EQ(TableFactory::kBlockBasedTableName(), std::string(ttf
->Name()));
3751 const auto parsed_bbto
= ttf
->GetOptions
<BlockBasedTableOptions
>();
3752 ASSERT_NE(parsed_bbto
, nullptr);
3753 ASSERT_EQ(special_bbto
.block_size
, parsed_bbto
->block_size
);
3754 ASSERT_EQ(special_bbto
.cache_index_and_filter_blocks
,
3755 parsed_bbto
->cache_index_and_filter_blocks
);
3757 ASSERT_OK(RocksDBOptionsParser::VerifyRocksDBOptionsFromFile(
3758 config_options
, base_db_opt
, cf_names
, base_cf_opts
, kOptionsFileName
,
3761 ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(
3762 config_options
, *parser
.db_opt(), base_db_opt
));
3763 for (int c
= 0; c
< num_cf
; ++c
) {
3764 const auto* cf_opt
= parser
.GetCFOptions(cf_names
[c
]);
3765 ASSERT_NE(cf_opt
, nullptr);
3766 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
3767 config_options
, base_cf_opts
[c
], *cf_opt
,
3768 &(parser
.cf_opt_maps()->at(c
))));
3771 // Further verify pointer-typed options
3772 for (int c
= 0; c
< num_cf
; ++c
) {
3773 const auto* cf_opt
= parser
.GetCFOptions(cf_names
[c
]);
3774 ASSERT_NE(cf_opt
, nullptr);
3775 VerifyCFPointerTypedOptions(&base_cf_opts
[c
], cf_opt
,
3776 &(parser
.cf_opt_maps()->at(c
)));
3779 ASSERT_EQ(parser
.GetCFOptions("does not exist"), nullptr);
3781 base_db_opt
.max_open_files
++;
3782 ASSERT_NOK(RocksDBOptionsParser::VerifyRocksDBOptionsFromFile(
3783 config_options
, base_db_opt
, cf_names
, base_cf_opts
, kOptionsFileName
,
3786 for (int c
= 0; c
< num_cf
; ++c
) {
3787 if (base_cf_opts
[c
].compaction_filter
) {
3788 delete base_cf_opts
[c
].compaction_filter
;
3793 TEST_F(OptionsParserTest
, DifferentDefault
) {
3794 const std::string kOptionsFileName
= "test-persisted-options.ini";
3796 ColumnFamilyOptions cf_level_opts
;
3797 ASSERT_EQ(CompactionPri::kMinOverlappingRatio
, cf_level_opts
.compaction_pri
);
3798 cf_level_opts
.OptimizeLevelStyleCompaction();
3800 ColumnFamilyOptions cf_univ_opts
;
3801 cf_univ_opts
.OptimizeUniversalStyleCompaction();
3803 ASSERT_OK(PersistRocksDBOptions(DBOptions(), {"default", "universal"},
3804 {cf_level_opts
, cf_univ_opts
},
3805 kOptionsFileName
, fs_
.get()));
3807 RocksDBOptionsParser parser
;
3808 ASSERT_OK(parser
.Parse(kOptionsFileName
, fs_
.get(), false,
3809 4096 /* readahead_size */));
3812 Options old_default_opts
;
3813 old_default_opts
.OldDefaults();
3814 ASSERT_EQ(10 * 1048576, old_default_opts
.max_bytes_for_level_base
);
3815 ASSERT_EQ(5000, old_default_opts
.max_open_files
);
3816 ASSERT_EQ(2 * 1024U * 1024U, old_default_opts
.delayed_write_rate
);
3817 ASSERT_EQ(WALRecoveryMode::kTolerateCorruptedTailRecords
,
3818 old_default_opts
.wal_recovery_mode
);
3821 Options old_default_opts
;
3822 old_default_opts
.OldDefaults(4, 6);
3823 ASSERT_EQ(10 * 1048576, old_default_opts
.max_bytes_for_level_base
);
3824 ASSERT_EQ(5000, old_default_opts
.max_open_files
);
3827 Options old_default_opts
;
3828 old_default_opts
.OldDefaults(4, 7);
3829 ASSERT_NE(10 * 1048576, old_default_opts
.max_bytes_for_level_base
);
3830 ASSERT_NE(4, old_default_opts
.table_cache_numshardbits
);
3831 ASSERT_EQ(5000, old_default_opts
.max_open_files
);
3832 ASSERT_EQ(2 * 1024U * 1024U, old_default_opts
.delayed_write_rate
);
3835 ColumnFamilyOptions old_default_cf_opts
;
3836 old_default_cf_opts
.OldDefaults();
3837 ASSERT_EQ(2 * 1048576, old_default_cf_opts
.target_file_size_base
);
3838 ASSERT_EQ(4 << 20, old_default_cf_opts
.write_buffer_size
);
3839 ASSERT_EQ(2 * 1048576, old_default_cf_opts
.target_file_size_base
);
3840 ASSERT_EQ(0, old_default_cf_opts
.soft_pending_compaction_bytes_limit
);
3841 ASSERT_EQ(0, old_default_cf_opts
.hard_pending_compaction_bytes_limit
);
3842 ASSERT_EQ(CompactionPri::kByCompensatedSize
,
3843 old_default_cf_opts
.compaction_pri
);
3846 ColumnFamilyOptions old_default_cf_opts
;
3847 old_default_cf_opts
.OldDefaults(4, 6);
3848 ASSERT_EQ(2 * 1048576, old_default_cf_opts
.target_file_size_base
);
3849 ASSERT_EQ(CompactionPri::kByCompensatedSize
,
3850 old_default_cf_opts
.compaction_pri
);
3853 ColumnFamilyOptions old_default_cf_opts
;
3854 old_default_cf_opts
.OldDefaults(4, 7);
3855 ASSERT_NE(2 * 1048576, old_default_cf_opts
.target_file_size_base
);
3856 ASSERT_EQ(CompactionPri::kByCompensatedSize
,
3857 old_default_cf_opts
.compaction_pri
);
3860 Options old_default_opts
;
3861 old_default_opts
.OldDefaults(5, 1);
3862 ASSERT_EQ(2 * 1024U * 1024U, old_default_opts
.delayed_write_rate
);
3865 Options old_default_opts
;
3866 old_default_opts
.OldDefaults(5, 2);
3867 ASSERT_EQ(16 * 1024U * 1024U, old_default_opts
.delayed_write_rate
);
3868 ASSERT_TRUE(old_default_opts
.compaction_pri
==
3869 CompactionPri::kByCompensatedSize
);
3872 Options old_default_opts
;
3873 old_default_opts
.OldDefaults(5, 18);
3874 ASSERT_TRUE(old_default_opts
.compaction_pri
==
3875 CompactionPri::kByCompensatedSize
);
3879 small_opts
.OptimizeForSmallDb();
3880 ASSERT_EQ(2 << 20, small_opts
.write_buffer_size
);
3881 ASSERT_EQ(5000, small_opts
.max_open_files
);
3884 class OptionsSanityCheckTest
: public OptionsParserTest
,
3885 public ::testing::WithParamInterface
<bool> {
3887 ConfigOptions config_options_
;
3890 OptionsSanityCheckTest() {
3891 config_options_
.ignore_unknown_options
= false;
3892 config_options_
.ignore_unsupported_options
= GetParam();
3893 config_options_
.input_strings_escaped
= true;
3897 Status
SanityCheckOptions(const DBOptions
& db_opts
,
3898 const ColumnFamilyOptions
& cf_opts
,
3899 ConfigOptions::SanityLevel level
) {
3900 config_options_
.sanity_level
= level
;
3901 return RocksDBOptionsParser::VerifyRocksDBOptionsFromFile(
3902 config_options_
, db_opts
, {"default"}, {cf_opts
}, kOptionsFileName
,
3906 Status
SanityCheckCFOptions(const ColumnFamilyOptions
& cf_opts
,
3907 ConfigOptions::SanityLevel level
) {
3908 return SanityCheckOptions(DBOptions(), cf_opts
, level
);
3911 void SanityCheckCFOptions(const ColumnFamilyOptions
& opts
, bool exact
) {
3912 ASSERT_OK(SanityCheckCFOptions(
3913 opts
, ConfigOptions::kSanityLevelLooselyCompatible
));
3914 ASSERT_OK(SanityCheckCFOptions(opts
, ConfigOptions::kSanityLevelNone
));
3917 SanityCheckCFOptions(opts
, ConfigOptions::kSanityLevelExactMatch
));
3920 SanityCheckCFOptions(opts
, ConfigOptions::kSanityLevelExactMatch
));
3924 Status
SanityCheckDBOptions(const DBOptions
& db_opts
,
3925 ConfigOptions::SanityLevel level
) {
3926 return SanityCheckOptions(db_opts
, ColumnFamilyOptions(), level
);
3929 void SanityCheckDBOptions(const DBOptions
& opts
, bool exact
) {
3930 ASSERT_OK(SanityCheckDBOptions(
3931 opts
, ConfigOptions::kSanityLevelLooselyCompatible
));
3932 ASSERT_OK(SanityCheckDBOptions(opts
, ConfigOptions::kSanityLevelNone
));
3935 SanityCheckDBOptions(opts
, ConfigOptions::kSanityLevelExactMatch
));
3938 SanityCheckDBOptions(opts
, ConfigOptions::kSanityLevelExactMatch
));
3942 Status
PersistOptions(const DBOptions
& db_opts
,
3943 const ColumnFamilyOptions
& cf_opts
) {
3944 Status s
= fs_
->DeleteFile(kOptionsFileName
, IOOptions(), nullptr);
3948 return PersistRocksDBOptions(db_opts
, {"default"}, {cf_opts
},
3949 kOptionsFileName
, fs_
.get());
3952 Status
PersistCFOptions(const ColumnFamilyOptions
& cf_opts
) {
3953 return PersistOptions(DBOptions(), cf_opts
);
3956 Status
PersistDBOptions(const DBOptions
& db_opts
) {
3957 return PersistOptions(db_opts
, ColumnFamilyOptions());
3960 const std::string kOptionsFileName
= "OPTIONS";
3963 TEST_P(OptionsSanityCheckTest
, CFOptionsSanityCheck
) {
3964 ColumnFamilyOptions opts
;
3967 // default ColumnFamilyOptions
3969 ASSERT_OK(PersistCFOptions(opts
));
3971 SanityCheckCFOptions(opts
, ConfigOptions::kSanityLevelExactMatch
));
3976 // Okay to change prefix_extractor form nullptr to non-nullptr
3977 ASSERT_EQ(opts
.prefix_extractor
.get(), nullptr);
3978 opts
.prefix_extractor
.reset(NewCappedPrefixTransform(10));
3979 ASSERT_OK(SanityCheckCFOptions(
3980 opts
, ConfigOptions::kSanityLevelLooselyCompatible
));
3981 ASSERT_OK(SanityCheckCFOptions(opts
, ConfigOptions::kSanityLevelNone
));
3983 // persist the change
3984 ASSERT_OK(PersistCFOptions(opts
));
3986 SanityCheckCFOptions(opts
, ConfigOptions::kSanityLevelExactMatch
));
3988 // use same prefix extractor but with different parameter
3989 opts
.prefix_extractor
.reset(NewCappedPrefixTransform(15));
3990 // expect pass only in
3991 // ConfigOptions::kSanityLevelLooselyCompatible
3993 SanityCheckCFOptions(opts
, ConfigOptions::kSanityLevelExactMatch
));
3994 ASSERT_OK(SanityCheckCFOptions(
3995 opts
, ConfigOptions::kSanityLevelLooselyCompatible
));
3996 ASSERT_OK(SanityCheckCFOptions(opts
, ConfigOptions::kSanityLevelNone
));
3998 // repeat the test with FixedPrefixTransform
3999 opts
.prefix_extractor
.reset(NewFixedPrefixTransform(10));
4001 SanityCheckCFOptions(opts
, ConfigOptions::kSanityLevelExactMatch
));
4002 ASSERT_OK(SanityCheckCFOptions(
4003 opts
, ConfigOptions::kSanityLevelLooselyCompatible
));
4004 ASSERT_OK(SanityCheckCFOptions(opts
, ConfigOptions::kSanityLevelNone
));
4006 // persist the change of prefix_extractor
4007 ASSERT_OK(PersistCFOptions(opts
));
4009 SanityCheckCFOptions(opts
, ConfigOptions::kSanityLevelExactMatch
));
4011 // use same prefix extractor but with different parameter
4012 opts
.prefix_extractor
.reset(NewFixedPrefixTransform(15));
4013 // expect pass only in
4014 // ConfigOptions::kSanityLevelLooselyCompatible
4015 SanityCheckCFOptions(opts
, false);
4017 // Change prefix extractor from non-nullptr to nullptr
4018 opts
.prefix_extractor
.reset();
4019 // expect pass as it's safe to change prefix_extractor
4020 // from non-null to null
4021 ASSERT_OK(SanityCheckCFOptions(
4022 opts
, ConfigOptions::kSanityLevelLooselyCompatible
));
4023 ASSERT_OK(SanityCheckCFOptions(opts
, ConfigOptions::kSanityLevelNone
));
4025 // persist the change
4026 ASSERT_OK(PersistCFOptions(opts
));
4027 ASSERT_OK(SanityCheckCFOptions(opts
, ConfigOptions::kSanityLevelExactMatch
));
4031 for (int tb
= 0; tb
<= 2; ++tb
) {
4032 // change the table factory
4033 opts
.table_factory
.reset(test::RandomTableFactory(&rnd
, tb
));
4034 ASSERT_NOK(SanityCheckCFOptions(
4035 opts
, ConfigOptions::kSanityLevelLooselyCompatible
));
4036 ASSERT_OK(SanityCheckCFOptions(opts
, ConfigOptions::kSanityLevelNone
));
4038 // persist the change
4039 ASSERT_OK(PersistCFOptions(opts
));
4041 SanityCheckCFOptions(opts
, ConfigOptions::kSanityLevelExactMatch
));
4047 // Test when going from nullptr -> merge operator
4048 opts
.merge_operator
.reset(test::RandomMergeOperator(&rnd
));
4049 ASSERT_OK(SanityCheckCFOptions(
4050 opts
, ConfigOptions::kSanityLevelLooselyCompatible
));
4051 ASSERT_OK(SanityCheckCFOptions(opts
, ConfigOptions::kSanityLevelNone
));
4053 // persist the change
4054 ASSERT_OK(PersistCFOptions(opts
));
4055 SanityCheckCFOptions(opts
, config_options_
.ignore_unsupported_options
);
4057 for (int test
= 0; test
< 5; ++test
) {
4058 // change the merge operator
4059 opts
.merge_operator
.reset(test::RandomMergeOperator(&rnd
));
4060 ASSERT_NOK(SanityCheckCFOptions(
4061 opts
, ConfigOptions::kSanityLevelLooselyCompatible
));
4062 ASSERT_OK(SanityCheckCFOptions(opts
, ConfigOptions::kSanityLevelNone
));
4064 // persist the change
4065 ASSERT_OK(PersistCFOptions(opts
));
4066 SanityCheckCFOptions(opts
, config_options_
.ignore_unsupported_options
);
4069 // Test when going from merge operator -> nullptr
4070 opts
.merge_operator
= nullptr;
4071 ASSERT_NOK(SanityCheckCFOptions(
4072 opts
, ConfigOptions::kSanityLevelLooselyCompatible
));
4073 ASSERT_OK(SanityCheckCFOptions(opts
, ConfigOptions::kSanityLevelNone
));
4075 // persist the change
4076 ASSERT_OK(PersistCFOptions(opts
));
4077 SanityCheckCFOptions(opts
, true);
4080 // compaction_filter
4082 for (int test
= 0; test
< 5; ++test
) {
4083 // change the compaction filter
4084 opts
.compaction_filter
= test::RandomCompactionFilter(&rnd
);
4085 SanityCheckCFOptions(opts
, false);
4087 // persist the change
4088 ASSERT_OK(PersistCFOptions(opts
));
4089 SanityCheckCFOptions(opts
, config_options_
.ignore_unsupported_options
);
4090 delete opts
.compaction_filter
;
4091 opts
.compaction_filter
= nullptr;
4095 // compaction_filter_factory
4097 for (int test
= 0; test
< 5; ++test
) {
4098 // change the compaction filter factory
4099 opts
.compaction_filter_factory
.reset(
4100 test::RandomCompactionFilterFactory(&rnd
));
4101 SanityCheckCFOptions(opts
, false);
4103 // persist the change
4104 ASSERT_OK(PersistCFOptions(opts
));
4105 SanityCheckCFOptions(opts
, config_options_
.ignore_unsupported_options
);
4110 TEST_P(OptionsSanityCheckTest
, DBOptionsSanityCheck
) {
4114 // default DBOptions
4116 ASSERT_OK(PersistDBOptions(opts
));
4118 SanityCheckDBOptions(opts
, ConfigOptions::kSanityLevelExactMatch
));
4121 // File checksum generator
4123 class MockFileChecksumGenFactory
: public FileChecksumGenFactory
{
4125 static const char* kClassName() { return "Mock"; }
4126 const char* Name() const override
{ return kClassName(); }
4127 std::unique_ptr
<FileChecksumGenerator
> CreateFileChecksumGenerator(
4128 const FileChecksumGenContext
& /*context*/) override
{
4133 // Okay to change file_checksum_gen_factory form nullptr to non-nullptr
4134 ASSERT_EQ(opts
.file_checksum_gen_factory
.get(), nullptr);
4135 opts
.file_checksum_gen_factory
.reset(new MockFileChecksumGenFactory());
4137 // persist the change
4138 ASSERT_OK(PersistDBOptions(opts
));
4139 SanityCheckDBOptions(opts
, config_options_
.ignore_unsupported_options
);
4141 // Change file_checksum_gen_factory from non-nullptr to nullptr
4142 opts
.file_checksum_gen_factory
.reset();
4143 // expect pass as it's safe to change file_checksum_gen_factory
4144 // from non-null to null
4145 SanityCheckDBOptions(opts
, false);
4147 // persist the change
4148 ASSERT_OK(PersistDBOptions(opts
));
4149 ASSERT_OK(SanityCheckDBOptions(opts
, ConfigOptions::kSanityLevelExactMatch
));
4153 bool IsEscapedString(const std::string
& str
) {
4154 for (size_t i
= 0; i
< str
.size(); ++i
) {
4155 if (str
[i
] == '\\') {
4156 // since we already handle those two consecutive '\'s in
4157 // the next if-then branch, any '\' appear at the end
4158 // of an escaped string in such case is not valid.
4159 if (i
== str
.size() - 1) {
4162 if (str
[i
+ 1] == '\\') {
4163 // if there're two consecutive '\'s, skip the second one.
4167 switch (str
[i
+ 1]) {
4173 // if true, '\' together with str[i + 1] is not a valid escape.
4174 if (UnescapeChar(str
[i
+ 1]) == str
[i
+ 1]) {
4178 } else if (isSpecialChar(str
[i
]) && (i
== 0 || str
[i
- 1] != '\\')) {
4186 TEST_F(OptionsParserTest
, IntegerParsing
) {
4187 ASSERT_EQ(ParseUint64("18446744073709551615"), 18446744073709551615U);
4188 ASSERT_EQ(ParseUint32("4294967295"), 4294967295U);
4189 ASSERT_EQ(ParseSizeT("18446744073709551615"), 18446744073709551615U);
4190 ASSERT_EQ(ParseInt64("9223372036854775807"), 9223372036854775807);
4191 ASSERT_EQ(ParseInt64("-9223372036854775808"),
4192 std::numeric_limits
<int64_t>::min());
4193 ASSERT_EQ(ParseInt32("2147483647"), 2147483647);
4194 ASSERT_EQ(ParseInt32("-2147483648"), std::numeric_limits
<int32_t>::min());
4195 ASSERT_EQ(ParseInt("-32767"), -32767);
4196 ASSERT_EQ(ParseDouble("-1.234567"), -1.234567);
4199 TEST_F(OptionsParserTest
, EscapeOptionString
) {
4200 ASSERT_EQ(UnescapeOptionString(
4201 "This is a test string with \\# \\: and \\\\ escape chars."),
4202 "This is a test string with # : and \\ escape chars.");
4205 EscapeOptionString("This is a test string with # : and \\ escape chars."),
4206 "This is a test string with \\# \\: and \\\\ escape chars.");
4208 std::string readible_chars
=
4209 "A String like this \"1234567890-=_)(*&^%$#@!ertyuiop[]{POIU"
4210 "YTREWQasdfghjkl;':LKJHGFDSAzxcvbnm,.?>"
4211 "<MNBVCXZ\\\" should be okay to \\#\\\\\\:\\#\\#\\#\\ "
4212 "be serialized and deserialized";
4214 std::string escaped_string
= EscapeOptionString(readible_chars
);
4215 ASSERT_TRUE(IsEscapedString(escaped_string
));
4216 // This two transformations should be canceled and should output
4217 // the original input.
4218 ASSERT_EQ(UnescapeOptionString(escaped_string
), readible_chars
);
4220 std::string all_chars
;
4221 for (unsigned char c
= 0;; ++c
) {
4227 escaped_string
= EscapeOptionString(all_chars
);
4228 ASSERT_TRUE(IsEscapedString(escaped_string
));
4229 ASSERT_EQ(UnescapeOptionString(escaped_string
), all_chars
);
4231 ASSERT_EQ(RocksDBOptionsParser::TrimAndRemoveComment(
4232 " A simple statement with a comment. # like this :)"),
4233 "A simple statement with a comment.");
4235 ASSERT_EQ(RocksDBOptionsParser::TrimAndRemoveComment(
4236 "Escape \\# and # comment together ."),
4240 static void TestAndCompareOption(const ConfigOptions
& config_options
,
4241 const OptionTypeInfo
& opt_info
,
4242 const std::string
& opt_name
, void* base_ptr
,
4243 void* comp_ptr
, bool strip
= false) {
4244 std::string result
, mismatch
;
4245 ASSERT_OK(opt_info
.Serialize(config_options
, opt_name
, base_ptr
, &result
));
4247 ASSERT_EQ(result
.at(0), '{');
4248 ASSERT_EQ(result
.at(result
.size() - 1), '}');
4249 result
= result
.substr(1, result
.size() - 2);
4251 ASSERT_OK(opt_info
.Parse(config_options
, opt_name
, result
, comp_ptr
));
4252 ASSERT_TRUE(opt_info
.AreEqual(config_options
, opt_name
, base_ptr
, comp_ptr
,
4256 static void TestParseAndCompareOption(const ConfigOptions
& config_options
,
4257 const OptionTypeInfo
& opt_info
,
4258 const std::string
& opt_name
,
4259 const std::string
& opt_value
,
4260 void* base_ptr
, void* comp_ptr
,
4261 bool strip
= false) {
4262 ASSERT_OK(opt_info
.Parse(config_options
, opt_name
, opt_value
, base_ptr
));
4263 TestAndCompareOption(config_options
, opt_info
, opt_name
, base_ptr
, comp_ptr
,
4267 template <typename T
>
4268 void TestOptInfo(const ConfigOptions
& config_options
, OptionType opt_type
,
4271 OptionTypeInfo
opt_info(0, opt_type
);
4272 ASSERT_FALSE(opt_info
.AreEqual(config_options
, "base", base
, comp
, &result
));
4273 ASSERT_EQ(result
, "base");
4274 ASSERT_NE(*base
, *comp
);
4275 TestAndCompareOption(config_options
, opt_info
, "base", base
, comp
);
4276 ASSERT_EQ(*base
, *comp
);
4279 class OptionTypeInfoTest
: public testing::Test
{};
4281 TEST_F(OptionTypeInfoTest
, BasicTypes
) {
4282 ConfigOptions config_options
;
4284 bool a
= true, b
= false;
4285 TestOptInfo(config_options
, OptionType::kBoolean
, &a
, &b
);
4288 int a
= 100, b
= 200;
4289 TestOptInfo(config_options
, OptionType::kInt
, &a
, &b
);
4292 int32_t a
= 100, b
= 200;
4293 TestOptInfo(config_options
, OptionType::kInt32T
, &a
, &b
);
4296 int64_t a
= 100, b
= 200;
4297 TestOptInfo(config_options
, OptionType::kInt64T
, &a
, &b
);
4300 unsigned int a
= 100, b
= 200;
4301 TestOptInfo(config_options
, OptionType::kUInt
, &a
, &b
);
4304 uint32_t a
= 100, b
= 200;
4305 TestOptInfo(config_options
, OptionType::kUInt32T
, &a
, &b
);
4308 uint64_t a
= 100, b
= 200;
4309 TestOptInfo(config_options
, OptionType::kUInt64T
, &a
, &b
);
4312 size_t a
= 100, b
= 200;
4313 TestOptInfo(config_options
, OptionType::kSizeT
, &a
, &b
);
4316 std::string a
= "100", b
= "200";
4317 TestOptInfo(config_options
, OptionType::kString
, &a
, &b
);
4320 double a
= 1.0, b
= 2.0;
4321 TestOptInfo(config_options
, OptionType::kDouble
, &a
, &b
);
4325 TEST_F(OptionTypeInfoTest
, TestInvalidArgs
) {
4326 ConfigOptions config_options
;
4337 ASSERT_NOK(OptionTypeInfo(0, OptionType::kBoolean
)
4338 .Parse(config_options
, "b", "x", &b
));
4340 OptionTypeInfo(0, OptionType::kInt
).Parse(config_options
, "b", "x", &i
));
4341 ASSERT_NOK(OptionTypeInfo(0, OptionType::kInt32T
)
4342 .Parse(config_options
, "b", "x", &i32
));
4343 ASSERT_NOK(OptionTypeInfo(0, OptionType::kInt64T
)
4344 .Parse(config_options
, "b", "x", &i64
));
4346 OptionTypeInfo(0, OptionType::kUInt
).Parse(config_options
, "b", "x", &u
));
4347 ASSERT_NOK(OptionTypeInfo(0, OptionType::kUInt32T
)
4348 .Parse(config_options
, "b", "x", &u32
));
4349 ASSERT_NOK(OptionTypeInfo(0, OptionType::kUInt64T
)
4350 .Parse(config_options
, "b", "x", &u64
));
4351 ASSERT_NOK(OptionTypeInfo(0, OptionType::kSizeT
)
4352 .Parse(config_options
, "b", "x", &sz
));
4353 ASSERT_NOK(OptionTypeInfo(0, OptionType::kDouble
)
4354 .Parse(config_options
, "b", "x", &d
));
4356 // Don't know how to convert Unknowns to anything else
4357 ASSERT_NOK(OptionTypeInfo(0, OptionType::kUnknown
)
4358 .Parse(config_options
, "b", "x", &d
));
4360 // Verify that if the parse function throws an exception, it is also trapped
4361 OptionTypeInfo
func_info(0, OptionType::kUnknown
,
4362 OptionVerificationType::kNormal
,
4363 OptionTypeFlags::kNone
,
4364 [](const ConfigOptions
&, const std::string
&,
4365 const std::string
& value
, void* addr
) {
4366 auto ptr
= static_cast<int*>(addr
);
4367 *ptr
= ParseInt(value
);
4368 return Status::OK();
4370 ASSERT_OK(func_info
.Parse(config_options
, "b", "1", &i
));
4371 ASSERT_NOK(func_info
.Parse(config_options
, "b", "x", &i
));
4374 TEST_F(OptionTypeInfoTest
, TestParseFunc
) {
4375 OptionTypeInfo
opt_info(0, OptionType::kUnknown
,
4376 OptionVerificationType::kNormal
,
4377 OptionTypeFlags::kNone
);
4378 opt_info
.SetParseFunc([](const ConfigOptions
& /*opts*/,
4379 const std::string
& name
, const std::string
& value
,
4381 auto ptr
= static_cast<std::string
*>(addr
);
4382 if (name
== "Oops") {
4383 return Status::InvalidArgument(value
);
4385 *ptr
= value
+ " " + name
;
4386 return Status::OK();
4389 ConfigOptions config_options
;
4391 ASSERT_OK(opt_info
.Parse(config_options
, "World", "Hello", &base
));
4392 ASSERT_EQ(base
, "Hello World");
4393 ASSERT_NOK(opt_info
.Parse(config_options
, "Oops", "Hello", &base
));
4396 TEST_F(OptionTypeInfoTest
, TestSerializeFunc
) {
4397 OptionTypeInfo
opt_info(0, OptionType::kString
,
4398 OptionVerificationType::kNormal
,
4399 OptionTypeFlags::kNone
);
4400 opt_info
.SetSerializeFunc([](const ConfigOptions
& /*opts*/,
4401 const std::string
& name
, const void* /*addr*/,
4402 std::string
* value
) {
4403 if (name
== "Oops") {
4404 return Status::InvalidArgument(name
);
4407 return Status::OK();
4410 ConfigOptions config_options
;
4413 ASSERT_OK(opt_info
.Serialize(config_options
, "Hello", &base
, &value
));
4414 ASSERT_EQ(value
, "Hello");
4415 ASSERT_NOK(opt_info
.Serialize(config_options
, "Oops", &base
, &value
));
4418 TEST_F(OptionTypeInfoTest
, TestEqualsFunc
) {
4419 OptionTypeInfo
opt_info(0, OptionType::kInt
, OptionVerificationType::kNormal
,
4420 OptionTypeFlags::kNone
);
4421 opt_info
.SetEqualsFunc([](const ConfigOptions
& /*opts*/,
4422 const std::string
& name
, const void* addr1
,
4423 const void* addr2
, std::string
* mismatch
) {
4424 auto i1
= *(static_cast<const int*>(addr1
));
4425 auto i2
= *(static_cast<const int*>(addr2
));
4428 } else if (name
== "GT") {
4430 } else if (name
== "EQ") {
4433 *mismatch
= name
+ "???";
4438 ConfigOptions config_options
;
4441 std::string mismatch
;
4442 ASSERT_TRUE(opt_info
.AreEqual(config_options
, "LT", &int1
, &int2
, &mismatch
));
4443 ASSERT_EQ(mismatch
, "");
4445 opt_info
.AreEqual(config_options
, "GT", &int1
, &int2
, &mismatch
));
4446 ASSERT_EQ(mismatch
, "GT");
4448 opt_info
.AreEqual(config_options
, "NO", &int1
, &int2
, &mismatch
));
4449 ASSERT_EQ(mismatch
, "NO???");
4452 TEST_F(OptionTypeInfoTest
, TestPrepareFunc
) {
4453 OptionTypeInfo
opt_info(0, OptionType::kInt
, OptionVerificationType::kNormal
,
4454 OptionTypeFlags::kNone
);
4455 opt_info
.SetPrepareFunc(
4456 [](const ConfigOptions
& /*opts*/, const std::string
& name
, void* addr
) {
4457 auto i1
= static_cast<int*>(addr
);
4460 } else if (name
== "/2") {
4463 return Status::InvalidArgument("Bad Argument", name
);
4465 return Status::OK();
4467 ConfigOptions config_options
;
4469 ASSERT_OK(opt_info
.Prepare(config_options
, "x2", &int1
));
4470 ASSERT_EQ(int1
, 200);
4471 ASSERT_OK(opt_info
.Prepare(config_options
, "/2", &int1
));
4472 ASSERT_EQ(int1
, 100);
4473 ASSERT_NOK(opt_info
.Prepare(config_options
, "??", &int1
));
4474 ASSERT_EQ(int1
, 100);
4476 TEST_F(OptionTypeInfoTest
, TestValidateFunc
) {
4477 OptionTypeInfo
opt_info(0, OptionType::kSizeT
,
4478 OptionVerificationType::kNormal
,
4479 OptionTypeFlags::kNone
);
4480 opt_info
.SetValidateFunc([](const DBOptions
& db_opts
,
4481 const ColumnFamilyOptions
& cf_opts
,
4482 const std::string
& name
, const void* addr
) {
4483 const auto sz
= static_cast<const size_t*>(addr
);
4484 bool is_valid
= false;
4485 if (name
== "keep_log_file_num") {
4486 is_valid
= (*sz
== db_opts
.keep_log_file_num
);
4487 } else if (name
== "write_buffer_size") {
4488 is_valid
= (*sz
== cf_opts
.write_buffer_size
);
4491 return Status::OK();
4493 return Status::InvalidArgument("Mismatched value", name
);
4496 ConfigOptions config_options
;
4497 DBOptions db_options
;
4498 ColumnFamilyOptions cf_options
;
4500 ASSERT_OK(opt_info
.Validate(db_options
, cf_options
, "keep_log_file_num",
4501 &db_options
.keep_log_file_num
));
4502 ASSERT_OK(opt_info
.Validate(db_options
, cf_options
, "write_buffer_size",
4503 &cf_options
.write_buffer_size
));
4504 ASSERT_NOK(opt_info
.Validate(db_options
, cf_options
, "keep_log_file_num",
4505 &cf_options
.write_buffer_size
));
4506 ASSERT_NOK(opt_info
.Validate(db_options
, cf_options
, "write_buffer_size",
4507 &db_options
.keep_log_file_num
));
4510 TEST_F(OptionTypeInfoTest
, TestOptionFlags
) {
4511 OptionTypeInfo
opt_none(0, OptionType::kString
,
4512 OptionVerificationType::kNormal
,
4513 OptionTypeFlags::kDontSerialize
);
4514 OptionTypeInfo
opt_never(0, OptionType::kString
,
4515 OptionVerificationType::kNormal
,
4516 OptionTypeFlags::kCompareNever
);
4517 OptionTypeInfo
opt_alias(0, OptionType::kString
,
4518 OptionVerificationType::kAlias
,
4519 OptionTypeFlags::kNone
);
4520 OptionTypeInfo
opt_deprecated(0, OptionType::kString
,
4521 OptionVerificationType::kDeprecated
,
4522 OptionTypeFlags::kNone
);
4523 ConfigOptions config_options
;
4524 std::string opts_str
;
4525 std::string base
= "base";
4526 std::string comp
= "comp";
4528 // If marked string none, the serialization returns not supported
4529 ASSERT_NOK(opt_none
.Serialize(config_options
, "None", &base
, &opts_str
));
4530 // If marked never compare, they match even when they do not
4531 ASSERT_TRUE(opt_never
.AreEqual(config_options
, "Never", &base
, &comp
, &base
));
4532 ASSERT_FALSE(opt_none
.AreEqual(config_options
, "Never", &base
, &comp
, &base
));
4534 // An alias can change the value via parse, but does nothing on serialize on
4537 ASSERT_OK(opt_alias
.Parse(config_options
, "Alias", "Alias", &base
));
4538 ASSERT_OK(opt_alias
.Serialize(config_options
, "Alias", &base
, &result
));
4540 opt_alias
.AreEqual(config_options
, "Alias", &base
, &comp
, &result
));
4541 ASSERT_EQ(base
, "Alias");
4542 ASSERT_NE(base
, comp
);
4544 // Deprecated options do nothing on any of the commands
4545 ASSERT_OK(opt_deprecated
.Parse(config_options
, "Alias", "Deprecated", &base
));
4546 ASSERT_OK(opt_deprecated
.Serialize(config_options
, "Alias", &base
, &result
));
4548 opt_deprecated
.AreEqual(config_options
, "Alias", &base
, &comp
, &result
));
4549 ASSERT_EQ(base
, "Alias");
4550 ASSERT_NE(base
, comp
);
4553 TEST_F(OptionTypeInfoTest
, TestCustomEnum
) {
4554 enum TestEnum
{ kA
, kB
, kC
};
4555 std::unordered_map
<std::string
, TestEnum
> enum_map
= {
4556 {"A", TestEnum::kA
},
4557 {"B", TestEnum::kB
},
4558 {"C", TestEnum::kC
},
4560 OptionTypeInfo opt_info
= OptionTypeInfo::Enum
<TestEnum
>(0, &enum_map
);
4562 ConfigOptions config_options
;
4563 std::string result
, mismatch
;
4567 ASSERT_OK(opt_info
.Parse(config_options
, "", "B", &e1
));
4568 ASSERT_OK(opt_info
.Serialize(config_options
, "", &e1
, &result
));
4569 ASSERT_EQ(e1
, TestEnum::kB
);
4570 ASSERT_EQ(result
, "B");
4572 ASSERT_FALSE(opt_info
.AreEqual(config_options
, "Enum", &e1
, &e2
, &mismatch
));
4573 ASSERT_EQ(mismatch
, "Enum");
4575 TestParseAndCompareOption(config_options
, opt_info
, "", "C", &e1
, &e2
);
4576 ASSERT_EQ(e2
, TestEnum::kC
);
4578 ASSERT_NOK(opt_info
.Parse(config_options
, "", "D", &e1
));
4579 ASSERT_EQ(e1
, TestEnum::kC
);
4582 TEST_F(OptionTypeInfoTest
, TestBuiltinEnum
) {
4583 ConfigOptions config_options
;
4584 for (auto iter
: OptionsHelper::compaction_style_string_map
) {
4585 CompactionStyle e1
, e2
;
4586 TestParseAndCompareOption(config_options
,
4587 OptionTypeInfo(0, OptionType::kCompactionStyle
),
4588 "CompactionStyle", iter
.first
, &e1
, &e2
);
4589 ASSERT_EQ(e1
, iter
.second
);
4591 for (auto iter
: OptionsHelper::compaction_pri_string_map
) {
4592 CompactionPri e1
, e2
;
4593 TestParseAndCompareOption(config_options
,
4594 OptionTypeInfo(0, OptionType::kCompactionPri
),
4595 "CompactionPri", iter
.first
, &e1
, &e2
);
4596 ASSERT_EQ(e1
, iter
.second
);
4598 for (auto iter
: OptionsHelper::compression_type_string_map
) {
4599 CompressionType e1
, e2
;
4600 TestParseAndCompareOption(config_options
,
4601 OptionTypeInfo(0, OptionType::kCompressionType
),
4602 "CompressionType", iter
.first
, &e1
, &e2
);
4603 ASSERT_EQ(e1
, iter
.second
);
4605 for (auto iter
: OptionsHelper::compaction_stop_style_string_map
) {
4606 CompactionStopStyle e1
, e2
;
4607 TestParseAndCompareOption(
4608 config_options
, OptionTypeInfo(0, OptionType::kCompactionStopStyle
),
4609 "CompactionStopStyle", iter
.first
, &e1
, &e2
);
4610 ASSERT_EQ(e1
, iter
.second
);
4612 for (auto iter
: OptionsHelper::checksum_type_string_map
) {
4613 ChecksumType e1
, e2
;
4614 TestParseAndCompareOption(config_options
,
4615 OptionTypeInfo(0, OptionType::kChecksumType
),
4616 "CheckSumType", iter
.first
, &e1
, &e2
);
4617 ASSERT_EQ(e1
, iter
.second
);
4619 for (auto iter
: OptionsHelper::encoding_type_string_map
) {
4620 EncodingType e1
, e2
;
4621 TestParseAndCompareOption(config_options
,
4622 OptionTypeInfo(0, OptionType::kEncodingType
),
4623 "EncodingType", iter
.first
, &e1
, &e2
);
4624 ASSERT_EQ(e1
, iter
.second
);
4628 TEST_F(OptionTypeInfoTest
, TestStruct
) {
4631 std::string s
= "Hello";
4639 std::unordered_map
<std::string
, OptionTypeInfo
> basic_type_map
= {
4640 {"i", {offsetof(struct Basic
, i
), OptionType::kInt
}},
4641 {"s", {offsetof(struct Basic
, s
), OptionType::kString
}},
4643 OptionTypeInfo basic_info
= OptionTypeInfo::Struct(
4644 "b", &basic_type_map
, 0, OptionVerificationType::kNormal
,
4645 OptionTypeFlags::kMutable
);
4647 std::unordered_map
<std::string
, OptionTypeInfo
> extended_type_map
= {
4648 {"j", {offsetof(struct Extended
, j
), OptionType::kInt
}},
4649 {"b", OptionTypeInfo::Struct(
4650 "b", &basic_type_map
, offsetof(struct Extended
, b
),
4651 OptionVerificationType::kNormal
, OptionTypeFlags::kNone
)},
4652 {"m", OptionTypeInfo::Struct(
4653 "m", &basic_type_map
, offsetof(struct Extended
, b
),
4654 OptionVerificationType::kNormal
, OptionTypeFlags::kMutable
)},
4656 OptionTypeInfo extended_info
= OptionTypeInfo::Struct(
4657 "e", &extended_type_map
, 0, OptionVerificationType::kNormal
,
4658 OptionTypeFlags::kMutable
);
4660 ConfigOptions config_options
;
4661 std::string mismatch
;
4662 TestParseAndCompareOption(config_options
, basic_info
, "b", "{i=33;s=33}",
4664 ASSERT_EQ(e1
.b
.i
, 33);
4665 ASSERT_EQ(e1
.b
.s
, "33");
4667 TestParseAndCompareOption(config_options
, basic_info
, "b.i", "44", &e1
.b
,
4669 ASSERT_EQ(e1
.b
.i
, 44);
4671 TestParseAndCompareOption(config_options
, basic_info
, "i", "55", &e1
.b
,
4673 ASSERT_EQ(e1
.b
.i
, 55);
4678 basic_info
.AreEqual(config_options
, "b", &e1
.b
, &e2
.b
, &mismatch
));
4679 ASSERT_EQ(mismatch
, "b.i");
4682 basic_info
.AreEqual(config_options
, "b.i", &e1
.b
, &e2
.b
, &mismatch
));
4683 ASSERT_EQ(mismatch
, "b.i");
4686 basic_info
.AreEqual(config_options
, "i", &e1
.b
, &e2
.b
, &mismatch
));
4687 ASSERT_EQ(mismatch
, "b.i");
4691 ASSERT_NOK(basic_info
.Parse(config_options
, "b", "{i=33;s=33;j=44}", &e1
.b
));
4692 ASSERT_NOK(basic_info
.Parse(config_options
, "b.j", "44", &e1
.b
));
4693 ASSERT_NOK(basic_info
.Parse(config_options
, "j", "44", &e1
.b
));
4695 TestParseAndCompareOption(config_options
, extended_info
, "e",
4696 "b={i=55;s=55}; j=22;", &e1
, &e2
);
4697 ASSERT_EQ(e1
.b
.i
, 55);
4698 ASSERT_EQ(e1
.j
, 22);
4699 ASSERT_EQ(e1
.b
.s
, "55");
4700 TestParseAndCompareOption(config_options
, extended_info
, "e.b",
4701 "{i=66;s=66;}", &e1
, &e2
);
4702 ASSERT_EQ(e1
.b
.i
, 66);
4703 ASSERT_EQ(e1
.j
, 22);
4704 ASSERT_EQ(e1
.b
.s
, "66");
4705 TestParseAndCompareOption(config_options
, extended_info
, "e.b.i", "77", &e1
,
4707 ASSERT_EQ(e1
.b
.i
, 77);
4708 ASSERT_EQ(e1
.j
, 22);
4709 ASSERT_EQ(e1
.b
.s
, "66");
4712 TEST_F(OptionTypeInfoTest
, TestArrayType
) {
4713 OptionTypeInfo array_info
= OptionTypeInfo::Array
<std::string
, 4>(
4714 0, OptionVerificationType::kNormal
, OptionTypeFlags::kNone
,
4715 {0, OptionType::kString
});
4716 std::array
<std::string
, 4> array1
, array2
;
4717 std::string mismatch
;
4719 ConfigOptions config_options
;
4720 TestParseAndCompareOption(config_options
, array_info
, "v", "a:b:c:d", &array1
,
4723 ASSERT_EQ(array1
.size(), 4);
4724 ASSERT_EQ(array1
[0], "a");
4725 ASSERT_EQ(array1
[1], "b");
4726 ASSERT_EQ(array1
[2], "c");
4727 ASSERT_EQ(array1
[3], "d");
4730 array_info
.AreEqual(config_options
, "v", &array1
, &array2
, &mismatch
));
4731 ASSERT_EQ(mismatch
, "v");
4733 // Test vectors with inner brackets
4734 TestParseAndCompareOption(config_options
, array_info
, "v", "a:{b}:c:d",
4736 ASSERT_EQ(array1
.size(), 4);
4737 ASSERT_EQ(array1
[0], "a");
4738 ASSERT_EQ(array1
[1], "b");
4739 ASSERT_EQ(array1
[2], "c");
4740 ASSERT_EQ(array1
[3], "d");
4742 std::array
<std::string
, 3> array3
, array4
;
4743 OptionTypeInfo bar_info
= OptionTypeInfo::Array
<std::string
, 3>(
4744 0, OptionVerificationType::kNormal
, OptionTypeFlags::kNone
,
4745 {0, OptionType::kString
}, '|');
4746 TestParseAndCompareOption(config_options
, bar_info
, "v", "x|y|z", &array3
,
4749 // Test arrays with inner array
4750 TestParseAndCompareOption(config_options
, bar_info
, "v",
4751 "a|{b1|b2}|{c1|c2|{d1|d2}}", &array3
, &array4
,
4753 ASSERT_EQ(array3
.size(), 3);
4754 ASSERT_EQ(array3
[0], "a");
4755 ASSERT_EQ(array3
[1], "b1|b2");
4756 ASSERT_EQ(array3
[2], "c1|c2|{d1|d2}");
4758 TestParseAndCompareOption(config_options
, bar_info
, "v",
4759 "{a1|a2}|{b1|{c1|c2}}|d1", &array3
, &array4
, true);
4760 ASSERT_EQ(array3
.size(), 3);
4761 ASSERT_EQ(array3
[0], "a1|a2");
4762 ASSERT_EQ(array3
[1], "b1|{c1|c2}");
4763 ASSERT_EQ(array3
[2], "d1");
4765 // Test invalid input: less element than requested
4766 auto s
= bar_info
.Parse(config_options
, "opt_name1", "a1|a2", &array3
);
4767 ASSERT_TRUE(s
.IsInvalidArgument());
4769 // Test invalid input: more element than requested
4770 s
= bar_info
.Parse(config_options
, "opt_name2", "a1|b|c1|d3", &array3
);
4771 ASSERT_TRUE(s
.IsInvalidArgument());
4774 TEST_F(OptionTypeInfoTest
, TestVectorType
) {
4775 OptionTypeInfo vec_info
= OptionTypeInfo::Vector
<std::string
>(
4776 0, OptionVerificationType::kNormal
, OptionTypeFlags::kNone
,
4777 {0, OptionType::kString
});
4778 std::vector
<std::string
> vec1
, vec2
;
4779 std::string mismatch
;
4781 ConfigOptions config_options
;
4782 TestParseAndCompareOption(config_options
, vec_info
, "v", "a:b:c:d", &vec1
,
4784 ASSERT_EQ(vec1
.size(), 4);
4785 ASSERT_EQ(vec1
[0], "a");
4786 ASSERT_EQ(vec1
[1], "b");
4787 ASSERT_EQ(vec1
[2], "c");
4788 ASSERT_EQ(vec1
[3], "d");
4790 ASSERT_FALSE(vec_info
.AreEqual(config_options
, "v", &vec1
, &vec2
, &mismatch
));
4791 ASSERT_EQ(mismatch
, "v");
4793 // Test vectors with inner brackets
4794 TestParseAndCompareOption(config_options
, vec_info
, "v", "a:{b}:c:d", &vec1
,
4796 ASSERT_EQ(vec1
.size(), 4);
4797 ASSERT_EQ(vec1
[0], "a");
4798 ASSERT_EQ(vec1
[1], "b");
4799 ASSERT_EQ(vec1
[2], "c");
4800 ASSERT_EQ(vec1
[3], "d");
4802 OptionTypeInfo bar_info
= OptionTypeInfo::Vector
<std::string
>(
4803 0, OptionVerificationType::kNormal
, OptionTypeFlags::kNone
,
4804 {0, OptionType::kString
}, '|');
4805 TestParseAndCompareOption(config_options
, vec_info
, "v", "x|y|z", &vec1
,
4807 // Test vectors with inner vector
4808 TestParseAndCompareOption(config_options
, bar_info
, "v",
4809 "a|{b1|b2}|{c1|c2|{d1|d2}}", &vec1
, &vec2
, false);
4810 ASSERT_EQ(vec1
.size(), 3);
4811 ASSERT_EQ(vec1
[0], "a");
4812 ASSERT_EQ(vec1
[1], "b1|b2");
4813 ASSERT_EQ(vec1
[2], "c1|c2|{d1|d2}");
4815 TestParseAndCompareOption(config_options
, bar_info
, "v",
4816 "{a1|a2}|{b1|{c1|c2}}|d1", &vec1
, &vec2
, true);
4817 ASSERT_EQ(vec1
.size(), 3);
4818 ASSERT_EQ(vec1
[0], "a1|a2");
4819 ASSERT_EQ(vec1
[1], "b1|{c1|c2}");
4820 ASSERT_EQ(vec1
[2], "d1");
4822 TestParseAndCompareOption(config_options
, bar_info
, "v", "{a1}", &vec1
, &vec2
,
4824 ASSERT_EQ(vec1
.size(), 1);
4825 ASSERT_EQ(vec1
[0], "a1");
4827 TestParseAndCompareOption(config_options
, bar_info
, "v", "{a1|a2}|{b1|b2}",
4828 &vec1
, &vec2
, true);
4829 ASSERT_EQ(vec1
.size(), 2);
4830 ASSERT_EQ(vec1
[0], "a1|a2");
4831 ASSERT_EQ(vec1
[1], "b1|b2");
4834 TEST_F(OptionTypeInfoTest
, TestStaticType
) {
4835 struct SimpleOptions
{
4840 static std::unordered_map
<std::string
, OptionTypeInfo
> type_map
= {
4841 {"size", {offsetof(struct SimpleOptions
, size
), OptionType::kSizeT
}},
4843 {offsetof(struct SimpleOptions
, verify
), OptionType::kBoolean
}},
4846 ConfigOptions config_options
;
4847 SimpleOptions opts
, copy
;
4849 opts
.verify
= false;
4850 std::string str
, mismatch
;
4853 OptionTypeInfo::SerializeType(config_options
, type_map
, &opts
, &str
));
4854 ASSERT_FALSE(OptionTypeInfo::TypesAreEqual(config_options
, type_map
, &opts
,
4856 ASSERT_OK(OptionTypeInfo::ParseType(config_options
, str
, type_map
, ©
));
4857 ASSERT_TRUE(OptionTypeInfo::TypesAreEqual(config_options
, type_map
, &opts
,
4861 class ConfigOptionsTest
: public testing::Test
{};
4863 TEST_F(ConfigOptionsTest
, EnvFromConfigOptions
) {
4864 ConfigOptions config_options
;
4867 Env
* mem_env
= NewMemEnv(Env::Default());
4868 config_options
.registry
->AddLibrary("custom-env", RegisterCustomEnv
,
4871 config_options
.env
= mem_env
;
4872 // First test that we can get the env as expected
4873 ASSERT_OK(GetDBOptionsFromString(config_options
, DBOptions(), kCustomEnvProp
,
4876 GetOptionsFromString(config_options
, Options(), kCustomEnvProp
, &opts
));
4877 ASSERT_NE(config_options
.env
, db_opts
.env
);
4878 ASSERT_EQ(opts
.env
, db_opts
.env
);
4879 Env
* custom_env
= db_opts
.env
;
4881 // Now try a "bad" env" and check that nothing changed
4882 config_options
.ignore_unsupported_options
= true;
4884 GetDBOptionsFromString(config_options
, db_opts
, "env=unknown", &db_opts
));
4885 ASSERT_OK(GetOptionsFromString(config_options
, opts
, "env=unknown", &opts
));
4886 ASSERT_EQ(config_options
.env
, mem_env
);
4887 ASSERT_EQ(db_opts
.env
, custom_env
);
4888 ASSERT_EQ(opts
.env
, db_opts
.env
);
4890 // Now try a "bad" env" ignoring unknown objects
4891 config_options
.ignore_unsupported_options
= false;
4893 GetDBOptionsFromString(config_options
, db_opts
, "env=unknown", &db_opts
));
4894 ASSERT_EQ(config_options
.env
, mem_env
);
4895 ASSERT_EQ(db_opts
.env
, custom_env
);
4896 ASSERT_EQ(opts
.env
, db_opts
.env
);
4900 TEST_F(ConfigOptionsTest
, MergeOperatorFromString
) {
4901 ConfigOptions config_options
;
4902 std::shared_ptr
<MergeOperator
> merge_op
;
4904 ASSERT_OK(MergeOperator::CreateFromString(config_options
, "put", &merge_op
));
4905 ASSERT_NE(merge_op
, nullptr);
4906 ASSERT_TRUE(merge_op
->IsInstanceOf("put"));
4907 ASSERT_STREQ(merge_op
->Name(), "PutOperator");
4910 MergeOperator::CreateFromString(config_options
, "put_v1", &merge_op
));
4911 ASSERT_NE(merge_op
, nullptr);
4912 ASSERT_TRUE(merge_op
->IsInstanceOf("PutOperator"));
4915 MergeOperator::CreateFromString(config_options
, "uint64add", &merge_op
));
4916 ASSERT_NE(merge_op
, nullptr);
4917 ASSERT_TRUE(merge_op
->IsInstanceOf("uint64add"));
4918 ASSERT_STREQ(merge_op
->Name(), "UInt64AddOperator");
4920 ASSERT_OK(MergeOperator::CreateFromString(config_options
, "max", &merge_op
));
4921 ASSERT_NE(merge_op
, nullptr);
4922 ASSERT_TRUE(merge_op
->IsInstanceOf("max"));
4923 ASSERT_STREQ(merge_op
->Name(), "MaxOperator");
4926 MergeOperator::CreateFromString(config_options
, "bytesxor", &merge_op
));
4927 ASSERT_NE(merge_op
, nullptr);
4928 ASSERT_TRUE(merge_op
->IsInstanceOf("bytesxor"));
4929 ASSERT_STREQ(merge_op
->Name(), BytesXOROperator::kClassName());
4932 MergeOperator::CreateFromString(config_options
, "sortlist", &merge_op
));
4933 ASSERT_NE(merge_op
, nullptr);
4934 ASSERT_TRUE(merge_op
->IsInstanceOf("sortlist"));
4935 ASSERT_STREQ(merge_op
->Name(), SortList::kClassName());
4937 ASSERT_OK(MergeOperator::CreateFromString(config_options
, "stringappend",
4939 ASSERT_NE(merge_op
, nullptr);
4940 ASSERT_TRUE(merge_op
->IsInstanceOf("stringappend"));
4941 ASSERT_STREQ(merge_op
->Name(), StringAppendOperator::kClassName());
4942 auto delimiter
= merge_op
->GetOptions
<std::string
>("Delimiter");
4943 ASSERT_NE(delimiter
, nullptr);
4944 ASSERT_EQ(*delimiter
, ",");
4946 ASSERT_OK(MergeOperator::CreateFromString(config_options
, "stringappendtest",
4948 ASSERT_NE(merge_op
, nullptr);
4949 ASSERT_TRUE(merge_op
->IsInstanceOf("stringappendtest"));
4950 ASSERT_STREQ(merge_op
->Name(), StringAppendTESTOperator::kClassName());
4951 delimiter
= merge_op
->GetOptions
<std::string
>("Delimiter");
4952 ASSERT_NE(delimiter
, nullptr);
4953 ASSERT_EQ(*delimiter
, ",");
4955 ASSERT_OK(MergeOperator::CreateFromString(
4956 config_options
, "id=stringappend; delimiter=||", &merge_op
));
4957 ASSERT_NE(merge_op
, nullptr);
4958 ASSERT_TRUE(merge_op
->IsInstanceOf("stringappend"));
4959 ASSERT_STREQ(merge_op
->Name(), StringAppendOperator::kClassName());
4960 delimiter
= merge_op
->GetOptions
<std::string
>("Delimiter");
4961 ASSERT_NE(delimiter
, nullptr);
4962 ASSERT_EQ(*delimiter
, "||");
4964 ASSERT_OK(MergeOperator::CreateFromString(
4965 config_options
, "id=stringappendtest; delimiter=&&", &merge_op
));
4966 ASSERT_NE(merge_op
, nullptr);
4967 ASSERT_TRUE(merge_op
->IsInstanceOf("stringappendtest"));
4968 ASSERT_STREQ(merge_op
->Name(), StringAppendTESTOperator::kClassName());
4969 delimiter
= merge_op
->GetOptions
<std::string
>("Delimiter");
4970 ASSERT_NE(delimiter
, nullptr);
4971 ASSERT_EQ(*delimiter
, "&&");
4973 std::shared_ptr
<MergeOperator
> copy
;
4974 std::string mismatch
;
4975 std::string opts_str
= merge_op
->ToString(config_options
);
4977 ASSERT_OK(MergeOperator::CreateFromString(config_options
, opts_str
, ©
));
4978 ASSERT_TRUE(merge_op
->AreEquivalent(config_options
, copy
.get(), &mismatch
));
4979 ASSERT_NE(copy
, nullptr);
4980 delimiter
= copy
->GetOptions
<std::string
>("Delimiter");
4981 ASSERT_NE(delimiter
, nullptr);
4982 ASSERT_EQ(*delimiter
, "&&");
4985 TEST_F(ConfigOptionsTest
, ConfiguringOptionsDoesNotRevertRateLimiterBandwidth
) {
4986 // Regression test for bug where rate limiter's dynamically set bandwidth
4987 // could be silently reverted when configuring an options structure with an
4988 // existing `rate_limiter`.
4989 Options base_options
;
4990 base_options
.rate_limiter
.reset(
4991 NewGenericRateLimiter(1 << 20 /* rate_bytes_per_sec */));
4992 Options
copy_options(base_options
);
4994 base_options
.rate_limiter
->SetBytesPerSecond(2 << 20);
4995 ASSERT_EQ(2 << 20, base_options
.rate_limiter
->GetBytesPerSecond());
4997 ASSERT_OK(GetOptionsFromString(base_options
, "", ©_options
));
4998 ASSERT_EQ(2 << 20, base_options
.rate_limiter
->GetBytesPerSecond());
5001 INSTANTIATE_TEST_CASE_P(OptionsSanityCheckTest
, OptionsSanityCheckTest
,
5003 #endif // !ROCKSDB_LITE
5005 } // namespace ROCKSDB_NAMESPACE
5007 int main(int argc
, char** argv
) {
5008 ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
5009 ::testing::InitGoogleTest(&argc
, argv
);
5011 ParseCommandLineFlags(&argc
, &argv
, true);
5013 return RUN_ALL_TESTS();