1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under the BSD-style license found in the
3 // LICENSE file in the root directory of this source tree. An additional grant
4 // of patent rights can be found in the PATENTS file in the same 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.
10 #ifndef __STDC_FORMAT_MACROS
11 #define __STDC_FORMAT_MACROS
16 #include <unordered_map>
19 #include "options/options_helper.h"
20 #include "options/options_parser.h"
21 #include "options/options_sanity_check.h"
22 #include "rocksdb/cache.h"
23 #include "rocksdb/convenience.h"
24 #include "rocksdb/memtablerep.h"
25 #include "rocksdb/utilities/leveldb_options.h"
26 #include "util/random.h"
27 #include "util/stderr_logger.h"
28 #include "util/string_util.h"
29 #include "util/testharness.h"
30 #include "util/testutil.h"
33 bool FLAGS_enable_print
= false;
35 #include <gflags/gflags.h>
36 using GFLAGS::ParseCommandLineFlags
;
37 DEFINE_bool(enable_print
, false, "Print options generated to console.");
42 class OptionsTest
: public testing::Test
{};
44 #ifndef ROCKSDB_LITE // GetOptionsFromMap is not supported in ROCKSDB_LITE
45 TEST_F(OptionsTest
, GetOptionsFromMapTest
) {
46 std::unordered_map
<std::string
, std::string
> cf_options_map
= {
47 {"write_buffer_size", "1"},
48 {"max_write_buffer_number", "2"},
49 {"min_write_buffer_number_to_merge", "3"},
50 {"max_write_buffer_number_to_maintain", "99"},
51 {"compression", "kSnappyCompression"},
52 {"compression_per_level",
61 "kZSTDNotFinalCompression"},
62 {"bottommost_compression", "kLZ4Compression"},
63 {"compression_opts", "4:5:6:7"},
65 {"level0_file_num_compaction_trigger", "8"},
66 {"level0_slowdown_writes_trigger", "9"},
67 {"level0_stop_writes_trigger", "10"},
68 {"target_file_size_base", "12"},
69 {"target_file_size_multiplier", "13"},
70 {"max_bytes_for_level_base", "14"},
71 {"level_compaction_dynamic_level_bytes", "true"},
72 {"max_bytes_for_level_multiplier", "15.0"},
73 {"max_bytes_for_level_multiplier_additional", "16:17:18"},
74 {"max_compaction_bytes", "21"},
75 {"soft_rate_limit", "1.1"},
76 {"hard_rate_limit", "2.1"},
77 {"hard_pending_compaction_bytes_limit", "211"},
78 {"arena_block_size", "22"},
79 {"disable_auto_compactions", "true"},
80 {"compaction_style", "kCompactionStyleLevel"},
81 {"compaction_pri", "kOldestSmallestSeqFirst"},
82 {"verify_checksums_in_compaction", "false"},
83 {"compaction_options_fifo", "23"},
84 {"max_sequential_skip_in_iterations", "24"},
85 {"inplace_update_support", "true"},
86 {"report_bg_io_stats", "true"},
87 {"compaction_measure_io_stats", "false"},
88 {"inplace_update_num_locks", "25"},
89 {"memtable_prefix_bloom_size_ratio", "0.26"},
90 {"memtable_huge_page_size", "28"},
91 {"bloom_locality", "29"},
92 {"max_successive_merges", "30"},
93 {"min_partial_merge_operands", "31"},
94 {"prefix_extractor", "fixed:31"},
95 {"optimize_filters_for_hits", "true"},
98 std::unordered_map
<std::string
, std::string
> db_options_map
= {
99 {"create_if_missing", "false"},
100 {"create_missing_column_families", "true"},
101 {"error_if_exists", "false"},
102 {"paranoid_checks", "true"},
103 {"max_open_files", "32"},
104 {"max_total_wal_size", "33"},
105 {"use_fsync", "true"},
106 {"db_log_dir", "/db_log_dir"},
107 {"wal_dir", "/wal_dir"},
108 {"delete_obsolete_files_period_micros", "34"},
109 {"max_background_compactions", "35"},
110 {"max_background_flushes", "36"},
111 {"max_log_file_size", "37"},
112 {"log_file_time_to_roll", "38"},
113 {"keep_log_file_num", "39"},
114 {"recycle_log_file_num", "5"},
115 {"max_manifest_file_size", "40"},
116 {"table_cache_numshardbits", "41"},
117 {"WAL_ttl_seconds", "43"},
118 {"WAL_size_limit_MB", "44"},
119 {"manifest_preallocation_size", "45"},
120 {"allow_mmap_reads", "true"},
121 {"allow_mmap_writes", "false"},
122 {"use_direct_reads", "false"},
123 {"use_direct_io_for_flush_and_compaction", "false"},
124 {"is_fd_close_on_exec", "true"},
125 {"skip_log_error_on_recovery", "false"},
126 {"stats_dump_period_sec", "46"},
127 {"advise_random_on_open", "true"},
128 {"use_adaptive_mutex", "false"},
129 {"new_table_reader_for_compaction_inputs", "true"},
130 {"compaction_readahead_size", "100"},
131 {"random_access_max_buffer_size", "3145728"},
132 {"writable_file_max_buffer_size", "314159"},
133 {"bytes_per_sync", "47"},
134 {"wal_bytes_per_sync", "48"},
137 ColumnFamilyOptions base_cf_opt
;
138 ColumnFamilyOptions new_cf_opt
;
139 ASSERT_OK(GetColumnFamilyOptionsFromMap(
140 base_cf_opt
, cf_options_map
, &new_cf_opt
));
141 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 1U);
142 ASSERT_EQ(new_cf_opt
.max_write_buffer_number
, 2);
143 ASSERT_EQ(new_cf_opt
.min_write_buffer_number_to_merge
, 3);
144 ASSERT_EQ(new_cf_opt
.max_write_buffer_number_to_maintain
, 99);
145 ASSERT_EQ(new_cf_opt
.compression
, kSnappyCompression
);
146 ASSERT_EQ(new_cf_opt
.compression_per_level
.size(), 9U);
147 ASSERT_EQ(new_cf_opt
.compression_per_level
[0], kNoCompression
);
148 ASSERT_EQ(new_cf_opt
.compression_per_level
[1], kSnappyCompression
);
149 ASSERT_EQ(new_cf_opt
.compression_per_level
[2], kZlibCompression
);
150 ASSERT_EQ(new_cf_opt
.compression_per_level
[3], kBZip2Compression
);
151 ASSERT_EQ(new_cf_opt
.compression_per_level
[4], kLZ4Compression
);
152 ASSERT_EQ(new_cf_opt
.compression_per_level
[5], kLZ4HCCompression
);
153 ASSERT_EQ(new_cf_opt
.compression_per_level
[6], kXpressCompression
);
154 ASSERT_EQ(new_cf_opt
.compression_per_level
[7], kZSTD
);
155 ASSERT_EQ(new_cf_opt
.compression_per_level
[8], kZSTDNotFinalCompression
);
156 ASSERT_EQ(new_cf_opt
.compression_opts
.window_bits
, 4);
157 ASSERT_EQ(new_cf_opt
.compression_opts
.level
, 5);
158 ASSERT_EQ(new_cf_opt
.compression_opts
.strategy
, 6);
159 ASSERT_EQ(new_cf_opt
.compression_opts
.max_dict_bytes
, 7);
160 ASSERT_EQ(new_cf_opt
.bottommost_compression
, kLZ4Compression
);
161 ASSERT_EQ(new_cf_opt
.num_levels
, 8);
162 ASSERT_EQ(new_cf_opt
.level0_file_num_compaction_trigger
, 8);
163 ASSERT_EQ(new_cf_opt
.level0_slowdown_writes_trigger
, 9);
164 ASSERT_EQ(new_cf_opt
.level0_stop_writes_trigger
, 10);
165 ASSERT_EQ(new_cf_opt
.target_file_size_base
, static_cast<uint64_t>(12));
166 ASSERT_EQ(new_cf_opt
.target_file_size_multiplier
, 13);
167 ASSERT_EQ(new_cf_opt
.max_bytes_for_level_base
, 14U);
168 ASSERT_EQ(new_cf_opt
.level_compaction_dynamic_level_bytes
, true);
169 ASSERT_EQ(new_cf_opt
.max_bytes_for_level_multiplier
, 15.0);
170 ASSERT_EQ(new_cf_opt
.max_bytes_for_level_multiplier_additional
.size(), 3U);
171 ASSERT_EQ(new_cf_opt
.max_bytes_for_level_multiplier_additional
[0], 16);
172 ASSERT_EQ(new_cf_opt
.max_bytes_for_level_multiplier_additional
[1], 17);
173 ASSERT_EQ(new_cf_opt
.max_bytes_for_level_multiplier_additional
[2], 18);
174 ASSERT_EQ(new_cf_opt
.max_compaction_bytes
, 21);
175 ASSERT_EQ(new_cf_opt
.hard_pending_compaction_bytes_limit
, 211);
176 ASSERT_EQ(new_cf_opt
.arena_block_size
, 22U);
177 ASSERT_EQ(new_cf_opt
.disable_auto_compactions
, true);
178 ASSERT_EQ(new_cf_opt
.compaction_style
, kCompactionStyleLevel
);
179 ASSERT_EQ(new_cf_opt
.compaction_pri
, kOldestSmallestSeqFirst
);
180 ASSERT_EQ(new_cf_opt
.compaction_options_fifo
.max_table_files_size
,
181 static_cast<uint64_t>(23));
182 ASSERT_EQ(new_cf_opt
.max_sequential_skip_in_iterations
,
183 static_cast<uint64_t>(24));
184 ASSERT_EQ(new_cf_opt
.inplace_update_support
, true);
185 ASSERT_EQ(new_cf_opt
.inplace_update_num_locks
, 25U);
186 ASSERT_EQ(new_cf_opt
.memtable_prefix_bloom_size_ratio
, 0.26);
187 ASSERT_EQ(new_cf_opt
.memtable_huge_page_size
, 28U);
188 ASSERT_EQ(new_cf_opt
.bloom_locality
, 29U);
189 ASSERT_EQ(new_cf_opt
.max_successive_merges
, 30U);
190 ASSERT_TRUE(new_cf_opt
.prefix_extractor
!= nullptr);
191 ASSERT_EQ(new_cf_opt
.optimize_filters_for_hits
, true);
192 ASSERT_EQ(std::string(new_cf_opt
.prefix_extractor
->Name()),
193 "rocksdb.FixedPrefix.31");
195 cf_options_map
["write_buffer_size"] = "hello";
196 ASSERT_NOK(GetColumnFamilyOptionsFromMap(
197 base_cf_opt
, cf_options_map
, &new_cf_opt
));
198 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt
, new_cf_opt
));
200 cf_options_map
["write_buffer_size"] = "1";
201 ASSERT_OK(GetColumnFamilyOptionsFromMap(
202 base_cf_opt
, cf_options_map
, &new_cf_opt
));
203 cf_options_map
["unknown_option"] = "1";
205 ASSERT_NOK(GetColumnFamilyOptionsFromMap(
206 base_cf_opt
, cf_options_map
, &new_cf_opt
));
207 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt
, new_cf_opt
));
209 DBOptions base_db_opt
;
210 DBOptions new_db_opt
;
211 ASSERT_OK(GetDBOptionsFromMap(base_db_opt
, db_options_map
, &new_db_opt
));
212 ASSERT_EQ(new_db_opt
.create_if_missing
, false);
213 ASSERT_EQ(new_db_opt
.create_missing_column_families
, true);
214 ASSERT_EQ(new_db_opt
.error_if_exists
, false);
215 ASSERT_EQ(new_db_opt
.paranoid_checks
, true);
216 ASSERT_EQ(new_db_opt
.max_open_files
, 32);
217 ASSERT_EQ(new_db_opt
.max_total_wal_size
, static_cast<uint64_t>(33));
218 ASSERT_EQ(new_db_opt
.use_fsync
, true);
219 ASSERT_EQ(new_db_opt
.db_log_dir
, "/db_log_dir");
220 ASSERT_EQ(new_db_opt
.wal_dir
, "/wal_dir");
221 ASSERT_EQ(new_db_opt
.delete_obsolete_files_period_micros
,
222 static_cast<uint64_t>(34));
223 ASSERT_EQ(new_db_opt
.max_background_compactions
, 35);
224 ASSERT_EQ(new_db_opt
.max_background_flushes
, 36);
225 ASSERT_EQ(new_db_opt
.max_log_file_size
, 37U);
226 ASSERT_EQ(new_db_opt
.log_file_time_to_roll
, 38U);
227 ASSERT_EQ(new_db_opt
.keep_log_file_num
, 39U);
228 ASSERT_EQ(new_db_opt
.recycle_log_file_num
, 5U);
229 ASSERT_EQ(new_db_opt
.max_manifest_file_size
, static_cast<uint64_t>(40));
230 ASSERT_EQ(new_db_opt
.table_cache_numshardbits
, 41);
231 ASSERT_EQ(new_db_opt
.WAL_ttl_seconds
, static_cast<uint64_t>(43));
232 ASSERT_EQ(new_db_opt
.WAL_size_limit_MB
, static_cast<uint64_t>(44));
233 ASSERT_EQ(new_db_opt
.manifest_preallocation_size
, 45U);
234 ASSERT_EQ(new_db_opt
.allow_mmap_reads
, true);
235 ASSERT_EQ(new_db_opt
.allow_mmap_writes
, false);
236 ASSERT_EQ(new_db_opt
.use_direct_reads
, false);
237 ASSERT_EQ(new_db_opt
.use_direct_io_for_flush_and_compaction
, false);
238 ASSERT_EQ(new_db_opt
.is_fd_close_on_exec
, true);
239 ASSERT_EQ(new_db_opt
.skip_log_error_on_recovery
, false);
240 ASSERT_EQ(new_db_opt
.stats_dump_period_sec
, 46U);
241 ASSERT_EQ(new_db_opt
.advise_random_on_open
, true);
242 ASSERT_EQ(new_db_opt
.use_adaptive_mutex
, false);
243 ASSERT_EQ(new_db_opt
.new_table_reader_for_compaction_inputs
, true);
244 ASSERT_EQ(new_db_opt
.compaction_readahead_size
, 100);
245 ASSERT_EQ(new_db_opt
.random_access_max_buffer_size
, 3145728);
246 ASSERT_EQ(new_db_opt
.writable_file_max_buffer_size
, 314159);
247 ASSERT_EQ(new_db_opt
.bytes_per_sync
, static_cast<uint64_t>(47));
248 ASSERT_EQ(new_db_opt
.wal_bytes_per_sync
, static_cast<uint64_t>(48));
250 #endif // !ROCKSDB_LITE
252 #ifndef ROCKSDB_LITE // GetColumnFamilyOptionsFromString is not supported in
254 TEST_F(OptionsTest
, GetColumnFamilyOptionsFromStringTest
) {
255 ColumnFamilyOptions base_cf_opt
;
256 ColumnFamilyOptions new_cf_opt
;
257 base_cf_opt
.table_factory
.reset();
258 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
, "", &new_cf_opt
));
259 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
260 "write_buffer_size=5", &new_cf_opt
));
261 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 5U);
262 ASSERT_TRUE(new_cf_opt
.table_factory
== nullptr);
263 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
264 "write_buffer_size=6;", &new_cf_opt
));
265 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 6U);
266 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
267 " write_buffer_size = 7 ", &new_cf_opt
));
268 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 7U);
269 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
270 " write_buffer_size = 8 ; ", &new_cf_opt
));
271 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 8U);
272 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
273 "write_buffer_size=9;max_write_buffer_number=10", &new_cf_opt
));
274 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 9U);
275 ASSERT_EQ(new_cf_opt
.max_write_buffer_number
, 10);
276 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
277 "write_buffer_size=11; max_write_buffer_number = 12 ;",
279 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 11U);
280 ASSERT_EQ(new_cf_opt
.max_write_buffer_number
, 12);
281 // Wrong name "max_write_buffer_number_"
282 ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt
,
283 "write_buffer_size=13;max_write_buffer_number_=14;",
285 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt
, new_cf_opt
));
287 // Wrong key/value pair
288 ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt
,
289 "write_buffer_size=13;max_write_buffer_number;", &new_cf_opt
));
290 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt
, new_cf_opt
));
292 // Error Paring value
293 ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt
,
294 "write_buffer_size=13;max_write_buffer_number=;", &new_cf_opt
));
295 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt
, new_cf_opt
));
297 // Missing option name
298 ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt
,
299 "write_buffer_size=13; =100;", &new_cf_opt
));
300 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt
, new_cf_opt
));
302 const int64_t kilo
= 1024UL;
303 const int64_t mega
= 1024 * kilo
;
304 const int64_t giga
= 1024 * mega
;
305 const int64_t tera
= 1024 * giga
;
308 ASSERT_OK(GetColumnFamilyOptionsFromString(
309 base_cf_opt
, "max_write_buffer_number=15K", &new_cf_opt
));
310 ASSERT_EQ(new_cf_opt
.max_write_buffer_number
, 15 * kilo
);
312 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
313 "max_write_buffer_number=16m;inplace_update_num_locks=17M",
315 ASSERT_EQ(new_cf_opt
.max_write_buffer_number
, 16 * mega
);
316 ASSERT_EQ(new_cf_opt
.inplace_update_num_locks
, 17 * mega
);
318 ASSERT_OK(GetColumnFamilyOptionsFromString(
320 "write_buffer_size=18g;prefix_extractor=capped:8;"
321 "arena_block_size=19G",
324 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 18 * giga
);
325 ASSERT_EQ(new_cf_opt
.arena_block_size
, 19 * giga
);
326 ASSERT_TRUE(new_cf_opt
.prefix_extractor
.get() != nullptr);
327 std::string
prefix_name(new_cf_opt
.prefix_extractor
->Name());
328 ASSERT_EQ(prefix_name
, "rocksdb.CappedPrefix.8");
331 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
332 "write_buffer_size=20t;arena_block_size=21T", &new_cf_opt
));
333 ASSERT_EQ(new_cf_opt
.write_buffer_size
, 20 * tera
);
334 ASSERT_EQ(new_cf_opt
.arena_block_size
, 21 * tera
);
336 // Nested block based table options
338 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
339 "write_buffer_size=10;max_write_buffer_number=16;"
340 "block_based_table_factory={};arena_block_size=1024",
342 ASSERT_TRUE(new_cf_opt
.table_factory
!= nullptr);
344 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
345 "write_buffer_size=10;max_write_buffer_number=16;"
346 "block_based_table_factory={block_cache=1M;block_size=4;};"
347 "arena_block_size=1024",
349 ASSERT_TRUE(new_cf_opt
.table_factory
!= nullptr);
351 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
352 "write_buffer_size=10;max_write_buffer_number=16;"
353 "block_based_table_factory={block_cache=1M;block_size=4;}",
355 ASSERT_TRUE(new_cf_opt
.table_factory
!= nullptr);
356 // Mismatch curly braces
357 ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt
,
358 "write_buffer_size=10;max_write_buffer_number=16;"
359 "block_based_table_factory={{{block_size=4;};"
360 "arena_block_size=1024",
362 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt
, new_cf_opt
));
364 // Unexpected chars after closing curly brace
365 ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt
,
366 "write_buffer_size=10;max_write_buffer_number=16;"
367 "block_based_table_factory={block_size=4;}};"
368 "arena_block_size=1024",
370 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt
, new_cf_opt
));
372 ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt
,
373 "write_buffer_size=10;max_write_buffer_number=16;"
374 "block_based_table_factory={block_size=4;}xdfa;"
375 "arena_block_size=1024",
377 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt
, new_cf_opt
));
379 ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt
,
380 "write_buffer_size=10;max_write_buffer_number=16;"
381 "block_based_table_factory={block_size=4;}xdfa",
383 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt
, new_cf_opt
));
385 // Invalid block based table option
386 ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt
,
387 "write_buffer_size=10;max_write_buffer_number=16;"
388 "block_based_table_factory={xx_block_size=4;}",
390 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt
, new_cf_opt
));
392 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
393 "optimize_filters_for_hits=true",
395 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
396 "optimize_filters_for_hits=false",
399 ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt
,
400 "optimize_filters_for_hits=junk",
402 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_cf_opt
, new_cf_opt
));
404 // Nested plain table options
406 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
407 "write_buffer_size=10;max_write_buffer_number=16;"
408 "plain_table_factory={};arena_block_size=1024",
410 ASSERT_TRUE(new_cf_opt
.table_factory
!= nullptr);
411 ASSERT_EQ(std::string(new_cf_opt
.table_factory
->Name()), "PlainTable");
413 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
414 "write_buffer_size=10;max_write_buffer_number=16;"
415 "plain_table_factory={user_key_len=66;bloom_bits_per_key=20;};"
416 "arena_block_size=1024",
418 ASSERT_TRUE(new_cf_opt
.table_factory
!= nullptr);
419 ASSERT_EQ(std::string(new_cf_opt
.table_factory
->Name()), "PlainTable");
422 ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt
,
423 "write_buffer_size=10;max_write_buffer_number=16;"
424 "memtable=skip_list:10;arena_block_size=1024",
426 ASSERT_TRUE(new_cf_opt
.memtable_factory
!= nullptr);
427 ASSERT_EQ(std::string(new_cf_opt
.memtable_factory
->Name()), "SkipListFactory");
429 #endif // !ROCKSDB_LITE
431 #ifndef ROCKSDB_LITE // GetBlockBasedTableOptionsFromString is not supported
432 TEST_F(OptionsTest
, GetBlockBasedTableOptionsFromString
) {
433 BlockBasedTableOptions table_opt
;
434 BlockBasedTableOptions new_opt
;
435 // make sure default values are overwritten by something else
436 ASSERT_OK(GetBlockBasedTableOptionsFromString(table_opt
,
437 "cache_index_and_filter_blocks=1;index_type=kHashSearch;"
438 "checksum=kxxHash;hash_index_allow_collision=1;no_block_cache=1;"
439 "block_cache=1M;block_cache_compressed=1k;block_size=1024;"
440 "block_size_deviation=8;block_restart_interval=4;"
441 "filter_policy=bloomfilter:4:true;whole_key_filtering=1;",
443 ASSERT_TRUE(new_opt
.cache_index_and_filter_blocks
);
444 ASSERT_EQ(new_opt
.index_type
, BlockBasedTableOptions::kHashSearch
);
445 ASSERT_EQ(new_opt
.checksum
, ChecksumType::kxxHash
);
446 ASSERT_TRUE(new_opt
.hash_index_allow_collision
);
447 ASSERT_TRUE(new_opt
.no_block_cache
);
448 ASSERT_TRUE(new_opt
.block_cache
!= nullptr);
449 ASSERT_EQ(new_opt
.block_cache
->GetCapacity(), 1024UL*1024UL);
450 ASSERT_TRUE(new_opt
.block_cache_compressed
!= nullptr);
451 ASSERT_EQ(new_opt
.block_cache_compressed
->GetCapacity(), 1024UL);
452 ASSERT_EQ(new_opt
.block_size
, 1024UL);
453 ASSERT_EQ(new_opt
.block_size_deviation
, 8);
454 ASSERT_EQ(new_opt
.block_restart_interval
, 4);
455 ASSERT_TRUE(new_opt
.filter_policy
!= nullptr);
458 ASSERT_NOK(GetBlockBasedTableOptionsFromString(table_opt
,
459 "cache_index_and_filter_blocks=1;index_type=kBinarySearch;"
462 ASSERT_EQ(table_opt
.cache_index_and_filter_blocks
,
463 new_opt
.cache_index_and_filter_blocks
);
464 ASSERT_EQ(table_opt
.index_type
, new_opt
.index_type
);
466 // unrecognized index type
467 ASSERT_NOK(GetBlockBasedTableOptionsFromString(table_opt
,
468 "cache_index_and_filter_blocks=1;index_type=kBinarySearchXX",
470 ASSERT_EQ(table_opt
.cache_index_and_filter_blocks
,
471 new_opt
.cache_index_and_filter_blocks
);
472 ASSERT_EQ(table_opt
.index_type
, new_opt
.index_type
);
474 // unrecognized checksum type
475 ASSERT_NOK(GetBlockBasedTableOptionsFromString(table_opt
,
476 "cache_index_and_filter_blocks=1;checksum=kxxHashXX",
478 ASSERT_EQ(table_opt
.cache_index_and_filter_blocks
,
479 new_opt
.cache_index_and_filter_blocks
);
480 ASSERT_EQ(table_opt
.index_type
, new_opt
.index_type
);
482 // unrecognized filter policy name
483 ASSERT_NOK(GetBlockBasedTableOptionsFromString(table_opt
,
484 "cache_index_and_filter_blocks=1;"
485 "filter_policy=bloomfilterxx:4:true",
487 ASSERT_EQ(table_opt
.cache_index_and_filter_blocks
,
488 new_opt
.cache_index_and_filter_blocks
);
489 ASSERT_EQ(table_opt
.filter_policy
, new_opt
.filter_policy
);
491 // unrecognized filter policy config
492 ASSERT_NOK(GetBlockBasedTableOptionsFromString(table_opt
,
493 "cache_index_and_filter_blocks=1;"
494 "filter_policy=bloomfilter:4",
496 ASSERT_EQ(table_opt
.cache_index_and_filter_blocks
,
497 new_opt
.cache_index_and_filter_blocks
);
498 ASSERT_EQ(table_opt
.filter_policy
, new_opt
.filter_policy
);
500 #endif // !ROCKSDB_LITE
503 #ifndef ROCKSDB_LITE // GetPlainTableOptionsFromString is not supported
504 TEST_F(OptionsTest
, GetPlainTableOptionsFromString
) {
505 PlainTableOptions table_opt
;
506 PlainTableOptions new_opt
;
507 // make sure default values are overwritten by something else
508 ASSERT_OK(GetPlainTableOptionsFromString(table_opt
,
509 "user_key_len=66;bloom_bits_per_key=20;hash_table_ratio=0.5;"
510 "index_sparseness=8;huge_page_tlb_size=4;encoding_type=kPrefix;"
511 "full_scan_mode=true;store_index_in_file=true",
513 ASSERT_EQ(new_opt
.user_key_len
, 66);
514 ASSERT_EQ(new_opt
.bloom_bits_per_key
, 20);
515 ASSERT_EQ(new_opt
.hash_table_ratio
, 0.5);
516 ASSERT_EQ(new_opt
.index_sparseness
, 8);
517 ASSERT_EQ(new_opt
.huge_page_tlb_size
, 4);
518 ASSERT_EQ(new_opt
.encoding_type
, EncodingType::kPrefix
);
519 ASSERT_TRUE(new_opt
.full_scan_mode
);
520 ASSERT_TRUE(new_opt
.store_index_in_file
);
523 ASSERT_NOK(GetPlainTableOptionsFromString(table_opt
,
524 "user_key_len=66;bloom_bits_per_key=20;hash_table_ratio=0.5;"
528 // unrecognized EncodingType
529 ASSERT_NOK(GetPlainTableOptionsFromString(table_opt
,
530 "user_key_len=66;bloom_bits_per_key=20;hash_table_ratio=0.5;"
531 "encoding_type=kPrefixXX",
534 #endif // !ROCKSDB_LITE
536 #ifndef ROCKSDB_LITE // GetMemTableRepFactoryFromString is not supported
537 TEST_F(OptionsTest
, GetMemTableRepFactoryFromString
) {
538 std::unique_ptr
<MemTableRepFactory
> new_mem_factory
= nullptr;
540 ASSERT_OK(GetMemTableRepFactoryFromString("skip_list", &new_mem_factory
));
541 ASSERT_OK(GetMemTableRepFactoryFromString("skip_list:16", &new_mem_factory
));
542 ASSERT_EQ(std::string(new_mem_factory
->Name()), "SkipListFactory");
543 ASSERT_NOK(GetMemTableRepFactoryFromString("skip_list:16:invalid_opt",
546 ASSERT_OK(GetMemTableRepFactoryFromString("prefix_hash", &new_mem_factory
));
547 ASSERT_OK(GetMemTableRepFactoryFromString("prefix_hash:1000",
549 ASSERT_EQ(std::string(new_mem_factory
->Name()), "HashSkipListRepFactory");
550 ASSERT_NOK(GetMemTableRepFactoryFromString("prefix_hash:1000:invalid_opt",
553 ASSERT_OK(GetMemTableRepFactoryFromString("hash_linkedlist",
555 ASSERT_OK(GetMemTableRepFactoryFromString("hash_linkedlist:1000",
557 ASSERT_EQ(std::string(new_mem_factory
->Name()), "HashLinkListRepFactory");
558 ASSERT_NOK(GetMemTableRepFactoryFromString("hash_linkedlist:1000:invalid_opt",
561 ASSERT_OK(GetMemTableRepFactoryFromString("vector", &new_mem_factory
));
562 ASSERT_OK(GetMemTableRepFactoryFromString("vector:1024", &new_mem_factory
));
563 ASSERT_EQ(std::string(new_mem_factory
->Name()), "VectorRepFactory");
564 ASSERT_NOK(GetMemTableRepFactoryFromString("vector:1024:invalid_opt",
567 ASSERT_NOK(GetMemTableRepFactoryFromString("cuckoo", &new_mem_factory
));
568 ASSERT_OK(GetMemTableRepFactoryFromString("cuckoo:1024", &new_mem_factory
));
569 ASSERT_EQ(std::string(new_mem_factory
->Name()), "HashCuckooRepFactory");
571 ASSERT_NOK(GetMemTableRepFactoryFromString("bad_factory", &new_mem_factory
));
573 #endif // !ROCKSDB_LITE
575 #ifndef ROCKSDB_LITE // GetOptionsFromString is not supported in RocksDB Lite
576 TEST_F(OptionsTest
, GetOptionsFromStringTest
) {
577 Options base_options
, new_options
;
578 base_options
.write_buffer_size
= 20;
579 base_options
.min_write_buffer_number_to_merge
= 15;
580 BlockBasedTableOptions block_based_table_options
;
581 block_based_table_options
.cache_index_and_filter_blocks
= true;
582 base_options
.table_factory
.reset(
583 NewBlockBasedTableFactory(block_based_table_options
));
584 ASSERT_OK(GetOptionsFromString(
586 "write_buffer_size=10;max_write_buffer_number=16;"
587 "block_based_table_factory={block_cache=1M;block_size=4;};"
588 "compression_opts=4:5:6;create_if_missing=true;max_open_files=1;"
589 "rate_limiter_bytes_per_sec=1024",
592 ASSERT_EQ(new_options
.compression_opts
.window_bits
, 4);
593 ASSERT_EQ(new_options
.compression_opts
.level
, 5);
594 ASSERT_EQ(new_options
.compression_opts
.strategy
, 6);
595 ASSERT_EQ(new_options
.compression_opts
.max_dict_bytes
, 0);
596 ASSERT_EQ(new_options
.bottommost_compression
, kDisableCompressionOption
);
597 ASSERT_EQ(new_options
.write_buffer_size
, 10U);
598 ASSERT_EQ(new_options
.max_write_buffer_number
, 16);
599 BlockBasedTableOptions new_block_based_table_options
=
600 dynamic_cast<BlockBasedTableFactory
*>(new_options
.table_factory
.get())
602 ASSERT_EQ(new_block_based_table_options
.block_cache
->GetCapacity(), 1U << 20);
603 ASSERT_EQ(new_block_based_table_options
.block_size
, 4U);
604 // don't overwrite block based table options
605 ASSERT_TRUE(new_block_based_table_options
.cache_index_and_filter_blocks
);
607 ASSERT_EQ(new_options
.create_if_missing
, true);
608 ASSERT_EQ(new_options
.max_open_files
, 1);
609 ASSERT_TRUE(new_options
.rate_limiter
.get() != nullptr);
612 TEST_F(OptionsTest
, DBOptionsSerialization
) {
613 Options base_options
, new_options
;
616 // Phase 1: Make big change in base_options
617 test::RandomInitDBOptions(&base_options
, &rnd
);
619 // Phase 2: obtain a string from base_option
620 std::string base_options_file_content
;
621 ASSERT_OK(GetStringFromDBOptions(&base_options_file_content
, base_options
));
623 // Phase 3: Set new_options from the derived string and expect
624 // new_options == base_options
625 ASSERT_OK(GetDBOptionsFromString(DBOptions(), base_options_file_content
,
627 ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(base_options
, new_options
));
630 TEST_F(OptionsTest
, ColumnFamilyOptionsSerialization
) {
631 ColumnFamilyOptions base_opt
, new_opt
;
633 // Phase 1: randomly assign base_opt
634 // custom type options
635 test::RandomInitCFOptions(&base_opt
, &rnd
);
637 // Phase 2: obtain a string from base_opt
638 std::string base_options_file_content
;
640 GetStringFromColumnFamilyOptions(&base_options_file_content
, base_opt
));
642 // Phase 3: Set new_opt from the derived string and expect
643 // new_opt == base_opt
644 ASSERT_OK(GetColumnFamilyOptionsFromString(
645 ColumnFamilyOptions(), base_options_file_content
, &new_opt
));
646 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_opt
, new_opt
));
647 if (base_opt
.compaction_filter
) {
648 delete base_opt
.compaction_filter
;
652 #endif // !ROCKSDB_LITE
655 const std::string
& opts_str
,
656 std::unordered_map
<std::string
, std::string
>* opts_map
);
658 #ifndef ROCKSDB_LITE // StringToMap is not supported in ROCKSDB_LITE
659 TEST_F(OptionsTest
, StringToMapTest
) {
660 std::unordered_map
<std::string
, std::string
> opts_map
;
662 ASSERT_OK(StringToMap("k1=v1;k2=v2;k3=v3", &opts_map
));
663 ASSERT_EQ(opts_map
["k1"], "v1");
664 ASSERT_EQ(opts_map
["k2"], "v2");
665 ASSERT_EQ(opts_map
["k3"], "v3");
668 ASSERT_OK(StringToMap("k1==v1;k2=v2=;", &opts_map
));
669 ASSERT_EQ(opts_map
["k1"], "=v1");
670 ASSERT_EQ(opts_map
["k2"], "v2=");
671 // Overwrriten option
673 ASSERT_OK(StringToMap("k1=v1;k1=v2;k3=v3", &opts_map
));
674 ASSERT_EQ(opts_map
["k1"], "v2");
675 ASSERT_EQ(opts_map
["k3"], "v3");
678 ASSERT_OK(StringToMap("k1=v1;k2=;k3=v3;k4=", &opts_map
));
679 ASSERT_EQ(opts_map
["k1"], "v1");
680 ASSERT_TRUE(opts_map
.find("k2") != opts_map
.end());
681 ASSERT_EQ(opts_map
["k2"], "");
682 ASSERT_EQ(opts_map
["k3"], "v3");
683 ASSERT_TRUE(opts_map
.find("k4") != opts_map
.end());
684 ASSERT_EQ(opts_map
["k4"], "");
686 ASSERT_OK(StringToMap("k1=v1;k2=;k3=v3;k4= ", &opts_map
));
687 ASSERT_EQ(opts_map
["k1"], "v1");
688 ASSERT_TRUE(opts_map
.find("k2") != opts_map
.end());
689 ASSERT_EQ(opts_map
["k2"], "");
690 ASSERT_EQ(opts_map
["k3"], "v3");
691 ASSERT_TRUE(opts_map
.find("k4") != opts_map
.end());
692 ASSERT_EQ(opts_map
["k4"], "");
694 ASSERT_OK(StringToMap("k1=v1;k2=;k3=", &opts_map
));
695 ASSERT_EQ(opts_map
["k1"], "v1");
696 ASSERT_TRUE(opts_map
.find("k2") != opts_map
.end());
697 ASSERT_EQ(opts_map
["k2"], "");
698 ASSERT_TRUE(opts_map
.find("k3") != opts_map
.end());
699 ASSERT_EQ(opts_map
["k3"], "");
701 ASSERT_OK(StringToMap("k1=v1;k2=;k3=;", &opts_map
));
702 ASSERT_EQ(opts_map
["k1"], "v1");
703 ASSERT_TRUE(opts_map
.find("k2") != opts_map
.end());
704 ASSERT_EQ(opts_map
["k2"], "");
705 ASSERT_TRUE(opts_map
.find("k3") != opts_map
.end());
706 ASSERT_EQ(opts_map
["k3"], "");
707 // Regular nested options
709 ASSERT_OK(StringToMap("k1=v1;k2={nk1=nv1;nk2=nv2};k3=v3", &opts_map
));
710 ASSERT_EQ(opts_map
["k1"], "v1");
711 ASSERT_EQ(opts_map
["k2"], "nk1=nv1;nk2=nv2");
712 ASSERT_EQ(opts_map
["k3"], "v3");
713 // Multi-level nested options
715 ASSERT_OK(StringToMap("k1=v1;k2={nk1=nv1;nk2={nnk1=nnk2}};"
716 "k3={nk1={nnk1={nnnk1=nnnv1;nnnk2;nnnv2}}};k4=v4",
718 ASSERT_EQ(opts_map
["k1"], "v1");
719 ASSERT_EQ(opts_map
["k2"], "nk1=nv1;nk2={nnk1=nnk2}");
720 ASSERT_EQ(opts_map
["k3"], "nk1={nnk1={nnnk1=nnnv1;nnnk2;nnnv2}}");
721 ASSERT_EQ(opts_map
["k4"], "v4");
722 // Garbage inside curly braces
724 ASSERT_OK(StringToMap("k1=v1;k2={dfad=};k3={=};k4=v4",
726 ASSERT_EQ(opts_map
["k1"], "v1");
727 ASSERT_EQ(opts_map
["k2"], "dfad=");
728 ASSERT_EQ(opts_map
["k3"], "=");
729 ASSERT_EQ(opts_map
["k4"], "v4");
730 // Empty nested options
732 ASSERT_OK(StringToMap("k1=v1;k2={};", &opts_map
));
733 ASSERT_EQ(opts_map
["k1"], "v1");
734 ASSERT_EQ(opts_map
["k2"], "");
736 ASSERT_OK(StringToMap("k1=v1;k2={{{{}}}{}{}};", &opts_map
));
737 ASSERT_EQ(opts_map
["k1"], "v1");
738 ASSERT_EQ(opts_map
["k2"], "{{{}}}{}{}");
739 // With random spaces
741 ASSERT_OK(StringToMap(" k1 = v1 ; k2= {nk1=nv1; nk2={nnk1=nnk2}} ; "
742 "k3={ { } }; k4= v4 ",
744 ASSERT_EQ(opts_map
["k1"], "v1");
745 ASSERT_EQ(opts_map
["k2"], "nk1=nv1; nk2={nnk1=nnk2}");
746 ASSERT_EQ(opts_map
["k3"], "{ }");
747 ASSERT_EQ(opts_map
["k4"], "v4");
750 ASSERT_NOK(StringToMap("k1=v1;k2=v2;=", &opts_map
));
751 ASSERT_NOK(StringToMap("=v1;k2=v2", &opts_map
));
752 ASSERT_NOK(StringToMap("k1=v1;k2v2;", &opts_map
));
753 ASSERT_NOK(StringToMap("k1=v1;k2=v2;fadfa", &opts_map
));
754 ASSERT_NOK(StringToMap("k1=v1;k2=v2;;", &opts_map
));
755 // Mismatch curly braces
756 ASSERT_NOK(StringToMap("k1=v1;k2={;k3=v3", &opts_map
));
757 ASSERT_NOK(StringToMap("k1=v1;k2={{};k3=v3", &opts_map
));
758 ASSERT_NOK(StringToMap("k1=v1;k2={}};k3=v3", &opts_map
));
759 ASSERT_NOK(StringToMap("k1=v1;k2={{}{}}};k3=v3", &opts_map
));
760 // However this is valid!
762 ASSERT_OK(StringToMap("k1=v1;k2=};k3=v3", &opts_map
));
763 ASSERT_EQ(opts_map
["k1"], "v1");
764 ASSERT_EQ(opts_map
["k2"], "}");
765 ASSERT_EQ(opts_map
["k3"], "v3");
767 // Invalid chars after closing curly brace
768 ASSERT_NOK(StringToMap("k1=v1;k2={{}}{};k3=v3", &opts_map
));
769 ASSERT_NOK(StringToMap("k1=v1;k2={{}}cfda;k3=v3", &opts_map
));
770 ASSERT_NOK(StringToMap("k1=v1;k2={{}} cfda;k3=v3", &opts_map
));
771 ASSERT_NOK(StringToMap("k1=v1;k2={{}} cfda", &opts_map
));
772 ASSERT_NOK(StringToMap("k1=v1;k2={{}}{}", &opts_map
));
773 ASSERT_NOK(StringToMap("k1=v1;k2={{dfdl}adfa}{}", &opts_map
));
775 #endif // ROCKSDB_LITE
777 #ifndef ROCKSDB_LITE // StringToMap is not supported in ROCKSDB_LITE
778 TEST_F(OptionsTest
, StringToMapRandomTest
) {
779 std::unordered_map
<std::string
, std::string
> opts_map
;
780 // Make sure segfault is not hit by semi-random strings
782 std::vector
<std::string
> bases
= {
783 "a={aa={};tt={xxx={}}};c=defff",
784 "a={aa={};tt={xxx={}}};c=defff;d={{}yxx{}3{xx}}",
785 "abc={{}{}{}{{{}}}{{}{}{}{}{}{}{}"};
787 for (std::string base
: bases
) {
788 for (int rand_seed
= 301; rand_seed
< 401; rand_seed
++) {
789 Random
rnd(rand_seed
);
790 for (int attempt
= 0; attempt
< 10; attempt
++) {
791 std::string str
= base
;
792 // Replace random position to space
793 size_t pos
= static_cast<size_t>(
794 rnd
.Uniform(static_cast<int>(base
.size())));
796 Status s
= StringToMap(str
, &opts_map
);
797 ASSERT_TRUE(s
.ok() || s
.IsInvalidArgument());
803 // Random Construct a string
804 std::vector
<char> chars
= {'{', '}', ' ', '=', ';', 'c'};
805 for (int rand_seed
= 301; rand_seed
< 1301; rand_seed
++) {
806 Random
rnd(rand_seed
);
807 int len
= rnd
.Uniform(30);
808 std::string str
= "";
809 for (int attempt
= 0; attempt
< len
; attempt
++) {
810 // Add a random character
811 size_t pos
= static_cast<size_t>(
812 rnd
.Uniform(static_cast<int>(chars
.size())));
813 str
.append(1, chars
[pos
]);
815 Status s
= StringToMap(str
, &opts_map
);
816 ASSERT_TRUE(s
.ok() || s
.IsInvalidArgument());
817 s
= StringToMap("name=" + str
, &opts_map
);
818 ASSERT_TRUE(s
.ok() || s
.IsInvalidArgument());
823 TEST_F(OptionsTest
, GetStringFromCompressionType
) {
826 ASSERT_OK(GetStringFromCompressionType(&res
, kNoCompression
));
827 ASSERT_EQ(res
, "kNoCompression");
829 ASSERT_OK(GetStringFromCompressionType(&res
, kSnappyCompression
));
830 ASSERT_EQ(res
, "kSnappyCompression");
832 ASSERT_OK(GetStringFromCompressionType(&res
, kDisableCompressionOption
));
833 ASSERT_EQ(res
, "kDisableCompressionOption");
835 ASSERT_OK(GetStringFromCompressionType(&res
, kLZ4Compression
));
836 ASSERT_EQ(res
, "kLZ4Compression");
838 ASSERT_OK(GetStringFromCompressionType(&res
, kZlibCompression
));
839 ASSERT_EQ(res
, "kZlibCompression");
842 GetStringFromCompressionType(&res
, static_cast<CompressionType
>(-10)));
844 #endif // !ROCKSDB_LITE
846 TEST_F(OptionsTest
, ConvertOptionsTest
) {
847 LevelDBOptions leveldb_opt
;
848 Options converted_opt
= ConvertOptions(leveldb_opt
);
850 ASSERT_EQ(converted_opt
.create_if_missing
, leveldb_opt
.create_if_missing
);
851 ASSERT_EQ(converted_opt
.error_if_exists
, leveldb_opt
.error_if_exists
);
852 ASSERT_EQ(converted_opt
.paranoid_checks
, leveldb_opt
.paranoid_checks
);
853 ASSERT_EQ(converted_opt
.env
, leveldb_opt
.env
);
854 ASSERT_EQ(converted_opt
.info_log
.get(), leveldb_opt
.info_log
);
855 ASSERT_EQ(converted_opt
.write_buffer_size
, leveldb_opt
.write_buffer_size
);
856 ASSERT_EQ(converted_opt
.max_open_files
, leveldb_opt
.max_open_files
);
857 ASSERT_EQ(converted_opt
.compression
, leveldb_opt
.compression
);
859 std::shared_ptr
<BlockBasedTableFactory
> table_factory
=
860 std::dynamic_pointer_cast
<BlockBasedTableFactory
>(
861 converted_opt
.table_factory
);
863 ASSERT_TRUE(table_factory
.get() != nullptr);
865 const BlockBasedTableOptions table_opt
= table_factory
->table_options();
867 ASSERT_EQ(table_opt
.block_cache
->GetCapacity(), 8UL << 20);
868 ASSERT_EQ(table_opt
.block_size
, leveldb_opt
.block_size
);
869 ASSERT_EQ(table_opt
.block_restart_interval
,
870 leveldb_opt
.block_restart_interval
);
871 ASSERT_EQ(table_opt
.filter_policy
.get(), leveldb_opt
.filter_policy
);
875 class OptionsParserTest
: public testing::Test
{
877 OptionsParserTest() { env_
.reset(new test::StringEnv(Env::Default())); }
880 std::unique_ptr
<test::StringEnv
> env_
;
883 TEST_F(OptionsParserTest
, Comment
) {
885 db_opt
.max_open_files
= 12345;
886 db_opt
.max_background_flushes
= 301;
887 db_opt
.max_total_wal_size
= 1024;
888 ColumnFamilyOptions cf_opt
;
890 std::string options_file_content
=
891 "# This is a testing option string.\n"
892 "# Currently we only support \"#\" styled comment.\n"
895 " rocksdb_version=3.14.0\n"
896 " options_file_version=1\n"
898 " # note that we don't support space around \"=\"\n"
899 " max_open_files=12345;\n"
900 " max_background_flushes=301 # comment after a statement is fine\n"
901 " # max_background_flushes=1000 # this line would be ignored\n"
902 " # max_background_compactions=2000 # so does this one\n"
903 " max_total_wal_size=1024 # keep_log_file_num=1000\n"
904 "[CFOptions \"default\"] # column family must be specified\n"
905 " # in the correct order\n"
906 " # if a section is blank, we will use the default\n";
908 const std::string kTestFileName
= "test-rocksdb-options.ini";
909 env_
->WriteToNewFile(kTestFileName
, options_file_content
);
910 RocksDBOptionsParser parser
;
911 ASSERT_OK(parser
.Parse(kTestFileName
, env_
.get()));
913 ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(*parser
.db_opt(), db_opt
));
914 ASSERT_EQ(parser
.NumColumnFamilies(), 1U);
915 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
916 *parser
.GetCFOptions("default"), cf_opt
));
919 TEST_F(OptionsParserTest
, ExtraSpace
) {
920 std::string options_file_content
=
921 "# This is a testing option string.\n"
922 "# Currently we only support \"#\" styled comment.\n"
925 " rocksdb_version = 3.14.0 \n"
926 " options_file_version=1 # some comment\n"
927 "[DBOptions ] # some comment\n"
928 "max_open_files=12345 \n"
929 " max_background_flushes = 301 \n"
930 " max_total_wal_size = 1024 # keep_log_file_num=1000\n"
931 " [CFOptions \"default\" ]\n"
932 " # if a section is blank, we will use the default\n";
934 const std::string kTestFileName
= "test-rocksdb-options.ini";
935 env_
->WriteToNewFile(kTestFileName
, options_file_content
);
936 RocksDBOptionsParser parser
;
937 ASSERT_OK(parser
.Parse(kTestFileName
, env_
.get()));
940 TEST_F(OptionsParserTest
, MissingDBOptions
) {
941 std::string options_file_content
=
942 "# This is a testing option string.\n"
943 "# Currently we only support \"#\" styled comment.\n"
946 " rocksdb_version=3.14.0\n"
947 " options_file_version=1\n"
948 "[CFOptions \"default\"]\n"
949 " # if a section is blank, we will use the default\n";
951 const std::string kTestFileName
= "test-rocksdb-options.ini";
952 env_
->WriteToNewFile(kTestFileName
, options_file_content
);
953 RocksDBOptionsParser parser
;
954 ASSERT_NOK(parser
.Parse(kTestFileName
, env_
.get()));
957 TEST_F(OptionsParserTest
, DoubleDBOptions
) {
959 db_opt
.max_open_files
= 12345;
960 db_opt
.max_background_flushes
= 301;
961 db_opt
.max_total_wal_size
= 1024;
962 ColumnFamilyOptions cf_opt
;
964 std::string options_file_content
=
965 "# This is a testing option string.\n"
966 "# Currently we only support \"#\" styled comment.\n"
969 " rocksdb_version=3.14.0\n"
970 " options_file_version=1\n"
972 " max_open_files=12345\n"
973 " max_background_flushes=301\n"
974 " max_total_wal_size=1024 # keep_log_file_num=1000\n"
976 "[CFOptions \"default\"]\n"
977 " # if a section is blank, we will use the default\n";
979 const std::string kTestFileName
= "test-rocksdb-options.ini";
980 env_
->WriteToNewFile(kTestFileName
, options_file_content
);
981 RocksDBOptionsParser parser
;
982 ASSERT_NOK(parser
.Parse(kTestFileName
, env_
.get()));
985 TEST_F(OptionsParserTest
, NoDefaultCFOptions
) {
987 db_opt
.max_open_files
= 12345;
988 db_opt
.max_background_flushes
= 301;
989 db_opt
.max_total_wal_size
= 1024;
990 ColumnFamilyOptions cf_opt
;
992 std::string options_file_content
=
993 "# This is a testing option string.\n"
994 "# Currently we only support \"#\" styled comment.\n"
997 " rocksdb_version=3.14.0\n"
998 " options_file_version=1\n"
1000 " max_open_files=12345\n"
1001 " max_background_flushes=301\n"
1002 " max_total_wal_size=1024 # keep_log_file_num=1000\n"
1003 "[CFOptions \"something_else\"]\n"
1004 " # if a section is blank, we will use the default\n";
1006 const std::string kTestFileName
= "test-rocksdb-options.ini";
1007 env_
->WriteToNewFile(kTestFileName
, options_file_content
);
1008 RocksDBOptionsParser parser
;
1009 ASSERT_NOK(parser
.Parse(kTestFileName
, env_
.get()));
1012 TEST_F(OptionsParserTest
, DefaultCFOptionsMustBeTheFirst
) {
1014 db_opt
.max_open_files
= 12345;
1015 db_opt
.max_background_flushes
= 301;
1016 db_opt
.max_total_wal_size
= 1024;
1017 ColumnFamilyOptions cf_opt
;
1019 std::string options_file_content
=
1020 "# This is a testing option string.\n"
1021 "# Currently we only support \"#\" styled comment.\n"
1024 " rocksdb_version=3.14.0\n"
1025 " options_file_version=1\n"
1027 " max_open_files=12345\n"
1028 " max_background_flushes=301\n"
1029 " max_total_wal_size=1024 # keep_log_file_num=1000\n"
1030 "[CFOptions \"something_else\"]\n"
1031 " # if a section is blank, we will use the default\n"
1032 "[CFOptions \"default\"]\n"
1033 " # if a section is blank, we will use the default\n";
1035 const std::string kTestFileName
= "test-rocksdb-options.ini";
1036 env_
->WriteToNewFile(kTestFileName
, options_file_content
);
1037 RocksDBOptionsParser parser
;
1038 ASSERT_NOK(parser
.Parse(kTestFileName
, env_
.get()));
1041 TEST_F(OptionsParserTest
, DuplicateCFOptions
) {
1043 db_opt
.max_open_files
= 12345;
1044 db_opt
.max_background_flushes
= 301;
1045 db_opt
.max_total_wal_size
= 1024;
1046 ColumnFamilyOptions cf_opt
;
1048 std::string options_file_content
=
1049 "# This is a testing option string.\n"
1050 "# Currently we only support \"#\" styled comment.\n"
1053 " rocksdb_version=3.14.0\n"
1054 " options_file_version=1\n"
1056 " max_open_files=12345\n"
1057 " max_background_flushes=301\n"
1058 " max_total_wal_size=1024 # keep_log_file_num=1000\n"
1059 "[CFOptions \"default\"]\n"
1060 "[CFOptions \"something_else\"]\n"
1061 "[CFOptions \"something_else\"]\n";
1063 const std::string kTestFileName
= "test-rocksdb-options.ini";
1064 env_
->WriteToNewFile(kTestFileName
, options_file_content
);
1065 RocksDBOptionsParser parser
;
1066 ASSERT_NOK(parser
.Parse(kTestFileName
, env_
.get()));
1069 TEST_F(OptionsParserTest
, ParseVersion
) {
1071 db_opt
.max_open_files
= 12345;
1072 db_opt
.max_background_flushes
= 301;
1073 db_opt
.max_total_wal_size
= 1024;
1074 ColumnFamilyOptions cf_opt
;
1076 std::string file_template
=
1077 "# This is a testing option string.\n"
1078 "# Currently we only support \"#\" styled comment.\n"
1081 " rocksdb_version=3.13.1\n"
1082 " options_file_version=%s\n"
1084 "[CFOptions \"default\"]\n";
1085 const int kLength
= 1000;
1086 char buffer
[kLength
];
1087 RocksDBOptionsParser parser
;
1089 const std::vector
<std::string
> invalid_versions
= {
1090 "a.b.c", "3.2.2b", "3.-12", "3. 1", // only digits and dots are allowed
1092 "1.2.3" // can only contains at most one dot.
1093 "0", // options_file_version must be at least one
1095 ".", ".1.2", // must have at least one digit before each dot
1096 "1.2.", "1.", "2.34."}; // must have at least one digit after each dot
1097 for (auto iv
: invalid_versions
) {
1098 snprintf(buffer
, kLength
- 1, file_template
.c_str(), iv
.c_str());
1101 env_
->WriteToNewFile(iv
, buffer
);
1102 ASSERT_NOK(parser
.Parse(iv
, env_
.get()));
1105 const std::vector
<std::string
> valid_versions
= {
1106 "1.232", "100", "3.12", "1", "12.3 ", " 1.25 "};
1107 for (auto vv
: valid_versions
) {
1108 snprintf(buffer
, kLength
- 1, file_template
.c_str(), vv
.c_str());
1110 env_
->WriteToNewFile(vv
, buffer
);
1111 ASSERT_OK(parser
.Parse(vv
, env_
.get()));
1115 void VerifyCFPointerTypedOptions(
1116 ColumnFamilyOptions
* base_cf_opt
, const ColumnFamilyOptions
* new_cf_opt
,
1117 const std::unordered_map
<std::string
, std::string
>* new_cf_opt_map
) {
1118 std::string name_buffer
;
1119 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(*base_cf_opt
, *new_cf_opt
,
1122 // change the name of merge operator back-and-forth
1124 auto* merge_operator
= dynamic_cast<test::ChanglingMergeOperator
*>(
1125 base_cf_opt
->merge_operator
.get());
1126 if (merge_operator
!= nullptr) {
1127 name_buffer
= merge_operator
->Name();
1128 // change the name and expect non-ok status
1129 merge_operator
->SetName("some-other-name");
1130 ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
1131 *base_cf_opt
, *new_cf_opt
, new_cf_opt_map
));
1132 // change the name back and expect ok status
1133 merge_operator
->SetName(name_buffer
);
1134 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(*base_cf_opt
, *new_cf_opt
,
1139 // change the name of the compaction filter factory back-and-forth
1141 auto* compaction_filter_factory
=
1142 dynamic_cast<test::ChanglingCompactionFilterFactory
*>(
1143 base_cf_opt
->compaction_filter_factory
.get());
1144 if (compaction_filter_factory
!= nullptr) {
1145 name_buffer
= compaction_filter_factory
->Name();
1146 // change the name and expect non-ok status
1147 compaction_filter_factory
->SetName("some-other-name");
1148 ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
1149 *base_cf_opt
, *new_cf_opt
, new_cf_opt_map
));
1150 // change the name back and expect ok status
1151 compaction_filter_factory
->SetName(name_buffer
);
1152 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(*base_cf_opt
, *new_cf_opt
,
1157 // test by setting compaction_filter to nullptr
1159 auto* tmp_compaction_filter
= base_cf_opt
->compaction_filter
;
1160 if (tmp_compaction_filter
!= nullptr) {
1161 base_cf_opt
->compaction_filter
= nullptr;
1162 // set compaction_filter to nullptr and expect non-ok status
1163 ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
1164 *base_cf_opt
, *new_cf_opt
, new_cf_opt_map
));
1165 // set the value back and expect ok status
1166 base_cf_opt
->compaction_filter
= tmp_compaction_filter
;
1167 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(*base_cf_opt
, *new_cf_opt
,
1172 // test by setting table_factory to nullptr
1174 auto tmp_table_factory
= base_cf_opt
->table_factory
;
1175 if (tmp_table_factory
!= nullptr) {
1176 base_cf_opt
->table_factory
.reset();
1177 // set table_factory to nullptr and expect non-ok status
1178 ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
1179 *base_cf_opt
, *new_cf_opt
, new_cf_opt_map
));
1180 // set the value back and expect ok status
1181 base_cf_opt
->table_factory
= tmp_table_factory
;
1182 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(*base_cf_opt
, *new_cf_opt
,
1187 // test by setting memtable_factory to nullptr
1189 auto tmp_memtable_factory
= base_cf_opt
->memtable_factory
;
1190 if (tmp_memtable_factory
!= nullptr) {
1191 base_cf_opt
->memtable_factory
.reset();
1192 // set memtable_factory to nullptr and expect non-ok status
1193 ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
1194 *base_cf_opt
, *new_cf_opt
, new_cf_opt_map
));
1195 // set the value back and expect ok status
1196 base_cf_opt
->memtable_factory
= tmp_memtable_factory
;
1197 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(*base_cf_opt
, *new_cf_opt
,
1203 TEST_F(OptionsParserTest
, DumpAndParse
) {
1204 DBOptions base_db_opt
;
1205 std::vector
<ColumnFamilyOptions
> base_cf_opts
;
1206 std::vector
<std::string
> cf_names
= {"default", "cf1", "cf2", "cf3",
1208 "p\\i\\k\\a\\chu\\\\\\",
1209 "###rocksdb#1-testcf#2###"};
1210 const int num_cf
= static_cast<int>(cf_names
.size());
1212 test::RandomInitDBOptions(&base_db_opt
, &rnd
);
1213 base_db_opt
.db_log_dir
+= "/#odd #but #could #happen #path #/\\\\#OMG";
1214 for (int c
= 0; c
< num_cf
; ++c
) {
1215 ColumnFamilyOptions cf_opt
;
1216 Random
cf_rnd(0xFB + c
);
1217 test::RandomInitCFOptions(&cf_opt
, &cf_rnd
);
1219 cf_opt
.prefix_extractor
.reset(test::RandomSliceTransform(&rnd
, c
));
1222 cf_opt
.table_factory
.reset(test::RandomTableFactory(&rnd
, c
));
1224 base_cf_opts
.emplace_back(cf_opt
);
1227 const std::string kOptionsFileName
= "test-persisted-options.ini";
1228 ASSERT_OK(PersistRocksDBOptions(base_db_opt
, cf_names
, base_cf_opts
,
1229 kOptionsFileName
, env_
.get()));
1231 RocksDBOptionsParser parser
;
1232 ASSERT_OK(parser
.Parse(kOptionsFileName
, env_
.get()));
1234 ASSERT_OK(RocksDBOptionsParser::VerifyRocksDBOptionsFromFile(
1235 base_db_opt
, cf_names
, base_cf_opts
, kOptionsFileName
, env_
.get()));
1238 RocksDBOptionsParser::VerifyDBOptions(*parser
.db_opt(), base_db_opt
));
1239 for (int c
= 0; c
< num_cf
; ++c
) {
1240 const auto* cf_opt
= parser
.GetCFOptions(cf_names
[c
]);
1241 ASSERT_NE(cf_opt
, nullptr);
1242 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
1243 base_cf_opts
[c
], *cf_opt
, &(parser
.cf_opt_maps()->at(c
))));
1246 // Further verify pointer-typed options
1247 for (int c
= 0; c
< num_cf
; ++c
) {
1248 const auto* cf_opt
= parser
.GetCFOptions(cf_names
[c
]);
1249 ASSERT_NE(cf_opt
, nullptr);
1250 VerifyCFPointerTypedOptions(&base_cf_opts
[c
], cf_opt
,
1251 &(parser
.cf_opt_maps()->at(c
)));
1254 ASSERT_EQ(parser
.GetCFOptions("does not exist"), nullptr);
1256 base_db_opt
.max_open_files
++;
1257 ASSERT_NOK(RocksDBOptionsParser::VerifyRocksDBOptionsFromFile(
1258 base_db_opt
, cf_names
, base_cf_opts
, kOptionsFileName
, env_
.get()));
1260 for (int c
= 0; c
< num_cf
; ++c
) {
1261 if (base_cf_opts
[c
].compaction_filter
) {
1262 delete base_cf_opts
[c
].compaction_filter
;
1267 TEST_F(OptionsParserTest
, DifferentDefault
) {
1268 const std::string kOptionsFileName
= "test-persisted-options.ini";
1270 ColumnFamilyOptions cf_level_opts
;
1271 cf_level_opts
.OptimizeLevelStyleCompaction();
1273 ColumnFamilyOptions cf_univ_opts
;
1274 cf_univ_opts
.OptimizeUniversalStyleCompaction();
1276 ASSERT_OK(PersistRocksDBOptions(DBOptions(), {"default", "universal"},
1277 {cf_level_opts
, cf_univ_opts
},
1278 kOptionsFileName
, env_
.get()));
1280 RocksDBOptionsParser parser
;
1281 ASSERT_OK(parser
.Parse(kOptionsFileName
, env_
.get()));
1284 Options old_default_opts
;
1285 old_default_opts
.OldDefaults();
1286 ASSERT_EQ(10 * 1048576, old_default_opts
.max_bytes_for_level_base
);
1287 ASSERT_EQ(5000, old_default_opts
.max_open_files
);
1288 ASSERT_EQ(-1, old_default_opts
.base_background_compactions
);
1289 ASSERT_EQ(2 * 1024U * 1024U, old_default_opts
.delayed_write_rate
);
1290 ASSERT_EQ(WALRecoveryMode::kTolerateCorruptedTailRecords
,
1291 old_default_opts
.wal_recovery_mode
);
1294 Options old_default_opts
;
1295 old_default_opts
.OldDefaults(4, 6);
1296 ASSERT_EQ(10 * 1048576, old_default_opts
.max_bytes_for_level_base
);
1297 ASSERT_EQ(5000, old_default_opts
.max_open_files
);
1300 Options old_default_opts
;
1301 old_default_opts
.OldDefaults(4, 7);
1302 ASSERT_NE(10 * 1048576, old_default_opts
.max_bytes_for_level_base
);
1303 ASSERT_NE(4, old_default_opts
.table_cache_numshardbits
);
1304 ASSERT_EQ(5000, old_default_opts
.max_open_files
);
1305 ASSERT_EQ(2 * 1024U * 1024U, old_default_opts
.delayed_write_rate
);
1308 ColumnFamilyOptions old_default_cf_opts
;
1309 old_default_cf_opts
.OldDefaults();
1310 ASSERT_EQ(2 * 1048576, old_default_cf_opts
.target_file_size_base
);
1311 ASSERT_EQ(4 << 20, old_default_cf_opts
.write_buffer_size
);
1312 ASSERT_EQ(2 * 1048576, old_default_cf_opts
.target_file_size_base
);
1313 ASSERT_EQ(0, old_default_cf_opts
.soft_pending_compaction_bytes_limit
);
1314 ASSERT_EQ(0, old_default_cf_opts
.hard_pending_compaction_bytes_limit
);
1315 ASSERT_EQ(CompactionPri::kByCompensatedSize
,
1316 old_default_cf_opts
.compaction_pri
);
1319 ColumnFamilyOptions old_default_cf_opts
;
1320 old_default_cf_opts
.OldDefaults(4, 6);
1321 ASSERT_EQ(2 * 1048576, old_default_cf_opts
.target_file_size_base
);
1322 ASSERT_EQ(CompactionPri::kByCompensatedSize
,
1323 old_default_cf_opts
.compaction_pri
);
1326 ColumnFamilyOptions old_default_cf_opts
;
1327 old_default_cf_opts
.OldDefaults(4, 7);
1328 ASSERT_NE(2 * 1048576, old_default_cf_opts
.target_file_size_base
);
1329 ASSERT_EQ(CompactionPri::kByCompensatedSize
,
1330 old_default_cf_opts
.compaction_pri
);
1333 Options old_default_opts
;
1334 old_default_opts
.OldDefaults(5, 1);
1335 ASSERT_EQ(2 * 1024U * 1024U, old_default_opts
.delayed_write_rate
);
1338 Options old_default_opts
;
1339 old_default_opts
.OldDefaults(5, 2);
1340 ASSERT_EQ(16 * 1024U * 1024U, old_default_opts
.delayed_write_rate
);
1344 small_opts
.OptimizeForSmallDb();
1345 ASSERT_EQ(2 << 20, small_opts
.write_buffer_size
);
1346 ASSERT_EQ(5000, small_opts
.max_open_files
);
1349 class OptionsSanityCheckTest
: public OptionsParserTest
{
1351 OptionsSanityCheckTest() {}
1354 Status
SanityCheckCFOptions(const ColumnFamilyOptions
& cf_opts
,
1355 OptionsSanityCheckLevel level
) {
1356 return RocksDBOptionsParser::VerifyRocksDBOptionsFromFile(
1357 DBOptions(), {"default"}, {cf_opts
}, kOptionsFileName
, env_
.get(),
1361 Status
PersistCFOptions(const ColumnFamilyOptions
& cf_opts
) {
1362 Status s
= env_
->DeleteFile(kOptionsFileName
);
1366 return PersistRocksDBOptions(DBOptions(), {"default"}, {cf_opts
},
1367 kOptionsFileName
, env_
.get());
1370 const std::string kOptionsFileName
= "OPTIONS";
1373 TEST_F(OptionsSanityCheckTest
, SanityCheck
) {
1374 ColumnFamilyOptions opts
;
1377 // default ColumnFamilyOptions
1379 ASSERT_OK(PersistCFOptions(opts
));
1380 ASSERT_OK(SanityCheckCFOptions(opts
, kSanityLevelExactMatch
));
1385 // Okay to change prefix_extractor form nullptr to non-nullptr
1386 ASSERT_EQ(opts
.prefix_extractor
.get(), nullptr);
1387 opts
.prefix_extractor
.reset(NewCappedPrefixTransform(10));
1388 ASSERT_OK(SanityCheckCFOptions(opts
, kSanityLevelLooselyCompatible
));
1389 ASSERT_OK(SanityCheckCFOptions(opts
, kSanityLevelNone
));
1391 // persist the change
1392 ASSERT_OK(PersistCFOptions(opts
));
1393 ASSERT_OK(SanityCheckCFOptions(opts
, kSanityLevelExactMatch
));
1395 // use same prefix extractor but with different parameter
1396 opts
.prefix_extractor
.reset(NewCappedPrefixTransform(15));
1397 // expect pass only in kSanityLevelNone
1398 ASSERT_NOK(SanityCheckCFOptions(opts
, kSanityLevelLooselyCompatible
));
1399 ASSERT_OK(SanityCheckCFOptions(opts
, kSanityLevelNone
));
1401 // repeat the test with FixedPrefixTransform
1402 opts
.prefix_extractor
.reset(NewFixedPrefixTransform(10));
1403 ASSERT_NOK(SanityCheckCFOptions(opts
, kSanityLevelLooselyCompatible
));
1404 ASSERT_OK(SanityCheckCFOptions(opts
, kSanityLevelNone
));
1406 // persist the change of prefix_extractor
1407 ASSERT_OK(PersistCFOptions(opts
));
1408 ASSERT_OK(SanityCheckCFOptions(opts
, kSanityLevelExactMatch
));
1410 // use same prefix extractor but with different parameter
1411 opts
.prefix_extractor
.reset(NewFixedPrefixTransform(15));
1412 // expect pass only in kSanityLevelNone
1413 ASSERT_NOK(SanityCheckCFOptions(opts
, kSanityLevelLooselyCompatible
));
1414 ASSERT_OK(SanityCheckCFOptions(opts
, kSanityLevelNone
));
1416 // Change prefix extractor from non-nullptr to nullptr
1417 opts
.prefix_extractor
.reset();
1418 // expect pass as it's safe to change prefix_extractor
1419 // from non-null to null
1420 ASSERT_OK(SanityCheckCFOptions(opts
, kSanityLevelLooselyCompatible
));
1421 ASSERT_OK(SanityCheckCFOptions(opts
, kSanityLevelNone
));
1423 // persist the change
1424 ASSERT_OK(PersistCFOptions(opts
));
1425 ASSERT_OK(SanityCheckCFOptions(opts
, kSanityLevelExactMatch
));
1429 for (int tb
= 0; tb
<= 2; ++tb
) {
1430 // change the table factory
1431 opts
.table_factory
.reset(test::RandomTableFactory(&rnd
, tb
));
1432 ASSERT_NOK(SanityCheckCFOptions(opts
, kSanityLevelLooselyCompatible
));
1433 ASSERT_OK(SanityCheckCFOptions(opts
, kSanityLevelNone
));
1435 // persist the change
1436 ASSERT_OK(PersistCFOptions(opts
));
1437 ASSERT_OK(SanityCheckCFOptions(opts
, kSanityLevelExactMatch
));
1443 for (int test
= 0; test
< 5; ++test
) {
1444 // change the merge operator
1445 opts
.merge_operator
.reset(test::RandomMergeOperator(&rnd
));
1446 ASSERT_NOK(SanityCheckCFOptions(opts
, kSanityLevelLooselyCompatible
));
1447 ASSERT_OK(SanityCheckCFOptions(opts
, kSanityLevelNone
));
1449 // persist the change
1450 ASSERT_OK(PersistCFOptions(opts
));
1451 ASSERT_OK(SanityCheckCFOptions(opts
, kSanityLevelExactMatch
));
1455 // compaction_filter
1457 for (int test
= 0; test
< 5; ++test
) {
1458 // change the compaction filter
1459 opts
.compaction_filter
= test::RandomCompactionFilter(&rnd
);
1460 ASSERT_NOK(SanityCheckCFOptions(opts
, kSanityLevelExactMatch
));
1461 ASSERT_OK(SanityCheckCFOptions(opts
, kSanityLevelLooselyCompatible
));
1463 // persist the change
1464 ASSERT_OK(PersistCFOptions(opts
));
1465 ASSERT_OK(SanityCheckCFOptions(opts
, kSanityLevelExactMatch
));
1466 delete opts
.compaction_filter
;
1467 opts
.compaction_filter
= nullptr;
1471 // compaction_filter_factory
1473 for (int test
= 0; test
< 5; ++test
) {
1474 // change the compaction filter factory
1475 opts
.compaction_filter_factory
.reset(
1476 test::RandomCompactionFilterFactory(&rnd
));
1477 ASSERT_NOK(SanityCheckCFOptions(opts
, kSanityLevelExactMatch
));
1478 ASSERT_OK(SanityCheckCFOptions(opts
, kSanityLevelLooselyCompatible
));
1480 // persist the change
1481 ASSERT_OK(PersistCFOptions(opts
));
1482 ASSERT_OK(SanityCheckCFOptions(opts
, kSanityLevelExactMatch
));
1488 bool IsEscapedString(const std::string
& str
) {
1489 for (size_t i
= 0; i
< str
.size(); ++i
) {
1490 if (str
[i
] == '\\') {
1491 // since we already handle those two consecutive '\'s in
1492 // the next if-then branch, any '\' appear at the end
1493 // of an escaped string in such case is not valid.
1494 if (i
== str
.size() - 1) {
1497 if (str
[i
+ 1] == '\\') {
1498 // if there're two consecutive '\'s, skip the second one.
1502 switch (str
[i
+ 1]) {
1508 // if true, '\' together with str[i + 1] is not a valid escape.
1509 if (UnescapeChar(str
[i
+ 1]) == str
[i
+ 1]) {
1513 } else if (isSpecialChar(str
[i
]) && (i
== 0 || str
[i
- 1] != '\\')) {
1521 TEST_F(OptionsParserTest
, EscapeOptionString
) {
1522 ASSERT_EQ(UnescapeOptionString(
1523 "This is a test string with \\# \\: and \\\\ escape chars."),
1524 "This is a test string with # : and \\ escape chars.");
1527 EscapeOptionString("This is a test string with # : and \\ escape chars."),
1528 "This is a test string with \\# \\: and \\\\ escape chars.");
1530 std::string readible_chars
=
1531 "A String like this \"1234567890-=_)(*&^%$#@!ertyuiop[]{POIU"
1532 "YTREWQasdfghjkl;':LKJHGFDSAzxcvbnm,.?>"
1533 "<MNBVCXZ\\\" should be okay to \\#\\\\\\:\\#\\#\\#\\ "
1534 "be serialized and deserialized";
1536 std::string escaped_string
= EscapeOptionString(readible_chars
);
1537 ASSERT_TRUE(IsEscapedString(escaped_string
));
1538 // This two transformations should be canceled and should output
1539 // the original input.
1540 ASSERT_EQ(UnescapeOptionString(escaped_string
), readible_chars
);
1542 std::string all_chars
;
1543 for (unsigned char c
= 0;; ++c
) {
1549 escaped_string
= EscapeOptionString(all_chars
);
1550 ASSERT_TRUE(IsEscapedString(escaped_string
));
1551 ASSERT_EQ(UnescapeOptionString(escaped_string
), all_chars
);
1553 ASSERT_EQ(RocksDBOptionsParser::TrimAndRemoveComment(
1554 " A simple statement with a comment. # like this :)"),
1555 "A simple statement with a comment.");
1557 ASSERT_EQ(RocksDBOptionsParser::TrimAndRemoveComment(
1558 "Escape \\# and # comment together ."),
1561 #endif // !ROCKSDB_LITE
1562 } // namespace rocksdb
1564 int main(int argc
, char** argv
) {
1565 ::testing::InitGoogleTest(&argc
, argv
);
1567 ParseCommandLineFlags(&argc
, &argv
, true);
1569 return RUN_ALL_TESTS();