/Users/deen/code/yugabyte-db/src/yb/rocksdb/util/options_helper.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 | | |
21 | | #include "yb/rocksdb/util/options_helper.h" |
22 | | |
23 | | #include <cassert> |
24 | | #include <vector> |
25 | | |
26 | | #include "yb/rocksdb/cache.h" |
27 | | #include "yb/rocksdb/compaction_filter.h" |
28 | | #include "yb/rocksdb/convenience.h" |
29 | | #include "yb/rocksdb/db/dbformat.h" |
30 | | #include "yb/rocksdb/filter_policy.h" |
31 | | #include "yb/rocksdb/flush_block_policy.h" |
32 | | #include "yb/rocksdb/memtablerep.h" |
33 | | #include "yb/rocksdb/merge_operator.h" |
34 | | #include "yb/rocksdb/options.h" |
35 | | #include "yb/rocksdb/rate_limiter.h" |
36 | | #include "yb/rocksdb/slice_transform.h" |
37 | | #include "yb/rocksdb/table.h" |
38 | | #include "yb/rocksdb/table/block_based_table_factory.h" |
39 | | #include "yb/rocksdb/table/plain_table_factory.h" |
40 | | |
41 | | #include "yb/util/string_util.h" |
42 | | |
43 | | namespace rocksdb { |
44 | | |
45 | | #ifndef ROCKSDB_LITE |
46 | 205M | bool isSpecialChar(const char c) { |
47 | 205M | if (c == '\\' || c == '#' || c == ':' || c == '\r' || c == '\n') { |
48 | 80 | return true; |
49 | 80 | } |
50 | 205M | return false; |
51 | 205M | } |
52 | | |
53 | 214 | char UnescapeChar(const char c) { |
54 | 214 | static const std::unordered_map<char, char> convert_map = {{'r', '\r'}, |
55 | 214 | {'n', '\n'}}; |
56 | | |
57 | 214 | auto iter = convert_map.find(c); |
58 | 214 | if (iter == convert_map.end()) { |
59 | 210 | return c; |
60 | 210 | } |
61 | 4 | return iter->second; |
62 | 4 | } |
63 | | |
64 | 71 | char EscapeChar(const char c) { |
65 | 71 | static const std::unordered_map<char, char> convert_map = {{'\n', 'n'}, |
66 | 71 | {'\r', 'r'}}; |
67 | | |
68 | 71 | auto iter = convert_map.find(c); |
69 | 71 | if (iter == convert_map.end()) { |
70 | 69 | return c; |
71 | 69 | } |
72 | 2 | return iter->second; |
73 | 2 | } |
74 | | |
75 | 4.01M | std::string EscapeOptionString(const std::string& raw_string) { |
76 | 4.01M | std::string output; |
77 | 205M | for (auto c : raw_string) { |
78 | 205M | if (isSpecialChar(c)) { |
79 | 71 | output += '\\'; |
80 | 71 | output += EscapeChar(c); |
81 | 205M | } else { |
82 | 205M | output += c; |
83 | 205M | } |
84 | 205M | } |
85 | | |
86 | 4.01M | return output; |
87 | 4.01M | } |
88 | | |
89 | 122M | std::string UnescapeOptionString(const std::string& escaped_string) { |
90 | 122M | bool escaped = false; |
91 | 122M | std::string output; |
92 | | |
93 | 868M | for (auto c : escaped_string) { |
94 | 868M | if (escaped) { |
95 | 212 | output += UnescapeChar(c); |
96 | 212 | escaped = false; |
97 | 868M | } else { |
98 | 868M | if (c == '\\') { |
99 | 212 | escaped = true; |
100 | 212 | continue; |
101 | 212 | } |
102 | 868M | output += c; |
103 | 868M | } |
104 | 868M | } |
105 | 122M | return output; |
106 | 122M | } |
107 | | |
108 | | namespace { |
109 | 21.9k | std::string trim(const std::string& str) { |
110 | 21.9k | if (str.empty()) return std::string(); |
111 | 20.7k | size_t start = 0; |
112 | 20.7k | size_t end = str.size() - 1; |
113 | 21.6k | while (isspace(str[start]) != 0 && start <= end) { |
114 | 873 | ++start; |
115 | 873 | } |
116 | 21.9k | while (isspace(str[end]) != 0 && start <= end) { |
117 | 1.18k | --end; |
118 | 1.18k | } |
119 | 20.7k | if (start <= end) { |
120 | 20.5k | return str.substr(start, end - start + 1); |
121 | 20.5k | } |
122 | 184 | return std::string(); |
123 | 184 | } |
124 | | |
125 | | template <typename T> |
126 | | bool ParseEnum(const std::unordered_map<std::string, T>& type_map, |
127 | 7.02M | const std::string& type, T* value) { |
128 | 7.02M | auto iter = type_map.find(type); |
129 | 7.02M | if (iter != type_map.end()) { |
130 | 7.02M | *value = iter->second; |
131 | 7.02M | return true; |
132 | 7.02M | } |
133 | 805 | return false; |
134 | 805 | } options_helper.cc:_ZN7rocksdb12_GLOBAL__N_19ParseEnumINS_15CompactionStyleEEEbRKNSt3__113unordered_mapINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEET_NS3_4hashISA_EENS3_8equal_toISA_EENS8_INS3_4pairIKSA_SB_EEEEEERSH_PSB_ Line | Count | Source | 127 | 1.00M | const std::string& type, T* value) { | 128 | 1.00M | auto iter = type_map.find(type); | 129 | 1.00M | if (iter != type_map.end()) { | 130 | 1.00M | *value = iter->second; | 131 | 1.00M | return true; | 132 | 1.00M | } | 133 | 230 | return false; | 134 | 230 | } |
options_helper.cc:_ZN7rocksdb12_GLOBAL__N_19ParseEnumINS_15CompressionTypeEEEbRKNSt3__113unordered_mapINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEET_NS3_4hashISA_EENS3_8equal_toISA_EENS8_INS3_4pairIKSA_SB_EEEEEERSH_PSB_ Line | Count | Source | 127 | 1.01M | const std::string& type, T* value) { | 128 | 1.01M | auto iter = type_map.find(type); | 129 | 1.01M | if (iter != type_map.end()) { | 130 | 1.00M | *value = iter->second; | 131 | 1.00M | return true; | 132 | 1.00M | } | 133 | 235 | return false; | 134 | 235 | } |
options_helper.cc:_ZN7rocksdb12_GLOBAL__N_19ParseEnumINS_12ChecksumTypeEEEbRKNSt3__113unordered_mapINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEET_NS3_4hashISA_EENS3_8equal_toISA_EENS8_INS3_4pairIKSA_SB_EEEEEERSH_PSB_ Line | Count | Source | 127 | 1.00M | const std::string& type, T* value) { | 128 | 1.00M | auto iter = type_map.find(type); | 129 | 1.00M | if (iter != type_map.end()) { | 130 | 1.00M | *value = iter->second; | 131 | 1.00M | return true; | 132 | 1.00M | } | 133 | 18.4E | return false; | 134 | 18.4E | } |
options_helper.cc:_ZN7rocksdb12_GLOBAL__N_19ParseEnumINS_9IndexTypeEEEbRKNSt3__113unordered_mapINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEET_NS3_4hashISA_EENS3_8equal_toISA_EENS8_INS3_4pairIKSA_SB_EEEEEERSH_PSB_ Line | Count | Source | 127 | 1.00M | const std::string& type, T* value) { | 128 | 1.00M | auto iter = type_map.find(type); | 129 | 1.00M | if (iter != type_map.end()) { | 130 | 1.00M | *value = iter->second; | 131 | 1.00M | return true; | 132 | 1.00M | } | 133 | 155 | return false; | 134 | 155 | } |
options_helper.cc:_ZN7rocksdb12_GLOBAL__N_19ParseEnumINS_12EncodingTypeEEEbRKNSt3__113unordered_mapINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEET_NS3_4hashISA_EENS3_8equal_toISA_EENS8_INS3_4pairIKSA_SB_EEEEEERSH_PSB_ Line | Count | Source | 127 | 2 | const std::string& type, T* value) { | 128 | 2 | auto iter = type_map.find(type); | 129 | 2 | if (iter != type_map.end()) { | 130 | 1 | *value = iter->second; | 131 | 1 | return true; | 132 | 1 | } | 133 | 1 | return false; | 134 | 1 | } |
options_helper.cc:_ZN7rocksdb12_GLOBAL__N_19ParseEnumINS_15WALRecoveryModeEEEbRKNSt3__113unordered_mapINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEET_NS3_4hashISA_EENS3_8equal_toISA_EENS8_INS3_4pairIKSA_SB_EEEEEERSH_PSB_ Line | Count | Source | 127 | 1.00M | const std::string& type, T* value) { | 128 | 1.00M | auto iter = type_map.find(type); | 129 | 1.00M | if (iter != type_map.end()) { | 130 | 1.00M | *value = iter->second; | 131 | 1.00M | return true; | 132 | 1.00M | } | 133 | 191 | return false; | 134 | 191 | } |
options_helper.cc:_ZN7rocksdb12_GLOBAL__N_19ParseEnumINS_9DBOptions10AccessHintEEEbRKNSt3__113unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEET_NS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SC_EEEEEERSI_PSC_ Line | Count | Source | 127 | 1.00M | const std::string& type, T* value) { | 128 | 1.00M | auto iter = type_map.find(type); | 129 | 1.00M | if (iter != type_map.end()) { | 130 | 1.00M | *value = iter->second; | 131 | 1.00M | return true; | 132 | 1.00M | } | 133 | 12 | return false; | 134 | 12 | } |
options_helper.cc:_ZN7rocksdb12_GLOBAL__N_19ParseEnumINS_12InfoLogLevelEEEbRKNSt3__113unordered_mapINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEET_NS3_4hashISA_EENS3_8equal_toISA_EENS8_INS3_4pairIKSA_SB_EEEEEERSH_PSB_ Line | Count | Source | 127 | 1.00M | const std::string& type, T* value) { | 128 | 1.00M | auto iter = type_map.find(type); | 129 | 1.00M | if (iter != type_map.end()) { | 130 | 1.00M | *value = iter->second; | 131 | 1.00M | return true; | 132 | 1.00M | } | 133 | 61 | return false; | 134 | 61 | } |
|
135 | | |
136 | | template <typename T> |
137 | | bool SerializeEnum(const std::unordered_map<std::string, T>& type_map, |
138 | 7.02M | const T& type, std::string* value) { |
139 | 17.1M | for (const auto& pair : type_map) { |
140 | 17.1M | if (pair.second == type) { |
141 | 7.02M | *value = pair.first; |
142 | 7.02M | return true; |
143 | 7.02M | } |
144 | 17.1M | } |
145 | 2.77k | return false; |
146 | 7.02M | } options_helper.cc:_ZN7rocksdb12_GLOBAL__N_113SerializeEnumINS_15CompressionTypeEEEbRKNSt3__113unordered_mapINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEET_NS3_4hashISA_EENS3_8equal_toISA_EENS8_INS3_4pairIKSA_SB_EEEEEERKSB_PSA_ Line | Count | Source | 138 | 1.00M | const T& type, std::string* value) { | 139 | 2.02M | for (const auto& pair : type_map) { | 140 | 2.02M | if (pair.second == type) { | 141 | 1.00M | *value = pair.first; | 142 | 1.00M | return true; | 143 | 1.00M | } | 144 | 2.02M | } | 145 | 400 | return false; | 146 | 1.00M | } |
options_helper.cc:_ZN7rocksdb12_GLOBAL__N_113SerializeEnumINS_15CompactionStyleEEEbRKNSt3__113unordered_mapINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEET_NS3_4hashISA_EENS3_8equal_toISA_EENS8_INS3_4pairIKSA_SB_EEEEEERKSB_PSA_ Line | Count | Source | 138 | 1.00M | const T& type, std::string* value) { | 139 | 2.04M | for (const auto& pair : type_map) { | 140 | 2.04M | if (pair.second == type) { | 141 | 1.00M | *value = pair.first; | 142 | 1.00M | return true; | 143 | 1.00M | } | 144 | 2.04M | } | 145 | 250 | return false; | 146 | 1.00M | } |
options_helper.cc:_ZN7rocksdb12_GLOBAL__N_113SerializeEnumINS_12ChecksumTypeEEEbRKNSt3__113unordered_mapINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEET_NS3_4hashISA_EENS3_8equal_toISA_EENS8_INS3_4pairIKSA_SB_EEEEEERKSB_PSA_ Line | Count | Source | 138 | 1.00M | const T& type, std::string* value) { | 139 | 2.00M | for (const auto& pair : type_map) { | 140 | 2.00M | if (pair.second == type) { | 141 | 1.00M | *value = pair.first; | 142 | 1.00M | return true; | 143 | 1.00M | } | 144 | 2.00M | } | 145 | 269 | return false; | 146 | 1.00M | } |
options_helper.cc:_ZN7rocksdb12_GLOBAL__N_113SerializeEnumINS_9IndexTypeEEEbRKNSt3__113unordered_mapINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEET_NS3_4hashISA_EENS3_8equal_toISA_EENS8_INS3_4pairIKSA_SB_EEEEEERKSB_PSA_ Line | Count | Source | 138 | 1.00M | const T& type, std::string* value) { | 139 | 1.00M | for (const auto& pair : type_map) { | 140 | 1.00M | if (pair.second == type) { | 141 | 1.00M | *value = pair.first; | 142 | 1.00M | return true; | 143 | 1.00M | } | 144 | 1.00M | } | 145 | 266 | return false; | 146 | 1.00M | } |
Unexecuted instantiation: options_helper.cc:_ZN7rocksdb12_GLOBAL__N_113SerializeEnumINS_12EncodingTypeEEEbRKNSt3__113unordered_mapINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEET_NS3_4hashISA_EENS3_8equal_toISA_EENS8_INS3_4pairIKSA_SB_EEEEEERKSB_PSA_ options_helper.cc:_ZN7rocksdb12_GLOBAL__N_113SerializeEnumINS_15WALRecoveryModeEEEbRKNSt3__113unordered_mapINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEET_NS3_4hashISA_EENS3_8equal_toISA_EENS8_INS3_4pairIKSA_SB_EEEEEERKSB_PSA_ Line | Count | Source | 138 | 1.00M | const T& type, std::string* value) { | 139 | 3.99M | for (const auto& pair : type_map) { | 140 | 3.99M | if (pair.second == type) { | 141 | 999k | *value = pair.first; | 142 | 999k | return true; | 143 | 999k | } | 144 | 3.99M | } | 145 | 261 | return false; | 146 | 1.00M | } |
options_helper.cc:_ZN7rocksdb12_GLOBAL__N_113SerializeEnumINS_9DBOptions10AccessHintEEEbRKNSt3__113unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEET_NS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SC_EEEEEERKSC_PSB_ Line | Count | Source | 138 | 1.00M | const T& type, std::string* value) { | 139 | 1.99M | for (const auto& pair : type_map) { | 140 | 1.99M | if (pair.second == type) { | 141 | 999k | *value = pair.first; | 142 | 999k | return true; | 143 | 999k | } | 144 | 1.99M | } | 145 | 562 | return false; | 146 | 1.00M | } |
options_helper.cc:_ZN7rocksdb12_GLOBAL__N_113SerializeEnumINS_12InfoLogLevelEEEbRKNSt3__113unordered_mapINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEET_NS3_4hashISA_EENS3_8equal_toISA_EENS8_INS3_4pairIKSA_SB_EEEEEERKSB_PSA_ Line | Count | Source | 138 | 999k | const T& type, std::string* value) { | 139 | 4.02M | for (const auto& pair : type_map) { | 140 | 4.02M | if (pair.second == type) { | 141 | 999k | *value = pair.first; | 142 | 999k | return true; | 143 | 999k | } | 144 | 4.02M | } | 145 | 766 | return false; | 146 | 999k | } |
|
147 | | |
148 | | bool SerializeVectorCompressionType(const std::vector<CompressionType>& types, |
149 | 1.00M | std::string* value) { |
150 | 1.00M | std::stringstream ss; |
151 | 1.00M | bool result; |
152 | 1.00M | for (size_t i = 0; i < types.size(); ++i) { |
153 | 1.66k | if (i > 0) { |
154 | 1.60k | ss << ':'; |
155 | 1.60k | } |
156 | 1.66k | std::string string_type; |
157 | 1.66k | result = SerializeEnum<CompressionType>(compression_type_string_map, |
158 | 1.66k | types[i], &string_type); |
159 | 1.66k | if (result == false) { |
160 | 0 | return result; |
161 | 0 | } |
162 | 1.66k | ss << string_type; |
163 | 1.66k | } |
164 | 1.00M | *value = ss.str(); |
165 | 1.00M | return true; |
166 | 1.00M | } |
167 | | |
168 | 35.3M | bool ParseBoolean(const std::string& type, const std::string& value) { |
169 | 35.3M | if (value == "true" || value == "1") { |
170 | 13.6M | return true; |
171 | 21.7M | } else if (value == "false" || value == "0") { |
172 | 21.7M | return false; |
173 | 21.7M | } |
174 | 18.4E | throw std::invalid_argument(type); |
175 | 18.4E | } |
176 | | |
177 | 43.0M | uint64_t ParseUint64(const std::string& value) { |
178 | 43.0M | size_t endchar; |
179 | 43.0M | #ifndef CYGWIN |
180 | 43.0M | uint64_t num = std::stoull(value.c_str(), &endchar); |
181 | | #else |
182 | | char* endptr; |
183 | | uint64_t num = std::strtoul(value.c_str(), &endptr, 0); |
184 | | endchar = endptr - value.c_str(); |
185 | | #endif |
186 | | |
187 | 43.0M | if (endchar < value.length()) { |
188 | 11 | char c = value[endchar]; |
189 | 11 | if (c == 'k' || c == 'K') |
190 | 2 | num <<= 10LL; |
191 | 9 | else if (c == 'm' || c == 'M') |
192 | 5 | num <<= 20LL; |
193 | 4 | else if (c == 'g' || c == 'G') |
194 | 2 | num <<= 30LL; |
195 | 2 | else if (c == 't' || c == 'T') |
196 | 2 | num <<= 40LL; |
197 | 11 | } |
198 | | |
199 | 43.0M | return num; |
200 | 43.0M | } |
201 | | |
202 | 18.0M | size_t ParseSizeT(const std::string& value) { |
203 | 18.0M | return static_cast<size_t>(ParseUint64(value)); |
204 | 18.0M | } |
205 | | |
206 | 7.03M | uint32_t ParseUint32(const std::string& value) { |
207 | 7.03M | uint64_t num = ParseUint64(value); |
208 | 7.03M | if ((num >> 32LL) == 0) { |
209 | 7.02M | return static_cast<uint32_t>(num); |
210 | 797 | } else { |
211 | 797 | throw std::out_of_range(value); |
212 | 797 | } |
213 | 7.03M | } |
214 | | |
215 | 22.7M | int ParseInt(const std::string& value) { |
216 | 22.7M | size_t endchar; |
217 | 22.7M | #ifndef CYGWIN |
218 | 22.7M | int num = std::stoi(value.c_str(), &endchar); |
219 | | #else |
220 | | char* endptr; |
221 | | int num = std::strtoul(value.c_str(), &endptr, 0); |
222 | | endchar = endptr - value.c_str(); |
223 | | #endif |
224 | | |
225 | 22.7M | if (endchar < value.length()) { |
226 | 3 | char c = value[endchar]; |
227 | 3 | if (c == 'k' || c == 'K') |
228 | 1 | num *= (1 << 10); |
229 | 2 | else if (c == 'm' || c == 'M') |
230 | 1 | num *= (1 << 20); |
231 | 1 | else if (c == 'g' || c == 'G') |
232 | 0 | num *= (1 << 30); |
233 | 3 | } |
234 | | |
235 | 22.7M | return num; |
236 | 22.7M | } |
237 | | |
238 | 1.00M | double ParseDouble(const std::string& value) { |
239 | 1.00M | #ifndef CYGWIN |
240 | 1.00M | return std::stod(value); |
241 | | #else |
242 | | return std::strtod(value.c_str(), 0); |
243 | | #endif |
244 | 1.00M | } |
245 | | |
246 | | bool ParseVectorCompressionType( |
247 | | const std::string& value, |
248 | 1.00M | std::vector<CompressionType>* compression_per_level) { |
249 | 1.00M | compression_per_level->clear(); |
250 | 1.00M | size_t start = 0; |
251 | 1.01M | while (start < value.size()) { |
252 | 3.81k | size_t end = value.find(':', start); |
253 | 3.81k | bool is_ok; |
254 | 3.81k | CompressionType type; |
255 | 3.81k | if (end == std::string::npos) { |
256 | 103 | is_ok = ParseEnum<CompressionType>(compression_type_string_map, |
257 | 103 | value.substr(start), &type); |
258 | 103 | if (!is_ok) { |
259 | 0 | return false; |
260 | 0 | } |
261 | 103 | compression_per_level->emplace_back(type); |
262 | 103 | break; |
263 | 3.71k | } else { |
264 | 3.71k | is_ok = ParseEnum<CompressionType>( |
265 | 3.71k | compression_type_string_map, value.substr(start, end - start), &type); |
266 | 3.71k | if (!is_ok) { |
267 | 0 | return false; |
268 | 0 | } |
269 | 3.71k | compression_per_level->emplace_back(type); |
270 | 3.71k | start = end + 1; |
271 | 3.71k | } |
272 | 3.81k | } |
273 | 1.00M | return true; |
274 | 1.00M | } |
275 | | |
276 | | bool ParseSliceTransformHelper( |
277 | | const std::string& kFixedPrefixName, const std::string& kCappedPrefixName, |
278 | | const std::string& value, |
279 | 1.00M | std::shared_ptr<const SliceTransform>* slice_transform) { |
280 | 1.00M | static const std::string kNullptrString = "nullptr"; |
281 | 1.00M | auto& pe_value = value; |
282 | 1.00M | if (pe_value.size() > kFixedPrefixName.size() && |
283 | 1.00M | pe_value.compare(0, kFixedPrefixName.size(), kFixedPrefixName) == 0) { |
284 | 1.55k | int prefix_length = ParseInt(trim(value.substr(kFixedPrefixName.size()))); |
285 | 1.55k | slice_transform->reset(NewFixedPrefixTransform(prefix_length)); |
286 | 1.00M | } else if (pe_value.size() > kCappedPrefixName.size() && |
287 | 3.87k | pe_value.compare(0, kCappedPrefixName.size(), kCappedPrefixName) == |
288 | 772 | 0) { |
289 | 772 | int prefix_length = |
290 | 772 | ParseInt(trim(pe_value.substr(kCappedPrefixName.size()))); |
291 | 772 | slice_transform->reset(NewCappedPrefixTransform(prefix_length)); |
292 | 1.00M | } else if (value == kNullptrString) { |
293 | 1.00M | slice_transform->reset(); |
294 | 3.90k | } else { |
295 | 3.90k | return false; |
296 | 3.90k | } |
297 | | |
298 | 1.00M | return true; |
299 | 1.00M | } |
300 | | |
301 | | bool ParseSliceTransform( |
302 | | const std::string& value, |
303 | 1.00M | std::shared_ptr<const SliceTransform>* slice_transform) { |
304 | | // While we normally don't convert the string representation of a |
305 | | // pointer-typed option into its instance, here we do so for backward |
306 | | // compatibility as we allow this action in SetOption(). |
307 | | |
308 | | // TODO(yhchiang): A possible better place for these serialization / |
309 | | // deserialization is inside the class definition of pointer-typed |
310 | | // option itself, but this requires a bigger change of public API. |
311 | 1.00M | bool result = |
312 | 1.00M | ParseSliceTransformHelper("fixed:", "capped:", value, slice_transform); |
313 | 1.00M | if (result) { |
314 | 1.00M | return result; |
315 | 1.00M | } |
316 | 3.18k | result = ParseSliceTransformHelper( |
317 | 3.18k | "rocksdb.FixedPrefix.", "rocksdb.CappedPrefix.", value, slice_transform); |
318 | 3.18k | if (result) { |
319 | 2.32k | return result; |
320 | 2.32k | } |
321 | | // TODO(yhchiang): we can further support other default |
322 | | // SliceTransforms here. |
323 | 859 | return false; |
324 | 859 | } |
325 | | |
326 | | bool ParseOptionHelper(char* opt_address, const OptionType& opt_type, |
327 | 120M | const std::string& value) { |
328 | 120M | switch (opt_type) { |
329 | 35.0M | case OptionType::kBoolean: |
330 | 35.0M | *reinterpret_cast<bool*>(opt_address) = ParseBoolean("", value); |
331 | 35.0M | break; |
332 | 22.0M | case OptionType::kInt: |
333 | 22.0M | *reinterpret_cast<int*>(opt_address) = ParseInt(value); |
334 | 22.0M | break; |
335 | 1.00M | case OptionType::kUInt: |
336 | 1.00M | *reinterpret_cast<unsigned int*>(opt_address) = ParseUint32(value); |
337 | 1.00M | break; |
338 | 6.03M | case OptionType::kUInt32T: |
339 | 6.03M | *reinterpret_cast<uint32_t*>(opt_address) = ParseUint32(value); |
340 | 6.03M | break; |
341 | 18.0M | case OptionType::kUInt64T: |
342 | 18.0M | *reinterpret_cast<uint64_t*>(opt_address) = ParseUint64(value); |
343 | 18.0M | break; |
344 | 18.0M | case OptionType::kSizeT: |
345 | 18.0M | *reinterpret_cast<size_t*>(opt_address) = ParseSizeT(value); |
346 | 18.0M | break; |
347 | 2.00M | case OptionType::kString: |
348 | 2.00M | *reinterpret_cast<std::string*>(opt_address) = value; |
349 | 2.00M | break; |
350 | 1.00M | case OptionType::kDouble: |
351 | 1.00M | *reinterpret_cast<double*>(opt_address) = ParseDouble(value); |
352 | 1.00M | break; |
353 | 1.00M | case OptionType::kCompactionStyle: |
354 | 1.00M | return ParseEnum<CompactionStyle>( |
355 | 1.00M | compaction_style_string_map, value, |
356 | 1.00M | reinterpret_cast<CompactionStyle*>(opt_address)); |
357 | 1.00M | case OptionType::kCompressionType: |
358 | 1.00M | return ParseEnum<CompressionType>( |
359 | 1.00M | compression_type_string_map, value, |
360 | 1.00M | reinterpret_cast<CompressionType*>(opt_address)); |
361 | 1.00M | case OptionType::kVectorCompressionType: |
362 | 1.00M | return ParseVectorCompressionType( |
363 | 1.00M | value, reinterpret_cast<std::vector<CompressionType>*>(opt_address)); |
364 | 1.00M | case OptionType::kSliceTransform: |
365 | 1.00M | return ParseSliceTransform( |
366 | 1.00M | value, reinterpret_cast<std::shared_ptr<const SliceTransform>*>( |
367 | 1.00M | opt_address)); |
368 | 1.00M | case OptionType::kChecksumType: |
369 | 1.00M | return ParseEnum<ChecksumType>( |
370 | 1.00M | checksum_type_string_map, value, |
371 | 1.00M | reinterpret_cast<ChecksumType*>(opt_address)); |
372 | 1.00M | case OptionType::kBlockBasedTableIndexType: |
373 | 1.00M | return ParseEnum<IndexType>( |
374 | 1.00M | block_base_table_index_type_string_map, value, |
375 | 1.00M | reinterpret_cast<IndexType*>(opt_address)); |
376 | 2 | case OptionType::kEncodingType: |
377 | 2 | return ParseEnum<EncodingType>( |
378 | 2 | encoding_type_string_map, value, |
379 | 2 | reinterpret_cast<EncodingType*>(opt_address)); |
380 | 1.00M | case OptionType::kWALRecoveryMode: |
381 | 1.00M | return ParseEnum<WALRecoveryMode>( |
382 | 1.00M | wal_recovery_mode_string_map, value, |
383 | 1.00M | reinterpret_cast<WALRecoveryMode*>(opt_address)); |
384 | 1.00M | case OptionType::kAccessHint: |
385 | 1.00M | return ParseEnum<DBOptions::AccessHint>( |
386 | 1.00M | access_hint_string_map, value, |
387 | 1.00M | reinterpret_cast<DBOptions::AccessHint*>(opt_address)); |
388 | 1.00M | case OptionType::kInfoLogLevel: |
389 | 1.00M | return ParseEnum<InfoLogLevel>( |
390 | 1.00M | info_log_level_string_map, value, |
391 | 1.00M | reinterpret_cast<InfoLogLevel*>(opt_address)); |
392 | 8.04M | default: |
393 | 8.04M | return false; |
394 | 103M | } |
395 | 103M | return true; |
396 | 103M | } |
397 | | |
398 | | } // anonymouse namespace |
399 | | |
400 | | bool SerializeSingleOptionHelper(const char* opt_address, |
401 | | const OptionType opt_type, |
402 | 129M | std::string* value) { |
403 | 129M | static const std::string kNullptrString = "nullptr"; |
404 | 129M | assert(value); |
405 | 129M | switch (opt_type) { |
406 | 35.0M | case OptionType::kBoolean: |
407 | 21.4M | *value = *(reinterpret_cast<const bool*>(opt_address)) ? "true" : "false"; |
408 | 35.0M | break; |
409 | 22.0M | case OptionType::kInt: |
410 | 22.0M | *value = ToString(*(reinterpret_cast<const int*>(opt_address))); |
411 | 22.0M | break; |
412 | 999k | case OptionType::kUInt: |
413 | 999k | *value = ToString(*(reinterpret_cast<const unsigned int*>(opt_address))); |
414 | 999k | break; |
415 | 6.02M | case OptionType::kUInt32T: |
416 | 6.02M | *value = ToString(*(reinterpret_cast<const uint32_t*>(opt_address))); |
417 | 6.02M | break; |
418 | 18.0M | case OptionType::kUInt64T: |
419 | 18.0M | *value = ToString(*(reinterpret_cast<const uint64_t*>(opt_address))); |
420 | 18.0M | break; |
421 | 18.0M | case OptionType::kSizeT: |
422 | 18.0M | *value = ToString(*(reinterpret_cast<const size_t*>(opt_address))); |
423 | 18.0M | break; |
424 | 1.00M | case OptionType::kDouble: |
425 | 1.00M | *value = ToString(*(reinterpret_cast<const double*>(opt_address))); |
426 | 1.00M | break; |
427 | 2.00M | case OptionType::kString: |
428 | 2.00M | *value = EscapeOptionString( |
429 | 2.00M | *(reinterpret_cast<const std::string*>(opt_address))); |
430 | 2.00M | break; |
431 | 1.00M | case OptionType::kCompactionStyle: |
432 | 1.00M | return SerializeEnum<CompactionStyle>( |
433 | 1.00M | compaction_style_string_map, |
434 | 1.00M | *(reinterpret_cast<const CompactionStyle*>(opt_address)), value); |
435 | 1.00M | case OptionType::kCompressionType: |
436 | 1.00M | return SerializeEnum<CompressionType>( |
437 | 1.00M | compression_type_string_map, |
438 | 1.00M | *(reinterpret_cast<const CompressionType*>(opt_address)), value); |
439 | 1.00M | case OptionType::kVectorCompressionType: |
440 | 1.00M | return SerializeVectorCompressionType( |
441 | 1.00M | *(reinterpret_cast<const std::vector<CompressionType>*>(opt_address)), |
442 | 1.00M | value); |
443 | 0 | break; |
444 | 2.01M | case OptionType::kSliceTransform: { |
445 | 2.01M | const auto* slice_transform_ptr = |
446 | 2.01M | reinterpret_cast<const std::shared_ptr<const SliceTransform>*>( |
447 | 2.01M | opt_address); |
448 | 6.13k | *value = slice_transform_ptr->get() ? slice_transform_ptr->get()->Name() |
449 | 2.00M | : kNullptrString; |
450 | 2.01M | break; |
451 | 0 | } |
452 | 2.01M | case OptionType::kTableFactory: { |
453 | 2.01M | const auto* table_factory_ptr = |
454 | 2.01M | reinterpret_cast<const std::shared_ptr<const TableFactory>*>( |
455 | 2.01M | opt_address); |
456 | 2.01M | *value = table_factory_ptr->get() ? table_factory_ptr->get()->Name() |
457 | 47 | : kNullptrString; |
458 | 2.01M | break; |
459 | 0 | } |
460 | 2.01M | case OptionType::kComparator: { |
461 | | // it's a const pointer of const Comparator* |
462 | 2.01M | const auto* ptr = reinterpret_cast<const Comparator* const*>(opt_address); |
463 | | // Since the user-specified comparator will be wrapped by |
464 | | // InternalKeyComparator, we should persist the user-specified one |
465 | | // instead of InternalKeyComparator. |
466 | 2.01M | const auto* internal_comparator = |
467 | 2.01M | dynamic_cast<const InternalKeyComparator*>(*ptr); |
468 | 2.01M | if (internal_comparator != nullptr) { |
469 | 2.01M | *value = internal_comparator->user_comparator()->Name(); |
470 | 342 | } else { |
471 | 312 | *value = *ptr ? (*ptr)->Name() : kNullptrString; |
472 | 342 | } |
473 | 2.01M | break; |
474 | 0 | } |
475 | 2.01M | case OptionType::kCompactionFilter: { |
476 | | // it's a const pointer of const CompactionFilter* |
477 | 2.01M | const auto* ptr = |
478 | 2.01M | reinterpret_cast<const CompactionFilter* const*>(opt_address); |
479 | 2.01M | *value = *ptr ? (*ptr)->Name() : kNullptrString; |
480 | 2.01M | break; |
481 | 0 | } |
482 | 2.01M | case OptionType::kCompactionFilterFactory: { |
483 | 2.01M | const auto* ptr = |
484 | 2.01M | reinterpret_cast<const std::shared_ptr<CompactionFilterFactory>*>( |
485 | 2.01M | opt_address); |
486 | 1.97M | *value = ptr->get() ? ptr->get()->Name() : kNullptrString; |
487 | 2.01M | break; |
488 | 0 | } |
489 | 2.01M | case OptionType::kMemTableRepFactory: { |
490 | 2.01M | const auto* ptr = |
491 | 2.01M | reinterpret_cast<const std::shared_ptr<MemTableRepFactory>*>( |
492 | 2.01M | opt_address); |
493 | 18.4E | *value = ptr->get() ? ptr->get()->Name() : kNullptrString; |
494 | 2.01M | break; |
495 | 0 | } |
496 | 2.01M | case OptionType::kMergeOperator: { |
497 | 2.01M | const auto* ptr = |
498 | 2.01M | reinterpret_cast<const std::shared_ptr<MergeOperator>*>(opt_address); |
499 | 2.01M | *value = ptr->get() ? ptr->get()->Name() : kNullptrString; |
500 | 2.01M | break; |
501 | 0 | } |
502 | 2.00M | case OptionType::kFilterPolicy: { |
503 | 2.00M | const auto* ptr = |
504 | 2.00M | reinterpret_cast<const std::shared_ptr<FilterPolicy>*>(opt_address); |
505 | 1.90M | *value = ptr->get() ? ptr->get()->Name() : kNullptrString; |
506 | 2.00M | break; |
507 | 0 | } |
508 | 1.00M | case OptionType::kChecksumType: |
509 | 1.00M | return SerializeEnum<ChecksumType>( |
510 | 1.00M | checksum_type_string_map, |
511 | 1.00M | *reinterpret_cast<const ChecksumType*>(opt_address), value); |
512 | 1.00M | case OptionType::kBlockBasedTableIndexType: |
513 | 1.00M | return SerializeEnum<IndexType>( |
514 | 1.00M | block_base_table_index_type_string_map, |
515 | 1.00M | *reinterpret_cast<const IndexType*>(opt_address), |
516 | 1.00M | value); |
517 | 2.00M | case OptionType::kFlushBlockPolicyFactory: { |
518 | 2.00M | const auto* ptr = |
519 | 2.00M | reinterpret_cast<const std::shared_ptr<FlushBlockPolicyFactory>*>( |
520 | 2.00M | opt_address); |
521 | 18.4E | *value = ptr->get() ? ptr->get()->Name() : kNullptrString; |
522 | 2.00M | break; |
523 | 0 | } |
524 | 0 | case OptionType::kEncodingType: |
525 | 0 | return SerializeEnum<EncodingType>( |
526 | 0 | encoding_type_string_map, |
527 | 0 | *reinterpret_cast<const EncodingType*>(opt_address), value); |
528 | 1.00M | case OptionType::kWALRecoveryMode: |
529 | 1.00M | return SerializeEnum<WALRecoveryMode>( |
530 | 1.00M | wal_recovery_mode_string_map, |
531 | 1.00M | *reinterpret_cast<const WALRecoveryMode*>(opt_address), value); |
532 | 999k | case OptionType::kAccessHint: |
533 | 999k | return SerializeEnum<DBOptions::AccessHint>( |
534 | 999k | access_hint_string_map, |
535 | 999k | *reinterpret_cast<const DBOptions::AccessHint*>(opt_address), value); |
536 | 999k | case OptionType::kInfoLogLevel: |
537 | 999k | return SerializeEnum<InfoLogLevel>( |
538 | 999k | info_log_level_string_map, |
539 | 999k | *reinterpret_cast<const InfoLogLevel*>(opt_address), value); |
540 | 0 | default: |
541 | 0 | return false; |
542 | 120M | } |
543 | 120M | return true; |
544 | 120M | } |
545 | | |
546 | | |
547 | | template<typename OptionsType> |
548 | | bool ParseMemtableOptions(const std::string& name, const std::string& value, |
549 | 984k | OptionsType* new_options) { |
550 | 984k | if (name == "write_buffer_size") { |
551 | 1 | new_options->write_buffer_size = ParseSizeT(value); |
552 | 984k | } else if (name == "arena_block_size") { |
553 | 0 | new_options->arena_block_size = ParseSizeT(value); |
554 | 984k | } else if (name == "memtable_prefix_bloom_bits") { |
555 | 0 | new_options->memtable_prefix_bloom_bits = ParseUint32(value); |
556 | 984k | } else if (name == "memtable_prefix_bloom_probes") { |
557 | 0 | new_options->memtable_prefix_bloom_probes = ParseUint32(value); |
558 | 984k | } else if (name == "memtable_prefix_bloom_huge_page_tlb_size") { |
559 | 0 | new_options->memtable_prefix_bloom_huge_page_tlb_size = |
560 | 0 | ParseSizeT(value); |
561 | 984k | } else if (name == "max_successive_merges") { |
562 | 0 | new_options->max_successive_merges = ParseSizeT(value); |
563 | 984k | } else if (name == "filter_deletes") { |
564 | 0 | new_options->filter_deletes = ParseBoolean(name, value); |
565 | 984k | } else if (name == "max_write_buffer_number") { |
566 | 2 | new_options->max_write_buffer_number = ParseInt(value); |
567 | 984k | } else if (name == "inplace_update_num_locks") { |
568 | 0 | new_options->inplace_update_num_locks = ParseSizeT(value); |
569 | 984k | } else { |
570 | 984k | return false; |
571 | 984k | } |
572 | 3 | return true; |
573 | 3 | } |
574 | | |
575 | | template<typename OptionsType> |
576 | | bool ParseCompactionOptions(const std::string& name, const std::string& value, |
577 | 984k | OptionsType* new_options) { |
578 | 984k | if (name == "disable_auto_compactions") { |
579 | 328k | new_options->disable_auto_compactions = ParseBoolean(name, value); |
580 | 656k | } else if (name == "soft_rate_limit") { |
581 | | // Deprecated options but still leave it here to avoid older options |
582 | | // strings can be consumed. |
583 | 656k | } else if (name == "soft_pending_compaction_bytes_limit") { |
584 | 0 | new_options->soft_pending_compaction_bytes_limit = ParseUint64(value); |
585 | 656k | } else if (name == "hard_pending_compaction_bytes_limit") { |
586 | 0 | new_options->hard_pending_compaction_bytes_limit = ParseUint64(value); |
587 | 656k | } else if (name == "hard_rate_limit") { |
588 | | // Deprecated options but still leave it here to avoid older options |
589 | | // strings can be consumed. |
590 | 656k | } else if (name == "level0_file_num_compaction_trigger") { |
591 | 1 | new_options->level0_file_num_compaction_trigger = ParseInt(value); |
592 | 656k | } else if (name == "level0_slowdown_writes_trigger") { |
593 | 328k | new_options->level0_slowdown_writes_trigger = ParseInt(value); |
594 | 328k | } else if (name == "level0_stop_writes_trigger") { |
595 | 328k | new_options->level0_stop_writes_trigger = ParseInt(value); |
596 | 18.4E | } else if (name == "max_grandparent_overlap_factor") { |
597 | 0 | new_options->max_grandparent_overlap_factor = ParseInt(value); |
598 | 18.4E | } else if (name == "expanded_compaction_factor") { |
599 | 0 | new_options->expanded_compaction_factor = ParseInt(value); |
600 | 18.4E | } else if (name == "source_compaction_factor") { |
601 | 0 | new_options->source_compaction_factor = ParseInt(value); |
602 | 18.4E | } else if (name == "target_file_size_base") { |
603 | 1 | new_options->target_file_size_base = ParseInt(value); |
604 | 18.4E | } else if (name == "target_file_size_multiplier") { |
605 | 0 | new_options->target_file_size_multiplier = ParseInt(value); |
606 | 18.4E | } else if (name == "max_bytes_for_level_base") { |
607 | 2 | new_options->max_bytes_for_level_base = ParseUint64(value); |
608 | 18.4E | } else if (name == "max_bytes_for_level_multiplier") { |
609 | 0 | new_options->max_bytes_for_level_multiplier = ParseInt(value); |
610 | 18.4E | } else if (name == "max_bytes_for_level_multiplier_additional") { |
611 | 0 | new_options->max_bytes_for_level_multiplier_additional.clear(); |
612 | 0 | size_t start = 0; |
613 | 0 | while (true) { |
614 | 0 | size_t end = value.find(':', start); |
615 | 0 | if (end == std::string::npos) { |
616 | 0 | new_options->max_bytes_for_level_multiplier_additional.push_back( |
617 | 0 | ParseInt(value.substr(start))); |
618 | 0 | break; |
619 | 0 | } else { |
620 | 0 | new_options->max_bytes_for_level_multiplier_additional.push_back( |
621 | 0 | ParseInt(value.substr(start, end - start))); |
622 | 0 | start = end + 1; |
623 | 0 | } |
624 | 0 | } |
625 | 18.4E | } else if (name == "verify_checksums_in_compaction") { |
626 | 0 | new_options->verify_checksums_in_compaction = ParseBoolean(name, value); |
627 | 18.4E | } else { |
628 | 18.4E | return false; |
629 | 18.4E | } |
630 | 984k | return true; |
631 | 984k | } |
632 | | |
633 | | template<typename OptionsType> |
634 | | bool ParseMiscOptions(const std::string& name, const std::string& value, |
635 | 3 | OptionsType* new_options) { |
636 | 3 | if (name == "max_sequential_skip_in_iterations") { |
637 | 2 | new_options->max_sequential_skip_in_iterations = ParseUint64(value); |
638 | 1 | } else if (name == "paranoid_file_checks") { |
639 | 1 | new_options->paranoid_file_checks = ParseBoolean(name, value); |
640 | 0 | } else { |
641 | 0 | return false; |
642 | 0 | } |
643 | 3 | return true; |
644 | 3 | } |
645 | | |
646 | | Status GetMutableOptionsFromStrings( |
647 | | const MutableCFOptions& base_options, |
648 | | const std::unordered_map<std::string, std::string>& options_map, |
649 | 656k | MutableCFOptions* new_options) { |
650 | 656k | assert(new_options); |
651 | 656k | *new_options = base_options; |
652 | 984k | for (const auto& o : options_map) { |
653 | 984k | try { |
654 | 984k | if (ParseMemtableOptions(o.first, o.second, new_options)) { |
655 | 984k | } else if (ParseCompactionOptions(o.first, o.second, new_options)) { |
656 | 18.4E | } else if (ParseMiscOptions(o.first, o.second, new_options)) { |
657 | 18.4E | } else { |
658 | 18.4E | return STATUS(InvalidArgument, |
659 | 18.4E | "unsupported dynamic option: " + o.first); |
660 | 18.4E | } |
661 | 0 | } catch (std::exception& e) { |
662 | 0 | return STATUS(InvalidArgument, "error parsing " + o.first + ":" + |
663 | 0 | std::string(e.what())); |
664 | 0 | } |
665 | 984k | } |
666 | 656k | return Status::OK(); |
667 | 656k | } |
668 | | |
669 | | Status StringToMap(const std::string& opts_str, |
670 | 5.07k | std::unordered_map<std::string, std::string>* opts_map) { |
671 | 5.07k | assert(opts_map); |
672 | | // Example: |
673 | | // opts_str = "write_buffer_size=1024;max_write_buffer_number=2;" |
674 | | // "nested_opt={opt1=1;opt2=2};max_bytes_for_level_base=100" |
675 | 5.07k | size_t pos = 0; |
676 | 5.07k | std::string opts = trim(opts_str); |
677 | 9.57k | while (pos < opts.size()) { |
678 | 8.89k | size_t eq_pos = opts.find('=', pos); |
679 | 8.89k | if (eq_pos == std::string::npos) { |
680 | 606 | return STATUS(InvalidArgument, "Mismatched key value pair, '=' expected"); |
681 | 606 | } |
682 | 8.28k | std::string key = trim(opts.substr(pos, eq_pos - pos)); |
683 | 8.28k | if (key.empty()) { |
684 | 589 | return STATUS(InvalidArgument, "Empty key found"); |
685 | 589 | } |
686 | | |
687 | | // skip space after '=' and look for '{' for possible nested options |
688 | 7.69k | pos = eq_pos + 1; |
689 | 8.29k | while (pos < opts.size() && isspace(opts[pos])) { |
690 | 596 | ++pos; |
691 | 596 | } |
692 | | // Empty value at the end |
693 | 7.69k | if (pos >= opts.size()) { |
694 | 149 | (*opts_map)[key] = ""; |
695 | 149 | break; |
696 | 149 | } |
697 | 7.54k | if (opts[pos] == '{') { |
698 | 4.18k | int count = 1; |
699 | 4.18k | size_t brace_pos = pos + 1; |
700 | 71.1k | while (brace_pos < opts.size()) { |
701 | 69.8k | if (opts[brace_pos] == '{') { |
702 | 18.9k | ++count; |
703 | 50.8k | } else if (opts[brace_pos] == '}') { |
704 | 20.7k | --count; |
705 | 20.7k | if (count == 0) { |
706 | 2.89k | break; |
707 | 2.89k | } |
708 | 66.9k | } |
709 | 66.9k | ++brace_pos; |
710 | 66.9k | } |
711 | | // found the matching closing brace |
712 | 4.18k | if (count == 0) { |
713 | 2.89k | (*opts_map)[key] = trim(opts.substr(pos + 1, brace_pos - pos - 1)); |
714 | | // skip all whitespace and move to the next ';' |
715 | | // brace_pos points to the next position after the matching '}' |
716 | 2.89k | pos = brace_pos + 1; |
717 | 2.99k | while (pos < opts.size() && isspace(opts[pos])) { |
718 | 102 | ++pos; |
719 | 102 | } |
720 | 2.89k | if (pos < opts.size() && opts[pos] != ';') { |
721 | 827 | return STATUS(InvalidArgument, |
722 | 827 | "Unexpected chars after nested options"); |
723 | 827 | } |
724 | 2.06k | ++pos; |
725 | 1.29k | } else { |
726 | 1.29k | return STATUS(InvalidArgument, |
727 | 1.29k | "Mismatched curly braces for nested options"); |
728 | 1.29k | } |
729 | 3.36k | } else { |
730 | 3.36k | size_t sc_pos = opts.find(';', pos); |
731 | 3.36k | if (sc_pos == std::string::npos) { |
732 | 932 | (*opts_map)[key] = trim(opts.substr(pos)); |
733 | | // It either ends with a trailing semi-colon or the last key-value pair |
734 | 932 | break; |
735 | 2.42k | } else { |
736 | 2.42k | (*opts_map)[key] = trim(opts.substr(pos, sc_pos - pos)); |
737 | 2.42k | } |
738 | 2.42k | pos = sc_pos + 1; |
739 | 2.42k | } |
740 | 7.54k | } |
741 | | |
742 | 1.76k | return Status::OK(); |
743 | 5.07k | } |
744 | | |
745 | | Status ParseColumnFamilyOption(const std::string& name, |
746 | | const std::string& org_value, |
747 | | ColumnFamilyOptions* new_options, |
748 | 46.2M | bool input_strings_escaped = false) { |
749 | 46.2M | const std::string& value = |
750 | 18.4E | input_strings_escaped ? UnescapeOptionString(org_value) : org_value; |
751 | 46.2M | try { |
752 | 46.2M | if (name == "max_bytes_for_level_multiplier_additional") { |
753 | 3 | new_options->max_bytes_for_level_multiplier_additional.clear(); |
754 | 3 | size_t start = 0; |
755 | 9 | while (true) { |
756 | 9 | size_t end = value.find(':', start); |
757 | 9 | if (end == std::string::npos) { |
758 | 3 | new_options->max_bytes_for_level_multiplier_additional.push_back( |
759 | 3 | ParseInt(value.substr(start))); |
760 | 3 | break; |
761 | 6 | } else { |
762 | 6 | new_options->max_bytes_for_level_multiplier_additional.push_back( |
763 | 6 | ParseInt(value.substr(start, end - start))); |
764 | 6 | start = end + 1; |
765 | 6 | } |
766 | 9 | } |
767 | 46.2M | } else if (name == "block_based_table_factory") { |
768 | | // Nested options |
769 | 5 | BlockBasedTableOptions table_opt, base_table_options; |
770 | 5 | auto block_based_table_factory = dynamic_cast<BlockBasedTableFactory*>( |
771 | 5 | new_options->table_factory.get()); |
772 | 5 | if (block_based_table_factory != nullptr) { |
773 | 1 | base_table_options = block_based_table_factory->table_options(); |
774 | 1 | } |
775 | 5 | Status table_opt_s = GetBlockBasedTableOptionsFromString( |
776 | 5 | base_table_options, value, &table_opt); |
777 | 5 | if (!table_opt_s.ok()) { |
778 | 1 | return STATUS(InvalidArgument, |
779 | 1 | "unable to parse the specified CF option " + name); |
780 | 1 | } |
781 | 4 | new_options->table_factory.reset(NewBlockBasedTableFactory(table_opt)); |
782 | 46.2M | } else if (name == "plain_table_factory") { |
783 | | // Nested options |
784 | 2 | PlainTableOptions table_opt, base_table_options; |
785 | 2 | auto plain_table_factory = dynamic_cast<PlainTableFactory*>( |
786 | 2 | new_options->table_factory.get()); |
787 | 2 | if (plain_table_factory != nullptr) { |
788 | 0 | base_table_options = plain_table_factory->table_options(); |
789 | 0 | } |
790 | 2 | Status table_opt_s = GetPlainTableOptionsFromString( |
791 | 2 | base_table_options, value, &table_opt); |
792 | 2 | if (!table_opt_s.ok()) { |
793 | 0 | return STATUS(InvalidArgument, |
794 | 0 | "unable to parse the specified CF option " + name); |
795 | 0 | } |
796 | 2 | new_options->table_factory.reset(NewPlainTableFactory(table_opt)); |
797 | 46.2M | } else if (name == "memtable") { |
798 | 1 | std::unique_ptr<MemTableRepFactory> new_mem_factory; |
799 | 1 | Status mem_factory_s = |
800 | 1 | GetMemTableRepFactoryFromString(value, &new_mem_factory); |
801 | 1 | if (!mem_factory_s.ok()) { |
802 | 0 | return STATUS(InvalidArgument, |
803 | 0 | "unable to parse the specified CF option " + name); |
804 | 0 | } |
805 | 1 | new_options->memtable_factory.reset(new_mem_factory.release()); |
806 | 46.2M | } else if (name == "compression_opts") { |
807 | 3 | size_t start = 0; |
808 | 3 | size_t end = value.find(':'); |
809 | 3 | if (end == std::string::npos) { |
810 | 0 | return STATUS(InvalidArgument, |
811 | 0 | "unable to parse the specified CF option " + name); |
812 | 0 | } |
813 | 3 | new_options->compression_opts.window_bits = |
814 | 3 | ParseInt(value.substr(start, end - start)); |
815 | 3 | start = end + 1; |
816 | 3 | end = value.find(':', start); |
817 | 3 | if (end == std::string::npos) { |
818 | 0 | return STATUS(InvalidArgument, |
819 | 0 | "unable to parse the specified CF option " + name); |
820 | 0 | } |
821 | 3 | new_options->compression_opts.level = |
822 | 3 | ParseInt(value.substr(start, end - start)); |
823 | 3 | start = end + 1; |
824 | 3 | if (start >= value.size()) { |
825 | 0 | return STATUS(InvalidArgument, |
826 | 0 | "unable to parse the specified CF option " + name); |
827 | 0 | } |
828 | 3 | new_options->compression_opts.strategy = |
829 | 3 | ParseInt(value.substr(start, value.size() - start)); |
830 | 46.2M | } else if (name == "compaction_options_fifo") { |
831 | 3 | new_options->compaction_options_fifo.max_table_files_size = |
832 | 3 | ParseUint64(value); |
833 | 46.2M | } else { |
834 | 46.2M | auto iter = cf_options_type_info.find(name); |
835 | 46.2M | if (iter == cf_options_type_info.end()) { |
836 | 2 | return STATUS(InvalidArgument, |
837 | 2 | "Unable to parse the specified CF option " + name); |
838 | 2 | } |
839 | 46.2M | const auto& opt_info = iter->second; |
840 | 46.2M | if (ParseOptionHelper( |
841 | 46.2M | reinterpret_cast<char*>(new_options) + opt_info.offset, |
842 | 40.2M | opt_info.type, value)) { |
843 | 40.2M | return Status::OK(); |
844 | 40.2M | } |
845 | 6.01M | switch (opt_info.verification) { |
846 | 6.03M | case OptionVerificationType::kByName: |
847 | 6.03M | case OptionVerificationType::kByNameAllowNull: |
848 | 6.03M | return STATUS(NotSupported, |
849 | 6.03M | "Deserializing the specified CF option " + name + |
850 | 6.03M | " is not supported"); |
851 | 0 | case OptionVerificationType::kDeprecated: |
852 | 0 | return Status::OK(); |
853 | 0 | default: |
854 | 0 | return STATUS(InvalidArgument, |
855 | 3 | "Unable to parse the specified CF option " + name); |
856 | 3 | } |
857 | 3 | } |
858 | 3 | } catch (const std::exception&) { |
859 | 3 | return STATUS(InvalidArgument, |
860 | 3 | "unable to parse the specified option " + name); |
861 | 3 | } |
862 | 16 | return Status::OK(); |
863 | 16 | } |
864 | | |
865 | | bool SerializeSingleDBOption(std::string* opt_string, |
866 | | const DBOptions& db_options, |
867 | | const std::string& name, |
868 | 56.8M | const std::string& delimiter) { |
869 | 56.8M | auto iter = db_options_type_info.find(name); |
870 | 56.8M | if (iter == db_options_type_info.end()) { |
871 | 0 | return false; |
872 | 0 | } |
873 | 56.8M | auto& opt_info = iter->second; |
874 | 56.8M | const char* opt_address = |
875 | 56.8M | reinterpret_cast<const char*>(&db_options) + opt_info.offset; |
876 | 56.8M | std::string value; |
877 | 56.8M | bool result = SerializeSingleOptionHelper(opt_address, opt_info.type, &value); |
878 | 56.8M | if (result) { |
879 | 56.8M | *opt_string = name + "=" + value + delimiter; |
880 | 56.8M | } |
881 | 56.8M | return result; |
882 | 56.8M | } |
883 | | |
884 | | Status GetStringFromDBOptions(std::string* opt_string, |
885 | | const DBOptions& db_options, |
886 | 1.00M | const std::string& delimiter) { |
887 | 1.00M | assert(opt_string); |
888 | 1.00M | opt_string->clear(); |
889 | 1.00M | for (auto iter = db_options_type_info.begin(); |
890 | 57.8M | iter != db_options_type_info.end(); ++iter) { |
891 | 56.8M | if (iter->second.verification == OptionVerificationType::kDeprecated) { |
892 | | // If the option is no longer used in rocksdb and marked as deprecated, |
893 | | // we skip it in the serialization. |
894 | 0 | continue; |
895 | 0 | } |
896 | 56.8M | std::string single_output; |
897 | 56.8M | bool result = SerializeSingleDBOption(&single_output, db_options, |
898 | 56.8M | iter->first, delimiter); |
899 | 56.8M | assert(result); |
900 | 56.9M | if (result) { |
901 | 56.9M | opt_string->append(single_output); |
902 | 56.9M | } |
903 | 56.8M | } |
904 | 1.00M | return Status::OK(); |
905 | 1.00M | } |
906 | | |
907 | | bool SerializeSingleColumnFamilyOption(std::string* opt_string, |
908 | | const ColumnFamilyOptions& cf_options, |
909 | | const std::string& name, |
910 | 46.1M | const std::string& delimiter) { |
911 | 46.1M | auto iter = cf_options_type_info.find(name); |
912 | 46.1M | if (iter == cf_options_type_info.end()) { |
913 | 0 | return false; |
914 | 0 | } |
915 | 46.1M | auto& opt_info = iter->second; |
916 | 46.1M | const char* opt_address = |
917 | 46.1M | reinterpret_cast<const char*>(&cf_options) + opt_info.offset; |
918 | 46.1M | std::string value; |
919 | 46.1M | bool result = SerializeSingleOptionHelper(opt_address, opt_info.type, &value); |
920 | 46.2M | if (result) { |
921 | 46.2M | *opt_string = name + "=" + value + delimiter; |
922 | 46.2M | } |
923 | 46.1M | return result; |
924 | 46.1M | } |
925 | | |
926 | | Status GetStringFromColumnFamilyOptions(std::string* opt_string, |
927 | | const ColumnFamilyOptions& cf_options, |
928 | 1.00M | const std::string& delimiter) { |
929 | 1.00M | assert(opt_string); |
930 | 1.00M | opt_string->clear(); |
931 | 1.00M | for (auto iter = cf_options_type_info.begin(); |
932 | 50.2M | iter != cf_options_type_info.end(); ++iter) { |
933 | 49.2M | if (iter->second.verification == OptionVerificationType::kDeprecated) { |
934 | | // If the option is no longer used in rocksdb and marked as deprecated, |
935 | | // we skip it in the serialization. |
936 | 3.01M | continue; |
937 | 3.01M | } |
938 | 46.1M | std::string single_output; |
939 | 46.1M | bool result = SerializeSingleColumnFamilyOption(&single_output, cf_options, |
940 | 46.1M | iter->first, delimiter); |
941 | 46.2M | if (result) { |
942 | 46.2M | opt_string->append(single_output); |
943 | 18.4E | } else { |
944 | 18.4E | return STATUS(InvalidArgument, "failed to serialize %s\n", |
945 | 18.4E | iter->first.c_str()); |
946 | 18.4E | } |
947 | 46.2M | assert(result); |
948 | 46.2M | } |
949 | 1.03M | return Status::OK(); |
950 | 1.00M | } |
951 | | |
952 | | bool SerializeSingleBlockBasedTableOption( |
953 | | std::string* opt_string, const BlockBasedTableOptions& bbt_options, |
954 | 17.0M | const std::string& name, const std::string& delimiter) { |
955 | 17.0M | auto iter = block_based_table_type_info.find(name); |
956 | 17.0M | if (iter == block_based_table_type_info.end()) { |
957 | 0 | return false; |
958 | 0 | } |
959 | 17.0M | auto& opt_info = iter->second; |
960 | 17.0M | const char* opt_address = |
961 | 17.0M | reinterpret_cast<const char*>(&bbt_options) + opt_info.offset; |
962 | 17.0M | std::string value; |
963 | 17.0M | bool result = SerializeSingleOptionHelper(opt_address, opt_info.type, &value); |
964 | 17.0M | if (result) { |
965 | 17.0M | *opt_string = name + "=" + value + delimiter; |
966 | 17.0M | } |
967 | 17.0M | return result; |
968 | 17.0M | } |
969 | | |
970 | | Status GetStringFromBlockBasedTableOptions( |
971 | | std::string* opt_string, const BlockBasedTableOptions& bbt_options, |
972 | 1.00M | const std::string& delimiter) { |
973 | 1.00M | assert(opt_string); |
974 | 1.00M | opt_string->clear(); |
975 | 1.00M | for (auto iter = block_based_table_type_info.begin(); |
976 | 18.0M | iter != block_based_table_type_info.end(); ++iter) { |
977 | 17.0M | if (iter->second.verification == OptionVerificationType::kDeprecated) { |
978 | | // If the option is no longer used in rocksdb and marked as deprecated, |
979 | | // we skip it in the serialization. |
980 | 0 | continue; |
981 | 0 | } |
982 | 17.0M | std::string single_output; |
983 | 17.0M | bool result = SerializeSingleBlockBasedTableOption( |
984 | 17.0M | &single_output, bbt_options, iter->first, delimiter); |
985 | 17.0M | assert(result); |
986 | 17.0M | if (result) { |
987 | 17.0M | opt_string->append(single_output); |
988 | 17.0M | } |
989 | 17.0M | } |
990 | 1.00M | return Status::OK(); |
991 | 1.00M | } |
992 | | |
993 | | Status GetStringFromTableFactory(std::string* opts_str, const TableFactory* tf, |
994 | 1.00M | const std::string& delimiter) { |
995 | 1.00M | const auto* bbtf = dynamic_cast<const BlockBasedTableFactory*>(tf); |
996 | 1.00M | opts_str->clear(); |
997 | 1.00M | if (bbtf != nullptr) { |
998 | 1.00M | return GetStringFromBlockBasedTableOptions(opts_str, bbtf->table_options(), |
999 | 1.00M | delimiter); |
1000 | 1.00M | } |
1001 | | |
1002 | 2.07k | return Status::OK(); |
1003 | 2.07k | } |
1004 | | |
1005 | | Status ParseDBOption(const std::string& name, |
1006 | | const std::string& org_value, |
1007 | | DBOptions* new_options, |
1008 | 56.9M | bool input_strings_escaped = false) { |
1009 | 56.9M | const std::string& value = |
1010 | 18.4E | input_strings_escaped ? UnescapeOptionString(org_value) : org_value; |
1011 | 56.9M | try { |
1012 | 56.9M | if (name == "rate_limiter_bytes_per_sec") { |
1013 | 1 | new_options->rate_limiter.reset( |
1014 | 1 | NewGenericRateLimiter(static_cast<int64_t>(ParseUint64(value)))); |
1015 | 56.9M | } else { |
1016 | 56.9M | auto iter = db_options_type_info.find(name); |
1017 | 56.9M | if (iter == db_options_type_info.end()) { |
1018 | 3 | return STATUS(InvalidArgument, "Unrecognized option DBOptions:", name); |
1019 | 3 | } |
1020 | 56.9M | const auto& opt_info = iter->second; |
1021 | 56.9M | if (ParseOptionHelper( |
1022 | 56.9M | reinterpret_cast<char*>(new_options) + opt_info.offset, |
1023 | 56.9M | opt_info.type, value)) { |
1024 | 56.9M | return Status::OK(); |
1025 | 56.9M | } |
1026 | 18.4E | switch (opt_info.verification) { |
1027 | 0 | case OptionVerificationType::kByName: |
1028 | 0 | case OptionVerificationType::kByNameAllowNull: |
1029 | 0 | return STATUS(NotSupported, |
1030 | 0 | "Deserializing the specified DB option " + name + |
1031 | 0 | " is not supported"); |
1032 | 0 | case OptionVerificationType::kDeprecated: |
1033 | 0 | return Status::OK(); |
1034 | 0 | default: |
1035 | 0 | return STATUS(InvalidArgument, |
1036 | 0 | "Unable to parse the specified DB option " + name); |
1037 | 0 | } |
1038 | 0 | } |
1039 | 0 | } catch (const std::exception&) { |
1040 | 0 | return STATUS(InvalidArgument, "Unable to parse DBOptions:", name); |
1041 | 0 | } |
1042 | 1 | return Status::OK(); |
1043 | 1 | } |
1044 | | |
1045 | | std::string ParseBlockBasedTableOption(const std::string& name, |
1046 | | const std::string& org_value, |
1047 | | BlockBasedTableOptions* new_options, |
1048 | 17.0M | bool input_strings_escaped = false) { |
1049 | 17.0M | const std::string& value = |
1050 | 18.4E | input_strings_escaped ? UnescapeOptionString(org_value) : org_value; |
1051 | 17.0M | if (!input_strings_escaped) { |
1052 | | // if the input string is not escaped, it means this function is |
1053 | | // invoked from SetOptions, which takes the old format. |
1054 | 28 | if (name == "block_cache") { |
1055 | 4 | new_options->block_cache = NewLRUCache(ParseSizeT(value)); |
1056 | 4 | return ""; |
1057 | 24 | } else if (name == "block_cache_compressed") { |
1058 | 1 | new_options->block_cache_compressed = NewLRUCache(ParseSizeT(value)); |
1059 | 1 | return ""; |
1060 | 23 | } else if (name == "filter_policy") { |
1061 | | // Expect the following format |
1062 | | // bloomfilter:int:bool |
1063 | 3 | const std::string kName = "bloomfilter:"; |
1064 | 3 | if (value.compare(0, kName.size(), kName) != 0) { |
1065 | 1 | return "Invalid filter policy name"; |
1066 | 1 | } |
1067 | 2 | size_t pos = value.find(':', kName.size()); |
1068 | 2 | if (pos == std::string::npos) { |
1069 | 1 | return "Invalid filter policy config, missing bits_per_key"; |
1070 | 1 | } |
1071 | 1 | int bits_per_key = |
1072 | 1 | ParseInt(trim(value.substr(kName.size(), pos - kName.size()))); |
1073 | 1 | bool use_block_based_builder = |
1074 | 1 | ParseBoolean("use_block_based_builder", trim(value.substr(pos + 1))); |
1075 | 1 | new_options->filter_policy.reset( |
1076 | 1 | NewBloomFilterPolicy(bits_per_key, use_block_based_builder)); |
1077 | 1 | return ""; |
1078 | 1 | } |
1079 | 28 | } |
1080 | 17.0M | const auto iter = block_based_table_type_info.find(name); |
1081 | 17.0M | if (iter == block_based_table_type_info.end()) { |
1082 | 2 | return "Unrecognized option"; |
1083 | 2 | } |
1084 | 17.0M | const auto& opt_info = iter->second; |
1085 | 17.0M | if (!ParseOptionHelper(reinterpret_cast<char*>(new_options) + opt_info.offset, |
1086 | 2.00M | opt_info.type, value)) { |
1087 | 2.00M | return "Invalid value"; |
1088 | 2.00M | } |
1089 | 15.0M | return ""; |
1090 | 15.0M | } |
1091 | | |
1092 | | std::string ParsePlainTableOptions(const std::string& name, |
1093 | | const std::string& org_value, |
1094 | | PlainTableOptions* new_option, |
1095 | 13 | bool input_strings_escaped = false) { |
1096 | 13 | const std::string& value = |
1097 | 13 | input_strings_escaped ? UnescapeOptionString(org_value) : org_value; |
1098 | 13 | const auto iter = plain_table_type_info.find(name); |
1099 | 13 | if (iter == plain_table_type_info.end()) { |
1100 | 1 | return "Unrecognized option"; |
1101 | 1 | } |
1102 | 12 | const auto& opt_info = iter->second; |
1103 | 12 | if (!ParseOptionHelper(reinterpret_cast<char*>(new_option) + opt_info.offset, |
1104 | 1 | opt_info.type, value)) { |
1105 | 1 | return "Invalid value"; |
1106 | 1 | } |
1107 | 11 | return ""; |
1108 | 11 | } |
1109 | | |
1110 | | Status GetBlockBasedTableOptionsFromMap( |
1111 | | const BlockBasedTableOptions& table_options, |
1112 | | const std::unordered_map<std::string, std::string>& opts_map, |
1113 | 1.00M | BlockBasedTableOptions* new_table_options, bool input_strings_escaped) { |
1114 | 1.00M | assert(new_table_options); |
1115 | 1.00M | *new_table_options = table_options; |
1116 | 17.0M | for (const auto& o : opts_map) { |
1117 | 17.0M | auto error_message = ParseBlockBasedTableOption( |
1118 | 17.0M | o.first, o.second, new_table_options, input_strings_escaped); |
1119 | 17.0M | if (error_message != "") { |
1120 | 2.00M | const auto iter = block_based_table_type_info.find(o.first); |
1121 | 2.00M | if (iter == block_based_table_type_info.end() || |
1122 | 2.00M | !input_strings_escaped || // !input_strings_escaped indicates |
1123 | | // the old API, where everything is |
1124 | | // parsable. |
1125 | 2.00M | (iter->second.verification != OptionVerificationType::kByName && |
1126 | 0 | iter->second.verification != |
1127 | 0 | OptionVerificationType::kByNameAllowNull && |
1128 | 6 | iter->second.verification != OptionVerificationType::kDeprecated)) { |
1129 | 6 | return STATUS(InvalidArgument, "Can't parse BlockBasedTableOptions:", |
1130 | 6 | o.first + " " + error_message); |
1131 | 6 | } |
1132 | 2.00M | } |
1133 | 17.0M | } |
1134 | 1.00M | return Status::OK(); |
1135 | 1.00M | } |
1136 | | |
1137 | | Status GetBlockBasedTableOptionsFromString( |
1138 | | const BlockBasedTableOptions& table_options, |
1139 | | const std::string& opts_str, |
1140 | 11 | BlockBasedTableOptions* new_table_options) { |
1141 | 11 | std::unordered_map<std::string, std::string> opts_map; |
1142 | 11 | Status s = StringToMap(opts_str, &opts_map); |
1143 | 11 | if (!s.ok()) { |
1144 | 0 | return s; |
1145 | 0 | } |
1146 | 11 | return GetBlockBasedTableOptionsFromMap(table_options, opts_map, |
1147 | 11 | new_table_options); |
1148 | 11 | } |
1149 | | |
1150 | | Status GetPlainTableOptionsFromMap( |
1151 | | const PlainTableOptions& table_options, |
1152 | | const std::unordered_map<std::string, std::string>& opts_map, |
1153 | 1.64k | PlainTableOptions* new_table_options, bool input_strings_escaped) { |
1154 | 1.64k | assert(new_table_options); |
1155 | 1.64k | *new_table_options = table_options; |
1156 | 13 | for (const auto& o : opts_map) { |
1157 | 13 | auto error_message = ParsePlainTableOptions( |
1158 | 13 | o.first, o.second, new_table_options, input_strings_escaped); |
1159 | 13 | if (error_message != "") { |
1160 | 2 | const auto iter = plain_table_type_info.find(o.first); |
1161 | 2 | if (iter == plain_table_type_info.end() || |
1162 | 1 | !input_strings_escaped || // !input_strings_escaped indicates |
1163 | | // the old API, where everything is |
1164 | | // parsable. |
1165 | 0 | (iter->second.verification != OptionVerificationType::kByName && |
1166 | 0 | iter->second.verification != |
1167 | 0 | OptionVerificationType::kByNameAllowNull && |
1168 | 2 | iter->second.verification != OptionVerificationType::kDeprecated)) { |
1169 | 2 | return STATUS(InvalidArgument, "Can't parse PlainTableOptions:", |
1170 | 2 | o.first + " " + error_message); |
1171 | 2 | } |
1172 | 2 | } |
1173 | 13 | } |
1174 | 1.64k | return Status::OK(); |
1175 | 1.64k | } |
1176 | | |
1177 | | Status GetPlainTableOptionsFromString( |
1178 | | const PlainTableOptions& table_options, |
1179 | | const std::string& opts_str, |
1180 | 5 | PlainTableOptions* new_table_options) { |
1181 | 5 | std::unordered_map<std::string, std::string> opts_map; |
1182 | 5 | Status s = StringToMap(opts_str, &opts_map); |
1183 | 5 | if (!s.ok()) { |
1184 | 0 | return s; |
1185 | 0 | } |
1186 | 5 | return GetPlainTableOptionsFromMap(table_options, opts_map, |
1187 | 5 | new_table_options); |
1188 | 5 | } |
1189 | | |
1190 | | Status GetMemTableRepFactoryFromString(const std::string& opts_str, |
1191 | 14 | std::unique_ptr<MemTableRepFactory>* new_mem_factory) { |
1192 | 14 | std::vector<std::string> opts_list = StringSplit(opts_str, ':'); |
1193 | 14 | size_t len = opts_list.size(); |
1194 | | |
1195 | 14 | if (opts_list.size() <= 0 || opts_list.size() > 2) { |
1196 | 4 | return STATUS(InvalidArgument, "Can't parse memtable_factory option ", |
1197 | 4 | opts_str); |
1198 | 4 | } |
1199 | | |
1200 | 10 | MemTableRepFactory* mem_factory = nullptr; |
1201 | | |
1202 | 10 | if (opts_list[0] == "skip_list") { |
1203 | | // Expecting format |
1204 | | // skip_list:<lookahead> |
1205 | 3 | if (2 == len) { |
1206 | 2 | size_t lookahead = ParseSizeT(opts_list[1]); |
1207 | 2 | mem_factory = new SkipListFactory(lookahead); |
1208 | 1 | } else if (1 == len) { |
1209 | 1 | mem_factory = new SkipListFactory(); |
1210 | 1 | } |
1211 | 7 | } else if (opts_list[0] == "prefix_hash") { |
1212 | | // Expecting format |
1213 | | // prfix_hash:<hash_bucket_count> |
1214 | 2 | if (2 == len) { |
1215 | 1 | size_t hash_bucket_count = ParseSizeT(opts_list[1]); |
1216 | 1 | mem_factory = NewHashSkipListRepFactory(hash_bucket_count); |
1217 | 1 | } else if (1 == len) { |
1218 | 1 | mem_factory = NewHashSkipListRepFactory(); |
1219 | 1 | } |
1220 | 5 | } else if (opts_list[0] == "hash_linkedlist") { |
1221 | | // Expecting format |
1222 | | // hash_linkedlist:<hash_bucket_count> |
1223 | 2 | if (2 == len) { |
1224 | 1 | size_t hash_bucket_count = ParseSizeT(opts_list[1]); |
1225 | 1 | mem_factory = NewHashLinkListRepFactory(hash_bucket_count); |
1226 | 1 | } else if (1 == len) { |
1227 | 1 | mem_factory = NewHashLinkListRepFactory(); |
1228 | 1 | } |
1229 | 3 | } else if (opts_list[0] == "vector") { |
1230 | | // Expecting format |
1231 | | // vector:<count> |
1232 | 2 | if (2 == len) { |
1233 | 1 | size_t count = ParseSizeT(opts_list[1]); |
1234 | 1 | mem_factory = new VectorRepFactory(count); |
1235 | 1 | } else if (1 == len) { |
1236 | 1 | mem_factory = new VectorRepFactory(); |
1237 | 1 | } |
1238 | 1 | } else { |
1239 | 1 | return STATUS(InvalidArgument, "Unrecognized memtable_factory option ", |
1240 | 1 | opts_str); |
1241 | 1 | } |
1242 | | |
1243 | 9 | if (mem_factory != nullptr) { |
1244 | 9 | new_mem_factory->reset(mem_factory); |
1245 | 9 | } |
1246 | | |
1247 | 9 | return Status::OK(); |
1248 | 9 | } |
1249 | | |
1250 | | Status GetColumnFamilyOptionsFromMap( |
1251 | | const ColumnFamilyOptions& base_options, |
1252 | | const std::unordered_map<std::string, std::string>& opts_map, |
1253 | 1.00M | ColumnFamilyOptions* new_options, bool input_strings_escaped) { |
1254 | 1.00M | return GetColumnFamilyOptionsFromMapInternal( |
1255 | 1.00M | base_options, opts_map, new_options, input_strings_escaped); |
1256 | 1.00M | } |
1257 | | |
1258 | | Status GetColumnFamilyOptionsFromMapInternal( |
1259 | | const ColumnFamilyOptions& base_options, |
1260 | | const std::unordered_map<std::string, std::string>& opts_map, |
1261 | | ColumnFamilyOptions* new_options, bool input_strings_escaped, |
1262 | 1.00M | std::vector<std::string>* unsupported_options_names) { |
1263 | 1.00M | assert(new_options); |
1264 | 1.00M | *new_options = base_options; |
1265 | 1.00M | if (unsupported_options_names) { |
1266 | 0 | unsupported_options_names->clear(); |
1267 | 0 | } |
1268 | 46.2M | for (const auto& o : opts_map) { |
1269 | 46.2M | auto s = ParseColumnFamilyOption(o.first, o.second, new_options, |
1270 | 46.2M | input_strings_escaped); |
1271 | 46.2M | if (!s.ok()) { |
1272 | 6.03M | if (s.IsNotSupported()) { |
1273 | | // If the deserialization of the specified option is not supported |
1274 | | // and an output vector of unsupported_options is provided, then |
1275 | | // we log the name of the unsupported option and proceed. |
1276 | 6.03M | if (unsupported_options_names != nullptr) { |
1277 | 0 | unsupported_options_names->push_back(o.first); |
1278 | 0 | } |
1279 | | // Note that we still return Status::OK in such case to maintain |
1280 | | // the backward compatibility in the old public API defined in |
1281 | | // rocksdb/convenience.h |
1282 | 560 | } else { |
1283 | 560 | return s; |
1284 | 560 | } |
1285 | 6.03M | } |
1286 | 46.2M | } |
1287 | 1.00M | return Status::OK(); |
1288 | 1.00M | } |
1289 | | |
1290 | | Status GetColumnFamilyOptionsFromString( |
1291 | | const ColumnFamilyOptions& base_options, |
1292 | | const std::string& opts_str, |
1293 | 30 | ColumnFamilyOptions* new_options) { |
1294 | 30 | std::unordered_map<std::string, std::string> opts_map; |
1295 | 30 | Status s = StringToMap(opts_str, &opts_map); |
1296 | 30 | if (!s.ok()) { |
1297 | 6 | return s; |
1298 | 6 | } |
1299 | 24 | return GetColumnFamilyOptionsFromMap(base_options, opts_map, new_options); |
1300 | 24 | } |
1301 | | |
1302 | | Status GetDBOptionsFromMap( |
1303 | | const DBOptions& base_options, |
1304 | | const std::unordered_map<std::string, std::string>& opts_map, |
1305 | 1.00M | DBOptions* new_options, bool input_strings_escaped) { |
1306 | 1.00M | return GetDBOptionsFromMapInternal( |
1307 | 1.00M | base_options, opts_map, new_options, input_strings_escaped); |
1308 | 1.00M | } |
1309 | | |
1310 | | Status GetDBOptionsFromMapInternal( |
1311 | | const DBOptions& base_options, |
1312 | | const std::unordered_map<std::string, std::string>& opts_map, |
1313 | | DBOptions* new_options, bool input_strings_escaped, |
1314 | 1.00M | std::vector<std::string>* unsupported_options_names) { |
1315 | 1.00M | assert(new_options); |
1316 | 1.00M | *new_options = base_options; |
1317 | 1.00M | if (unsupported_options_names) { |
1318 | 0 | unsupported_options_names->clear(); |
1319 | 0 | } |
1320 | 56.9M | for (const auto& o : opts_map) { |
1321 | 56.9M | auto s = ParseDBOption(o.first, o.second, |
1322 | 56.9M | new_options, input_strings_escaped); |
1323 | 56.9M | if (!s.ok()) { |
1324 | 0 | if (s.IsNotSupported()) { |
1325 | | // If the deserialization of the specified option is not supported |
1326 | | // and an output vector of unsupported_options is provided, then |
1327 | | // we log the name of the unsupported option and proceed. |
1328 | 0 | if (unsupported_options_names != nullptr) { |
1329 | 0 | unsupported_options_names->push_back(o.first); |
1330 | 0 | } |
1331 | | // Note that we still return Status::OK in such case to maintain |
1332 | | // the backward compatibility in the old public API defined in |
1333 | | // rocksdb/convenience.h |
1334 | 0 | } else { |
1335 | 0 | return s; |
1336 | 0 | } |
1337 | 0 | } |
1338 | 56.9M | } |
1339 | 1.00M | return Status::OK(); |
1340 | 1.00M | } |
1341 | | |
1342 | | Status GetDBOptionsFromString( |
1343 | | const DBOptions& base_options, |
1344 | | const std::string& opts_str, |
1345 | 1 | DBOptions* new_options) { |
1346 | 1 | std::unordered_map<std::string, std::string> opts_map; |
1347 | 1 | Status s = StringToMap(opts_str, &opts_map); |
1348 | 1 | if (!s.ok()) { |
1349 | 0 | return s; |
1350 | 0 | } |
1351 | 1 | return GetDBOptionsFromMap(base_options, opts_map, new_options); |
1352 | 1 | } |
1353 | | |
1354 | | Status GetOptionsFromString(const Options& base_options, |
1355 | 1 | const std::string& opts_str, Options* new_options) { |
1356 | 1 | std::unordered_map<std::string, std::string> opts_map; |
1357 | 1 | Status s = StringToMap(opts_str, &opts_map); |
1358 | 1 | if (!s.ok()) { |
1359 | 0 | return s; |
1360 | 0 | } |
1361 | 1 | DBOptions new_db_options(base_options); |
1362 | 1 | ColumnFamilyOptions new_cf_options(base_options); |
1363 | 6 | for (const auto& o : opts_map) { |
1364 | 6 | if (ParseDBOption(o.first, o.second, &new_db_options).ok()) { |
1365 | 3 | } else if (ParseColumnFamilyOption( |
1366 | 3 | o.first, o.second, &new_cf_options).ok()) { |
1367 | 0 | } else { |
1368 | 0 | return STATUS(InvalidArgument, "Can't parse option " + o.first); |
1369 | 0 | } |
1370 | 6 | } |
1371 | 1 | *new_options = Options(new_db_options, new_cf_options); |
1372 | 1 | return Status::OK(); |
1373 | 1 | } |
1374 | | |
1375 | | Status GetTableFactoryFromMap( |
1376 | | const std::string& factory_name, |
1377 | | const std::unordered_map<std::string, std::string>& opt_map, |
1378 | 1.00M | std::shared_ptr<TableFactory>* table_factory) { |
1379 | 1.00M | Status s; |
1380 | 1.00M | if (factory_name == BlockBasedTableFactory().Name()) { |
1381 | 1.00M | BlockBasedTableOptions bbt_opt; |
1382 | 1.00M | s = GetBlockBasedTableOptionsFromMap(BlockBasedTableOptions(), opt_map, |
1383 | 1.00M | &bbt_opt, true); |
1384 | 1.00M | if (!s.ok()) { |
1385 | 0 | return s; |
1386 | 0 | } |
1387 | 1.00M | table_factory->reset(new BlockBasedTableFactory(bbt_opt)); |
1388 | 1.00M | return Status::OK(); |
1389 | 1.63k | } else if (factory_name == PlainTableFactory().Name()) { |
1390 | 1.63k | PlainTableOptions pt_opt; |
1391 | 1.63k | s = GetPlainTableOptionsFromMap(PlainTableOptions(), opt_map, &pt_opt, |
1392 | 1.63k | true); |
1393 | 1.63k | if (!s.ok()) { |
1394 | 0 | return s; |
1395 | 0 | } |
1396 | 1.63k | table_factory->reset(new PlainTableFactory(pt_opt)); |
1397 | 1.63k | return Status::OK(); |
1398 | 1.63k | } |
1399 | | // Return OK for not supported table factories as TableFactory |
1400 | | // Deserialization is optional. |
1401 | 18.4E | table_factory->reset(); |
1402 | 18.4E | return Status::OK(); |
1403 | 18.4E | } |
1404 | | |
1405 | | ColumnFamilyOptions BuildColumnFamilyOptions( |
1406 | 1.00M | const Options& options, const MutableCFOptions& mutable_cf_options) { |
1407 | 1.00M | ColumnFamilyOptions cf_opts(options); |
1408 | | |
1409 | | // Memtable related options |
1410 | 1.00M | cf_opts.write_buffer_size = mutable_cf_options.write_buffer_size; |
1411 | 1.00M | cf_opts.max_write_buffer_number = mutable_cf_options.max_write_buffer_number; |
1412 | 1.00M | cf_opts.arena_block_size = mutable_cf_options.arena_block_size; |
1413 | 1.00M | cf_opts.memtable_prefix_bloom_bits = |
1414 | 1.00M | mutable_cf_options.memtable_prefix_bloom_bits; |
1415 | 1.00M | cf_opts.memtable_prefix_bloom_probes = |
1416 | 1.00M | mutable_cf_options.memtable_prefix_bloom_probes; |
1417 | 1.00M | cf_opts.memtable_prefix_bloom_huge_page_tlb_size = |
1418 | 1.00M | mutable_cf_options.memtable_prefix_bloom_huge_page_tlb_size; |
1419 | 1.00M | cf_opts.max_successive_merges = mutable_cf_options.max_successive_merges; |
1420 | 1.00M | cf_opts.filter_deletes = mutable_cf_options.filter_deletes; |
1421 | 1.00M | cf_opts.inplace_update_num_locks = |
1422 | 1.00M | mutable_cf_options.inplace_update_num_locks; |
1423 | | |
1424 | | // Compaction related options |
1425 | 1.00M | cf_opts.disable_auto_compactions = |
1426 | 1.00M | mutable_cf_options.disable_auto_compactions; |
1427 | 1.00M | cf_opts.level0_file_num_compaction_trigger = |
1428 | 1.00M | mutable_cf_options.level0_file_num_compaction_trigger; |
1429 | 1.00M | cf_opts.level0_slowdown_writes_trigger = |
1430 | 1.00M | mutable_cf_options.level0_slowdown_writes_trigger; |
1431 | 1.00M | cf_opts.level0_stop_writes_trigger = |
1432 | 1.00M | mutable_cf_options.level0_stop_writes_trigger; |
1433 | 1.00M | cf_opts.max_grandparent_overlap_factor = |
1434 | 1.00M | mutable_cf_options.max_grandparent_overlap_factor; |
1435 | 1.00M | cf_opts.expanded_compaction_factor = |
1436 | 1.00M | mutable_cf_options.expanded_compaction_factor; |
1437 | 1.00M | cf_opts.source_compaction_factor = |
1438 | 1.00M | mutable_cf_options.source_compaction_factor; |
1439 | 1.00M | cf_opts.target_file_size_base = mutable_cf_options.target_file_size_base; |
1440 | 1.00M | cf_opts.target_file_size_multiplier = |
1441 | 1.00M | mutable_cf_options.target_file_size_multiplier; |
1442 | 1.00M | cf_opts.max_bytes_for_level_base = |
1443 | 1.00M | mutable_cf_options.max_bytes_for_level_base; |
1444 | 1.00M | cf_opts.max_bytes_for_level_multiplier = |
1445 | 1.00M | mutable_cf_options.max_bytes_for_level_multiplier; |
1446 | | |
1447 | 1.00M | cf_opts.max_bytes_for_level_multiplier_additional.clear(); |
1448 | 1.00M | for (auto value : |
1449 | 7.03M | mutable_cf_options.max_bytes_for_level_multiplier_additional) { |
1450 | 7.03M | cf_opts.max_bytes_for_level_multiplier_additional.emplace_back(value); |
1451 | 7.03M | } |
1452 | | |
1453 | 1.00M | cf_opts.verify_checksums_in_compaction = |
1454 | 1.00M | mutable_cf_options.verify_checksums_in_compaction; |
1455 | | |
1456 | | // Misc options |
1457 | 1.00M | cf_opts.max_sequential_skip_in_iterations = |
1458 | 1.00M | mutable_cf_options.max_sequential_skip_in_iterations; |
1459 | 1.00M | cf_opts.paranoid_file_checks = mutable_cf_options.paranoid_file_checks; |
1460 | 1.00M | cf_opts.compaction_measure_io_stats = |
1461 | 1.00M | mutable_cf_options.compaction_measure_io_stats; |
1462 | | |
1463 | 1.00M | cf_opts.table_factory = options.table_factory; |
1464 | | // TODO(yhchiang): find some way to handle the following derived options |
1465 | | // * max_file_size |
1466 | | |
1467 | 1.00M | return cf_opts; |
1468 | 1.00M | } |
1469 | | |
1470 | | #endif // !ROCKSDB_LITE |
1471 | | } // namespace rocksdb |