YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/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
267M
bool isSpecialChar(const char c) {
47
267M
  if (
c == '\\'267M
||
c == '#'267M
|| c == ':' ||
c == '\r'267M
||
c == '\n'267M
) {
48
80
    return true;
49
80
  }
50
267M
  return false;
51
267M
}
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
214
}
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
71
}
74
75
5.12M
std::string EscapeOptionString(const std::string& raw_string) {
76
5.12M
  std::string output;
77
266M
  for (auto c : raw_string) {
78
266M
    if (isSpecialChar(c)) {
79
71
      output += '\\';
80
71
      output += EscapeChar(c);
81
266M
    } else {
82
266M
      output += c;
83
266M
    }
84
266M
  }
85
86
5.12M
  return output;
87
5.12M
}
88
89
156M
std::string UnescapeOptionString(const std::string& escaped_string) {
90
156M
  bool escaped = false;
91
156M
  std::string output;
92
93
1.11G
  for (auto c : escaped_string) {
94
1.11G
    if (escaped) {
95
212
      output += UnescapeChar(c);
96
212
      escaped = false;
97
1.11G
    } else {
98
1.11G
      if (c == '\\') {
99
212
        escaped = true;
100
212
        continue;
101
212
      }
102
1.11G
      output += c;
103
1.11G
    }
104
1.11G
  }
105
156M
  return output;
106
156M
}
107
108
namespace {
109
21.9k
std::string trim(const std::string& str) {
110
21.9k
  if (str.empty()) 
return std::string()1.17k
;
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 <= end873
) {
114
873
    ++start;
115
873
  }
116
21.9k
  while (isspace(str[end]) != 0 && 
start <= end1.36k
) {
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
20.7k
}
124
125
template <typename T>
126
bool ParseEnum(const std::unordered_map<std::string, T>& type_map,
127
8.98M
               const std::string& type, T* value) {
128
8.98M
  auto iter = type_map.find(type);
129
8.98M
  if (iter != type_map.end()) {
130
8.98M
    *value = iter->second;
131
8.98M
    return true;
132
8.98M
  }
133
905
  return false;
134
8.98M
}
options_helper.cc:bool rocksdb::(anonymous namespace)::ParseEnum<rocksdb::CompactionStyle>(std::__1::unordered_map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, rocksdb::CompactionStyle, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, rocksdb::CompactionStyle> > > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, rocksdb::CompactionStyle*)
Line
Count
Source
127
1.28M
               const std::string& type, T* value) {
128
1.28M
  auto iter = type_map.find(type);
129
1.28M
  if (iter != type_map.end()) {
130
1.28M
    *value = iter->second;
131
1.28M
    return true;
132
1.28M
  }
133
228
  return false;
134
1.28M
}
options_helper.cc:bool rocksdb::(anonymous namespace)::ParseEnum<rocksdb::CompressionType>(std::__1::unordered_map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, rocksdb::CompressionType, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, rocksdb::CompressionType> > > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, rocksdb::CompressionType*)
Line
Count
Source
127
1.28M
               const std::string& type, T* value) {
128
1.28M
  auto iter = type_map.find(type);
129
1.28M
  if (iter != type_map.end()) {
130
1.28M
    *value = iter->second;
131
1.28M
    return true;
132
1.28M
  }
133
188
  return false;
134
1.28M
}
options_helper.cc:bool rocksdb::(anonymous namespace)::ParseEnum<rocksdb::ChecksumType>(std::__1::unordered_map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, rocksdb::ChecksumType, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, rocksdb::ChecksumType> > > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, rocksdb::ChecksumType*)
Line
Count
Source
127
1.28M
               const std::string& type, T* value) {
128
1.28M
  auto iter = type_map.find(type);
129
1.28M
  if (iter != type_map.end()) {
130
1.28M
    *value = iter->second;
131
1.28M
    return true;
132
1.28M
  }
133
68
  return false;
134
1.28M
}
options_helper.cc:bool rocksdb::(anonymous namespace)::ParseEnum<rocksdb::IndexType>(std::__1::unordered_map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, rocksdb::IndexType, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, rocksdb::IndexType> > > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, rocksdb::IndexType*)
Line
Count
Source
127
1.28M
               const std::string& type, T* value) {
128
1.28M
  auto iter = type_map.find(type);
129
1.28M
  if (iter != type_map.end()) {
130
1.28M
    *value = iter->second;
131
1.28M
    return true;
132
1.28M
  }
133
113
  return false;
134
1.28M
}
options_helper.cc:bool rocksdb::(anonymous namespace)::ParseEnum<rocksdb::EncodingType>(std::__1::unordered_map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, rocksdb::EncodingType, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, rocksdb::EncodingType> > > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, rocksdb::EncodingType*)
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
2
}
options_helper.cc:bool rocksdb::(anonymous namespace)::ParseEnum<rocksdb::WALRecoveryMode>(std::__1::unordered_map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, rocksdb::WALRecoveryMode, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, rocksdb::WALRecoveryMode> > > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, rocksdb::WALRecoveryMode*)
Line
Count
Source
127
1.27M
               const std::string& type, T* value) {
128
1.27M
  auto iter = type_map.find(type);
129
1.27M
  if (iter != type_map.end()) {
130
1.27M
    *value = iter->second;
131
1.27M
    return true;
132
1.27M
  }
133
244
  return false;
134
1.27M
}
options_helper.cc:bool rocksdb::(anonymous namespace)::ParseEnum<rocksdb::DBOptions::AccessHint>(std::__1::unordered_map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, rocksdb::DBOptions::AccessHint, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, rocksdb::DBOptions::AccessHint> > > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, rocksdb::DBOptions::AccessHint*)
Line
Count
Source
127
1.27M
               const std::string& type, T* value) {
128
1.27M
  auto iter = type_map.find(type);
129
1.27M
  if (iter != type_map.end()) {
130
1.27M
    *value = iter->second;
131
1.27M
    return true;
132
1.27M
  }
133
2
  return false;
134
1.27M
}
options_helper.cc:bool rocksdb::(anonymous namespace)::ParseEnum<rocksdb::InfoLogLevel>(std::__1::unordered_map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, rocksdb::InfoLogLevel, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, rocksdb::InfoLogLevel> > > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, rocksdb::InfoLogLevel*)
Line
Count
Source
127
1.27M
               const std::string& type, T* value) {
128
1.27M
  auto iter = type_map.find(type);
129
1.27M
  if (iter != type_map.end()) {
130
1.27M
    *value = iter->second;
131
1.27M
    return true;
132
1.27M
  }
133
61
  return false;
134
1.27M
}
135
136
template <typename T>
137
bool SerializeEnum(const std::unordered_map<std::string, T>& type_map,
138
8.97M
                   const T& type, std::string* value) {
139
21.8M
  for (const auto& pair : type_map) {
140
21.8M
    if (pair.second == type) {
141
8.97M
      *value = pair.first;
142
8.97M
      return true;
143
8.97M
    }
144
21.8M
  }
145
3.20k
  return false;
146
8.97M
}
options_helper.cc:bool rocksdb::(anonymous namespace)::SerializeEnum<rocksdb::CompressionType>(std::__1::unordered_map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, rocksdb::CompressionType, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, rocksdb::CompressionType> > > const&, rocksdb::CompressionType const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*)
Line
Count
Source
138
1.28M
                   const T& type, std::string* value) {
139
2.58M
  for (const auto& pair : type_map) {
140
2.58M
    if (pair.second == type) {
141
1.28M
      *value = pair.first;
142
1.28M
      return true;
143
1.28M
    }
144
2.58M
  }
145
621
  return false;
146
1.28M
}
options_helper.cc:bool rocksdb::(anonymous namespace)::SerializeEnum<rocksdb::CompactionStyle>(std::__1::unordered_map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, rocksdb::CompactionStyle, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, rocksdb::CompactionStyle> > > const&, rocksdb::CompactionStyle const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*)
Line
Count
Source
138
1.28M
                   const T& type, std::string* value) {
139
2.60M
  for (const auto& pair : type_map) {
140
2.60M
    if (pair.second == type) {
141
1.28M
      *value = pair.first;
142
1.28M
      return true;
143
1.28M
    }
144
2.60M
  }
145
179
  return false;
146
1.28M
}
options_helper.cc:bool rocksdb::(anonymous namespace)::SerializeEnum<rocksdb::ChecksumType>(std::__1::unordered_map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, rocksdb::ChecksumType, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, rocksdb::ChecksumType> > > const&, rocksdb::ChecksumType const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*)
Line
Count
Source
138
1.28M
                   const T& type, std::string* value) {
139
2.56M
  for (const auto& pair : type_map) {
140
2.56M
    if (pair.second == type) {
141
1.28M
      *value = pair.first;
142
1.28M
      return true;
143
1.28M
    }
144
2.56M
  }
145
442
  return false;
146
1.28M
}
options_helper.cc:bool rocksdb::(anonymous namespace)::SerializeEnum<rocksdb::IndexType>(std::__1::unordered_map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, rocksdb::IndexType, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, rocksdb::IndexType> > > const&, rocksdb::IndexType const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*)
Line
Count
Source
138
1.28M
                   const T& type, std::string* value) {
139
1.28M
  for (const auto& pair : type_map) {
140
1.28M
    if (pair.second == type) {
141
1.28M
      *value = pair.first;
142
1.28M
      return true;
143
1.28M
    }
144
1.28M
  }
145
342
  return false;
146
1.28M
}
Unexecuted instantiation: options_helper.cc:bool rocksdb::(anonymous namespace)::SerializeEnum<rocksdb::EncodingType>(std::__1::unordered_map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, rocksdb::EncodingType, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, rocksdb::EncodingType> > > const&, rocksdb::EncodingType const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*)
options_helper.cc:bool rocksdb::(anonymous namespace)::SerializeEnum<rocksdb::WALRecoveryMode>(std::__1::unordered_map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, rocksdb::WALRecoveryMode, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, rocksdb::WALRecoveryMode> > > const&, rocksdb::WALRecoveryMode const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*)
Line
Count
Source
138
1.27M
                   const T& type, std::string* value) {
139
5.11M
  for (const auto& pair : type_map) {
140
5.11M
    if (pair.second == type) {
141
1.27M
      *value = pair.first;
142
1.27M
      return true;
143
1.27M
    }
144
5.11M
  }
145
260
  return false;
146
1.27M
}
options_helper.cc:bool rocksdb::(anonymous namespace)::SerializeEnum<rocksdb::DBOptions::AccessHint>(std::__1::unordered_map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, rocksdb::DBOptions::AccessHint, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, rocksdb::DBOptions::AccessHint> > > const&, rocksdb::DBOptions::AccessHint const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*)
Line
Count
Source
138
1.27M
                   const T& type, std::string* value) {
139
2.55M
  for (const auto& pair : type_map) {
140
2.55M
    if (pair.second == type) {
141
1.27M
      *value = pair.first;
142
1.27M
      return true;
143
1.27M
    }
144
2.55M
  }
145
507
  return false;
146
1.27M
}
options_helper.cc:bool rocksdb::(anonymous namespace)::SerializeEnum<rocksdb::InfoLogLevel>(std::__1::unordered_map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, rocksdb::InfoLogLevel, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, rocksdb::InfoLogLevel> > > const&, rocksdb::InfoLogLevel const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*)
Line
Count
Source
138
1.27M
                   const T& type, std::string* value) {
139
5.13M
  for (const auto& pair : type_map) {
140
5.13M
    if (pair.second == type) {
141
1.27M
      *value = pair.first;
142
1.27M
      return true;
143
1.27M
    }
144
5.13M
  }
145
849
  return false;
146
1.27M
}
147
148
bool SerializeVectorCompressionType(const std::vector<CompressionType>& types,
149
1.28M
                                    std::string* value) {
150
1.28M
  std::stringstream ss;
151
1.28M
  bool result;
152
1.28M
  for (size_t i = 0; i < types.size(); 
++i1.66k
) {
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.28M
  *value = ss.str();
165
1.28M
  return true;
166
1.28M
}
167
168
45.2M
bool ParseBoolean(const std::string& type, const std::string& value) {
169
45.2M
  if (value == "true" || 
value == "1"27.7M
) {
170
17.4M
    return true;
171
27.7M
  } else 
if (27.7M
value == "false"27.7M
||
value == "0"4
) {
172
27.7M
    return false;
173
27.7M
  }
174
18.4E
  throw std::invalid_argument(type);
175
45.2M
}
176
177
55.0M
uint64_t ParseUint64(const std::string& value) {
178
55.0M
  size_t endchar;
179
55.0M
#ifndef CYGWIN
180
55.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
55.0M
  if (endchar < value.length()) {
188
11
    char c = value[endchar];
189
11
    if (c == 'k' || 
c == 'K'9
)
190
2
      num <<= 10LL;
191
9
    else if (c == 'm' || c == 'M')
192
5
      num <<= 20LL;
193
4
    else if (c == 'g' || 
c == 'G'3
)
194
2
      num <<= 30LL;
195
2
    else if (c == 't' || 
c == 'T'1
)
196
2
      num <<= 40LL;
197
11
  }
198
199
55.0M
  return num;
200
55.0M
}
201
202
23.0M
size_t ParseSizeT(const std::string& value) {
203
23.0M
  return static_cast<size_t>(ParseUint64(value));
204
23.0M
}
205
206
8.98M
uint32_t ParseUint32(const std::string& value) {
207
8.98M
  uint64_t num = ParseUint64(value);
208
8.98M
  if ((num >> 32LL) == 0) {
209
8.98M
    return static_cast<uint32_t>(num);
210
8.98M
  } else {
211
105
    throw std::out_of_range(value);
212
105
  }
213
8.98M
}
214
215
29.0M
int ParseInt(const std::string& value) {
216
29.0M
  size_t endchar;
217
29.0M
#ifndef CYGWIN
218
29.0M
  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
29.0M
  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'1
)
230
1
      num *= (1 << 20);
231
1
    else if (c == 'g' || c == 'G')
232
0
      num *= (1 << 30);
233
3
  }
