YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/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