/Users/deen/code/yugabyte-db/src/yb/rocksdb/util/testutil.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
2 | | // This source code is licensed under the BSD-style license found in the |
3 | | // LICENSE file in the root directory of this source tree. An additional grant |
4 | | // of patent rights can be found in the PATENTS file in the same directory. |
5 | | // |
6 | | // The following only applies to changes made to this file as part of YugaByte development. |
7 | | // |
8 | | // Portions Copyright (c) YugaByte, Inc. |
9 | | // |
10 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
11 | | // in compliance with the License. You may obtain a copy of the License at |
12 | | // |
13 | | // http://www.apache.org/licenses/LICENSE-2.0 |
14 | | // |
15 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
16 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
17 | | // or implied. See the License for the specific language governing permissions and limitations |
18 | | // under the License. |
19 | | // |
20 | | // Copyright (c) 2011 The LevelDB Authors. All rights reserved. |
21 | | // Use of this source code is governed by a BSD-style license that can be |
22 | | // found in the LICENSE file. See the AUTHORS file for names of contributors. |
23 | | |
24 | | #include "yb/rocksdb/util/testutil.h" |
25 | | |
26 | | #include <boost/functional/hash.hpp> |
27 | | |
28 | | #include <gtest/gtest.h> |
29 | | |
30 | | #include "yb/gutil/casts.h" |
31 | | |
32 | | #include "yb/rocksdb/port/port.h" |
33 | | #include "yb/rocksdb/util/file_reader_writer.h" |
34 | | |
35 | | namespace rocksdb { |
36 | | namespace test { |
37 | | |
38 | 295k | extern std::string RandomHumanReadableString(Random* rnd, int len) { |
39 | 295k | std::string ret; |
40 | 295k | ret.resize(len); |
41 | 11.2M | for (int i = 0; i < len; ++i10.9M ) { |
42 | 10.9M | ret[i] = static_cast<char>('a' + rnd->Uniform(26)); |
43 | 10.9M | } |
44 | 295k | return ret; |
45 | 295k | } |
46 | | |
47 | 2.77M | std::string RandomKey(Random* rnd, int len, RandomKeyType type) { |
48 | | // Make sure to generate a wide variety of characters so we |
49 | | // test the boundary conditions for short-key optimizations. |
50 | 2.77M | static const char kTestChars[] = { |
51 | 2.77M | '\0', '\1', 'a', 'b', 'c', 'd', 'e', '\xfd', '\xfe', '\xff' |
52 | 2.77M | }; |
53 | 2.77M | std::string result; |
54 | 11.5M | for (int i = 0; i < len; i++8.76M ) { |
55 | 8.76M | std::size_t indx = 0; |
56 | 8.76M | switch (type) { |
57 | 8.76M | case RandomKeyType::RANDOM: |
58 | 8.76M | indx = rnd->Uniform(sizeof(kTestChars)); |
59 | 8.76M | break; |
60 | 0 | case RandomKeyType::LARGEST: |
61 | 0 | indx = sizeof(kTestChars) - 1; |
62 | 0 | break; |
63 | 0 | case RandomKeyType::MIDDLE: |
64 | 0 | indx = sizeof(kTestChars) / 2; |
65 | 0 | break; |
66 | 0 | case RandomKeyType::SMALLEST: |
67 | 0 | indx = 0; |
68 | 0 | break; |
69 | 8.76M | } |
70 | 8.76M | result += kTestChars[indx]; |
71 | 8.76M | } |
72 | 2.77M | return result; |
73 | 2.77M | } |
74 | | |
75 | | |
76 | 4.07k | WritableFileWriter* GetWritableFileWriter(WritableFile* wf) { |
77 | 4.07k | unique_ptr<WritableFile> file(wf); |
78 | 4.07k | return new WritableFileWriter(std::move(file), EnvOptions()); |
79 | 4.07k | } |
80 | | |
81 | 4.04k | RandomAccessFileReader* GetRandomAccessFileReader(RandomAccessFile* raf) { |
82 | 4.04k | unique_ptr<RandomAccessFile> file(raf); |
83 | 4.04k | return new RandomAccessFileReader(std::move(file)); |
84 | 4.04k | } |
85 | | |
86 | 112 | SequentialFileReader* GetSequentialFileReader(SequentialFile* se) { |
87 | 112 | unique_ptr<SequentialFile> file(se); |
88 | 112 | return new SequentialFileReader(std::move(file)); |
89 | 112 | } |
90 | | |
91 | 804 | void CorruptKeyType(InternalKey* ikey) { |
92 | 804 | std::string keystr = ikey->Encode().ToString(); |
93 | 804 | keystr[keystr.size() - 8] = kTypeLogData; |
94 | 804 | *ikey = InternalKey::DecodeFrom(Slice(keystr.data(), keystr.size())); |
95 | 804 | } |
96 | | |
97 | | std::string KeyStr(const std::string& user_key, const SequenceNumber& seq, |
98 | 10 | const ValueType& t, bool corrupt) { |
99 | 10 | InternalKey k(user_key, seq, t); |
100 | 10 | if (corrupt) { |
101 | 4 | CorruptKeyType(&k); |
102 | 4 | } |
103 | 10 | return k.Encode().ToString(); |
104 | 10 | } |
105 | | |
106 | 98 | std::string RandomName(Random* rnd, const size_t len) { |
107 | 98 | std::stringstream ss; |
108 | 1.07k | for (size_t i = 0; i < len; ++i980 ) { |
109 | 980 | ss << static_cast<char>(rnd->Uniform(26) + 'a'); |
110 | 980 | } |
111 | 98 | return ss.str(); |
112 | 98 | } |
113 | | |
114 | 1.10k | CompressionType RandomCompressionType(Random* rnd) { |
115 | 1.10k | return static_cast<CompressionType>(rnd->Uniform(6)); |
116 | 1.10k | } |
117 | | |
118 | | void RandomCompressionTypeVector(const size_t count, |
119 | | std::vector<CompressionType>* types, |
120 | 22 | Random* rnd) { |
121 | 22 | types->clear(); |
122 | 1.10k | for (size_t i = 0; i < count; ++i1.08k ) { |
123 | 1.08k | types->emplace_back(RandomCompressionType(rnd)); |
124 | 1.08k | } |
125 | 22 | } |
126 | | |
127 | 30 | const SliceTransform* RandomSliceTransform(Random* rnd, int pre_defined) { |
128 | 30 | int random_num = pre_defined >= 0 ? pre_defined4 : rnd->Uniform(4)26 ; |
129 | 30 | switch (random_num) { |
130 | 6 | case 0: |
131 | 6 | return NewFixedPrefixTransform(rnd->Uniform(20) + 1); |
132 | 14 | case 1: |
133 | 14 | return NewCappedPrefixTransform(rnd->Uniform(20) + 1); |
134 | 6 | case 2: |
135 | 6 | return NewNoopTransform(); |
136 | 4 | default: |
137 | 4 | return nullptr; |
138 | 30 | } |
139 | 30 | } |
140 | | |
141 | 0 | BlockBasedTableOptions RandomBlockBasedTableOptions(Random* rnd) { |
142 | 0 | BlockBasedTableOptions opt; |
143 | 0 | opt.cache_index_and_filter_blocks = rnd->Uniform(2); |
144 | 0 | opt.index_type = static_cast<IndexType>(rnd->Uniform(kElementsInIndexType)); |
145 | 0 | opt.hash_index_allow_collision = rnd->Uniform(2); |
146 | 0 | opt.checksum = static_cast<ChecksumType>(rnd->Uniform(3)); |
147 | 0 | opt.block_size = rnd->Uniform(10000000); |
148 | 0 | opt.block_size_deviation = rnd->Uniform(100); |
149 | 0 | opt.block_restart_interval = rnd->Uniform(100); |
150 | 0 | opt.index_block_restart_interval = rnd->Uniform(100); |
151 | 0 | opt.whole_key_filtering = rnd->Uniform(2); |
152 | |
|
153 | 0 | return opt; |
154 | 0 | } |
155 | | |
156 | 27 | TableFactory* RandomTableFactory(Random* rnd, int pre_defined) { |
157 | 27 | int random_num = pre_defined >= 0 ? pre_defined5 : rnd->Uniform(2)22 ; |
158 | 27 | switch (random_num) { |
159 | 14 | case 0: |
160 | 14 | return NewPlainTableFactory(); |
161 | 13 | default: |
162 | 13 | return NewBlockBasedTableFactory(); |
163 | 27 | } |
164 | 27 | } |
165 | | |
166 | 32 | MergeOperator* RandomMergeOperator(Random* rnd) { |
167 | 32 | return new ChanglingMergeOperator(RandomName(rnd, 10)); |
168 | 32 | } |
169 | | |
170 | 27 | CompactionFilter* RandomCompactionFilter(Random* rnd) { |
171 | 27 | return new ChanglingCompactionFilter(RandomName(rnd, 10)); |
172 | 27 | } |
173 | | |
174 | 27 | CompactionFilterFactory* RandomCompactionFilterFactory(Random* rnd) { |
175 | 27 | return new ChanglingCompactionFilterFactory(RandomName(rnd, 10)); |
176 | 27 | } |
177 | | |
178 | 5 | void RandomInitDBOptions(DBOptions* db_opt, Random* rnd) { |
179 | | // boolean options |
180 | 5 | db_opt->advise_random_on_open = rnd->Uniform(2); |
181 | 5 | db_opt->allow_mmap_reads = rnd->Uniform(2); |
182 | 5 | db_opt->allow_mmap_writes = rnd->Uniform(2); |
183 | 5 | db_opt->allow_os_buffer = rnd->Uniform(2); |
184 | 5 | db_opt->create_if_missing = rnd->Uniform(2); |
185 | 5 | db_opt->create_missing_column_families = rnd->Uniform(2); |
186 | 5 | db_opt->disableDataSync = rnd->Uniform(2); |
187 | 5 | db_opt->enable_thread_tracking = false; |
188 | 5 | db_opt->error_if_exists = rnd->Uniform(2); |
189 | 5 | db_opt->is_fd_close_on_exec = rnd->Uniform(2); |
190 | 5 | db_opt->paranoid_checks = rnd->Uniform(2); |
191 | 5 | db_opt->skip_log_error_on_recovery = rnd->Uniform(2); |
192 | 5 | db_opt->skip_stats_update_on_db_open = rnd->Uniform(2); |
193 | 5 | db_opt->use_adaptive_mutex = rnd->Uniform(2); |
194 | 5 | db_opt->use_fsync = rnd->Uniform(2); |
195 | 5 | db_opt->recycle_log_file_num = rnd->Uniform(2); |
196 | | |
197 | | // int options |
198 | 5 | db_opt->max_background_compactions = rnd->Uniform(100); |
199 | 5 | db_opt->max_background_flushes = rnd->Uniform(100); |
200 | 5 | db_opt->max_file_opening_threads = rnd->Uniform(100); |
201 | 5 | db_opt->max_open_files = rnd->Uniform(100); |
202 | 5 | db_opt->table_cache_numshardbits = rnd->Uniform(100); |
203 | | |
204 | | // size_t options |
205 | 5 | db_opt->db_write_buffer_size = rnd->Uniform(10000); |
206 | 5 | db_opt->keep_log_file_num = rnd->Uniform(10000); |
207 | 5 | db_opt->log_file_time_to_roll = rnd->Uniform(10000); |
208 | 5 | db_opt->manifest_preallocation_size = rnd->Uniform(10000); |
209 | 5 | db_opt->max_log_file_size = rnd->Uniform(10000); |
210 | | |
211 | | // std::string options |
212 | 5 | db_opt->db_log_dir = "path/to/db_log_dir"; |
213 | 5 | db_opt->wal_dir = "path/to/wal_dir"; |
214 | | |
215 | | // uint32_t options |
216 | 5 | db_opt->max_subcompactions = rnd->Uniform(100000); |
217 | | |
218 | | // uint64_t options |
219 | 5 | static const uint64_t uint_max = static_cast<uint64_t>(UINT_MAX); |
220 | 5 | db_opt->WAL_size_limit_MB = uint_max + rnd->Uniform(100000); |
221 | 5 | db_opt->WAL_ttl_seconds = uint_max + rnd->Uniform(100000); |
222 | 5 | db_opt->bytes_per_sync = uint_max + rnd->Uniform(100000); |
223 | 5 | db_opt->delayed_write_rate = uint_max + rnd->Uniform(100000); |
224 | 5 | db_opt->delete_obsolete_files_period_micros = uint_max + rnd->Uniform(100000); |
225 | 5 | db_opt->max_manifest_file_size = uint_max + rnd->Uniform(100000); |
226 | 5 | db_opt->max_total_wal_size = uint_max + rnd->Uniform(100000); |
227 | 5 | db_opt->wal_bytes_per_sync = uint_max + rnd->Uniform(100000); |
228 | | |
229 | | // unsigned int options |
230 | 5 | db_opt->stats_dump_period_sec = rnd->Uniform(100000); |
231 | 5 | } |
232 | | |
233 | 22 | void RandomInitCFOptions(ColumnFamilyOptions* cf_opt, Random* rnd) { |
234 | 22 | cf_opt->compaction_style = (CompactionStyle)(rnd->Uniform(4)); |
235 | | |
236 | | // boolean options |
237 | 22 | cf_opt->compaction_measure_io_stats = rnd->Uniform(2); |
238 | 22 | cf_opt->disable_auto_compactions = rnd->Uniform(2); |
239 | 22 | cf_opt->filter_deletes = rnd->Uniform(2); |
240 | 22 | cf_opt->inplace_update_support = rnd->Uniform(2); |
241 | 22 | cf_opt->level_compaction_dynamic_level_bytes = rnd->Uniform(2); |
242 | 22 | cf_opt->optimize_filters_for_hits = rnd->Uniform(2); |
243 | 22 | cf_opt->paranoid_file_checks = rnd->Uniform(2); |
244 | 22 | cf_opt->purge_redundant_kvs_while_flush = rnd->Uniform(2); |
245 | 22 | cf_opt->verify_checksums_in_compaction = rnd->Uniform(2); |
246 | | |
247 | | // double options |
248 | 22 | cf_opt->hard_rate_limit = static_cast<double>(rnd->Uniform(10000)) / 13; |
249 | 22 | cf_opt->soft_rate_limit = static_cast<double>(rnd->Uniform(10000)) / 13; |
250 | | |
251 | | // int options |
252 | 22 | cf_opt->expanded_compaction_factor = rnd->Uniform(100); |
253 | 22 | cf_opt->level0_file_num_compaction_trigger = rnd->Uniform(100); |
254 | 22 | cf_opt->level0_slowdown_writes_trigger = rnd->Uniform(100); |
255 | 22 | cf_opt->level0_stop_writes_trigger = rnd->Uniform(100); |
256 | 22 | cf_opt->max_bytes_for_level_multiplier = rnd->Uniform(100); |
257 | 22 | cf_opt->max_grandparent_overlap_factor = rnd->Uniform(100); |
258 | 22 | cf_opt->max_mem_compaction_level = rnd->Uniform(100); |
259 | 22 | cf_opt->max_write_buffer_number = rnd->Uniform(100); |
260 | 22 | cf_opt->max_write_buffer_number_to_maintain = rnd->Uniform(100); |
261 | 22 | cf_opt->min_write_buffer_number_to_merge = rnd->Uniform(100); |
262 | 22 | cf_opt->num_levels = rnd->Uniform(100); |
263 | 22 | cf_opt->source_compaction_factor = rnd->Uniform(100); |
264 | 22 | cf_opt->target_file_size_multiplier = rnd->Uniform(100); |
265 | | |
266 | | // size_t options |
267 | 22 | cf_opt->arena_block_size = rnd->Uniform(10000); |
268 | 22 | cf_opt->inplace_update_num_locks = rnd->Uniform(10000); |
269 | 22 | cf_opt->max_successive_merges = rnd->Uniform(10000); |
270 | 22 | cf_opt->memtable_prefix_bloom_huge_page_tlb_size = rnd->Uniform(10000); |
271 | 22 | cf_opt->write_buffer_size = rnd->Uniform(10000); |
272 | | |
273 | | // uint32_t options |
274 | 22 | cf_opt->bloom_locality = rnd->Uniform(10000); |
275 | 22 | cf_opt->memtable_prefix_bloom_bits = rnd->Uniform(10000); |
276 | 22 | cf_opt->memtable_prefix_bloom_probes = rnd->Uniform(10000); |
277 | 22 | cf_opt->min_partial_merge_operands = rnd->Uniform(10000); |
278 | 22 | cf_opt->max_bytes_for_level_base = rnd->Uniform(10000); |
279 | | |
280 | | // uint64_t options |
281 | 22 | static const uint64_t uint_max = static_cast<uint64_t>(UINT_MAX); |
282 | 22 | cf_opt->max_sequential_skip_in_iterations = uint_max + rnd->Uniform(10000); |
283 | 22 | cf_opt->target_file_size_base = uint_max + rnd->Uniform(10000); |
284 | | |
285 | | // unsigned int options |
286 | 22 | cf_opt->rate_limit_delay_max_milliseconds = rnd->Uniform(10000); |
287 | | |
288 | | // pointer typed options |
289 | 22 | cf_opt->prefix_extractor.reset(RandomSliceTransform(rnd)); |
290 | 22 | cf_opt->table_factory.reset(RandomTableFactory(rnd)); |
291 | 22 | cf_opt->merge_operator.reset(RandomMergeOperator(rnd)); |
292 | 22 | if (cf_opt->compaction_filter) { |
293 | 5 | delete cf_opt->compaction_filter; |
294 | 5 | } |
295 | 22 | cf_opt->compaction_filter = RandomCompactionFilter(rnd); |
296 | 22 | cf_opt->compaction_filter_factory.reset(RandomCompactionFilterFactory(rnd)); |
297 | | |
298 | | // custom typed options |
299 | 22 | cf_opt->compression = RandomCompressionType(rnd); |
300 | 22 | RandomCompressionTypeVector(cf_opt->num_levels, |
301 | 22 | &cf_opt->compression_per_level, rnd); |
302 | 22 | } |
303 | | |
304 | | namespace { |
305 | | |
306 | | enum TestBoundaryUserValueTag { |
307 | | TAG_INT_VALUE, |
308 | | TAG_STRING_VALUE, |
309 | | }; |
310 | | |
311 | 566 | Slice EncodeValue(const int64_t &value) { |
312 | 566 | return Slice(reinterpret_cast<const char *>(&value), sizeof(value)); |
313 | 566 | } |
314 | | |
315 | 104k | int CompareValues(int64_t lhs, int64_t rhs) { |
316 | 104k | return lhs > rhs ? 152.1k : (52.2k lhs == rhs52.2k ? 056 : -152.1k ); |
317 | 104k | } |
318 | | |
319 | 104k | int CompareValues(const std::string& lhs, const std::string& rhs) { |
320 | 104k | return lhs.compare(rhs); |
321 | 104k | } |
322 | | |
323 | 566 | Slice EncodeValue(const std::string &value) { |
324 | 566 | return value; |
325 | 566 | } |
326 | | |
327 | | template<UserBoundaryTag TAG, class T> |
328 | | class TestBoundaryUserValue : public UserBoundaryValue { |
329 | | public: |
330 | 104k | explicit TestBoundaryUserValue(T value) : value_(value) {} testutil.cc:rocksdb::test::(anonymous namespace)::TestBoundaryUserValue<0u, long long>::TestBoundaryUserValue(long long) Line | Count | Source | 330 | 52.3k | explicit TestBoundaryUserValue(T value) : value_(value) {} |
testutil.cc:rocksdb::test::(anonymous namespace)::TestBoundaryUserValue<1u, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::TestBoundaryUserValue(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >) Line | Count | Source | 330 | 52.3k | explicit TestBoundaryUserValue(T value) : value_(value) {} |
|
331 | | |
332 | 523k | UserBoundaryTag Tag() override { return TAG; } testutil.cc:rocksdb::test::(anonymous namespace)::TestBoundaryUserValue<0u, long long>::Tag() Line | Count | Source | 332 | 313k | UserBoundaryTag Tag() override { return TAG; } |
testutil.cc:rocksdb::test::(anonymous namespace)::TestBoundaryUserValue<1u, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::Tag() Line | Count | Source | 332 | 209k | UserBoundaryTag Tag() override { return TAG; } |
|
333 | | |
334 | 1.13k | Slice Encode() override { |
335 | 1.13k | return EncodeValue(value_); |
336 | 1.13k | } testutil.cc:rocksdb::test::(anonymous namespace)::TestBoundaryUserValue<0u, long long>::Encode() Line | Count | Source | 334 | 566 | Slice Encode() override { | 335 | 566 | return EncodeValue(value_); | 336 | 566 | } |
testutil.cc:rocksdb::test::(anonymous namespace)::TestBoundaryUserValue<1u, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::Encode() Line | Count | Source | 334 | 566 | Slice Encode() override { | 335 | 566 | return EncodeValue(value_); | 336 | 566 | } |
|
337 | | |
338 | 208k | int CompareTo(const UserBoundaryValue& rhs) override { |
339 | 208k | return CompareValues(value_, static_cast<const TestBoundaryUserValue<TAG, T>*>(&rhs)->value_); |
340 | 208k | } testutil.cc:rocksdb::test::(anonymous namespace)::TestBoundaryUserValue<0u, long long>::CompareTo(rocksdb::UserBoundaryValue const&) Line | Count | Source | 338 | 104k | int CompareTo(const UserBoundaryValue& rhs) override { | 339 | 104k | return CompareValues(value_, static_cast<const TestBoundaryUserValue<TAG, T>*>(&rhs)->value_); | 340 | 104k | } |
testutil.cc:rocksdb::test::(anonymous namespace)::TestBoundaryUserValue<1u, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::CompareTo(rocksdb::UserBoundaryValue const&) Line | Count | Source | 338 | 104k | int CompareTo(const UserBoundaryValue& rhs) override { | 339 | 104k | return CompareValues(value_, static_cast<const TestBoundaryUserValue<TAG, T>*>(&rhs)->value_); | 340 | 104k | } |
|
341 | | |
342 | 16 | const T& value() const { |
343 | 16 | return value_; |
344 | 16 | } testutil.cc:rocksdb::test::(anonymous namespace)::TestBoundaryUserValue<0u, long long>::value() const Line | Count | Source | 342 | 8 | const T& value() const { | 343 | 8 | return value_; | 344 | 8 | } |
testutil.cc:rocksdb::test::(anonymous namespace)::TestBoundaryUserValue<1u, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::value() const Line | Count | Source | 342 | 8 | const T& value() const { | 343 | 8 | return value_; | 344 | 8 | } |
|
345 | | |
346 | 104k | virtual ~TestBoundaryUserValue() {} testutil.cc:rocksdb::test::(anonymous namespace)::TestBoundaryUserValue<0u, long long>::~TestBoundaryUserValue() Line | Count | Source | 346 | 52.3k | virtual ~TestBoundaryUserValue() {} |
testutil.cc:rocksdb::test::(anonymous namespace)::TestBoundaryUserValue<1u, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::~TestBoundaryUserValue() Line | Count | Source | 346 | 52.3k | virtual ~TestBoundaryUserValue() {} |
|
347 | | private: |
348 | | T value_; |
349 | | }; |
350 | | |
351 | | // Use some weird logic to extract int value from key. |
352 | 102k | int64_t ExtractIntValue(Slice key) { |
353 | 102k | return boost::hash_range(key.data(), key.end()); |
354 | 102k | } |
355 | | |
356 | | // Use some weird logic to extract string value from key. |
357 | 102k | std::string ExtractStringValue(Slice key) { |
358 | 102k | std::string temp = key.ToBuffer(); |
359 | 102k | std::reverse(temp.begin(), temp.end()); |
360 | 102k | return temp; |
361 | 102k | } |
362 | | |
363 | | typedef TestBoundaryUserValue<TAG_INT_VALUE, int64_t> IntValue; |
364 | | typedef TestBoundaryUserValue<TAG_STRING_VALUE, std::string> StringValue; |
365 | | |
366 | | class TestBoundaryValuesExtractor: public BoundaryValuesExtractor { |
367 | | public: |
368 | 60 | Status Decode(UserBoundaryTag tag, Slice data, UserBoundaryValuePtr *value) override { |
369 | 60 | switch (static_cast<TestBoundaryUserValueTag>(tag)) { |
370 | 30 | case TAG_INT_VALUE: { |
371 | 30 | if (sizeof(int64_t) != data.size()) { |
372 | 0 | return STATUS(Corruption, "Invalid size of data " + std::to_string(data.size())); |
373 | 0 | } |
374 | | |
375 | 30 | int64_t temp; |
376 | 30 | memcpy(&temp, data.data(), sizeof(temp)); |
377 | 30 | *value = std::make_shared<IntValue>(temp); |
378 | 30 | break; |
379 | 30 | } |
380 | 30 | case TAG_STRING_VALUE: |
381 | 30 | *value = std::make_shared<StringValue>(data.ToBuffer()); |
382 | 30 | break; |
383 | 60 | } |
384 | 60 | return Status::OK(); |
385 | 60 | } |
386 | | |
387 | 52.2k | Status Extract(Slice user_key, Slice value, UserBoundaryValues *values) override { |
388 | 52.2k | values->push_back(MakeIntBoundaryValue(ExtractIntValue(user_key))); |
389 | 52.2k | values->push_back(MakeStringBoundaryValue(ExtractStringValue(user_key))); |
390 | 52.2k | return Status::OK(); |
391 | 52.2k | } |
392 | | |
393 | 35 | UserFrontierPtr CreateFrontier() override { |
394 | 35 | return new TestUserFrontier(0); |
395 | 35 | } |
396 | | |
397 | 34 | virtual ~TestBoundaryValuesExtractor() {} |
398 | | private: |
399 | | }; |
400 | | |
401 | | } // namespace |
402 | | |
403 | 84 | std::string TestUserFrontier::ToString() const { |
404 | 84 | return YB_CLASS_TO_STRING(value); |
405 | 84 | } |
406 | | |
407 | 8 | int64_t GetBoundaryInt(const UserBoundaryValues& values) { |
408 | 8 | auto value = UserValueWithTag(values, TAG_INT_VALUE); |
409 | 8 | EXPECT_NE(value, nullptr); |
410 | 8 | auto* int_value = down_cast<IntValue*>(value.get()); |
411 | 8 | return int_value ? int_value->value() : 00 ; |
412 | 8 | } |
413 | | |
414 | 8 | std::string GetBoundaryString(const UserBoundaryValues& values) { |
415 | 8 | auto value = UserValueWithTag(values, TAG_STRING_VALUE); |
416 | 8 | EXPECT_NE(value, nullptr); |
417 | 8 | auto* string_value = down_cast<StringValue*>(value.get()); |
418 | 8 | return string_value ? string_value->value() : std::string()0 ; |
419 | 8 | } |
420 | | |
421 | 34 | std::shared_ptr<BoundaryValuesExtractor> MakeBoundaryValuesExtractor() { |
422 | 34 | return std::make_shared<TestBoundaryValuesExtractor>(); |
423 | 34 | } |
424 | | |
425 | 52.2k | UserBoundaryValuePtr MakeIntBoundaryValue(int64_t value) { |
426 | 52.2k | return std::make_shared<TestBoundaryUserValue<TAG_INT_VALUE, int64_t>>(value); |
427 | 52.2k | } |
428 | | |
429 | 52.2k | UserBoundaryValuePtr MakeStringBoundaryValue(std::string value) { |
430 | 52.2k | return std::make_shared<TestBoundaryUserValue<TAG_STRING_VALUE, std::string>>(std::move(value)); |
431 | 52.2k | } |
432 | | |
433 | 50.2k | void BoundaryTestValues::Feed(Slice key) { |
434 | 50.2k | auto int_value = ExtractIntValue(key); |
435 | 50.2k | min_int = std::min(min_int, int_value); |
436 | 50.2k | max_int = std::max(max_int, int_value); |
437 | 50.2k | auto string_value = ExtractStringValue(key); |
438 | 50.2k | if (min_string.empty()) { |
439 | 44 | min_string = string_value; |
440 | 44 | max_string = std::move(string_value); |
441 | 50.1k | } else { |
442 | 50.1k | if (string_value < min_string) { |
443 | 4 | min_string = std::move(string_value); |
444 | 50.1k | } else if (string_value > max_string) { |
445 | 249 | max_string = std::move(string_value); |
446 | 249 | } |
447 | 50.1k | } |
448 | 50.2k | } |
449 | | |
450 | | void BoundaryTestValues::Check(const FileBoundaryValues<InternalKey>& smallest, |
451 | 1 | const FileBoundaryValues<InternalKey>& largest) { |
452 | 1 | ASSERT_EQ(min_int, GetBoundaryInt(smallest.user_values)); |
453 | 1 | ASSERT_EQ(max_int, GetBoundaryInt(largest.user_values)); |
454 | 1 | ASSERT_EQ(min_string, GetBoundaryString(smallest.user_values)); |
455 | 1 | ASSERT_EQ(max_string, GetBoundaryString(largest.user_values)); |
456 | 1 | } |
457 | | |
458 | | |
459 | | } // namespace test |
460 | | } // namespace rocksdb |