234
235
29.0M
  return num;
236
29.0M
}
237
238
1.28M
double ParseDouble(const std::string& value) {
239
1.28M
#ifndef CYGWIN
240
1.28M
  return std::stod(value);
241
#else
242
  return std::strtod(value.c_str(), 0);
243
#endif
244
1.28M
}
245
246
bool ParseVectorCompressionType(
247
    const std::string& value,
248
1.28M
    std::vector<CompressionType>* compression_per_level) {
249
1.28M
  compression_per_level->clear();
250
1.28M
  size_t start = 0;
251
1.28M
  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.28M
  return true;
274
1.28M
}
275
276
bool ParseSliceTransformHelper(
277
    const std::string& kFixedPrefixName, const std::string& kCappedPrefixName,
278
    const std::string& value,
279
1.28M
    std::shared_ptr<const SliceTransform>* slice_transform) {
280
1.28M
  static const std::string kNullptrString = "nullptr";
281
1.28M
  auto& pe_value = value;
282
1.28M
  if (pe_value.size() > kFixedPrefixName.size() &&
283
1.28M
      
pe_value.compare(0, kFixedPrefixName.size(), kFixedPrefixName) == 01.28M
) {
284
1.55k
    int prefix_length = ParseInt(trim(value.substr(kFixedPrefixName.size())));
285
1.55k
    slice_transform->reset(NewFixedPrefixTransform(prefix_length));
286
1.28M
  } else if (pe_value.size() > kCappedPrefixName.size() &&
287
1.28M
             pe_value.compare(0, kCappedPrefixName.size(), kCappedPrefixName) ==
288
3.87k
                 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.28M
  } else if (value == kNullptrString) {
293
1.28M
    slice_transform->reset();
294
1.28M
  } else {
295
4.03k
    return false;
296
4.03k
  }
297
298
1.28M
  return true;
299
1.28M
}
300
301
bool ParseSliceTransform(
302
    const std::string& value,
303
1.28M
    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.28M
  bool result =
312
1.28M
      ParseSliceTransformHelper("fixed:", "capped:", value, slice_transform);
313
1.28M
  if (result) {
314
1.28M
    return result;
315
1.28M
  }
316
3.26k
  result = ParseSliceTransformHelper(
317
3.26k
      "rocksdb.FixedPrefix.", "rocksdb.CappedPrefix.", value, slice_transform);
318
3.26k
  if (result) {
319
2.32k
    return result;
320
2.32k
  }
321
  // TODO(yhchiang): we can further support other default
322
  //                 SliceTransforms here.
323
943
  return false;
324
3.26k
}
325
326
bool ParseOptionHelper(char* opt_address, const OptionType& opt_type,
327
153M
                       const std::string& value) {
328
153M
  switch (opt_type) {
329
44.8M
    case OptionType::kBoolean:
330
44.8M
      *reinterpret_cast<bool*>(opt_address) = ParseBoolean("", value);
331
44.8M
      break;
332
28.2M
    case OptionType::kInt:
333
28.2M
      *reinterpret_cast<int*>(opt_address) = ParseInt(value);
334
28.2M
      break;
335
1.27M
    case OptionType::kUInt:
336
1.27M
      *reinterpret_cast<unsigned int*>(opt_address) = ParseUint32(value);
337
1.27M
      break;
338
7.70M
    case OptionType::kUInt32T:
339
7.70M
      *reinterpret_cast<uint32_t*>(opt_address) = ParseUint32(value);
340
7.70M
      break;
341
23.0M
    case OptionType::kUInt64T:
342
23.0M
      *reinterpret_cast<uint64_t*>(opt_address) = ParseUint64(value);
343
23.0M
      break;
344
23.0M
    case OptionType::kSizeT:
345
23.0M
      *reinterpret_cast<size_t*>(opt_address) = ParseSizeT(value);
346
23.0M
      break;
347
2.55M
    case OptionType::kString:
348
2.55M
      *reinterpret_cast<std::string*>(opt_address) = value;
349
2.55M
      break;
350
1.28M
    case OptionType::kDouble:
351
1.28M
      *reinterpret_cast<double*>(opt_address) = ParseDouble(value);
352
1.28M
      break;
353
1.28M
    case OptionType::kCompactionStyle:
354
1.28M
      return ParseEnum<CompactionStyle>(
355
1.28M
          compaction_style_string_map, value,
356
1.28M
          reinterpret_cast<CompactionStyle*>(opt_address));
357
1.28M
    case OptionType::kCompressionType:
358
1.28M
      return ParseEnum<CompressionType>(
359
1.28M
          compression_type_string_map, value,
360
1.28M
          reinterpret_cast<CompressionType*>(opt_address));
361
1.28M
    case OptionType::kVectorCompressionType:
362
1.28M
      return ParseVectorCompressionType(
363
1.28M
          value, reinterpret_cast<std::vector<CompressionType>*>(opt_address));
364
1.28M
    case OptionType::kSliceTransform:
365
1.28M
      return ParseSliceTransform(
366
1.28M
          value, reinterpret_cast<std::shared_ptr<const SliceTransform>*>(
367
1.28M
                     opt_address));
368
1.28M
    case OptionType::kChecksumType:
369
1.28M
      return ParseEnum<ChecksumType>(
370
1.28M
          checksum_type_string_map, value,
371
1.28M
          reinterpret_cast<ChecksumType*>(opt_address));
372
1.28M
    case OptionType::kBlockBasedTableIndexType:
373
1.28M
      return ParseEnum<IndexType>(
374
1.28M
          block_base_table_index_type_string_map, value,
375
1.28M
          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.27M
    case OptionType::kWALRecoveryMode:
381
1.27M
      return ParseEnum<WALRecoveryMode>(
382
1.27M
          wal_recovery_mode_string_map, value,
383
1.27M
          reinterpret_cast<WALRecoveryMode*>(opt_address));
384
1.27M
    case OptionType::kAccessHint:
385
1.27M
      return ParseEnum<DBOptions::AccessHint>(
386
1.27M
          access_hint_string_map, value,
387
1.27M
          reinterpret_cast<DBOptions::AccessHint*>(opt_address));
388
1.27M
    case OptionType::kInfoLogLevel:
389
1.27M
      return ParseEnum<InfoLogLevel>(
390
1.27M
          info_log_level_string_map, value,
391
1.27M
          reinterpret_cast<InfoLogLevel*>(opt_address));
392
10.2M
    default:
393
10.2M
      return false;
394
153M
  }
395
131M
  return true;
396
153M
}
397
398
}  // anonymouse namespace
399
400
bool SerializeSingleOptionHelper(const char* opt_address,
401
                                 const OptionType opt_type,
402
165M
                                 std::string* value) {
403
165M
  static const std::string kNullptrString = "nullptr";
404
165M
  assert(value);
405
0
  switch (opt_type) {
406
44.8M
    case OptionType::kBoolean:
407
44.8M
      *value = *(reinterpret_cast<const bool*>(opt_address)) ? 
"true"17.4M
:
"false"27.3M
;
408
44.8M
      break;
409
28.2M
    case OptionType::kInt:
410
28.2M
      *value = ToString(*(reinterpret_cast<const int*>(opt_address)));
411
28.2M
      break;
412
1.27M
    case OptionType::kUInt:
413
1.27M
      *value = ToString(*(reinterpret_cast<const unsigned int*>(opt_address)));
414
1.27M
      break;
415
7.70M
    case OptionType::kUInt32T:
416
7.70M
      *value = ToString(*(reinterpret_cast<const uint32_t*>(opt_address)));
417
7.70M
      break;
418
23.0M
    case OptionType::kUInt64T:
419
23.0M
      *value = ToString(*(reinterpret_cast<const uint64_t*>(opt_address)));
420
23.0M
      break;
421
23.0M
    case OptionType::kSizeT:
422
23.0M
      *value = ToString(*(reinterpret_cast<const size_t*>(opt_address)));
423
23.0M
      break;
424
1.28M
    case OptionType::kDouble:
425
1.28M
      *value = ToString(*(reinterpret_cast<const double*>(opt_address)));
426
1.28M
      break;
427
2.55M
    case OptionType::kString:
428
2.55M
      *value = EscapeOptionString(
429
2.55M
          *(reinterpret_cast<const std::string*>(opt_address)));
430
2.55M
      break;
431
1.28M
    case OptionType::kCompactionStyle:
432
1.28M
      return SerializeEnum<CompactionStyle>(
433
1.28M
          compaction_style_string_map,
434
1.28M
          *(reinterpret_cast<const CompactionStyle*>(opt_address)), value);
435
1.28M
    case OptionType::kCompressionType:
436
1.28M
      return SerializeEnum<CompressionType>(
437
1.28M
          compression_type_string_map,
438
1.28M
          *(reinterpret_cast<const CompressionType*>(opt_address)), value);
439
1.28M
    case OptionType::kVectorCompressionType:
440
1.28M
      return SerializeVectorCompressionType(
441
1.28M
          *(reinterpret_cast<const std::vector<CompressionType>*>(opt_address)),
442
1.28M
          value);
443
0
      break;
444
2.57M
    case OptionType::kSliceTransform: {
445
2.57M
      const auto* slice_transform_ptr =
446
2.57M
          reinterpret_cast<const std::shared_ptr<const SliceTransform>*>(
447
2.57M
              opt_address);
448
2.57M
      *value = slice_transform_ptr->get() ? 
slice_transform_ptr->get()->Name()6.13k
449
2.57M
                                          : 
kNullptrString2.56M
;
450
2.57M
      break;
451
0
    }
452
2.57M
    case OptionType::kTableFactory: {
453
2.57M
      const auto* table_factory_ptr =
454
2.57M
          reinterpret_cast<const std::shared_ptr<const TableFactory>*>(
455
2.57M
              opt_address);
456
2.57M
      *value = table_factory_ptr->get() ? 
table_factory_ptr->get()->Name()2.57M
457
2.57M
                                        : 
kNullptrString54
;
458
2.57M
      break;
459
0
    }
460
2.57M
    case OptionType::kComparator: {
461
      // it's a const pointer of const Comparator*
462
2.57M
      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.57M
      const auto* internal_comparator =
467
2.57M
          dynamic_cast<const InternalKeyComparator*>(*ptr);
468
2.57M
      if (internal_comparator != nullptr) {
469
2.57M
        *value = internal_comparator->user_comparator()->Name();
470
2.57M
      } else {
471
18.4E
        *value = 
*ptr202
?
(*ptr)->Name()312
: kNullptrString;
472
202
      }
473
2.57M
      break;
474
0
    }
475
2.57M
    case OptionType::kCompactionFilter: {
476
      // it's a const pointer of const CompactionFilter*
477
2.57M
      const auto* ptr =
478
2.57M
          reinterpret_cast<const CompactionFilter* const*>(opt_address);
479
2.57M
      *value = *ptr ? 
(*ptr)->Name()184
:
kNullptrString2.57M
;
480
2.57M
      break;
481
0
    }
482
2.57M
    case OptionType::kCompactionFilterFactory: {
483
2.57M
      const auto* ptr =
484
2.57M
          reinterpret_cast<const std::shared_ptr<CompactionFilterFactory>*>(
485
2.57M
              opt_address);
486
2.57M
      *value = ptr->get() ? 
ptr->get()->Name()2.52M
:
kNullptrString42.4k
;
487
2.57M
      break;
488
0
    }
489
2.57M
    case OptionType::kMemTableRepFactory: {
490
2.57M
      const auto* ptr =
491
2.57M
          reinterpret_cast<const std::shared_ptr<MemTableRepFactory>*>(
492
2.57M
              opt_address);
493
2.57M
      *value = ptr->get() ? 
ptr->get()->Name()2.57M
:
kNullptrString12
;
494
2.57M
      break;
495
0
    }
496
2.57M
    case OptionType::kMergeOperator: {
497
2.57M
      const auto* ptr =
498
2.57M
          reinterpret_cast<const std::shared_ptr<MergeOperator>*>(opt_address);
499
2.57M
      *value = ptr->get() ? 
ptr->get()->Name()1.70k
:
kNullptrString2.56M
;
500
2.57M
      break;
501
0
    }
502
2.56M
    case OptionType::kFilterPolicy: {
503
2.56M
      const auto* ptr =
504
2.56M
          reinterpret_cast<const std::shared_ptr<FilterPolicy>*>(opt_address);
505
2.56M
      *value = ptr->get() ? 
ptr->get()->Name()2.42M
:
kNullptrString140k
;
506
2.56M
      break;
507
0
    }
508
1.28M
    case OptionType::kChecksumType:
509
1.28M
      return SerializeEnum<ChecksumType>(
510
1.28M
          checksum_type_string_map,
511
1.28M
          *reinterpret_cast<const ChecksumType*>(opt_address), value);
512
1.28M
    case OptionType::kBlockBasedTableIndexType:
513
1.28M
      return SerializeEnum<IndexType>(
514
1.28M
          block_base_table_index_type_string_map,
515
1.28M
          *reinterpret_cast<const IndexType*>(opt_address),
516
1.28M
          value);
517
2.56M
    case OptionType::kFlushBlockPolicyFactory: {
518
2.56M
      const auto* ptr =
519
2.56M
          reinterpret_cast<const std::shared_ptr<FlushBlockPolicyFactory>*>(
520
2.56M
              opt_address);
521
18.4E
      *value = 
ptr->get()2.56M
?
ptr->get()->Name()2.56M
: kNullptrString;
522
2.56M
      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.27M
    case OptionType::kWALRecoveryMode:
529
1.27M
      return SerializeEnum<WALRecoveryMode>(
530
1.27M
          wal_recovery_mode_string_map,
531
1.27M
          *reinterpret_cast<const WALRecoveryMode*>(opt_address), value);
532
1.27M
    case OptionType::kAccessHint:
533
1.27M
      return SerializeEnum<DBOptions::AccessHint>(
534
1.27M
          access_hint_string_map,
535
1.27M
          *reinterpret_cast<const DBOptions::AccessHint*>(opt_address), value);
536
1.27M
    case OptionType::kInfoLogLevel:
537
1.27M
      return SerializeEnum<InfoLogLevel>(
538
1.27M
          info_log_level_string_map,
539
1.27M
          *reinterpret_cast<const InfoLogLevel*>(opt_address), value);
540
0
    default:
541
0
      return false;
542
165M
  }
543
154M
  return true;
544
165M
}
545
546
547
template<typename OptionsType>
548
bool ParseMemtableOptions(const std::string& name, const std::string& value,
549
1.26M
                          OptionsType* new_options) {
550
1.26M
  if (name == "write_buffer_size") {
551
1
    new_options->write_buffer_size = ParseSizeT(value);
552
1.26M
  } else if (name == "arena_block_size") {
553
0
    new_options->arena_block_size = ParseSizeT(value);
554
1.26M
  } else if (name == "memtable_prefix_bloom_bits") {
555
0
    new_options->memtable_prefix_bloom_bits = ParseUint32(value);
556
1.26M
  } else if (name == "memtable_prefix_bloom_probes") {
557
0
    new_options->memtable_prefix_bloom_probes = ParseUint32(value);
558
1.26M
  } 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
1.26M
  } else if (name == "max_successive_merges") {
562
0
    new_options->max_successive_merges = ParseSizeT(value);
563
1.26M
  } else if (name == "filter_deletes") {
564
0
    new_options->filter_deletes = ParseBoolean(name, value);
565
1.26M
  } else if (name == "max_write_buffer_number") {
566
2
    new_options->max_write_buffer_number = ParseInt(value);
567
1.26M
  } else if (name == "inplace_update_num_locks") {
568
0
    new_options->inplace_update_num_locks = ParseSizeT(value);
569
1.26M
  } else {
570
1.26M
    return false;
571
1.26M
  }
572
3
  return true;
573
1.26M
}
574
575
template<typename OptionsType>
576
bool ParseCompactionOptions(const std::string& name, const std::string& value,
577
1.26M
                            OptionsType* new_options) {
578
1.26M
  if (name == "disable_auto_compactions") {
579
421k
    new_options->disable_auto_compactions = ParseBoolean(name, value);
580
842k
  } else if (name == "soft_rate_limit") {
581
    // Deprecated options but still leave it here to avoid older options
582
    // strings can be consumed.
583
842k
  } else if (name == "soft_pending_compaction_bytes_limit") {
584
0
    new_options->soft_pending_compaction_bytes_limit = ParseUint64(value);
585
842k
  } else if (name == "hard_pending_compaction_bytes_limit") {
586
0
    new_options->hard_pending_compaction_bytes_limit = ParseUint64(value);
587
842k
  } else if (name == "hard_rate_limit") {
588
    // Deprecated options but still leave it here to avoid older options
589
    // strings can be consumed.
590
842k
  } else if (name == "level0_file_num_compaction_trigger") {
591
1
    new_options->level0_file_num_compaction_trigger = ParseInt(value);
592
842k
  } else if (name == "level0_slowdown_writes_trigger") {
593
421k
    new_options->level0_slowdown_writes_trigger = ParseInt(value);
594
421k
  } else 
if (421k
name == "level0_stop_writes_trigger"421k
) {
595
421k
    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
1.26M
  return true;
631
1.26M
}
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
2
  } else 
