/Users/deen/code/yugabyte-db/src/yb/rocksdb/util/options_test.cc
Line | Count | Source (jump to first uncovered line) |
1 | | |
2 | | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
3 | | // This source code is licensed under the BSD-style license found in the |
4 | | // LICENSE file in the root directory of this source tree. An additional grant |
5 | | // of patent rights can be found in the PATENTS file in the same directory. |
6 | | // |
7 | | // The following only applies to changes made to this file as part of YugaByte development. |
8 | | // |
9 | | // Portions Copyright (c) YugaByte, Inc. |
10 | | // |
11 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
12 | | // in compliance with the License. You may obtain a copy of the License at |
13 | | // |
14 | | // http://www.apache.org/licenses/LICENSE-2.0 |
15 | | // |
16 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
17 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
18 | | // or implied. See the License for the specific language governing permissions and limitations |
19 | | // under the License. |
20 | | // |
21 | | // Copyright (c) 2011 The LevelDB Authors. All rights reserved. |
22 | | // Use of this source code is governed by a BSD-style license that can be |
23 | | // found in the LICENSE file. See the AUTHORS file for names of contributors. |
24 | | |
25 | | #ifndef __STDC_FORMAT_MACROS |
26 | | #define __STDC_FORMAT_MACROS |
27 | | #endif |
28 | | |
29 | | #include <string> |
30 | | #include <unordered_map> |
31 | | |
32 | | #include <boost/preprocessor/stringize.hpp> |
33 | | |
34 | | #include <gtest/gtest.h> |
35 | | |
36 | | #include "yb/rocksdb/cache.h" |
37 | | #include "yb/rocksdb/convenience.h" |
38 | | #include "yb/rocksdb/memtablerep.h" |
39 | | #include "yb/rocksdb/utilities/leveldb_options.h" |
40 | | #include "yb/rocksdb/util/options_helper.h" |
41 | | #include "yb/rocksdb/util/options_parser.h" |
42 | | #include "yb/rocksdb/util/options_sanity_check.h" |
43 | | #include "yb/rocksdb/util/random.h" |
44 | | #include "yb/rocksdb/env.h" |
45 | | #include "yb/util/test_macros.h" |
46 | | #include "yb/rocksdb/util/testutil.h" |
47 | | #include "yb/util/format.h" |
48 | | |
49 | | #ifndef GFLAGS |
50 | | bool FLAGS_enable_print = false; |
51 | | #else |
52 | | #include <gflags/gflags.h> |
53 | | using GFLAGS::ParseCommandLineFlags; |
54 | | DEFINE_bool(enable_print, false, "Print options generated to console."); |
55 | | #endif // GFLAGS |
56 | | |
57 | | namespace rocksdb { |
58 | | |
59 | | class StderrLogger : public Logger { |
60 | | public: |
61 | | using Logger::Logv; |
62 | 0 | void Logv(const char* format, va_list ap) override { |
63 | 0 | vprintf(format, ap); |
64 | 0 | printf("\n"); |
65 | 0 | } |
66 | | }; |
67 | | |
68 | | Options PrintAndGetOptions(size_t total_write_buffer_limit, |
69 | | int read_amplification_threshold, |
70 | | int write_amplification_threshold, |
71 | 5 | uint64_t target_db_size = 68719476736) { |
72 | 5 | StderrLogger logger; |
73 | | |
74 | 5 | if (FLAGS_enable_print) { |
75 | 0 | printf("---- total_write_buffer_limit: %" ROCKSDB_PRIszt |
76 | 0 | " " |
77 | 0 | "read_amplification_threshold: %d write_amplification_threshold: %d " |
78 | 0 | "target_db_size %" PRIu64 " ----\n", |
79 | 0 | total_write_buffer_limit, read_amplification_threshold, |
80 | 0 | write_amplification_threshold, target_db_size); |
81 | 0 | } |
82 | | |
83 | 5 | Options options = |
84 | 5 | GetOptions(total_write_buffer_limit, read_amplification_threshold, |
85 | 5 | write_amplification_threshold, target_db_size); |
86 | 5 | if (FLAGS_enable_print) { |
87 | 0 | options.Dump(&logger); |
88 | 0 | printf("-------------------------------------\n\n\n"); |
89 | 0 | } |
90 | 5 | return options; |
91 | 5 | } |
92 | | |
93 | | class OptionsTest : public RocksDBTest {}; |
94 | | |
95 | 1 | TEST_F(OptionsTest, LooseCondition) { |
96 | 1 | Options options; |
97 | 1 | PrintAndGetOptions(static_cast<size_t>(10) * 1024 * 1024 * 1024, 100, 100); |
98 | | |
99 | | // Less mem table memory budget |
100 | 1 | PrintAndGetOptions(32 * 1024 * 1024, 100, 100); |
101 | | |
102 | | // Tight read amplification |
103 | 1 | options = PrintAndGetOptions(128 * 1024 * 1024, 8, 100); |
104 | 1 | ASSERT_EQ(options.compaction_style, kCompactionStyleLevel); |
105 | | |
106 | 1 | #ifndef ROCKSDB_LITE // Universal compaction is not supported in ROCKSDB_LITE |
107 | | // Tight write amplification |
108 | 1 | options = PrintAndGetOptions(128 * 1024 * 1024, 64, 10); |
109 | 1 | ASSERT_EQ(options.compaction_style, kCompactionStyleUniversal); |
110 | 1 | #endif // !ROCKSDB_LITE |
111 | | |
112 | | // Both tight amplifications |
113 | 1 | PrintAndGetOptions(128 * 1024 * 1024, 4, 8); |
114 | 1 | } |
115 | | |
116 | | #ifndef ROCKSDB_LITE // GetOptionsFromMap is not supported in ROCKSDB_LITE |
117 | 1 | TEST_F(OptionsTest, GetOptionsFromMapTest) { |
118 | 1 | std::unordered_map<std::string, std::string> cf_options_map = { |
119 | 1 | {"write_buffer_size", "1"}, |
120 | 1 | {"max_write_buffer_number", "2"}, |
121 | 1 | {"min_write_buffer_number_to_merge", "3"}, |
122 | 1 | {"max_write_buffer_number_to_maintain", "99"}, |
123 | 1 | {"compression", "kSnappyCompression"}, |
124 | 1 | {"compression_per_level", |
125 | 1 | "kNoCompression:" |
126 | 1 | "kSnappyCompression:" |
127 | 1 | "kZlibCompression:" |
128 | 1 | "kBZip2Compression:" |
129 | 1 | "kLZ4Compression:" |
130 | 1 | "kLZ4HCCompression:" |
131 | 1 | "kZSTDNotFinalCompression"}, |
132 | 1 | {"compression_opts", "4:5:6"}, |
133 | 1 | {"num_levels", "7"}, |
134 | 1 | {"level0_file_num_compaction_trigger", "8"}, |
135 | 1 | {"level0_slowdown_writes_trigger", "9"}, |
136 | 1 | {"level0_stop_writes_trigger", "10"}, |
137 | 1 | {"target_file_size_base", "12"}, |
138 | 1 | {"target_file_size_multiplier", "13"}, |
139 | 1 | {"max_bytes_for_level_base", "14"}, |
140 | 1 | {"level_compaction_dynamic_level_bytes", "true"}, |
141 | 1 | {"max_bytes_for_level_multiplier", "15"}, |
142 | 1 | {"max_bytes_for_level_multiplier_additional", "16:17:18"}, |
143 | 1 | {"expanded_compaction_factor", "19"}, |
144 | 1 | {"source_compaction_factor", "20"}, |
145 | 1 | {"max_grandparent_overlap_factor", "21"}, |
146 | 1 | {"soft_rate_limit", "1.1"}, |
147 | 1 | {"hard_rate_limit", "2.1"}, |
148 | 1 | {"hard_pending_compaction_bytes_limit", "211"}, |
149 | 1 | {"arena_block_size", "22"}, |
150 | 1 | {"disable_auto_compactions", "true"}, |
151 | 1 | {"compaction_style", "kCompactionStyleLevel"}, |
152 | 1 | {"verify_checksums_in_compaction", "false"}, |
153 | 1 | {"compaction_options_fifo", "23"}, |
154 | 1 | {"filter_deletes", "0"}, |
155 | 1 | {"max_sequential_skip_in_iterations", "24"}, |
156 | 1 | {"inplace_update_support", "true"}, |
157 | 1 | {"compaction_measure_io_stats", "true"}, |
158 | 1 | {"inplace_update_num_locks", "25"}, |
159 | 1 | {"memtable_prefix_bloom_bits", "26"}, |
160 | 1 | {"memtable_prefix_bloom_probes", "27"}, |
161 | 1 | {"memtable_prefix_bloom_huge_page_tlb_size", "28"}, |
162 | 1 | {"bloom_locality", "29"}, |
163 | 1 | {"max_successive_merges", "30"}, |
164 | 1 | {"min_partial_merge_operands", "31"}, |
165 | 1 | {"prefix_extractor", "fixed:31"}, |
166 | 1 | {"optimize_filters_for_hits", "true"}, |
167 | 1 | }; |
168 | | |
169 | 1 | std::unordered_map<std::string, std::string> db_options_map = { |
170 | 1 | {"create_if_missing", "false"}, |
171 | 1 | {"create_missing_column_families", "true"}, |
172 | 1 | {"error_if_exists", "false"}, |
173 | 1 | {"paranoid_checks", "true"}, |
174 | 1 | {"max_open_files", "32"}, |
175 | 1 | {"max_total_wal_size", "33"}, |
176 | 1 | {"disable_data_sync", "false"}, |
177 | 1 | {"use_fsync", "true"}, |
178 | 1 | {"db_log_dir", "/db_log_dir"}, |
179 | 1 | {"wal_dir", "/wal_dir"}, |
180 | 1 | {"delete_obsolete_files_period_micros", "34"}, |
181 | 1 | {"max_background_compactions", "35"}, |
182 | 1 | {"max_background_flushes", "36"}, |
183 | 1 | {"max_log_file_size", "37"}, |
184 | 1 | {"log_file_time_to_roll", "38"}, |
185 | 1 | {"keep_log_file_num", "39"}, |
186 | 1 | {"recycle_log_file_num", "5"}, |
187 | 1 | {"max_manifest_file_size", "40"}, |
188 | 1 | {"table_cache_numshardbits", "41"}, |
189 | 1 | {"WAL_ttl_seconds", "43"}, |
190 | 1 | {"WAL_size_limit_MB", "44"}, |
191 | 1 | {"manifest_preallocation_size", "45"}, |
192 | 1 | {"allow_os_buffer", "false"}, |
193 | 1 | {"allow_mmap_reads", "true"}, |
194 | 1 | {"allow_mmap_writes", "false"}, |
195 | 1 | {"is_fd_close_on_exec", "true"}, |
196 | 1 | {"skip_log_error_on_recovery", "false"}, |
197 | 1 | {"stats_dump_period_sec", "46"}, |
198 | 1 | {"advise_random_on_open", "true"}, |
199 | 1 | {"use_adaptive_mutex", "false"}, |
200 | 1 | {"new_table_reader_for_compaction_inputs", "true"}, |
201 | 1 | {"compaction_readahead_size", "100"}, |
202 | 1 | {"random_access_max_buffer_size", "3145728"}, |
203 | 1 | {"writable_file_max_buffer_size", "314159"}, |
204 | 1 | {"bytes_per_sync", "47"}, |
205 | 1 | {"wal_bytes_per_sync", "48"}, |
206 | 1 | }; |
207 | | |
208 | 1 | ColumnFamilyOptions base_cf_opt; |
209 | 1 | ColumnFamilyOptions new_cf_opt; |
210 | 1 | ASSERT_OK(GetColumnFamilyOptionsFromMap( |
211 | 1 | base_cf_opt, cf_options_map, &new_cf_opt)); |
212 | 1 | ASSERT_EQ(new_cf_opt.write_buffer_size, 1U); |
213 | 1 | ASSERT_EQ(new_cf_opt.max_write_buffer_number, 2); |
214 | 1 | ASSERT_EQ(new_cf_opt.min_write_buffer_number_to_merge, 3); |
215 | 1 | ASSERT_EQ(new_cf_opt.max_write_buffer_number_to_maintain, 99); |
216 | 1 | ASSERT_EQ(new_cf_opt.compression, kSnappyCompression); |
217 | 1 | ASSERT_EQ(new_cf_opt.compression_per_level.size(), 7U); |
218 | 1 | ASSERT_EQ(new_cf_opt.compression_per_level[0], kNoCompression); |
219 | 1 | ASSERT_EQ(new_cf_opt.compression_per_level[1], kSnappyCompression); |
220 | 1 | ASSERT_EQ(new_cf_opt.compression_per_level[2], kZlibCompression); |
221 | 1 | ASSERT_EQ(new_cf_opt.compression_per_level[3], kBZip2Compression); |
222 | 1 | ASSERT_EQ(new_cf_opt.compression_per_level[4], kLZ4Compression); |
223 | 1 | ASSERT_EQ(new_cf_opt.compression_per_level[5], kLZ4HCCompression); |
224 | 1 | ASSERT_EQ(new_cf_opt.compression_per_level[6], kZSTDNotFinalCompression); |
225 | 1 | ASSERT_EQ(new_cf_opt.compression_opts.window_bits, 4); |
226 | 1 | ASSERT_EQ(new_cf_opt.compression_opts.level, 5); |
227 | 1 | ASSERT_EQ(new_cf_opt.compression_opts.strategy, 6); |
228 | 1 | ASSERT_EQ(new_cf_opt.num_levels, 7); |
229 | 1 | ASSERT_EQ(new_cf_opt.level0_file_num_compaction_trigger, 8); |
230 | 1 | ASSERT_EQ(new_cf_opt.level0_slowdown_writes_trigger, 9); |
231 | 1 | ASSERT_EQ(new_cf_opt.level0_stop_writes_trigger, 10); |
232 | 1 | ASSERT_EQ(new_cf_opt.target_file_size_base, static_cast<uint64_t>(12)); |
233 | 1 | ASSERT_EQ(new_cf_opt.target_file_size_multiplier, 13); |
234 | 1 | ASSERT_EQ(new_cf_opt.max_bytes_for_level_base, 14U); |
235 | 1 | ASSERT_EQ(new_cf_opt.level_compaction_dynamic_level_bytes, true); |
236 | 1 | ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier, 15); |
237 | 1 | ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier_additional.size(), 3U); |
238 | 1 | ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier_additional[0], 16); |
239 | 1 | ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier_additional[1], 17); |
240 | 1 | ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier_additional[2], 18); |
241 | 1 | ASSERT_EQ(new_cf_opt.expanded_compaction_factor, 19); |
242 | 1 | ASSERT_EQ(new_cf_opt.source_compaction_factor, 20); |
243 | 1 | ASSERT_EQ(new_cf_opt.max_grandparent_overlap_factor, 21); |
244 | 1 | ASSERT_EQ(new_cf_opt.soft_rate_limit, 1.1); |
245 | 1 | ASSERT_EQ(new_cf_opt.hard_pending_compaction_bytes_limit, 211); |
246 | 1 | ASSERT_EQ(new_cf_opt.arena_block_size, 22U); |
247 | 1 | ASSERT_EQ(new_cf_opt.disable_auto_compactions, true); |
248 | 1 | ASSERT_EQ(new_cf_opt.compaction_style, kCompactionStyleLevel); |
249 | 1 | ASSERT_EQ(new_cf_opt.verify_checksums_in_compaction, false); |
250 | 1 | ASSERT_EQ(new_cf_opt.compaction_options_fifo.max_table_files_size, |
251 | 1 | static_cast<uint64_t>(23)); |
252 | 1 | ASSERT_EQ(new_cf_opt.filter_deletes, false); |
253 | 1 | ASSERT_EQ(new_cf_opt.max_sequential_skip_in_iterations, |
254 | 1 | static_cast<uint64_t>(24)); |
255 | 1 | ASSERT_EQ(new_cf_opt.inplace_update_support, true); |
256 | 1 | ASSERT_EQ(new_cf_opt.inplace_update_num_locks, 25U); |
257 | 1 | ASSERT_EQ(new_cf_opt.memtable_prefix_bloom_bits, 26U); |
258 | 1 | ASSERT_EQ(new_cf_opt.memtable_prefix_bloom_probes, 27U); |
259 | 1 | ASSERT_EQ(new_cf_opt.memtable_prefix_bloom_huge_page_tlb_size, 28U); |
260 | 1 | ASSERT_EQ(new_cf_opt.bloom_locality, 29U); |
261 | 1 | ASSERT_EQ(new_cf_opt.max_successive_merges, 30U); |
262 | 1 | ASSERT_EQ(new_cf_opt.min_partial_merge_operands, 31U); |
263 | 1 | ASSERT_TRUE(new_cf_opt.prefix_extractor != nullptr); |
264 | 1 | ASSERT_EQ(new_cf_opt.optimize_filters_for_hits, true); |
265 | 1 | ASSERT_EQ(std::string(new_cf_opt.prefix_extractor->Name()), |
266 | 1 | "rocksdb.FixedPrefix.31"); |
267 | | |
268 | 1 | cf_options_map["write_buffer_size"] = "hello"; |
269 | 1 | ASSERT_NOK(GetColumnFamilyOptionsFromMap( |
270 | 1 | base_cf_opt, cf_options_map, &new_cf_opt)); |
271 | 1 | cf_options_map["write_buffer_size"] = "1"; |
272 | 1 | ASSERT_OK(GetColumnFamilyOptionsFromMap( |
273 | 1 | base_cf_opt, cf_options_map, &new_cf_opt)); |
274 | 1 | cf_options_map["unknown_option"] = "1"; |
275 | 1 | ASSERT_NOK(GetColumnFamilyOptionsFromMap( |
276 | 1 | base_cf_opt, cf_options_map, &new_cf_opt)); |
277 | | |
278 | 1 | DBOptions base_db_opt; |
279 | 1 | DBOptions new_db_opt; |
280 | 1 | ASSERT_OK(GetDBOptionsFromMap(base_db_opt, db_options_map, &new_db_opt)); |
281 | 1 | ASSERT_EQ(new_db_opt.create_if_missing, false); |
282 | 1 | ASSERT_EQ(new_db_opt.create_missing_column_families, true); |
283 | 1 | ASSERT_EQ(new_db_opt.error_if_exists, false); |
284 | 1 | ASSERT_EQ(new_db_opt.paranoid_checks, true); |
285 | 1 | ASSERT_EQ(new_db_opt.max_open_files, 32); |
286 | 1 | ASSERT_EQ(new_db_opt.max_total_wal_size, static_cast<uint64_t>(33)); |
287 | 1 | ASSERT_EQ(new_db_opt.disableDataSync, false); |
288 | 1 | ASSERT_EQ(new_db_opt.use_fsync, true); |
289 | 1 | ASSERT_EQ(new_db_opt.db_log_dir, "/db_log_dir"); |
290 | 1 | ASSERT_EQ(new_db_opt.wal_dir, "/wal_dir"); |
291 | 1 | ASSERT_EQ(new_db_opt.delete_obsolete_files_period_micros, |
292 | 1 | static_cast<uint64_t>(34)); |
293 | 1 | ASSERT_EQ(new_db_opt.max_background_compactions, 35); |
294 | 1 | ASSERT_EQ(new_db_opt.max_background_flushes, 36); |
295 | 1 | ASSERT_EQ(new_db_opt.max_log_file_size, 37U); |
296 | 1 | ASSERT_EQ(new_db_opt.log_file_time_to_roll, 38U); |
297 | 1 | ASSERT_EQ(new_db_opt.keep_log_file_num, 39U); |
298 | 1 | ASSERT_EQ(new_db_opt.recycle_log_file_num, 5U); |
299 | 1 | ASSERT_EQ(new_db_opt.max_manifest_file_size, static_cast<uint64_t>(40)); |
300 | 1 | ASSERT_EQ(new_db_opt.table_cache_numshardbits, 41); |
301 | 1 | ASSERT_EQ(new_db_opt.WAL_ttl_seconds, static_cast<uint64_t>(43)); |
302 | 1 | ASSERT_EQ(new_db_opt.WAL_size_limit_MB, static_cast<uint64_t>(44)); |
303 | 1 | ASSERT_EQ(new_db_opt.manifest_preallocation_size, 45U); |
304 | 1 | ASSERT_EQ(new_db_opt.allow_os_buffer, false); |
305 | 1 | ASSERT_EQ(new_db_opt.allow_mmap_reads, true); |
306 | 1 | ASSERT_EQ(new_db_opt.allow_mmap_writes, false); |
307 | 1 | ASSERT_EQ(new_db_opt.is_fd_close_on_exec, true); |
308 | 1 | ASSERT_EQ(new_db_opt.skip_log_error_on_recovery, false); |
309 | 1 | ASSERT_EQ(new_db_opt.stats_dump_period_sec, 46U); |
310 | 1 | ASSERT_EQ(new_db_opt.advise_random_on_open, true); |
311 | 1 | ASSERT_EQ(new_db_opt.use_adaptive_mutex, false); |
312 | 1 | ASSERT_EQ(new_db_opt.new_table_reader_for_compaction_inputs, true); |
313 | 1 | ASSERT_EQ(new_db_opt.compaction_readahead_size, 100); |
314 | 1 | ASSERT_EQ(new_db_opt.random_access_max_buffer_size, 3145728); |
315 | 1 | ASSERT_EQ(new_db_opt.writable_file_max_buffer_size, 314159); |
316 | 1 | ASSERT_EQ(new_db_opt.bytes_per_sync, static_cast<uint64_t>(47)); |
317 | 1 | ASSERT_EQ(new_db_opt.wal_bytes_per_sync, static_cast<uint64_t>(48)); |
318 | 1 | } |
319 | | #endif // !ROCKSDB_LITE |
320 | | |
321 | | #ifndef ROCKSDB_LITE // GetColumnFamilyOptionsFromString is not supported in |
322 | | // ROCKSDB_LITE |
323 | 1 | TEST_F(OptionsTest, GetColumnFamilyOptionsFromStringTest) { |
324 | 1 | ColumnFamilyOptions base_cf_opt; |
325 | 1 | ColumnFamilyOptions new_cf_opt; |
326 | 1 | base_cf_opt.table_factory.reset(); |
327 | 1 | ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt, "", &new_cf_opt)); |
328 | 1 | ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt, |
329 | 1 | "write_buffer_size=5", &new_cf_opt)); |
330 | 1 | ASSERT_EQ(new_cf_opt.write_buffer_size, 5U); |
331 | 1 | ASSERT_TRUE(new_cf_opt.table_factory == nullptr); |
332 | 1 | ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt, |
333 | 1 | "write_buffer_size=6;", &new_cf_opt)); |
334 | 1 | ASSERT_EQ(new_cf_opt.write_buffer_size, 6U); |
335 | 1 | ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt, |
336 | 1 | " write_buffer_size = 7 ", &new_cf_opt)); |
337 | 1 | ASSERT_EQ(new_cf_opt.write_buffer_size, 7U); |
338 | 1 | ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt, |
339 | 1 | " write_buffer_size = 8 ; ", &new_cf_opt)); |
340 | 1 | ASSERT_EQ(new_cf_opt.write_buffer_size, 8U); |
341 | 1 | ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt, |
342 | 1 | "write_buffer_size=9;max_write_buffer_number=10", &new_cf_opt)); |
343 | 1 | ASSERT_EQ(new_cf_opt.write_buffer_size, 9U); |
344 | 1 | ASSERT_EQ(new_cf_opt.max_write_buffer_number, 10); |
345 | 1 | ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt, |
346 | 1 | "write_buffer_size=11; max_write_buffer_number = 12 ;", |
347 | 1 | &new_cf_opt)); |
348 | 1 | ASSERT_EQ(new_cf_opt.write_buffer_size, 11U); |
349 | 1 | ASSERT_EQ(new_cf_opt.max_write_buffer_number, 12); |
350 | | // Wrong name "max_write_buffer_number_" |
351 | 1 | ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt, |
352 | 1 | "write_buffer_size=13;max_write_buffer_number_=14;", |
353 | 1 | &new_cf_opt)); |
354 | | // Wrong key/value pair |
355 | 1 | ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt, |
356 | 1 | "write_buffer_size=13;max_write_buffer_number;", &new_cf_opt)); |
357 | | // Error Paring value |
358 | 1 | ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt, |
359 | 1 | "write_buffer_size=13;max_write_buffer_number=;", &new_cf_opt)); |
360 | | // Missing option name |
361 | 1 | ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt, |
362 | 1 | "write_buffer_size=13; =100;", &new_cf_opt)); |
363 | | |
364 | 1 | const int64_t kilo = 1024UL; |
365 | 1 | const int64_t mega = 1024 * kilo; |
366 | 1 | const int64_t giga = 1024 * mega; |
367 | 1 | const int64_t tera = 1024 * giga; |
368 | | |
369 | | // Units (k) |
370 | 1 | ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt, |
371 | 1 | "memtable_prefix_bloom_bits=14k;max_write_buffer_number=-15K", |
372 | 1 | &new_cf_opt)); |
373 | 1 | ASSERT_EQ(new_cf_opt.memtable_prefix_bloom_bits, 14UL * kilo); |
374 | 1 | ASSERT_EQ(new_cf_opt.max_write_buffer_number, -15 * kilo); |
375 | | // Units (m) |
376 | 1 | ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt, |
377 | 1 | "max_write_buffer_number=16m;inplace_update_num_locks=17M", |
378 | 1 | &new_cf_opt)); |
379 | 1 | ASSERT_EQ(new_cf_opt.max_write_buffer_number, 16 * mega); |
380 | 1 | ASSERT_EQ(new_cf_opt.inplace_update_num_locks, 17 * mega); |
381 | | // Units (g) |
382 | 1 | ASSERT_OK(GetColumnFamilyOptionsFromString( |
383 | 1 | base_cf_opt, |
384 | 1 | "write_buffer_size=18g;prefix_extractor=capped:8;" |
385 | 1 | "arena_block_size=19G", |
386 | 1 | &new_cf_opt)); |
387 | | |
388 | 1 | ASSERT_EQ(new_cf_opt.write_buffer_size, 18 * giga); |
389 | 1 | ASSERT_EQ(new_cf_opt.arena_block_size, 19 * giga); |
390 | 1 | ASSERT_TRUE(new_cf_opt.prefix_extractor.get() != nullptr); |
391 | 1 | std::string prefix_name(new_cf_opt.prefix_extractor->Name()); |
392 | 1 | ASSERT_EQ(prefix_name, "rocksdb.CappedPrefix.8"); |
393 | | |
394 | | // Units (t) |
395 | 1 | ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt, |
396 | 1 | "write_buffer_size=20t;arena_block_size=21T", &new_cf_opt)); |
397 | 1 | ASSERT_EQ(new_cf_opt.write_buffer_size, 20 * tera); |
398 | 1 | ASSERT_EQ(new_cf_opt.arena_block_size, 21 * tera); |
399 | | |
400 | | // Nested block based table options |
401 | | // Emtpy |
402 | 1 | ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt, |
403 | 1 | "write_buffer_size=10;max_write_buffer_number=16;" |
404 | 1 | "block_based_table_factory={};arena_block_size=1024", |
405 | 1 | &new_cf_opt)); |
406 | 1 | ASSERT_TRUE(new_cf_opt.table_factory != nullptr); |
407 | | // Non-empty |
408 | 1 | ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt, |
409 | 1 | "write_buffer_size=10;max_write_buffer_number=16;" |
410 | 1 | "block_based_table_factory={block_cache=1M;block_size=4;};" |
411 | 1 | "arena_block_size=1024", |
412 | 1 | &new_cf_opt)); |
413 | 1 | ASSERT_TRUE(new_cf_opt.table_factory != nullptr); |
414 | | // Last one |
415 | 1 | ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt, |
416 | 1 | "write_buffer_size=10;max_write_buffer_number=16;" |
417 | 1 | "block_based_table_factory={block_cache=1M;block_size=4;}", |
418 | 1 | &new_cf_opt)); |
419 | 1 | ASSERT_TRUE(new_cf_opt.table_factory != nullptr); |
420 | | // Mismatch curly braces |
421 | 1 | ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt, |
422 | 1 | "write_buffer_size=10;max_write_buffer_number=16;" |
423 | 1 | "block_based_table_factory={{{block_size=4;};" |
424 | 1 | "arena_block_size=1024", |
425 | 1 | &new_cf_opt)); |
426 | | // Unexpected chars after closing curly brace |
427 | 1 | ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt, |
428 | 1 | "write_buffer_size=10;max_write_buffer_number=16;" |
429 | 1 | "block_based_table_factory={block_size=4;}};" |
430 | 1 | "arena_block_size=1024", |
431 | 1 | &new_cf_opt)); |
432 | 1 | ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt, |
433 | 1 | "write_buffer_size=10;max_write_buffer_number=16;" |
434 | 1 | "block_based_table_factory={block_size=4;}xdfa;" |
435 | 1 | "arena_block_size=1024", |
436 | 1 | &new_cf_opt)); |
437 | 1 | ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt, |
438 | 1 | "write_buffer_size=10;max_write_buffer_number=16;" |
439 | 1 | "block_based_table_factory={block_size=4;}xdfa", |
440 | 1 | &new_cf_opt)); |
441 | | // Invalid block based table option |
442 | 1 | ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt, |
443 | 1 | "write_buffer_size=10;max_write_buffer_number=16;" |
444 | 1 | "block_based_table_factory={xx_block_size=4;}", |
445 | 1 | &new_cf_opt)); |
446 | 1 | ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt, |
447 | 1 | "optimize_filters_for_hits=true", |
448 | 1 | &new_cf_opt)); |
449 | 1 | ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt, |
450 | 1 | "optimize_filters_for_hits=false", |
451 | 1 | &new_cf_opt)); |
452 | 1 | ASSERT_NOK(GetColumnFamilyOptionsFromString(base_cf_opt, |
453 | 1 | "optimize_filters_for_hits=junk", |
454 | 1 | &new_cf_opt)); |
455 | | |
456 | | // Nested plain table options |
457 | | // Emtpy |
458 | 1 | ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt, |
459 | 1 | "write_buffer_size=10;max_write_buffer_number=16;" |
460 | 1 | "plain_table_factory={};arena_block_size=1024", |
461 | 1 | &new_cf_opt)); |
462 | 1 | ASSERT_TRUE(new_cf_opt.table_factory != nullptr); |
463 | 1 | ASSERT_EQ(std::string(new_cf_opt.table_factory->Name()), "PlainTable"); |
464 | | // Non-empty |
465 | 1 | ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt, |
466 | 1 | "write_buffer_size=10;max_write_buffer_number=16;" |
467 | 1 | "plain_table_factory={user_key_len=66;bloom_bits_per_key=20;};" |
468 | 1 | "arena_block_size=1024", |
469 | 1 | &new_cf_opt)); |
470 | 1 | ASSERT_TRUE(new_cf_opt.table_factory != nullptr); |
471 | 1 | ASSERT_EQ(std::string(new_cf_opt.table_factory->Name()), "PlainTable"); |
472 | | |
473 | | // memtable factory |
474 | 1 | ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt, |
475 | 1 | "write_buffer_size=10;max_write_buffer_number=16;" |
476 | 1 | "memtable=skip_list:10;arena_block_size=1024", |
477 | 1 | &new_cf_opt)); |
478 | 1 | ASSERT_TRUE(new_cf_opt.memtable_factory != nullptr); |
479 | 1 | ASSERT_EQ(std::string(new_cf_opt.memtable_factory->Name()), "SkipListFactory"); |
480 | 1 | } |
481 | | #endif // !ROCKSDB_LITE |
482 | | |
483 | | #ifndef ROCKSDB_LITE // GetBlockBasedTableOptionsFromString is not supported |
484 | 1 | TEST_F(OptionsTest, GetBlockBasedTableOptionsFromString) { |
485 | 1 | BlockBasedTableOptions table_opt; |
486 | 1 | BlockBasedTableOptions new_opt; |
487 | | // make sure default values are overwritten by something else |
488 | 1 | ASSERT_OK(GetBlockBasedTableOptionsFromString(table_opt, |
489 | 1 | "cache_index_and_filter_blocks=1;index_type=kHashSearch;" |
490 | 1 | "checksum=kxxHash;hash_index_allow_collision=1;no_block_cache=1;" |
491 | 1 | "block_cache=1M;block_cache_compressed=1k;block_size=1024;filter_block_size=4096;" |
492 | 1 | "block_size_deviation=8;block_restart_interval=4;index_block_size=16384;" |
493 | 1 | "min_keys_per_index_block=16;filter_policy=bloomfilter:4:true;whole_key_filtering=1;" |
494 | 1 | "skip_table_builder_flush=1", |
495 | 1 | &new_opt)); |
496 | 1 | ASSERT_TRUE(new_opt.cache_index_and_filter_blocks); |
497 | 1 | ASSERT_EQ(new_opt.index_type, IndexType::kHashSearch); |
498 | 1 | ASSERT_EQ(new_opt.checksum, ChecksumType::kxxHash); |
499 | 1 | ASSERT_TRUE(new_opt.hash_index_allow_collision); |
500 | 1 | ASSERT_TRUE(new_opt.no_block_cache); |
501 | 1 | ASSERT_TRUE(new_opt.block_cache != nullptr); |
502 | 1 | ASSERT_EQ(new_opt.block_cache->GetCapacity(), 1024UL*1024UL); |
503 | 1 | ASSERT_TRUE(new_opt.block_cache_compressed != nullptr); |
504 | 1 | ASSERT_EQ(new_opt.block_cache_compressed->GetCapacity(), 1024UL); |
505 | 1 | ASSERT_EQ(new_opt.block_size, 1024UL); |
506 | 1 | ASSERT_EQ(new_opt.filter_block_size, 4096UL); |
507 | 1 | ASSERT_EQ(new_opt.block_size_deviation, 8); |
508 | 1 | ASSERT_EQ(new_opt.block_restart_interval, 4); |
509 | 1 | ASSERT_EQ(new_opt.index_block_size, 16384UL); |
510 | 1 | ASSERT_EQ(new_opt.min_keys_per_index_block, 16); |
511 | 1 | ASSERT_TRUE(new_opt.filter_policy != nullptr); |
512 | 1 | ASSERT_TRUE(new_opt.skip_table_builder_flush); |
513 | | |
514 | | // unknown option |
515 | 1 | ASSERT_NOK(GetBlockBasedTableOptionsFromString(table_opt, |
516 | 1 | "cache_index_and_filter_blocks=1;index_type=kBinarySearch;" |
517 | 1 | "bad_option=1", |
518 | 1 | &new_opt)); |
519 | | |
520 | | // unrecognized index type |
521 | 1 | ASSERT_NOK(GetBlockBasedTableOptionsFromString(table_opt, |
522 | 1 | "cache_index_and_filter_blocks=1;index_type=kBinarySearchXX", |
523 | 1 | &new_opt)); |
524 | | |
525 | | // unrecognized checksum type |
526 | 1 | ASSERT_NOK(GetBlockBasedTableOptionsFromString(table_opt, |
527 | 1 | "cache_index_and_filter_blocks=1;checksum=kxxHashXX", |
528 | 1 | &new_opt)); |
529 | | |
530 | | // unrecognized filter policy name |
531 | 1 | ASSERT_NOK(GetBlockBasedTableOptionsFromString(table_opt, |
532 | 1 | "cache_index_and_filter_blocks=1;" |
533 | 1 | "filter_policy=bloomfilterxx:4:true", |
534 | 1 | &new_opt)); |
535 | | // unrecognized filter policy config |
536 | 1 | ASSERT_NOK(GetBlockBasedTableOptionsFromString(table_opt, |
537 | 1 | "cache_index_and_filter_blocks=1;" |
538 | 1 | "filter_policy=bloomfilter:4", |
539 | 1 | &new_opt)); |
540 | 1 | } |
541 | | #endif // !ROCKSDB_LITE |
542 | | |
543 | | |
544 | | #ifndef ROCKSDB_LITE // GetPlainTableOptionsFromString is not supported |
545 | 1 | TEST_F(OptionsTest, GetPlainTableOptionsFromString) { |
546 | 1 | PlainTableOptions table_opt; |
547 | 1 | PlainTableOptions new_opt; |
548 | | // make sure default values are overwritten by something else |
549 | 1 | ASSERT_OK(GetPlainTableOptionsFromString(table_opt, |
550 | 1 | "user_key_len=66;bloom_bits_per_key=20;hash_table_ratio=0.5;" |
551 | 1 | "index_sparseness=8;huge_page_tlb_size=4;encoding_type=kPrefix;" |
552 | 1 | "full_scan_mode=true;store_index_in_file=true", |
553 | 1 | &new_opt)); |
554 | 1 | ASSERT_EQ(new_opt.user_key_len, 66); |
555 | 1 | ASSERT_EQ(new_opt.bloom_bits_per_key, 20); |
556 | 1 | ASSERT_EQ(new_opt.hash_table_ratio, 0.5); |
557 | 1 | ASSERT_EQ(new_opt.index_sparseness, 8); |
558 | 1 | ASSERT_EQ(new_opt.huge_page_tlb_size, 4); |
559 | 1 | ASSERT_EQ(new_opt.encoding_type, EncodingType::kPrefix); |
560 | 1 | ASSERT_TRUE(new_opt.full_scan_mode); |
561 | 1 | ASSERT_TRUE(new_opt.store_index_in_file); |
562 | | |
563 | | // unknown option |
564 | 1 | ASSERT_NOK(GetPlainTableOptionsFromString(table_opt, |
565 | 1 | "user_key_len=66;bloom_bits_per_key=20;hash_table_ratio=0.5;" |
566 | 1 | "bad_option=1", |
567 | 1 | &new_opt)); |
568 | | |
569 | | // unrecognized EncodingType |
570 | 1 | ASSERT_NOK(GetPlainTableOptionsFromString(table_opt, |
571 | 1 | "user_key_len=66;bloom_bits_per_key=20;hash_table_ratio=0.5;" |
572 | 1 | "encoding_type=kPrefixXX", |
573 | 1 | &new_opt)); |
574 | 1 | } |
575 | | #endif // !ROCKSDB_LITE |
576 | | |
577 | | #ifndef ROCKSDB_LITE // GetMemTableRepFactoryFromString is not supported |
578 | 1 | TEST_F(OptionsTest, GetMemTableRepFactoryFromString) { |
579 | 1 | std::unique_ptr<MemTableRepFactory> new_mem_factory = nullptr; |
580 | | |
581 | 1 | ASSERT_OK(GetMemTableRepFactoryFromString("skip_list", &new_mem_factory)); |
582 | 1 | ASSERT_OK(GetMemTableRepFactoryFromString("skip_list:16", &new_mem_factory)); |
583 | 1 | ASSERT_EQ(std::string(new_mem_factory->Name()), "SkipListFactory"); |
584 | 1 | ASSERT_NOK(GetMemTableRepFactoryFromString("skip_list:16:invalid_opt", |
585 | 1 | &new_mem_factory)); |
586 | | |
587 | 1 | ASSERT_OK(GetMemTableRepFactoryFromString("prefix_hash", &new_mem_factory)); |
588 | 1 | ASSERT_OK(GetMemTableRepFactoryFromString("prefix_hash:1000", |
589 | 1 | &new_mem_factory)); |
590 | 1 | ASSERT_EQ(std::string(new_mem_factory->Name()), "HashSkipListRepFactory"); |
591 | 1 | ASSERT_NOK(GetMemTableRepFactoryFromString("prefix_hash:1000:invalid_opt", |
592 | 1 | &new_mem_factory)); |
593 | | |
594 | 1 | ASSERT_OK(GetMemTableRepFactoryFromString("hash_linkedlist", |
595 | 1 | &new_mem_factory)); |
596 | 1 | ASSERT_OK(GetMemTableRepFactoryFromString("hash_linkedlist:1000", |
597 | 1 | &new_mem_factory)); |
598 | 1 | ASSERT_EQ(std::string(new_mem_factory->Name()), "HashLinkListRepFactory"); |
599 | 1 | ASSERT_NOK(GetMemTableRepFactoryFromString("hash_linkedlist:1000:invalid_opt", |
600 | 1 | &new_mem_factory)); |
601 | | |
602 | 1 | ASSERT_OK(GetMemTableRepFactoryFromString("vector", &new_mem_factory)); |
603 | 1 | ASSERT_OK(GetMemTableRepFactoryFromString("vector:1024", &new_mem_factory)); |
604 | 1 | ASSERT_EQ(std::string(new_mem_factory->Name()), "VectorRepFactory"); |
605 | 1 | ASSERT_NOK(GetMemTableRepFactoryFromString("vector:1024:invalid_opt", |
606 | 1 | &new_mem_factory)); |
607 | | |
608 | 1 | ASSERT_NOK(GetMemTableRepFactoryFromString("bad_factory", &new_mem_factory)); |
609 | 1 | } |
610 | | #endif // !ROCKSDB_LITE |
611 | | |
612 | | #ifndef ROCKSDB_LITE // GetOptionsFromString is not supported in RocksDB Lite |
613 | 1 | TEST_F(OptionsTest, GetOptionsFromStringTest) { |
614 | 1 | Options base_options, new_options; |
615 | 1 | base_options.write_buffer_size = 20; |
616 | 1 | base_options.min_write_buffer_number_to_merge = 15; |
617 | 1 | BlockBasedTableOptions block_based_table_options; |
618 | 1 | block_based_table_options.cache_index_and_filter_blocks = true; |
619 | 1 | base_options.table_factory.reset( |
620 | 1 | NewBlockBasedTableFactory(block_based_table_options)); |
621 | 1 | ASSERT_OK(GetOptionsFromString( |
622 | 1 | base_options, |
623 | 1 | "write_buffer_size=10;max_write_buffer_number=16;" |
624 | 1 | "block_based_table_factory={block_cache=1M;block_size=4;};" |
625 | 1 | "create_if_missing=true;max_open_files=1;rate_limiter_bytes_per_sec=1024", |
626 | 1 | &new_options)); |
627 | | |
628 | 1 | ASSERT_EQ(new_options.write_buffer_size, 10U); |
629 | 1 | ASSERT_EQ(new_options.max_write_buffer_number, 16); |
630 | 1 | BlockBasedTableOptions new_block_based_table_options = |
631 | 1 | dynamic_cast<BlockBasedTableFactory*>(new_options.table_factory.get()) |
632 | 1 | ->table_options(); |
633 | 1 | ASSERT_EQ(new_block_based_table_options.block_cache->GetCapacity(), 1U << 20); |
634 | 1 | ASSERT_EQ(new_block_based_table_options.block_size, 4U); |
635 | | // don't overwrite block based table options |
636 | 1 | ASSERT_TRUE(new_block_based_table_options.cache_index_and_filter_blocks); |
637 | | |
638 | 1 | ASSERT_EQ(new_options.create_if_missing, true); |
639 | 1 | ASSERT_EQ(new_options.max_open_files, 1); |
640 | 1 | ASSERT_TRUE(new_options.rate_limiter.get() != nullptr); |
641 | 1 | } |
642 | | |
643 | 1 | TEST_F(OptionsTest, DBOptionsSerialization) { |
644 | 1 | Options base_options, new_options; |
645 | 1 | Random rnd(301); |
646 | | |
647 | | // Phase 1: Make big change in base_options |
648 | 1 | test::RandomInitDBOptions(&base_options, &rnd); |
649 | | |
650 | | // Phase 2: obtain a string from base_option |
651 | 1 | std::string base_options_file_content; |
652 | 1 | ASSERT_OK(GetStringFromDBOptions(&base_options_file_content, base_options)); |
653 | | |
654 | | // Phase 3: Set new_options from the derived string and expect |
655 | | // new_options == base_options |
656 | 1 | ASSERT_OK(GetDBOptionsFromString(DBOptions(), base_options_file_content, |
657 | 1 | &new_options)); |
658 | 1 | ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(base_options, new_options)); |
659 | 1 | } |
660 | | |
661 | 1 | TEST_F(OptionsTest, ColumnFamilyOptionsSerialization) { |
662 | 1 | ColumnFamilyOptions base_opt, new_opt; |
663 | 1 | Random rnd(302); |
664 | | // Phase 1: randomly assign base_opt |
665 | | // custom type options |
666 | 1 | test::RandomInitCFOptions(&base_opt, &rnd); |
667 | | |
668 | | // Phase 2: obtain a string from base_opt |
669 | 1 | std::string base_options_file_content; |
670 | 1 | ASSERT_OK( |
671 | 1 | GetStringFromColumnFamilyOptions(&base_options_file_content, base_opt)); |
672 | | |
673 | | // Phase 3: Set new_opt from the derived string and expect |
674 | | // new_opt == base_opt |
675 | 1 | ASSERT_OK(GetColumnFamilyOptionsFromString( |
676 | 1 | ColumnFamilyOptions(), base_options_file_content, &new_opt)); |
677 | 1 | ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(base_opt, new_opt)); |
678 | 1 | if (base_opt.compaction_filter) { |
679 | 1 | delete base_opt.compaction_filter; |
680 | 1 | } |
681 | 1 | } |
682 | | |
683 | | #endif // !ROCKSDB_LITE |
684 | | |
685 | | Status StringToMap( |
686 | | const std::string& opts_str, |
687 | | std::unordered_map<std::string, std::string>* opts_map); |
688 | | |
689 | | #ifndef ROCKSDB_LITE // StringToMap is not supported in ROCKSDB_LITE |
690 | 1 | TEST_F(OptionsTest, StringToMapTest) { |
691 | 1 | std::unordered_map<std::string, std::string> opts_map; |
692 | | // Regular options |
693 | 1 | ASSERT_OK(StringToMap("k1=v1;k2=v2;k3=v3", &opts_map)); |
694 | 1 | ASSERT_EQ(opts_map["k1"], "v1"); |
695 | 1 | ASSERT_EQ(opts_map["k2"], "v2"); |
696 | 1 | ASSERT_EQ(opts_map["k3"], "v3"); |
697 | | // Value with '=' |
698 | 1 | opts_map.clear(); |
699 | 1 | ASSERT_OK(StringToMap("k1==v1;k2=v2=;", &opts_map)); |
700 | 1 | ASSERT_EQ(opts_map["k1"], "=v1"); |
701 | 1 | ASSERT_EQ(opts_map["k2"], "v2="); |
702 | | // Overwrriten option |
703 | 1 | opts_map.clear(); |
704 | 1 | ASSERT_OK(StringToMap("k1=v1;k1=v2;k3=v3", &opts_map)); |
705 | 1 | ASSERT_EQ(opts_map["k1"], "v2"); |
706 | 1 | ASSERT_EQ(opts_map["k3"], "v3"); |
707 | | // Empty value |
708 | 1 | opts_map.clear(); |
709 | 1 | ASSERT_OK(StringToMap("k1=v1;k2=;k3=v3;k4=", &opts_map)); |
710 | 1 | ASSERT_EQ(opts_map["k1"], "v1"); |
711 | 1 | ASSERT_TRUE(opts_map.find("k2") != opts_map.end()); |
712 | 1 | ASSERT_EQ(opts_map["k2"], ""); |
713 | 1 | ASSERT_EQ(opts_map["k3"], "v3"); |
714 | 1 | ASSERT_TRUE(opts_map.find("k4") != opts_map.end()); |
715 | 1 | ASSERT_EQ(opts_map["k4"], ""); |
716 | 1 | opts_map.clear(); |
717 | 1 | ASSERT_OK(StringToMap("k1=v1;k2=;k3=v3;k4= ", &opts_map)); |
718 | 1 | ASSERT_EQ(opts_map["k1"], "v1"); |
719 | 1 | ASSERT_TRUE(opts_map.find("k2") != opts_map.end()); |
720 | 1 | ASSERT_EQ(opts_map["k2"], ""); |
721 | 1 | ASSERT_EQ(opts_map["k3"], "v3"); |
722 | 1 | ASSERT_TRUE(opts_map.find("k4") != opts_map.end()); |
723 | 1 | ASSERT_EQ(opts_map["k4"], ""); |
724 | 1 | opts_map.clear(); |
725 | 1 | ASSERT_OK(StringToMap("k1=v1;k2=;k3=", &opts_map)); |
726 | 1 | ASSERT_EQ(opts_map["k1"], "v1"); |
727 | 1 | ASSERT_TRUE(opts_map.find("k2") != opts_map.end()); |
728 | 1 | ASSERT_EQ(opts_map["k2"], ""); |
729 | 1 | ASSERT_TRUE(opts_map.find("k3") != opts_map.end()); |
730 | 1 | ASSERT_EQ(opts_map["k3"], ""); |
731 | 1 | opts_map.clear(); |
732 | 1 | ASSERT_OK(StringToMap("k1=v1;k2=;k3=;", &opts_map)); |
733 | 1 | ASSERT_EQ(opts_map["k1"], "v1"); |
734 | 1 | ASSERT_TRUE(opts_map.find("k2") != opts_map.end()); |
735 | 1 | ASSERT_EQ(opts_map["k2"], ""); |
736 | 1 | ASSERT_TRUE(opts_map.find("k3") != opts_map.end()); |
737 | 1 | ASSERT_EQ(opts_map["k3"], ""); |
738 | | // Regular nested options |
739 | 1 | opts_map.clear(); |
740 | 1 | ASSERT_OK(StringToMap("k1=v1;k2={nk1=nv1;nk2=nv2};k3=v3", &opts_map)); |
741 | 1 | ASSERT_EQ(opts_map["k1"], "v1"); |
742 | 1 | ASSERT_EQ(opts_map["k2"], "nk1=nv1;nk2=nv2"); |
743 | 1 | ASSERT_EQ(opts_map["k3"], "v3"); |
744 | | // Multi-level nested options |
745 | 1 | opts_map.clear(); |
746 | 1 | ASSERT_OK(StringToMap("k1=v1;k2={nk1=nv1;nk2={nnk1=nnk2}};" |
747 | 1 | "k3={nk1={nnk1={nnnk1=nnnv1;nnnk2;nnnv2}}};k4=v4", |
748 | 1 | &opts_map)); |
749 | 1 | ASSERT_EQ(opts_map["k1"], "v1"); |
750 | 1 | ASSERT_EQ(opts_map["k2"], "nk1=nv1;nk2={nnk1=nnk2}"); |
751 | 1 | ASSERT_EQ(opts_map["k3"], "nk1={nnk1={nnnk1=nnnv1;nnnk2;nnnv2}}"); |
752 | 1 | ASSERT_EQ(opts_map["k4"], "v4"); |
753 | | // Garbage inside curly braces |
754 | 1 | opts_map.clear(); |
755 | 1 | ASSERT_OK(StringToMap("k1=v1;k2={dfad=};k3={=};k4=v4", |
756 | 1 | &opts_map)); |
757 | 1 | ASSERT_EQ(opts_map["k1"], "v1"); |
758 | 1 | ASSERT_EQ(opts_map["k2"], "dfad="); |
759 | 1 | ASSERT_EQ(opts_map["k3"], "="); |
760 | 1 | ASSERT_EQ(opts_map["k4"], "v4"); |
761 | | // Empty nested options |
762 | 1 | opts_map.clear(); |
763 | 1 | ASSERT_OK(StringToMap("k1=v1;k2={};", &opts_map)); |
764 | 1 | ASSERT_EQ(opts_map["k1"], "v1"); |
765 | 1 | ASSERT_EQ(opts_map["k2"], ""); |
766 | 1 | opts_map.clear(); |
767 | 1 | ASSERT_OK(StringToMap("k1=v1;k2={{{{}}}{}{}};", &opts_map)); |
768 | 1 | ASSERT_EQ(opts_map["k1"], "v1"); |
769 | 1 | ASSERT_EQ(opts_map["k2"], "{{{}}}{}{}"); |
770 | | // With random spaces |
771 | 1 | opts_map.clear(); |
772 | 1 | ASSERT_OK(StringToMap(" k1 = v1 ; k2= {nk1=nv1; nk2={nnk1=nnk2}} ; " |
773 | 1 | "k3={ { } }; k4= v4 ", |
774 | 1 | &opts_map)); |
775 | 1 | ASSERT_EQ(opts_map["k1"], "v1"); |
776 | 1 | ASSERT_EQ(opts_map["k2"], "nk1=nv1; nk2={nnk1=nnk2}"); |
777 | 1 | ASSERT_EQ(opts_map["k3"], "{ }"); |
778 | 1 | ASSERT_EQ(opts_map["k4"], "v4"); |
779 | | |
780 | | // Empty key |
781 | 1 | ASSERT_NOK(StringToMap("k1=v1;k2=v2;=", &opts_map)); |
782 | 1 | ASSERT_NOK(StringToMap("=v1;k2=v2", &opts_map)); |
783 | 1 | ASSERT_NOK(StringToMap("k1=v1;k2v2;", &opts_map)); |
784 | 1 | ASSERT_NOK(StringToMap("k1=v1;k2=v2;fadfa", &opts_map)); |
785 | 1 | ASSERT_NOK(StringToMap("k1=v1;k2=v2;;", &opts_map)); |
786 | | // Mismatch curly braces |
787 | 1 | ASSERT_NOK(StringToMap("k1=v1;k2={;k3=v3", &opts_map)); |
788 | 1 | ASSERT_NOK(StringToMap("k1=v1;k2={{};k3=v3", &opts_map)); |
789 | 1 | ASSERT_NOK(StringToMap("k1=v1;k2={}};k3=v3", &opts_map)); |
790 | 1 | ASSERT_NOK(StringToMap("k1=v1;k2={{}{}}};k3=v3", &opts_map)); |
791 | | // However this is valid! |
792 | 1 | opts_map.clear(); |
793 | 1 | ASSERT_OK(StringToMap("k1=v1;k2=};k3=v3", &opts_map)); |
794 | 1 | ASSERT_EQ(opts_map["k1"], "v1"); |
795 | 1 | ASSERT_EQ(opts_map["k2"], "}"); |
796 | 1 | ASSERT_EQ(opts_map["k3"], "v3"); |
797 | | |
798 | | // Invalid chars after closing curly brace |
799 | 1 | ASSERT_NOK(StringToMap("k1=v1;k2={{}}{};k3=v3", &opts_map)); |
800 | 1 | ASSERT_NOK(StringToMap("k1=v1;k2={{}}cfda;k3=v3", &opts_map)); |
801 | 1 | ASSERT_NOK(StringToMap("k1=v1;k2={{}} cfda;k3=v3", &opts_map)); |
802 | 1 | ASSERT_NOK(StringToMap("k1=v1;k2={{}} cfda", &opts_map)); |
803 | 1 | ASSERT_NOK(StringToMap("k1=v1;k2={{}}{}", &opts_map)); |
804 | 1 | ASSERT_NOK(StringToMap("k1=v1;k2={{dfdl}adfa}{}", &opts_map)); |
805 | 1 | } |
806 | | #endif // ROCKSDB_LITE |
807 | | |
808 | | #ifndef ROCKSDB_LITE // StringToMap is not supported in ROCKSDB_LITE |
809 | 1 | TEST_F(OptionsTest, StringToMapRandomTest) { |
810 | 1 | std::unordered_map<std::string, std::string> opts_map; |
811 | | // Make sure segfault is not hit by semi-random strings |
812 | | |
813 | 1 | std::vector<std::string> bases = { |
814 | 1 | "a={aa={};tt={xxx={}}};c=defff", |
815 | 1 | "a={aa={};tt={xxx={}}};c=defff;d={{}yxx{}3{xx}}", |
816 | 1 | "abc={{}{}{}{{{}}}{{}{}{}{}{}{}{}"}; |
817 | | |
818 | 3 | for (std::string base : bases) { |
819 | 303 | for (int rand_seed = 301; rand_seed < 401; rand_seed++) { |
820 | 300 | Random rnd(rand_seed); |
821 | 3.30k | for (int attempt = 0; attempt < 10; attempt++) { |
822 | 3.00k | std::string str = base; |
823 | | // Replace random position to space |
824 | 3.00k | size_t pos = static_cast<size_t>( |
825 | 3.00k | rnd.Uniform(static_cast<int>(base.size()))); |
826 | 3.00k | str[pos] = ' '; |
827 | 3.00k | Status s = StringToMap(str, &opts_map); |
828 | 3.00k | ASSERT_TRUE(s.ok() || s.IsInvalidArgument()); |
829 | 3.00k | opts_map.clear(); |
830 | 3.00k | } |
831 | 300 | } |
832 | 3 | } |
833 | | |
834 | | // Random Construct a string |
835 | 1 | std::vector<char> chars = {'{', '}', ' ', '=', ';', 'c'}; |
836 | 1.00k | for (int rand_seed = 301; rand_seed < 1301; rand_seed++) { |
837 | 1.00k | Random rnd(rand_seed); |
838 | 1.00k | int len = rnd.Uniform(30); |
839 | 1.00k | std::string str = ""; |
840 | 15.5k | for (int attempt = 0; attempt < len; attempt++) { |
841 | | // Add a random character |
842 | 14.5k | size_t pos = static_cast<size_t>( |
843 | 14.5k | rnd.Uniform(static_cast<int>(chars.size()))); |
844 | 14.5k | str.append(1, chars[pos]); |
845 | 14.5k | } |
846 | 1.00k | Status s = StringToMap(str, &opts_map); |
847 | 1.00k | ASSERT_TRUE(s.ok() || s.IsInvalidArgument()); |
848 | 1.00k | s = StringToMap("name=" + str, &opts_map); |
849 | 1.00k | ASSERT_TRUE(s.ok() || s.IsInvalidArgument()); |
850 | 1.00k | opts_map.clear(); |
851 | 1.00k | } |
852 | 1 | } |
853 | | #endif // !ROCKSDB_LITE |
854 | | |
855 | 1 | TEST_F(OptionsTest, ConvertOptionsTest) { |
856 | 1 | LevelDBOptions leveldb_opt; |
857 | 1 | Options converted_opt = ConvertOptions(leveldb_opt); |
858 | | |
859 | 1 | ASSERT_EQ(converted_opt.create_if_missing, leveldb_opt.create_if_missing); |
860 | 1 | ASSERT_EQ(converted_opt.error_if_exists, leveldb_opt.error_if_exists); |
861 | 1 | ASSERT_EQ(converted_opt.paranoid_checks, leveldb_opt.paranoid_checks); |
862 | 1 | ASSERT_EQ(converted_opt.env, leveldb_opt.env); |
863 | 1 | ASSERT_EQ(converted_opt.info_log.get(), leveldb_opt.info_log); |
864 | 1 | ASSERT_EQ(converted_opt.write_buffer_size, leveldb_opt.write_buffer_size); |
865 | 1 | ASSERT_EQ(converted_opt.max_open_files, leveldb_opt.max_open_files); |
866 | 1 | ASSERT_EQ(converted_opt.compression, leveldb_opt.compression); |
867 | | |
868 | 1 | std::shared_ptr<BlockBasedTableFactory> table_factory = |
869 | 1 | std::dynamic_pointer_cast<BlockBasedTableFactory>( |
870 | 1 | converted_opt.table_factory); |
871 | | |
872 | 1 | ASSERT_TRUE(table_factory.get() != nullptr); |
873 | | |
874 | 1 | const BlockBasedTableOptions table_opt = table_factory->table_options(); |
875 | | |
876 | 1 | ASSERT_EQ(table_opt.block_cache->GetCapacity(), 8UL << 20); |
877 | 1 | ASSERT_EQ(table_opt.block_size, leveldb_opt.block_size); |
878 | 1 | ASSERT_EQ(table_opt.block_restart_interval, |
879 | 1 | leveldb_opt.block_restart_interval); |
880 | 1 | ASSERT_EQ(table_opt.filter_policy.get(), leveldb_opt.filter_policy); |
881 | 1 | } |
882 | | |
883 | | #ifndef ROCKSDB_LITE |
884 | | class OptionsParserTest : public RocksDBTest { |
885 | | public: |
886 | 12 | OptionsParserTest() { env_.reset(new test::StringEnv(Env::Default())); } |
887 | | |
888 | | protected: |
889 | | std::unique_ptr<test::StringEnv> env_; |
890 | | }; |
891 | | |
892 | 1 | TEST_F(OptionsParserTest, Comment) { |
893 | 1 | DBOptions db_opt; |
894 | 1 | db_opt.max_open_files = 12345; |
895 | 1 | db_opt.max_background_flushes = 301; |
896 | 1 | db_opt.max_total_wal_size = 1024; |
897 | 1 | ColumnFamilyOptions cf_opt; |
898 | | |
899 | 1 | std::string options_file_content = |
900 | 1 | "# This is a testing option string.\n" |
901 | 1 | "# Currently we only support \"#\" styled comment.\n" |
902 | 1 | "\n" |
903 | 1 | "[Version]\n" |
904 | 1 | " rocksdb_version=3.14.0\n" |
905 | 1 | " options_file_version=1\n" |
906 | 1 | "[ DBOptions ]\n" |
907 | 1 | " # note that we don't support space around \"=\"\n" |
908 | 1 | " max_open_files=12345;\n" |
909 | 1 | " max_background_flushes=301 # comment after a statement is fine\n" |
910 | 1 | " # max_background_flushes=1000 # this line would be ignored\n" |
911 | 1 | " # max_background_compactions=2000 # so does this one\n" |
912 | 1 | " max_total_wal_size=1024 # keep_log_file_num=1000\n" |
913 | 1 | "[CFOptions \"default\"] # column family must be specified\n" |
914 | 1 | " # in the correct order\n" |
915 | 1 | " # if a section is blank, we will use the default\n"; |
916 | | |
917 | 1 | const std::string kTestFileName = "test-rocksdb-options.ini"; |
918 | 1 | ASSERT_OK(env_->WriteToNewFile(kTestFileName, options_file_content)); |
919 | 1 | RocksDBOptionsParser parser; |
920 | 1 | ASSERT_OK(parser.Parse(kTestFileName, env_.get())); |
921 | | |
922 | 1 | ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(*parser.db_opt(), db_opt)); |
923 | 1 | ASSERT_EQ(parser.NumColumnFamilies(), 1U); |
924 | 1 | ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions( |
925 | 1 | *parser.GetCFOptions("default"), cf_opt)); |
926 | 1 | } |
927 | | |
928 | 1 | TEST_F(OptionsParserTest, ExtraSpace) { |
929 | 1 | std::string options_file_content = |
930 | 1 | "# This is a testing option string.\n" |
931 | 1 | "# Currently we only support \"#\" styled comment.\n" |
932 | 1 | "\n" |
933 | 1 | "[ Version ]\n" |
934 | 1 | " rocksdb_version = 3.14.0 \n" |
935 | 1 | " options_file_version=1 # some comment\n" |
936 | 1 | "[DBOptions ] # some comment\n" |
937 | 1 | "max_open_files=12345 \n" |
938 | 1 | " max_background_flushes = 301 \n" |
939 | 1 | " max_total_wal_size = 1024 # keep_log_file_num=1000\n" |
940 | 1 | " [CFOptions \"default\" ]\n" |
941 | 1 | " # if a section is blank, we will use the default\n"; |
942 | | |
943 | 1 | const std::string kTestFileName = "test-rocksdb-options.ini"; |
944 | 1 | ASSERT_OK(env_->WriteToNewFile(kTestFileName, options_file_content)); |
945 | 1 | RocksDBOptionsParser parser; |
946 | 1 | ASSERT_OK(parser.Parse(kTestFileName, env_.get())); |
947 | 1 | } |
948 | | |
949 | 1 | TEST_F(OptionsParserTest, MissingDBOptions) { |
950 | 1 | std::string options_file_content = |
951 | 1 | "# This is a testing option string.\n" |
952 | 1 | "# Currently we only support \"#\" styled comment.\n" |
953 | 1 | "\n" |
954 | 1 | "[Version]\n" |
955 | 1 | " rocksdb_version=3.14.0\n" |
956 | 1 | " options_file_version=1\n" |
957 | 1 | "[CFOptions \"default\"]\n" |
958 | 1 | " # if a section is blank, we will use the default\n"; |
959 | | |
960 | 1 | const std::string kTestFileName = "test-rocksdb-options.ini"; |
961 | 1 | ASSERT_OK(env_->WriteToNewFile(kTestFileName, options_file_content)); |
962 | 1 | RocksDBOptionsParser parser; |
963 | 1 | ASSERT_NOK(parser.Parse(kTestFileName, env_.get())); |
964 | 1 | } |
965 | | |
966 | 1 | TEST_F(OptionsParserTest, DoubleDBOptions) { |
967 | 1 | DBOptions db_opt; |
968 | 1 | db_opt.max_open_files = 12345; |
969 | 1 | db_opt.max_background_flushes = 301; |
970 | 1 | db_opt.max_total_wal_size = 1024; |
971 | 1 | ColumnFamilyOptions cf_opt; |
972 | | |
973 | 1 | std::string options_file_content = |
974 | 1 | "# This is a testing option string.\n" |
975 | 1 | "# Currently we only support \"#\" styled comment.\n" |
976 | 1 | "\n" |
977 | 1 | "[Version]\n" |
978 | 1 | " rocksdb_version=3.14.0\n" |
979 | 1 | " options_file_version=1\n" |
980 | 1 | "[DBOptions]\n" |
981 | 1 | " max_open_files=12345\n" |
982 | 1 | " max_background_flushes=301\n" |
983 | 1 | " max_total_wal_size=1024 # keep_log_file_num=1000\n" |
984 | 1 | "[DBOptions]\n" |
985 | 1 | "[CFOptions \"default\"]\n" |
986 | 1 | " # if a section is blank, we will use the default\n"; |
987 | | |
988 | 1 | const std::string kTestFileName = "test-rocksdb-options.ini"; |
989 | 1 | ASSERT_OK(env_->WriteToNewFile(kTestFileName, options_file_content)); |
990 | 1 | RocksDBOptionsParser parser; |
991 | 1 | ASSERT_NOK(parser.Parse(kTestFileName, env_.get())); |
992 | 1 | } |
993 | | |
994 | 1 | TEST_F(OptionsParserTest, NoDefaultCFOptions) { |
995 | 1 | DBOptions db_opt; |
996 | 1 | db_opt.max_open_files = 12345; |
997 | 1 | db_opt.max_background_flushes = 301; |
998 | 1 | db_opt.max_total_wal_size = 1024; |
999 | 1 | ColumnFamilyOptions cf_opt; |
1000 | | |
1001 | 1 | std::string options_file_content = |
1002 | 1 | "# This is a testing option string.\n" |
1003 | 1 | "# Currently we only support \"#\" styled comment.\n" |
1004 | 1 | "\n" |
1005 | 1 | "[Version]\n" |
1006 | 1 | " rocksdb_version=3.14.0\n" |
1007 | 1 | " options_file_version=1\n" |
1008 | 1 | "[DBOptions]\n" |
1009 | 1 | " max_open_files=12345\n" |
1010 | 1 | " max_background_flushes=301\n" |
1011 | 1 | " max_total_wal_size=1024 # keep_log_file_num=1000\n" |
1012 | 1 | "[CFOptions \"something_else\"]\n" |
1013 | 1 | " # if a section is blank, we will use the default\n"; |
1014 | | |
1015 | 1 | const std::string kTestFileName = "test-rocksdb-options.ini"; |
1016 | 1 | ASSERT_OK(env_->WriteToNewFile(kTestFileName, options_file_content)); |
1017 | 1 | RocksDBOptionsParser parser; |
1018 | 1 | ASSERT_NOK(parser.Parse(kTestFileName, env_.get())); |
1019 | 1 | } |
1020 | | |
1021 | 1 | TEST_F(OptionsParserTest, DefaultCFOptionsMustBeTheFirst) { |
1022 | 1 | DBOptions db_opt; |
1023 | 1 | db_opt.max_open_files = 12345; |
1024 | 1 | db_opt.max_background_flushes = 301; |
1025 | 1 | db_opt.max_total_wal_size = 1024; |
1026 | 1 | ColumnFamilyOptions cf_opt; |
1027 | | |
1028 | 1 | std::string options_file_content = |
1029 | 1 | "# This is a testing option string.\n" |
1030 | 1 | "# Currently we only support \"#\" styled comment.\n" |
1031 | 1 | "\n" |
1032 | 1 | "[Version]\n" |
1033 | 1 | " rocksdb_version=3.14.0\n" |
1034 | 1 | " options_file_version=1\n" |
1035 | 1 | "[DBOptions]\n" |
1036 | 1 | " max_open_files=12345\n" |
1037 | 1 | " max_background_flushes=301\n" |
1038 | 1 | " max_total_wal_size=1024 # keep_log_file_num=1000\n" |
1039 | 1 | "[CFOptions \"something_else\"]\n" |
1040 | 1 | " # if a section is blank, we will use the default\n" |
1041 | 1 | "[CFOptions \"default\"]\n" |
1042 | 1 | " # if a section is blank, we will use the default\n"; |
1043 | | |
1044 | 1 | const std::string kTestFileName = "test-rocksdb-options.ini"; |
1045 | 1 | ASSERT_OK(env_->WriteToNewFile(kTestFileName, options_file_content)); |
1046 | 1 | RocksDBOptionsParser parser; |
1047 | 1 | ASSERT_NOK(parser.Parse(kTestFileName, env_.get())); |
1048 | 1 | } |
1049 | | |
1050 | 1 | TEST_F(OptionsParserTest, DuplicateCFOptions) { |
1051 | 1 | DBOptions db_opt; |
1052 | 1 | db_opt.max_open_files = 12345; |
1053 | 1 | db_opt.max_background_flushes = 301; |
1054 | 1 | db_opt.max_total_wal_size = 1024; |
1055 | 1 | ColumnFamilyOptions cf_opt; |
1056 | | |
1057 | 1 | std::string options_file_content = |
1058 | 1 | "# This is a testing option string.\n" |
1059 | 1 | "# Currently we only support \"#\" styled comment.\n" |
1060 | 1 | "\n" |
1061 | 1 | "[Version]\n" |
1062 | 1 | " rocksdb_version=3.14.0\n" |
1063 | 1 | " options_file_version=1\n" |
1064 | 1 | "[DBOptions]\n" |
1065 | 1 | " max_open_files=12345\n" |
1066 | 1 | " max_background_flushes=301\n" |
1067 | 1 | " max_total_wal_size=1024 # keep_log_file_num=1000\n" |
1068 | 1 | "[CFOptions \"default\"]\n" |
1069 | 1 | "[CFOptions \"something_else\"]\n" |
1070 | 1 | "[CFOptions \"something_else\"]\n"; |
1071 | | |
1072 | 1 | const std::string kTestFileName = "test-rocksdb-options.ini"; |
1073 | 1 | ASSERT_OK(env_->WriteToNewFile(kTestFileName, options_file_content)); |
1074 | 1 | RocksDBOptionsParser parser; |
1075 | 1 | ASSERT_NOK(parser.Parse(kTestFileName, env_.get())); |
1076 | 1 | } |
1077 | | |
1078 | 1 | TEST_F(OptionsParserTest, ParseVersion) { |
1079 | 1 | DBOptions db_opt; |
1080 | 1 | db_opt.max_open_files = 12345; |
1081 | 1 | db_opt.max_background_flushes = 301; |
1082 | 1 | db_opt.max_total_wal_size = 1024; |
1083 | 1 | ColumnFamilyOptions cf_opt; |
1084 | | |
1085 | 1 | std::string file_template = |
1086 | 1 | "# This is a testing option string.\n" |
1087 | 1 | "# Currently we only support \"#\" styled comment.\n" |
1088 | 1 | "\n" |
1089 | 1 | "[Version]\n" |
1090 | 1 | " rocksdb_version=3.13.1\n" |
1091 | 1 | " options_file_version=%s\n" |
1092 | 1 | "[DBOptions]\n" |
1093 | 1 | "[CFOptions \"default\"]\n"; |
1094 | 1 | const int kLength = 1000; |
1095 | 1 | char buffer[kLength]; |
1096 | 1 | RocksDBOptionsParser parser; |
1097 | | |
1098 | 1 | const std::vector<std::string> invalid_versions = { |
1099 | 1 | "a.b.c", "3.2.2b", "3.-12", "3. 1", // only digits and dots are allowed |
1100 | 1 | "1.2.3.4", |
1101 | 1 | "1.2.3" // can only contains at most one dot. |
1102 | 1 | "0", // options_file_version must be at least one |
1103 | 1 | "3..2", |
1104 | 1 | ".", ".1.2", // must have at least one digit before each dot |
1105 | 1 | "1.2.", "1.", "2.34."}; // must have at least one digit after each dot |
1106 | 12 | for (auto iv : invalid_versions) { |
1107 | 12 | snprintf(buffer, kLength - 1, file_template.c_str(), iv.c_str()); |
1108 | | |
1109 | 12 | parser.Reset(); |
1110 | 12 | ASSERT_OK(env_->WriteToNewFile(iv, buffer)); |
1111 | 12 | ASSERT_NOK(parser.Parse(iv, env_.get())); |
1112 | 12 | } |
1113 | | |
1114 | 1 | const std::vector<std::string> valid_versions = { |
1115 | 1 | "1.232", "100", "3.12", "1", "12.3 ", " 1.25 "}; |
1116 | 6 | for (auto vv : valid_versions) { |
1117 | 6 | snprintf(buffer, kLength - 1, file_template.c_str(), vv.c_str()); |
1118 | 6 | parser.Reset(); |
1119 | 6 | ASSERT_OK(env_->WriteToNewFile(vv, buffer)); |
1120 | 6 | ASSERT_OK(parser.Parse(vv, env_.get())); |
1121 | 6 | } |
1122 | 1 | } |
1123 | | |
1124 | | void VerifyCFPointerTypedOptions( |
1125 | | ColumnFamilyOptions* base_cf_opt, const ColumnFamilyOptions* new_cf_opt, |
1126 | 6 | const std::unordered_map<std::string, std::string>* new_cf_opt_map) { |
1127 | 6 | std::string name_buffer; |
1128 | 6 | ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(*base_cf_opt, *new_cf_opt, |
1129 | 6 | new_cf_opt_map)); |
1130 | | |
1131 | | // change the name of merge operator back-and-forth |
1132 | 6 | { |
1133 | 6 | auto* merge_operator = dynamic_cast<test::ChanglingMergeOperator*>( |
1134 | 6 | base_cf_opt->merge_operator.get()); |
1135 | 6 | if (merge_operator != nullptr) { |
1136 | 6 | name_buffer = merge_operator->Name(); |
1137 | | // change the name and expect non-ok status |
1138 | 6 | merge_operator->SetName("some-other-name"); |
1139 | 6 | ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions( |
1140 | 6 | *base_cf_opt, *new_cf_opt, new_cf_opt_map)); |
1141 | | // change the name back and expect ok status |
1142 | 6 | merge_operator->SetName(name_buffer); |
1143 | 6 | ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(*base_cf_opt, *new_cf_opt, |
1144 | 6 | new_cf_opt_map)); |
1145 | 6 | } |
1146 | 6 | } |
1147 | | |
1148 | | // change the name of the compaction filter factory back-and-forth |
1149 | 6 | { |
1150 | 6 | auto* compaction_filter_factory = |
1151 | 6 | dynamic_cast<test::ChanglingCompactionFilterFactory*>( |
1152 | 6 | base_cf_opt->compaction_filter_factory.get()); |
1153 | 6 | if (compaction_filter_factory != nullptr) { |
1154 | 6 | name_buffer = compaction_filter_factory->Name(); |
1155 | | // change the name and expect non-ok status |
1156 | 6 | compaction_filter_factory->SetName("some-other-name"); |
1157 | 6 | ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions( |
1158 | 6 | *base_cf_opt, *new_cf_opt, new_cf_opt_map)); |
1159 | | // change the name back and expect ok status |
1160 | 6 | compaction_filter_factory->SetName(name_buffer); |
1161 | 6 | ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(*base_cf_opt, *new_cf_opt, |
1162 | 6 | new_cf_opt_map)); |
1163 | 6 | } |
1164 | 6 | } |
1165 | | |
1166 | | // test by setting compaction_filter to nullptr |
1167 | 6 | { |
1168 | 6 | auto* tmp_compaction_filter = base_cf_opt->compaction_filter; |
1169 | 6 | if (tmp_compaction_filter != nullptr) { |
1170 | 6 | base_cf_opt->compaction_filter = nullptr; |
1171 | | // set compaction_filter to nullptr and expect non-ok status |
1172 | 6 | ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions( |
1173 | 6 | *base_cf_opt, *new_cf_opt, new_cf_opt_map)); |
1174 | | // set the value back and expect ok status |
1175 | 6 | base_cf_opt->compaction_filter = tmp_compaction_filter; |
1176 | 6 | ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(*base_cf_opt, *new_cf_opt, |
1177 | 6 | new_cf_opt_map)); |
1178 | 6 | } |
1179 | 6 | } |
1180 | | |
1181 | | // test by setting table_factory to nullptr |
1182 | 6 | { |
1183 | 6 | auto tmp_table_factory = base_cf_opt->table_factory; |
1184 | 6 | if (tmp_table_factory != nullptr) { |
1185 | 6 | base_cf_opt->table_factory.reset(); |
1186 | | // set table_factory to nullptr and expect non-ok status |
1187 | 6 | ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions( |
1188 | 6 | *base_cf_opt, *new_cf_opt, new_cf_opt_map)); |
1189 | | // set the value back and expect ok status |
1190 | 6 | base_cf_opt->table_factory = tmp_table_factory; |
1191 | 6 | ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(*base_cf_opt, *new_cf_opt, |
1192 | 6 | new_cf_opt_map)); |
1193 | 6 | } |
1194 | 6 | } |
1195 | | |
1196 | | // test by setting memtable_factory to nullptr |
1197 | 6 | { |
1198 | 6 | auto tmp_memtable_factory = base_cf_opt->memtable_factory; |
1199 | 6 | if (tmp_memtable_factory != nullptr) { |
1200 | 6 | base_cf_opt->memtable_factory.reset(); |
1201 | | // set memtable_factory to nullptr and expect non-ok status |
1202 | 6 | ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions( |
1203 | 6 | *base_cf_opt, *new_cf_opt, new_cf_opt_map)); |
1204 | | // set the value back and expect ok status |
1205 | 6 | base_cf_opt->memtable_factory = tmp_memtable_factory; |
1206 | 6 | ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(*base_cf_opt, *new_cf_opt, |
1207 | 6 | new_cf_opt_map)); |
1208 | 6 | } |
1209 | 6 | } |
1210 | 6 | } |
1211 | | |
1212 | 1 | TEST_F(OptionsParserTest, DumpAndParse) { |
1213 | 1 | DBOptions base_db_opt; |
1214 | 1 | std::vector<ColumnFamilyOptions> base_cf_opts; |
1215 | 1 | std::vector<std::string> cf_names = {"default", "cf1", "cf2", "cf3", |
1216 | 1 | "c:f:4:4:4" |
1217 | 1 | "p\\i\\k\\a\\chu\\\\\\", |
1218 | 1 | "###rocksdb#1-testcf#2###"}; |
1219 | 1 | const int num_cf = static_cast<int>(cf_names.size()); |
1220 | 1 | Random rnd(302); |
1221 | 1 | test::RandomInitDBOptions(&base_db_opt, &rnd); |
1222 | 1 | base_db_opt.db_log_dir += "/#odd #but #could #happen #path #/\\\\#OMG"; |
1223 | 7 | for (int c = 0; c < num_cf; ++c) { |
1224 | 6 | ColumnFamilyOptions cf_opt; |
1225 | 6 | Random cf_rnd(0xFB + c); |
1226 | 6 | test::RandomInitCFOptions(&cf_opt, &cf_rnd); |
1227 | 6 | if (c < 4) { |
1228 | 4 | cf_opt.prefix_extractor.reset(test::RandomSliceTransform(&rnd, c)); |
1229 | 4 | } |
1230 | 6 | if (c < 3) { |
1231 | 3 | cf_opt.table_factory.reset(test::RandomTableFactory(&rnd, c)); |
1232 | 3 | } |
1233 | 6 | base_cf_opts.emplace_back(cf_opt); |
1234 | 6 | } |
1235 | | |
1236 | 1 | const std::string kOptionsFileName = "test-persisted-options.ini"; |
1237 | 1 | ASSERT_OK(PersistRocksDBOptions(base_db_opt, cf_names, base_cf_opts, |
1238 | 1 | kOptionsFileName, env_.get())); |
1239 | | |
1240 | 1 | RocksDBOptionsParser parser; |
1241 | 1 | ASSERT_OK(parser.Parse(kOptionsFileName, env_.get())); |
1242 | | |
1243 | 1 | ASSERT_OK(RocksDBOptionsParser::VerifyRocksDBOptionsFromFile( |
1244 | 1 | base_db_opt, cf_names, base_cf_opts, kOptionsFileName, env_.get())); |
1245 | | |
1246 | 1 | ASSERT_OK( |
1247 | 1 | RocksDBOptionsParser::VerifyDBOptions(*parser.db_opt(), base_db_opt)); |
1248 | 7 | for (int c = 0; c < num_cf; ++c) { |
1249 | 6 | const auto* cf_opt = parser.GetCFOptions(cf_names[c]); |
1250 | 6 | ASSERT_NE(cf_opt, nullptr); |
1251 | 6 | ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions( |
1252 | 6 | base_cf_opts[c], *cf_opt, &(parser.cf_opt_maps()->at(c)))); |
1253 | 6 | } |
1254 | | |
1255 | | // Further verify pointer-typed options |
1256 | 7 | for (int c = 0; c < num_cf; ++c) { |
1257 | 6 | const auto* cf_opt = parser.GetCFOptions(cf_names[c]); |
1258 | 6 | ASSERT_NE(cf_opt, nullptr); |
1259 | 6 | VerifyCFPointerTypedOptions(&base_cf_opts[c], cf_opt, |
1260 | 6 | &(parser.cf_opt_maps()->at(c))); |
1261 | 6 | } |
1262 | | |
1263 | 1 | ASSERT_EQ(parser.GetCFOptions("does not exist"), nullptr); |
1264 | | |
1265 | 1 | base_db_opt.max_open_files++; |
1266 | 1 | ASSERT_NOK(RocksDBOptionsParser::VerifyRocksDBOptionsFromFile( |
1267 | 1 | base_db_opt, cf_names, base_cf_opts, kOptionsFileName, env_.get())); |
1268 | | |
1269 | 7 | for (int c = 0; c < num_cf; ++c) { |
1270 | 6 | if (base_cf_opts[c].compaction_filter) { |
1271 | 6 | delete base_cf_opts[c].compaction_filter; |
1272 | 6 | } |
1273 | 6 | } |
1274 | 1 | } |
1275 | | |
1276 | 1 | TEST_F(OptionsParserTest, DifferentDefault) { |
1277 | 1 | const std::string kOptionsFileName = "test-persisted-options.ini"; |
1278 | | |
1279 | 1 | ColumnFamilyOptions cf_level_opts; |
1280 | 1 | cf_level_opts.OptimizeLevelStyleCompaction(); |
1281 | | |
1282 | 1 | ColumnFamilyOptions cf_univ_opts; |
1283 | 1 | cf_univ_opts.OptimizeUniversalStyleCompaction(); |
1284 | | |
1285 | 1 | ASSERT_OK(PersistRocksDBOptions(DBOptions(), {"default", "universal"}, |
1286 | 1 | {cf_level_opts, cf_univ_opts}, |
1287 | 1 | kOptionsFileName, env_.get())); |
1288 | | |
1289 | 1 | RocksDBOptionsParser parser; |
1290 | 1 | ASSERT_OK(parser.Parse(kOptionsFileName, env_.get())); |
1291 | 1 | } |
1292 | | |
1293 | | class OptionsSanityCheckTest : public OptionsParserTest { |
1294 | | public: |
1295 | 1 | OptionsSanityCheckTest() {} |
1296 | | |
1297 | | protected: |
1298 | | Status SanityCheckCFOptions(const ColumnFamilyOptions& cf_opts, |
1299 | 65 | OptionsSanityCheckLevel level) { |
1300 | 65 | return RocksDBOptionsParser::VerifyRocksDBOptionsFromFile( |
1301 | 65 | DBOptions(), {"default"}, {cf_opts}, kOptionsFileName, env_.get(), |
1302 | 65 | level); |
1303 | 65 | } |
1304 | | |
1305 | 21 | Status PersistCFOptions(const ColumnFamilyOptions& cf_opts) { |
1306 | 21 | Status s = env_->DeleteFile(kOptionsFileName); |
1307 | 21 | if (!s.ok()) { |
1308 | 0 | return s; |
1309 | 0 | } |
1310 | 21 | return PersistRocksDBOptions(DBOptions(), {"default"}, {cf_opts}, |
1311 | 21 | kOptionsFileName, env_.get()); |
1312 | 21 | } |
1313 | | |
1314 | | const std::string kOptionsFileName = "OPTIONS"; |
1315 | | }; |
1316 | | |
1317 | 1 | TEST_F(OptionsSanityCheckTest, SanityCheck) { |
1318 | 1 | ColumnFamilyOptions opts; |
1319 | 1 | Random rnd(301); |
1320 | | |
1321 | | // default ColumnFamilyOptions |
1322 | 1 | { |
1323 | 1 | ASSERT_OK(PersistCFOptions(opts)); |
1324 | 1 | ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelExactMatch)); |
1325 | 1 | } |
1326 | | |
1327 | | // prefix_extractor |
1328 | 1 | { |
1329 | | // Okay to change prefix_extractor form nullptr to non-nullptr |
1330 | 1 | ASSERT_EQ(opts.prefix_extractor.get(), nullptr); |
1331 | 1 | opts.prefix_extractor.reset(NewCappedPrefixTransform(10)); |
1332 | 1 | ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible)); |
1333 | 1 | ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelNone)); |
1334 | | |
1335 | | // persist the change |
1336 | 1 | ASSERT_OK(PersistCFOptions(opts)); |
1337 | 1 | ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelExactMatch)); |
1338 | | |
1339 | | // use same prefix extractor but with different parameter |
1340 | 1 | opts.prefix_extractor.reset(NewCappedPrefixTransform(15)); |
1341 | | // expect pass only in kSanityLevelNone |
1342 | 1 | ASSERT_NOK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible)); |
1343 | 1 | ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelNone)); |
1344 | | |
1345 | | // repeat the test with FixedPrefixTransform |
1346 | 1 | opts.prefix_extractor.reset(NewFixedPrefixTransform(10)); |
1347 | 1 | ASSERT_NOK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible)); |
1348 | 1 | ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelNone)); |
1349 | | |
1350 | | // persist the change of prefix_extractor |
1351 | 1 | ASSERT_OK(PersistCFOptions(opts)); |
1352 | 1 | ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelExactMatch)); |
1353 | | |
1354 | | // use same prefix extractor but with different parameter |
1355 | 1 | opts.prefix_extractor.reset(NewFixedPrefixTransform(15)); |
1356 | | // expect pass only in kSanityLevelNone |
1357 | 1 | ASSERT_NOK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible)); |
1358 | 1 | ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelNone)); |
1359 | | |
1360 | | // Change prefix extractor from non-nullptr to nullptr |
1361 | 1 | opts.prefix_extractor.reset(); |
1362 | | // expect pass as it's safe to change prefix_extractor |
1363 | | // from non-null to null |
1364 | 1 | ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible)); |
1365 | 1 | ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelNone)); |
1366 | 1 | } |
1367 | | // persist the change |
1368 | 1 | ASSERT_OK(PersistCFOptions(opts)); |
1369 | 1 | ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelExactMatch)); |
1370 | | |
1371 | | // table_factory |
1372 | 1 | { |
1373 | 3 | for (int tb = 0; tb <= 1; ++tb) { |
1374 | | // change the table factory |
1375 | 2 | opts.table_factory.reset(test::RandomTableFactory(&rnd, tb)); |
1376 | 2 | ASSERT_NOK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible)); |
1377 | 2 | ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelNone)); |
1378 | | |
1379 | | // persist the change |
1380 | 2 | ASSERT_OK(PersistCFOptions(opts)); |
1381 | 2 | ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelExactMatch)); |
1382 | 2 | } |
1383 | 1 | } |
1384 | | |
1385 | | // merge_operator |
1386 | 1 | { |
1387 | 6 | for (int test = 0; test < 5; ++test) { |
1388 | | // change the merge operator |
1389 | 5 | opts.merge_operator.reset(test::RandomMergeOperator(&rnd)); |
1390 | 5 | ASSERT_NOK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible)); |
1391 | 5 | ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelNone)); |
1392 | | |
1393 | | // persist the change |
1394 | 5 | ASSERT_OK(PersistCFOptions(opts)); |
1395 | 5 | ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelExactMatch)); |
1396 | 5 | } |
1397 | 1 | } |
1398 | | |
1399 | | // compaction_filter |
1400 | 1 | { |
1401 | 6 | for (int test = 0; test < 5; ++test) { |
1402 | | // change the compaction filter |
1403 | 5 | opts.compaction_filter = test::RandomCompactionFilter(&rnd); |
1404 | 5 | ASSERT_NOK(SanityCheckCFOptions(opts, kSanityLevelExactMatch)); |
1405 | 5 | ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible)); |
1406 | | |
1407 | | // persist the change |
1408 | 5 | ASSERT_OK(PersistCFOptions(opts)); |
1409 | 5 | ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelExactMatch)); |
1410 | 5 | delete opts.compaction_filter; |
1411 | 5 | opts.compaction_filter = nullptr; |
1412 | 5 | } |
1413 | 1 | } |
1414 | | |
1415 | | // compaction_filter_factory |
1416 | 1 | { |
1417 | 6 | for (int test = 0; test < 5; ++test) { |
1418 | | // change the compaction filter factory |
1419 | 5 | opts.compaction_filter_factory.reset( |
1420 | 5 | test::RandomCompactionFilterFactory(&rnd)); |
1421 | 5 | ASSERT_NOK(SanityCheckCFOptions(opts, kSanityLevelExactMatch)); |
1422 | 5 | ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible)); |
1423 | | |
1424 | | // persist the change |
1425 | 5 | ASSERT_OK(PersistCFOptions(opts)); |
1426 | 5 | ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelExactMatch)); |
1427 | 5 | } |
1428 | 1 | } |
1429 | 1 | } |
1430 | | |
1431 | | namespace { |
1432 | 2 | bool IsEscapedString(const std::string& str) { |
1433 | 438 | for (size_t i = 0; i < str.size(); ++i) { |
1434 | 436 | if (str[i] == '\\') { |
1435 | | // since we already handle those two consecutive '\'s in |
1436 | | // the next if-then branch, any '\' appear at the end |
1437 | | // of an escaped string in such case is not valid. |
1438 | 21 | if (i == str.size() - 1) { |
1439 | 0 | return false; |
1440 | 0 | } |
1441 | 21 | if (str[i + 1] == '\\') { |
1442 | | // if there're two consecutive '\'s, skip the second one. |
1443 | 10 | i++; |
1444 | 10 | continue; |
1445 | 10 | } |
1446 | 11 | switch (str[i + 1]) { |
1447 | 3 | case ':': |
1448 | 3 | case '\\': |
1449 | 9 | case '#': |
1450 | 9 | continue; |
1451 | 2 | default: |
1452 | | // if true, '\' together with str[i + 1] is not a valid escape. |
1453 | 2 | if (UnescapeChar(str[i + 1]) == str[i + 1]) { |
1454 | 0 | return false; |
1455 | 0 | } |
1456 | 415 | } |
1457 | 415 | } else if (isSpecialChar(str[i]) && (i == 0 || str[i - 1] != '\\')) { |
1458 | 0 | return false; |
1459 | 0 | } |
1460 | 436 | } |
1461 | 2 | return true; |
1462 | 2 | } |
1463 | | } // namespace |
1464 | | |
1465 | 1 | TEST_F(OptionsParserTest, EscapeOptionString) { |
1466 | 1 | ASSERT_EQ(UnescapeOptionString( |
1467 | 1 | "This is a test string with \\# \\: and \\\\ escape chars."), |
1468 | 1 | "This is a test string with # : and \\ escape chars."); |
1469 | | |
1470 | 1 | ASSERT_EQ( |
1471 | 1 | EscapeOptionString("This is a test string with # : and \\ escape chars."), |
1472 | 1 | "This is a test string with \\# \\: and \\\\ escape chars."); |
1473 | | |
1474 | 1 | std::string readible_chars = |
1475 | 1 | "A String like this \"1234567890-=_)(*&^%$#@!ertyuiop[]{POIU" |
1476 | 1 | "YTREWQasdfghjkl;':LKJHGFDSAzxcvbnm,.?>" |
1477 | 1 | "<MNBVCXZ\\\" should be okay to \\#\\\\\\:\\#\\#\\#\\ " |
1478 | 1 | "be serialized and deserialized"; |
1479 | | |
1480 | 1 | std::string escaped_string = EscapeOptionString(readible_chars); |
1481 | 1 | ASSERT_TRUE(IsEscapedString(escaped_string)); |
1482 | | // This two transformations should be canceled and should output |
1483 | | // the original input. |
1484 | 1 | ASSERT_EQ(UnescapeOptionString(escaped_string), readible_chars); |
1485 | | |
1486 | 1 | std::string all_chars; |
1487 | 256 | for (unsigned char c = 0;; ++c) { |
1488 | 256 | all_chars += c; |
1489 | 256 | if (c == 255) { |
1490 | 1 | break; |
1491 | 1 | } |
1492 | 256 | } |
1493 | 1 | escaped_string = EscapeOptionString(all_chars); |
1494 | 1 | ASSERT_TRUE(IsEscapedString(escaped_string)); |
1495 | 1 | ASSERT_EQ(UnescapeOptionString(escaped_string), all_chars); |
1496 | | |
1497 | 1 | ASSERT_EQ(RocksDBOptionsParser::TrimAndRemoveComment( |
1498 | 1 | " A simple statement with a comment. # like this :)"), |
1499 | 1 | "A simple statement with a comment."); |
1500 | | |
1501 | 1 | ASSERT_EQ(RocksDBOptionsParser::TrimAndRemoveComment( |
1502 | 1 | "Escape \\# and # comment together ."), |
1503 | 1 | "Escape \\# and"); |
1504 | 1 | } |
1505 | | |
1506 | | // Only run the tests to verify new fields in options are settable through |
1507 | | // string on limited platforms as it depends on behavior of compilers. |
1508 | | #if defined(__linux__) && !defined(__clang__) |
1509 | | |
1510 | | struct OffsetGap { |
1511 | | size_t begin_offset; |
1512 | | size_t end_offset; |
1513 | | const char* name; |
1514 | | |
1515 | | std::string ToString() const { |
1516 | | return yb::Format("{$0, $1, $2}", begin_offset, end_offset, name); |
1517 | | } |
1518 | | }; |
1519 | | |
1520 | | typedef std::vector<OffsetGap> OffsetGaps; |
1521 | | |
1522 | | std::vector<Slice> SettableSlices(const char* start_ptr, |
1523 | | size_t total_size, |
1524 | | const OffsetGaps& blacklist) { |
1525 | | size_t offset = 0; |
1526 | | std::vector<Slice> result; |
1527 | | result.reserve(blacklist.size() + 1); |
1528 | | for (auto& tuple : blacklist) { |
1529 | | result.emplace_back(start_ptr + offset, tuple.begin_offset - offset); |
1530 | | offset = tuple.end_offset; |
1531 | | } |
1532 | | result.emplace_back(start_ptr + offset, total_size - offset); |
1533 | | return result; |
1534 | | } |
1535 | | |
1536 | | constexpr char kUnsetMark1 = 'R'; |
1537 | | constexpr char kUnsetMark2 = ~kUnsetMark1; |
1538 | | |
1539 | | void FillWithSpecialChar(char* start_ptr, |
1540 | | size_t total_size, |
1541 | | const OffsetGaps& blacklist, |
1542 | | char unset_mark) { |
1543 | | for (auto& slice : SettableSlices(start_ptr, total_size, blacklist)) { |
1544 | | std::memset(slice.mutable_data(), unset_mark, slice.size()); |
1545 | | } |
1546 | | } |
1547 | | |
1548 | | // Finds offsets of bytes that are different for |
1549 | | // [start_ptr1, start_ptr1 + total_size) and [start_ptr2, start_ptr2 + total_size) |
1550 | | // Do not check offsets specified by blacklist |
1551 | | std::vector<size_t> DifferentBytes(const char* start_ptr1, |
1552 | | const char* start_ptr2, |
1553 | | size_t total_size, |
1554 | | const OffsetGaps& blacklist) { |
1555 | | std::vector<size_t> result; |
1556 | | for (auto& slice : SettableSlices(start_ptr1, total_size, blacklist)) { |
1557 | | for (const char* ptr = slice.cdata(); ptr != slice.cend(); ++ptr) { |
1558 | | if (*ptr != start_ptr2[ptr - start_ptr1]) { |
1559 | | result.push_back(ptr - start_ptr1); |
1560 | | } |
1561 | | } |
1562 | | } |
1563 | | return result; |
1564 | | } |
1565 | | |
1566 | | // Stores object of T in POD-buffer. After object is created all its bytes, except blacklist are |
1567 | | // filled with unset_mark. |
1568 | | template<class T> |
1569 | | class UnsetHolder { |
1570 | | public: |
1571 | | template<class... Args> |
1572 | | UnsetHolder(char unset_mark, const OffsetGaps& blacklist, Args&&... args) |
1573 | | : blacklist_(blacklist) { |
1574 | | new (&storage_) T(std::forward<Args>(args)...); |
1575 | | FillWithSpecialChar(raw_data(), sizeof(T), blacklist, unset_mark); |
1576 | | } |
1577 | | |
1578 | | UnsetHolder(const UnsetHolder&) = delete; |
1579 | | void operator=(const UnsetHolder&) = delete; |
1580 | | |
1581 | | ~UnsetHolder() { |
1582 | | get()->~T(); |
1583 | | } |
1584 | | |
1585 | | std::vector<size_t> DifferentBytes(const UnsetHolder& rhs) const { |
1586 | | return rocksdb::DifferentBytes(raw_data(), rhs.raw_data(), sizeof(T), blacklist_); |
1587 | | } |
1588 | | |
1589 | | T* operator->() { |
1590 | | return get(); |
1591 | | } |
1592 | | |
1593 | | T* get() { |
1594 | | return reinterpret_cast<T*>(&storage_);; |
1595 | | } |
1596 | | |
1597 | | char* raw_data() { |
1598 | | return reinterpret_cast<char*>(&storage_);; |
1599 | | } |
1600 | | |
1601 | | const char* raw_data() const { |
1602 | | return reinterpret_cast<const char*>(&storage_);; |
1603 | | } |
1604 | | |
1605 | | T& operator*() { |
1606 | | return *get(); |
1607 | | } |
1608 | | |
1609 | | private: |
1610 | | const OffsetGaps& blacklist_; |
1611 | | typename std::aligned_storage<sizeof(T), alignof(T)>::type storage_; |
1612 | | }; |
1613 | | |
1614 | | void InitDefault(BlockBasedTableOptions*) {} |
1615 | | |
1616 | | Status GetFromString(BlockBasedTableOptions* source, BlockBasedTableOptions* destination) { |
1617 | | const char* const kOptionsString = |
1618 | | "cache_index_and_filter_blocks=1;index_type=kHashSearch;" |
1619 | | "checksum=kxxHash;hash_index_allow_collision=1;no_block_cache=1;" |
1620 | | "block_cache=1M;block_cache_compressed=1k;block_size=1024;filter_block_size=16384;" |
1621 | | "block_size_deviation=8;block_restart_interval=4; " |
1622 | | "index_block_restart_interval=4;index_block_size=16384;min_keys_per_index_block=16;" |
1623 | | "filter_policy=bloomfilter:4:true;whole_key_filtering=1;" |
1624 | | "skip_table_builder_flush=1;format_version=1;" |
1625 | | "hash_index_allow_collision=false;"; |
1626 | | |
1627 | | RETURN_NOT_OK(GetBlockBasedTableOptionsFromString(*source, kOptionsString, destination)); |
1628 | | |
1629 | | // This option is not setable: |
1630 | | destination->use_delta_encoding = false; |
1631 | | |
1632 | | EXPECT_NE(nullptr, destination->block_cache.get()); |
1633 | | EXPECT_NE(nullptr, destination->block_cache_compressed.get()); |
1634 | | EXPECT_NE(nullptr, destination->filter_policy.get()); |
1635 | | |
1636 | | return Status::OK(); |
1637 | | } |
1638 | | |
1639 | | void InitDefault(DBOptions*) {} |
1640 | | |
1641 | | Status GetFromString(DBOptions* source, DBOptions* destination) { |
1642 | | const char* const kOptionsString = |
1643 | | "wal_bytes_per_sync=4295048118;" |
1644 | | "delete_obsolete_files_period_micros=4294967758;" |
1645 | | "WAL_ttl_seconds=4295008036;" |
1646 | | "WAL_size_limit_MB=4295036161;" |
1647 | | "wal_dir=path/to/wal_dir;" |
1648 | | "db_write_buffer_size=2587;" |
1649 | | "max_subcompactions=64330;" |
1650 | | "table_cache_numshardbits=28;" |
1651 | | "max_open_files=72;" |
1652 | | "max_file_opening_threads=35;" |
1653 | | "base_background_compactions=3;" |
1654 | | "max_background_compactions=33;" |
1655 | | "use_fsync=true;" |
1656 | | "use_adaptive_mutex=true;" |
1657 | | "max_total_wal_size=4295005604;" |
1658 | | "compaction_readahead_size=0;" |
1659 | | "new_table_reader_for_compaction_inputs=true;" |
1660 | | "keep_log_file_num=4890;" |
1661 | | "skip_stats_update_on_db_open=true;" |
1662 | | "max_manifest_file_size=4295009941;" |
1663 | | "db_log_dir=path/to/db_log_dir;" |
1664 | | "skip_log_error_on_recovery=true;" |
1665 | | "writable_file_max_buffer_size=1048576;" |
1666 | | "paranoid_checks=false;" |
1667 | | "is_fd_close_on_exec=true;" |
1668 | | "bytes_per_sync=4295013613;" |
1669 | | "enable_thread_tracking=true;" |
1670 | | "disable_data_sync=true;" |
1671 | | "recycle_log_file_num=0;" |
1672 | | "disableDataSync=true;" |
1673 | | "create_missing_column_families=true;" |
1674 | | "log_file_time_to_roll=3097;" |
1675 | | "max_background_flushes=35;" |
1676 | | "create_if_missing=true;" |
1677 | | "error_if_exists=true;" |
1678 | | "allow_os_buffer=true;" |
1679 | | "delayed_write_rate=4294976214;" |
1680 | | "manifest_preallocation_size=1222;" |
1681 | | "allow_mmap_writes=true;" |
1682 | | "stats_dump_period_sec=70127;" |
1683 | | "allow_fallocate=true;" |
1684 | | "allow_mmap_reads=true;" |
1685 | | "max_log_file_size=4607;" |
1686 | | "random_access_max_buffer_size=1048576;" |
1687 | | "advise_random_on_open=true;" |
1688 | | "fail_if_options_file_error=true;" |
1689 | | "allow_concurrent_memtable_write=true;" |
1690 | | "wal_recovery_mode=kPointInTimeRecovery;" |
1691 | | "enable_write_thread_adaptive_yield=true;" |
1692 | | "write_thread_slow_yield_usec=5;" |
1693 | | "write_thread_max_yield_usec=1000;" |
1694 | | "access_hint_on_compaction_start=NONE;" |
1695 | | "max_file_size_for_compaction=123;" |
1696 | | "initial_seqno=432;" |
1697 | | "num_reserved_small_compaction_threads=-1;" |
1698 | | "compaction_size_threshold_bytes=18446744073709551615;" |
1699 | | "info_log_level=DEBUG_LEVEL;"; |
1700 | | |
1701 | | return GetDBOptionsFromString(*source, kOptionsString, destination); |
1702 | | } |
1703 | | |
1704 | | // We want padding bytes to have the same values for test purposes, therefore we need to use |
1705 | | // exactly the same saved default value instead of using CompactionOptionsUniversal(). |
1706 | | static CompactionOptionsUniversal kCompactionOptionsUniversalDefault; |
1707 | | |
1708 | | void InitDefault(ColumnFamilyOptions* options) { |
1709 | | options->compaction_options_universal = kCompactionOptionsUniversalDefault; |
1710 | | // Deprecatd option which is not initialized. Need to set it to avoid |
1711 | | // Valgrind error |
1712 | | options->max_mem_compaction_level = 0; |
1713 | | } |
1714 | | |
1715 | | Status GetFromString(ColumnFamilyOptions* source, ColumnFamilyOptions* destination) { |
1716 | | // Need to update the option string if a new option is added. |
1717 | | const char* const kOptionsString = |
1718 | | "compaction_filter_factory=mpudlojcujCompactionFilterFactory;" |
1719 | | "table_factory=PlainTable;" |
1720 | | "prefix_extractor=rocksdb.CappedPrefix.13;" |
1721 | | "comparator=leveldb.BytewiseComparator;" |
1722 | | "compression_per_level=kBZip2Compression:kBZip2Compression:" |
1723 | | "kBZip2Compression:kNoCompression:kZlibCompression:kBZip2Compression:" |
1724 | | "kSnappyCompression;" |
1725 | | "max_bytes_for_level_base=986;" |
1726 | | "bloom_locality=8016;" |
1727 | | "target_file_size_base=4294976376;" |
1728 | | "memtable_prefix_bloom_huge_page_tlb_size=2557;" |
1729 | | "max_successive_merges=5497;" |
1730 | | "max_sequential_skip_in_iterations=4294971408;" |
1731 | | "arena_block_size=1893;" |
1732 | | "target_file_size_multiplier=35;" |
1733 | | "source_compaction_factor=54;" |
1734 | | "min_write_buffer_number_to_merge=9;" |
1735 | | "max_write_buffer_number=84;" |
1736 | | "write_buffer_size=1653;" |
1737 | | "max_grandparent_overlap_factor=64;" |
1738 | | "max_bytes_for_level_multiplier=60;" |
1739 | | "memtable_factory=SkipListFactory;" |
1740 | | "compression=kNoCompression;" |
1741 | | "min_partial_merge_operands=7576;" |
1742 | | "level0_stop_writes_trigger=33;" |
1743 | | "num_levels=99;" |
1744 | | "level0_slowdown_writes_trigger=22;" |
1745 | | "level0_file_num_compaction_trigger=14;" |
1746 | | "expanded_compaction_factor=34;" |
1747 | | "compaction_filter=urxcqstuwnCompactionFilter;" |
1748 | | "soft_rate_limit=530.615385;" |
1749 | | "soft_pending_compaction_bytes_limit=0;" |
1750 | | "max_write_buffer_number_to_maintain=84;" |
1751 | | "verify_checksums_in_compaction=false;" |
1752 | | "merge_operator=aabcxehazrMergeOperator;" |
1753 | | "memtable_prefix_bloom_bits=4642;" |
1754 | | "paranoid_file_checks=true;" |
1755 | | "inplace_update_num_locks=7429;" |
1756 | | "optimize_filters_for_hits=false;" |
1757 | | "level_compaction_dynamic_level_bytes=false;" |
1758 | | "inplace_update_support=false;" |
1759 | | "compaction_style=kCompactionStyleFIFO;" |
1760 | | "memtable_prefix_bloom_probes=2511;" |
1761 | | "purge_redundant_kvs_while_flush=true;" |
1762 | | "filter_deletes=false;" |
1763 | | "hard_pending_compaction_bytes_limit=0;" |
1764 | | "disable_auto_compactions=false;" |
1765 | | "compaction_measure_io_stats=true;"; |
1766 | | |
1767 | | RETURN_NOT_OK(GetColumnFamilyOptionsFromString(*source, kOptionsString, destination)); |
1768 | | |
1769 | | // Following options are not settable through |
1770 | | // GetColumnFamilyOptionsFromString(): |
1771 | | destination->rate_limit_delay_max_milliseconds = 33; |
1772 | | destination->compaction_pri = CompactionPri::kOldestSmallestSeqFirst; |
1773 | | destination->compaction_options_universal = kCompactionOptionsUniversalDefault; |
1774 | | destination->compression_opts = CompressionOptions(); |
1775 | | destination->hard_rate_limit = 0; |
1776 | | destination->soft_rate_limit = 0; |
1777 | | destination->compaction_options_fifo = CompactionOptionsFIFO(); |
1778 | | destination->max_mem_compaction_level = 0; |
1779 | | |
1780 | | return Status::OK(); |
1781 | | } |
1782 | | |
1783 | | // Takes 2 sorted collections and removes all entries that is present in both of them. |
1784 | | // After execution of this function c1 contains entries there were not contained in c2. |
1785 | | // And vise versa. |
1786 | | template<class Collection> |
1787 | | void FindDelta(Collection* c1, Collection* c2) { |
1788 | | auto w1 = c1->begin(); |
1789 | | auto w2 = c2->begin(); |
1790 | | auto i1 = c1->begin(); |
1791 | | auto i2 = c2->begin(); |
1792 | | while (i1 != c1->end() && i2 != c2->end()) { |
1793 | | if (*i1 < *i2) { |
1794 | | *w1 = *i1; |
1795 | | ++w1; |
1796 | | ++i1; |
1797 | | } else if (*i2 < *i1) { |
1798 | | *w2 = *i2; |
1799 | | ++w2; |
1800 | | ++i2; |
1801 | | } else { |
1802 | | ++i1; |
1803 | | ++i2; |
1804 | | } |
1805 | | } |
1806 | | c1->erase(w1, i1); |
1807 | | c2->erase(w2, i2); |
1808 | | } |
1809 | | |
1810 | | template<class T> |
1811 | | void TestAllFieldsSettable(const OffsetGaps& blacklist) { |
1812 | | std::vector<size_t> unset_bytes_base; |
1813 | | { |
1814 | | UnsetHolder<T> value1(kUnsetMark1, blacklist); |
1815 | | UnsetHolder<T> value2(kUnsetMark2, blacklist); |
1816 | | |
1817 | | *value1 = T(); |
1818 | | *value2 = T(); |
1819 | | |
1820 | | InitDefault(value1.get()); |
1821 | | InitDefault(value2.get()); |
1822 | | |
1823 | | // Count padding bytes by setting all bytes in the memory to a special char, |
1824 | | // copy a well constructed struct to this memory and see how many special |
1825 | | // bytes left. |
1826 | | |
1827 | | unset_bytes_base = value1.DifferentBytes(value2); |
1828 | | } |
1829 | | |
1830 | | { |
1831 | | UnsetHolder<T> value1(kUnsetMark1, blacklist); |
1832 | | UnsetHolder<T> value2(kUnsetMark2, blacklist); |
1833 | | |
1834 | | UnsetHolder<T> new_value1(kUnsetMark1, blacklist); |
1835 | | UnsetHolder<T> new_value2(kUnsetMark2, blacklist); |
1836 | | |
1837 | | // Need to update the option string if a new option is added. |
1838 | | ASSERT_OK(GetFromString(value1.get(), new_value1.get())); |
1839 | | ASSERT_OK(GetFromString(value2.get(), new_value2.get())); |
1840 | | |
1841 | | auto actual_unset_bytes = new_value1.DifferentBytes(new_value2); |
1842 | | auto unset_bytes_copy = unset_bytes_base; |
1843 | | FindDelta(&unset_bytes_copy, &actual_unset_bytes); |
1844 | | ASSERT_EQ(unset_bytes_copy, actual_unset_bytes) << yb::Format("Blacklist: $0", blacklist); |
1845 | | |
1846 | | // The byte could be one of 3 types: |
1847 | | // 1) Padding byte, then it is same in new_value1 and value1. |
1848 | | // 2) Settable by from string, then it should differ in new_value1 and value1. |
1849 | | // 3) Blacklisted |
1850 | | auto parsed_bytes = new_value1.DifferentBytes(value1); |
1851 | | auto all_non_blacklisted = parsed_bytes; |
1852 | | all_non_blacklisted.insert(all_non_blacklisted.end(), |
1853 | | unset_bytes_base.begin(), |
1854 | | unset_bytes_base.end()); |
1855 | | std::sort(all_non_blacklisted.begin(), all_non_blacklisted.end()); |
1856 | | all_non_blacklisted.erase(std::unique(all_non_blacklisted.begin(), all_non_blacklisted.end()), |
1857 | | all_non_blacklisted.end()); |
1858 | | |
1859 | | // Check that (1) and (2) does not overlap. |
1860 | | ASSERT_EQ(unset_bytes_base.size() + parsed_bytes.size(), all_non_blacklisted.size()) |
1861 | | << yb::Format("Blacklist: $0", blacklist); |
1862 | | |
1863 | | // Check that (1) + (2) is all that is not (3). |
1864 | | std::vector<Slice> settable_slices = SettableSlices(value1.raw_data(), sizeof(T), blacklist); |
1865 | | std::vector<size_t> all_settable; |
1866 | | for (auto& slice : settable_slices) { |
1867 | | for (const char* p = slice.cdata(); p != slice.cend(); ++p) |
1868 | | all_settable.push_back(p - value1.raw_data()); |
1869 | | } |
1870 | | FindDelta(&all_settable, &all_non_blacklisted); |
1871 | | ASSERT_EQ(all_settable, all_non_blacklisted) << yb::Format("Blacklist: $0", blacklist); |
1872 | | } |
1873 | | } |
1874 | | |
1875 | | #define BLACKLIST_ENTRY(type, field) \ |
1876 | | {offsetof(type, field), \ |
1877 | | offsetof(type, field) + sizeof(static_cast<type*>(nullptr)->field), \ |
1878 | | BOOST_PP_STRINGIZE(field)} |
1879 | | |
1880 | | // If the test fails, likely a new option is added to BlockBasedTableOptions |
1881 | | // but it cannot be set through GetBlockBasedTableOptionsFromString(), or the |
1882 | | // test is not updated accordingly. |
1883 | | // After adding an option, we need to make sure it is settable by |
1884 | | // GetBlockBasedTableOptionsFromString() and add the option to the input string |
1885 | | // passed to the GetBlockBasedTableOptionsFromString() in this test. |
1886 | | // If it is a complicated type, you also need to add the field to |
1887 | | // kBbtoBlacklist, and maybe add customized verification for it. |
1888 | | TEST_F(OptionsParserTest, BlockBasedTableOptionsAllFieldsSettable) { |
1889 | | // Items in the form of <offset, size>. Need to be in ascending order |
1890 | | // and not overlapping. Need to updated if new pointer-option is added. |
1891 | | const OffsetGaps kBbtoBlacklist = { |
1892 | | BLACKLIST_ENTRY(BlockBasedTableOptions, flush_block_policy_factory), |
1893 | | BLACKLIST_ENTRY(BlockBasedTableOptions, block_cache), |
1894 | | BLACKLIST_ENTRY(BlockBasedTableOptions, block_cache_compressed), |
1895 | | BLACKLIST_ENTRY(BlockBasedTableOptions, data_block_key_value_encoding_format), |
1896 | | BLACKLIST_ENTRY(BlockBasedTableOptions, filter_policy), |
1897 | | BLACKLIST_ENTRY(BlockBasedTableOptions, supported_filter_policies), |
1898 | | }; |
1899 | | |
1900 | | // In this test, we catch a new option of BlockBasedTableOptions that is not |
1901 | | // settable through GetBlockBasedTableOptionsFromString(). |
1902 | | // We count padding bytes of the option struct, and assert it to be the same |
1903 | | // as unset bytes of an option struct initialized by |
1904 | | // GetBlockBasedTableOptionsFromString(). |
1905 | | TestAllFieldsSettable<BlockBasedTableOptions>(kBbtoBlacklist); |
1906 | | } |
1907 | | |
1908 | | // If the test fails, likely a new option is added to DBOptions |
1909 | | // but it cannot be set through GetDBOptionsFromString(), or the test is not |
1910 | | // updated accordingly. |
1911 | | // After adding an option, we need to make sure it is settable by |
1912 | | // GetDBOptionsFromString() and add the option to the input string passed to |
1913 | | // DBOptionsFromString()in this test. |
1914 | | // If it is a complicated type, you also need to add the field to |
1915 | | // kDBOptionsBlacklist, and maybe add customized verification for it. |
1916 | | TEST_F(OptionsParserTest, DBOptionsAllFieldsSettable) { |
1917 | | const OffsetGaps kDBOptionsBlacklist = { |
1918 | | BLACKLIST_ENTRY(DBOptions, env), |
1919 | | BLACKLIST_ENTRY(DBOptions, checkpoint_env), |
1920 | | BLACKLIST_ENTRY(DBOptions, priority_thread_pool_for_compactions_and_flushes), |
1921 | | BLACKLIST_ENTRY(DBOptions, rate_limiter), |
1922 | | BLACKLIST_ENTRY(DBOptions, sst_file_manager), |
1923 | | BLACKLIST_ENTRY(DBOptions, info_log), |
1924 | | BLACKLIST_ENTRY(DBOptions, statistics), |
1925 | | BLACKLIST_ENTRY(DBOptions, db_paths), |
1926 | | BLACKLIST_ENTRY(DBOptions, db_log_dir), |
1927 | | BLACKLIST_ENTRY(DBOptions, wal_dir), |
1928 | | BLACKLIST_ENTRY(DBOptions, memory_monitor), |
1929 | | BLACKLIST_ENTRY(DBOptions, listeners), |
1930 | | BLACKLIST_ENTRY(DBOptions, row_cache), |
1931 | | BLACKLIST_ENTRY(DBOptions, wal_filter), |
1932 | | BLACKLIST_ENTRY(DBOptions, boundary_extractor), |
1933 | | BLACKLIST_ENTRY(DBOptions, max_file_size_for_compaction), |
1934 | | BLACKLIST_ENTRY(DBOptions, mem_table_flush_filter_factory), |
1935 | | BLACKLIST_ENTRY(DBOptions, log_prefix), |
1936 | | BLACKLIST_ENTRY(DBOptions, mem_tracker), |
1937 | | BLACKLIST_ENTRY(DBOptions, block_based_table_mem_tracker), |
1938 | | BLACKLIST_ENTRY(DBOptions, iterator_replacer), |
1939 | | BLACKLIST_ENTRY(DBOptions, compaction_file_filter_factory), |
1940 | | }; |
1941 | | |
1942 | | TestAllFieldsSettable<DBOptions>(kDBOptionsBlacklist); |
1943 | | } |
1944 | | |
1945 | | // If the test fails, likely a new option is added to ColumnFamilyOptions |
1946 | | // but it cannot be set through GetColumnFamilyOptionsFromString(), or the |
1947 | | // test is not updated accordingly. |
1948 | | // After adding an option, we need to make sure it is settable by |
1949 | | // GetColumnFamilyOptionsFromString() and add the option to the input |
1950 | | // string passed to GetColumnFamilyOptionsFromString()in this test. |
1951 | | // If it is a complicated type, you also need to add the field to |
1952 | | // kColumnFamilyOptionsBlacklist, and maybe add customized verification |
1953 | | // for it. |
1954 | | TEST_F(OptionsParserTest, ColumnFamilyOptionsAllFieldsSettable) { |
1955 | | const OffsetGaps kColumnFamilyOptionsBlacklist = { |
1956 | | BLACKLIST_ENTRY(ColumnFamilyOptions, comparator), |
1957 | | BLACKLIST_ENTRY(ColumnFamilyOptions, merge_operator), |
1958 | | BLACKLIST_ENTRY(ColumnFamilyOptions, compaction_filter), |
1959 | | BLACKLIST_ENTRY(ColumnFamilyOptions, compaction_filter_factory), |
1960 | | BLACKLIST_ENTRY(ColumnFamilyOptions, compression_per_level), |
1961 | | BLACKLIST_ENTRY(ColumnFamilyOptions, prefix_extractor), |
1962 | | BLACKLIST_ENTRY(ColumnFamilyOptions, max_bytes_for_level_multiplier_additional), |
1963 | | BLACKLIST_ENTRY(ColumnFamilyOptions, memtable_factory), |
1964 | | BLACKLIST_ENTRY(ColumnFamilyOptions, table_factory), |
1965 | | BLACKLIST_ENTRY(ColumnFamilyOptions, table_properties_collector_factories), |
1966 | | BLACKLIST_ENTRY(ColumnFamilyOptions, inplace_callback), |
1967 | | }; |
1968 | | |
1969 | | TestAllFieldsSettable<ColumnFamilyOptions>(kColumnFamilyOptionsBlacklist); |
1970 | | } |
1971 | | #endif // __linux__ && !clang |
1972 | | #endif // !ROCKSDB_LITE |
1973 | | |
1974 | | } // namespace rocksdb |
1975 | | |
1976 | 13.2k | int main(int argc, char** argv) { |
1977 | 13.2k | ::testing::InitGoogleTest(&argc, argv); |
1978 | 13.2k | #ifdef GFLAGS |
1979 | 13.2k | ParseCommandLineFlags(&argc, &argv, true); |
1980 | 13.2k | #endif // GFLAGS |
1981 | 13.2k | return RUN_ALL_TESTS(); |
1982 | 13.2k | } |