if (1
name == "paranoid_file_checks"1
) {
639
1
    new_options->paranoid_file_checks = ParseBoolean(name, value);
640
1
  } 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
842k
    MutableCFOptions* new_options) {
650
842k
  assert(new_options);
651
0
  *new_options = base_options;
652
1.26M
  for (const auto& o : options_map) {
653
1.26M
    try {
654
1.26M
      if (ParseMemtableOptions(o.first, o.second, new_options)) {
655
1.26M
      } else 
if (1.26M
ParseCompactionOptions(o.first, o.second, new_options)1.26M
) {
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
1.26M
    } catch (std::exception& e) {
662
0
      return STATUS(InvalidArgument, "error parsing " + o.first + ":" +
663
0
                                     std::string(e.what()));
664
0
    }
665
1.26M
  }
666
842k
  return Status::OK();
667
842k
}
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
0
  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])8.14k
) {
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
20.7k
        }
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])2.47k
) {
718
102
          ++pos;
719
102
        }
720
2.89k
        if (pos < opts.size() && 
opts[pos] != ';'2.37k
) {
721
827
          return STATUS(InvalidArgument,
722
827
              "Unexpected chars after nested options");
723
827
        }
724
2.06k
        ++pos;
725
2.06k
      } else {
726
1.29k
        return STATUS(InvalidArgument,
727
1.29k
            "Mismatched curly braces for nested options");
728
1.29k
      }
729
4.18k
    } 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
59.0M
                               bool input_strings_escaped = false) {
749
59.0M
  const std::string& value =
750
18.4E
      
input_strings_escaped59.0M
?
UnescapeOptionString(org_value)59.0M
: org_value;
751
59.0M
  try {
752
59.0M
    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
59.0M
    } 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
59.0M
    } 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
59.0M
    } 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
59.0M
    } 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
59.0M
    } else if (name == "compaction_options_fifo") {
831
3
      new_options->compaction_options_fifo.max_table_files_size =
832
3
          ParseUint64(value);
833
59.0M
    } else {
834
59.0M
      auto iter = cf_options_type_info.find(name);
835
59.0M
      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
59.0M
      const auto& opt_info = iter->second;
840
59.0M
      if (ParseOptionHelper(
841
59.0M
              reinterpret_cast<char*>(new_options) + opt_info.offset,
842
59.0M
              opt_info.type, value)) {
843
51.3M
        return Status::OK();
844
51.3M
      }
845
7.68M
      switch (opt_info.verification) {
846
7.71M
        case OptionVerificationType::kByName:
847
7.71M
        case OptionVerificationType::kByNameAllowNull:
848
7.71M
          return STATUS(NotSupported,
849
7.71M
              "Deserializing the specified CF option " + name +
850
7.71M
                  " is not supported");
851
0
        case OptionVerificationType::kDeprecated:
852
0
          return Status::OK();
853
0
        default:
854
0
          return STATUS(InvalidArgument,
855
7.68M
              "Unable to parse the specified CF option " + name);
856
7.68M
      }
857
7.68M
    }
858
59.0M
  } 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
59.0M
}
864
865
bool SerializeSingleDBOption(std::string* opt_string,
866
                             const DBOptions& db_options,
867
                             const std::string& name,
868
72.7M
                             const std::string& delimiter) {
869
72.7M
  auto iter = db_options_type_info.find(name);
870
72.7M
  if (iter == db_options_type_info.end()) {
871
0
    return false;
872
0
  }
873
72.7M
  auto& opt_info = iter->second;
874
72.7M
  const char* opt_address =
875
72.7M
      reinterpret_cast<const char*>(&db_options) + opt_info.offset;
876
72.7M
  std::string value;
877
72.7M
  bool result = SerializeSingleOptionHelper(opt_address, opt_info.type, &value);
878
72.8M
  if (
result72.7M
) {
879
72.8M
    *opt_string = name + "=" + value + delimiter;
880
72.8M
  }
881
72.7M
  return result;
882
72.7M
}
883
884
Status GetStringFromDBOptions(std::string* opt_string,
885
                              const DBOptions& db_options,
886
1.27M
                              const std::string& delimiter) {
887
1.27M
  assert(opt_string);
888
0
  opt_string->clear();
889
1.27M
  for (auto iter = db_options_type_info.begin();
890
74.0M
       iter != db_options_type_info.end(); 
++iter72.7M
) {
891
72.7M
    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
72.7M
    std::string single_output;
897
72.7M
    bool result = SerializeSingleDBOption(&single_output, db_options,
898
72.7M
                                          iter->first, delimiter);
899
72.7M
    assert(result);
900
72.8M
    if (
result72.7M
) {
901
72.8M
      opt_string->append(single_output);
902
72.8M
    }
903
72.7M
  }
904
1.27M
  return Status::OK();
905
1.27M
}
906
907
bool SerializeSingleColumnFamilyOption(std::string* opt_string,
908
                                       const ColumnFamilyOptions& cf_options,
909
                                       const std::string& name,
910
59.0M
                                       const std::string& delimiter) {
911
59.0M
  auto iter = cf_options_type_info.find(name);
912
59.0M
  if (iter == cf_options_type_info.end()) {
913
0
    return false;
914
0
  }
915
59.0M
  auto& opt_info = iter->second;
916
59.0M
  const char* opt_address =
917
59.0M
      reinterpret_cast<const char*>(&cf_options) + opt_info.offset;
918
59.0M
  std::string value;
919
59.0M
  bool result = SerializeSingleOptionHelper(opt_address, opt_info.type, &value);
920
59.0M
  if (
result59.0M
) {
921
59.0M
    *opt_string = name + "=" + value + delimiter;
922
59.0M
  }
923
59.0M
  return result;
924
59.0M
}
925
926
Status GetStringFromColumnFamilyOptions(std::string* opt_string,
927
                                        const ColumnFamilyOptions& cf_options,
928
1.28M
                                        const std::string& delimiter) {
929
1.28M
  assert(opt_string);
930
0
  opt_string->clear();
931
1.28M
  for (auto iter = cf_options_type_info.begin();
932
64.2M
       iter != cf_options_type_info.end(); 
++iter62.9M
) {
933
62.8M
    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.85M
      continue;
937
3.85M
    }
938
59.0M
    std::string single_output;
939
59.0M
    bool result = SerializeSingleColumnFamilyOption(&single_output, cf_options,
940
59.0M
                                                    iter->first, delimiter);
941
59.0M
    if (
result59.0M
) {
942
59.0M
      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
59.0M
    assert(result);
948
59.0M
  }
949
1.31M
  return Status::OK();
950
1.28M
}
951
952
bool SerializeSingleBlockBasedTableOption(
953
    std::string* opt_string, const BlockBasedTableOptions& bbt_options,
954
21.8M
    const std::string& name, const std::string& delimiter) {
955
21.8M
  auto iter = block_based_table_type_info.find(name);
956
21.8M
  if (iter == block_based_table_type_info.end()) {
957
0
    return false;
958
0
  }
959
21.8M
  auto& opt_info = iter->second;
960
21.8M
  const char* opt_address =
961
21.8M
      reinterpret_cast<const char*>(&bbt_options) + opt_info.offset;
962
21.8M
  std::string value;
963
21.8M
  bool result = SerializeSingleOptionHelper(opt_address, opt_info.type, &value);
964
21.8M
  if (
result21.8M
) {
965
21.8M
    *opt_string = name + "=" + value + delimiter;
966
21.8M
  }
967
21.8M
  return result;
968
21.8M
}
969
970
Status GetStringFromBlockBasedTableOptions(
971
    std::string* opt_string, const BlockBasedTableOptions& bbt_options,
972
1.28M
    const std::string& delimiter) {
973
1.28M
  assert(opt_string);
974
0
  opt_string->clear();
975
1.28M
  for (auto iter = block_based_table_type_info.begin();
976
23.0M
       iter != block_based_table_type_info.end(); 
++iter21.8M
) {
977
21.8M
    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
21.8M
    std::string single_output;
983
21.8M
    bool result = SerializeSingleBlockBasedTableOption(
984
21.8M
        &single_output, bbt_options, iter->first, delimiter);
985
21.8M
    assert(result);
986
21.8M
    if (
result21.8M
) {
987
21.8M
      opt_string->append(single_output);
988
21.8M
    }
989
21.8M
  }
990
1.28M
  return Status::OK();
991
1.28M
}
992
993
Status GetStringFromTableFactory(std::string* opts_str, const TableFactory* tf,
994
1.28M
                                 const std::string& delimiter) {
995
1.28M
  const auto* bbtf = dynamic_cast<const BlockBasedTableFactory*>(tf);
996
1.28M
  opts_str->clear();
997
1.28M
  if (bbtf != nullptr) {
998
1.28M
    return GetStringFromBlockBasedTableOptions(opts_str, bbtf->table_options(),
999
1.28M
                                               delimiter);
1000
1.28M
  }
1001
1002
1.90k
  return Status::OK();
1003
1.28M
}
1004
1005
Status ParseDBOption(const std::string& name,
1006
                     const std::string& org_value,
1007
                     DBOptions* new_options,
1008
72.8M
                     bool input_strings_escaped = false) {
1009
72.8M
  const std::string& value =
1010
18.4E
      
input_strings_escaped72.8M
?
UnescapeOptionString(org_value)72.8M
: org_value;
1011
72.8M
  try {
1012
72.8M
    if (name == "rate_limiter_bytes_per_sec") {
1013
1
      new_options->rate_limiter.reset(
1014
1
          NewGenericRateLimiter(static_cast<int64_t>(ParseUint64(value))));
1015
72.8M
    } else {
1016
72.8M
      auto iter = db_options_type_info.find(name);
1017
72.8M
      if (iter == db_options_type_info.end()) {
1018
3
        return STATUS(InvalidArgument, "Unrecognized option DBOptions:", name);
1019
3
      }
1020
72.8M
      const auto& opt_info = iter->second;
1021
72.8M
      if (ParseOptionHelper(
1022
72.8M
              reinterpret_cast<char*>(new_options) + opt_info.offset,
1023
72.8M
              opt_info.type, value)) {
1024
72.8M
        return Status::OK();
1025
72.8M
      }
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
18.4E
              "Unable to parse the specified DB option " + name);
1037
18.4E
      }
1038
18.4E
    }
1039
72.8M
  } catch (const std::exception&) {
1040
0
    return STATUS(InvalidArgument, "Unable to parse DBOptions:", name);
1041
0
  }
1042
1
  return Status::OK();
1043
72.8M
}
1044
1045
std::string ParseBlockBasedTableOption(const std::string& name,
1046
                                       const std::string& org_value,
1047
                                       BlockBasedTableOptions* new_options,
1048
21.8M
                                       bool input_strings_escaped = false) {
1049
21.8M
  const std::string& value =
1050
18.4E
      
input_strings_escaped21.8M
?
UnescapeOptionString(org_value)21.8M
: org_value;
1051
21.8M
  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
2
    }
1079
28
  }
1080
21.8M
  const auto iter = block_based_table_type_info.find(name);
1081
21.8M
  if (iter == block_based_table_type_info.end()) {
1082
2
    return "Unrecognized option";
1083
2
  }
1084
21.8M
  const auto& opt_info = iter->second;
1085
21.8M
  if (!ParseOptionHelper(reinterpret_cast<char*>(new_options) + opt_info.offset,
1086
21.8M
                         opt_info.type, value)) {
1087
2.56M
    return "Invalid value";
1088
2.56M
  }
1089
19.2M
  return "";
1090
21.8M
}
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)0
: 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
12
                         opt_info.type, value)) {
1105
1
    return "Invalid value";
1106
1
  }
1107
11
  return "";
1108
12
}
1109
1110
Status GetBlockBasedTableOptionsFromMap(
1111
    const BlockBasedTableOptions& table_options,
1112
    const std::unordered_map<std::string, std::string>& opts_map,
1113
1.28M
    BlockBasedTableOptions* new_table_options, bool input_strings_escaped) {
1114
1.28M
  assert(new_table_options);
1115
0
  *new_table_options = table_options;
1116
21.8M
  for (const auto& o : opts_map) {
1117
21.8M
    auto error_message = ParseBlockBasedTableOption(
1118
21.8M
        o.first, o.second, new_table_options, input_strings_escaped);
1119
21.8M
    if (error_message != "") {
1120
2.56M
      const auto iter = block_based_table_type_info.find(o.first);
1121
2.56M
      if (iter == block_based_table_type_info.end() ||
1122
2.56M
          !input_strings_escaped ||  // !input_strings_escaped indicates
1123
                                     // the old API, where everything is
1124
                                     // parsable.
1125
2.56M
          (iter->second.verification != OptionVerificationType::kByName &&
1126
2.56M
           iter->second.verification !=
1127
0
               OptionVerificationType::kByNameAllowNull &&
1128
2.56M
           
iter->second.verification != OptionVerificationType::kDeprecated0
)) {
1129
6
        return STATUS(InvalidArgument, "Can't parse BlockBasedTableOptions:",
1130
6
                                       o.first + " " + error_message);
1131
6
      }
1132
2.56M
    }
1133
21.8M
  }
1134
1.28M
  return Status::OK();
1135
1.28M
}
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
0
  *new_table_options = table_options;
1156
1.64k
  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
2
          
!input_strings_escaped1
|| // !input_strings_escaped indicates
1163
                                     // the old API, where everything is
1164
                                     // parsable.
1165
2
          
(0
iter->second.verification != OptionVerificationType::kByName0
&&
1166
0
           iter->second.verification !=
1167
0
               OptionVerificationType::kByNameAllowNull &&
1168
2
           
iter->second.verification != OptionVerificationType::kDeprecated0
)) {
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
2
    } else 
if (1
1 == len1
) {
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
2
  } 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
10
}
1249
1250
Status GetColumnFamilyOptionsFromMap(
1251
    const ColumnFamilyOptions& base_options,
1252
    const std::unordered_map<std::string, std::string>& opts_map,
1253
1.28M
    ColumnFamilyOptions* new_options, bool input_strings_escaped) {
1254
1.28M
  return GetColumnFamilyOptionsFromMapInternal(
1255
1.28M
      base_options, opts_map, new_options, input_strings_escaped);
1256
1.28M
}
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.28M
    std::vector<std::string>* unsupported_options_names) {
1263
1.28M
  assert(new_options);
1264
0
  *new_options = base_options;
1265
1.28M
  if (unsupported_options_names) {
1266
0
    unsupported_options_names->clear();
1267
0
  }
1268
59.0M
  for (const auto& o : opts_map) {
1269
59.0M
    auto s = ParseColumnFamilyOption(o.first, o.second, new_options,
1270
59.0M
                                 input_strings_escaped);
1271
59.0M
    if (!s.ok()) {
1272
7.71M
      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
7.71M
        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
7.71M
      } else {
1283
430
        return s;
1284
430
      }
1285
7.71M
    }
1286
59.0M
  }
1287
1.28M
  return Status::OK();
1288
1.28M
}
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
30
}
1301
1302
Status GetDBOptionsFromMap(
1303
    const DBOptions& base_options,
1304
    const std::unordered_map<std::string, std::string>& opts_map,
1305
1.27M
    DBOptions* new_options, bool input_strings_escaped) {
1306
1.27M
  return GetDBOptionsFromMapInternal(
1307
1.27M
      base_options, opts_map, new_options, input_strings_escaped);
1308
1.27M
}
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.27M
    std::vector<std::string>* unsupported_options_names) {
1315
1.27M
  assert(new_options);
1316
0
  *new_options = base_options;
1317
1.27M
  if (unsupported_options_names) {
1318
0
    unsupported_options_names->clear();
1319
0
  }
1320
72.8M
  for (const auto& o : opts_map) {
1321
72.8M
    auto s = ParseDBOption(o.first, o.second,
1322
72.8M
                           new_options, input_strings_escaped);
1323
72.8M
    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
72.8M
  }
1339
1.27M
  return Status::OK();
1340
1.27M
}
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
3
    } 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.28M
    std::shared_ptr<TableFactory>* table_factory) {
1379
1.28M
  Status s;
1380
1.28M
  if (factory_name == BlockBasedTableFactory().Name()) {
1381
1.28M
    BlockBasedTableOptions bbt_opt;
1382
1.28M
    s = GetBlockBasedTableOptionsFromMap(BlockBasedTableOptions(), opt_map,
1383
1.28M
                                         &bbt_opt, true);
1384
1.28M
    if (!s.ok()) {
1385
0
      return s;
1386
0
    }
1387
1.28M
    table_factory->reset(new BlockBasedTableFactory(bbt_opt));
1388
1.28M
    return Status::OK();
1389
1.28M
  } else 
if (1.62k
factory_name == PlainTableFactory().Name()1.62k
) {
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
1.28M
}
1404
1405
ColumnFamilyOptions BuildColumnFamilyOptions(
1406
1.28M
    const Options& options, const MutableCFOptions& mutable_cf_options) {
1407
1.28M
  ColumnFamilyOptions cf_opts(options);
1408
1409
  // Memtable related options
1410
1.28M
  cf_opts.write_buffer_size = mutable_cf_options.write_buffer_size;
1411
1.28M
  cf_opts.max_write_buffer_number = mutable_cf_options.max_write_buffer_number;
1412
1.28M
  cf_opts.arena_block_size = mutable_cf_options.arena_block_size;
1413
1.28M
  cf_opts.memtable_prefix_bloom_bits =
1414
1.28M
      mutable_cf_options.memtable_prefix_bloom_bits;
1415
1.28M
  cf_opts.memtable_prefix_bloom_probes =
1416
1.28M
      mutable_cf_options.memtable_prefix_bloom_probes;
1417
1.28M
  cf_opts.memtable_prefix_bloom_huge_page_tlb_size =
1418
1.28M
      mutable_cf_options.memtable_prefix_bloom_huge_page_tlb_size;
1419
1.28M
  cf_opts.max_successive_merges = mutable_cf_options.max_successive_merges;
1420
1.28M
  cf_opts.filter_deletes = mutable_cf_options.filter_deletes;
1421
1.28M
  cf_opts.inplace_update_num_locks =
1422
1.28M
      mutable_cf_options.inplace_update_num_locks;
1423
1424
  // Compaction related options
1425
1.28M
  cf_opts.disable_auto_compactions =
1426
1.28M
      mutable_cf_options.disable_auto_compactions;
1427
1.28M
  cf_opts.level0_file_num_compaction_trigger =
1428
1.28M
      mutable_cf_options.level0_file_num_compaction_trigger;
1429
1.28M
  cf_opts.level0_slowdown_writes_trigger =
1430
1.28M
      mutable_cf_options.level0_slowdown_writes_trigger;
1431
1.28M
  cf_opts.level0_stop_writes_trigger =
1432
1.28M
      mutable_cf_options.level0_stop_writes_trigger;
1433
1.28M
  cf_opts.max_grandparent_overlap_factor =
1434
1.28M
      mutable_cf_options.max_grandparent_overlap_factor;
1435
1.28M
  cf_opts.expanded_compaction_factor =
1436
1.28M
      mutable_cf_options.expanded_compaction_factor;
1437
1.28M
  cf_opts.source_compaction_factor =
1438
1.28M
      mutable_cf_options.source_compaction_factor;
1439
1.28M
  cf_opts.target_file_size_base = mutable_cf_options.target_file_size_base;
1440
1.28M
  cf_opts.target_file_size_multiplier =
1441
1.28M
      mutable_cf_options.target_file_size_multiplier;
1442
1.28M
  cf_opts.max_bytes_for_level_base =
1443
1.28M
      mutable_cf_options.max_bytes_for_level_base;
1444
1.28M
  cf_opts.max_bytes_for_level_multiplier =
1445
1.28M
      mutable_cf_options.max_bytes_for_level_multiplier;
1446
1447
1.28M
  cf_opts.max_bytes_for_level_multiplier_additional.clear();
1448
1.28M
  for (auto value :
1449
8.99M
       mutable_cf_options.max_bytes_for_level_multiplier_additional) {
1450
8.99M
    cf_opts.max_bytes_for_level_multiplier_additional.emplace_back(value);
1451
8.99M
  }
1452
1453
1.28M
  cf_opts.verify_checksums_in_compaction =
1454
1.28M
      mutable_cf_options.verify_checksums_in_compaction;
1455
1456
  // Misc options
1457
1.28M
  cf_opts.max_sequential_skip_in_iterations =
1458
1.28M
      mutable_cf_options.max_sequential_skip_in_iterations;
1459
1.28M
  cf_opts.paranoid_file_checks = mutable_cf_options.paranoid_file_checks;
1460
1.28M
  cf_opts.compaction_measure_io_stats =
1461
1.28M
      mutable_cf_options.compaction_measure_io_stats;
1462
1463
1.28M
  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.28M
  return cf_opts;
1468
1.28M
}
1469
1470
#endif  // !ROCKSDB_LITE
1471
}  // namespace rocksdb