Coverage Report

Created: 2026-11-12 08:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rocksdb/table/plain/plain_table_factory.cc
Line
Count
Source
1
// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
2
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
3
// Use of this source code is governed by a BSD-style license that can be
4
// found in the LICENSE file. See the AUTHORS file for names of contributors.
5
6
#include "table/plain/plain_table_factory.h"
7
8
#include <cstdint>
9
#include <memory>
10
11
#include "db/dbformat.h"
12
#include "port/port.h"
13
#include "rocksdb/convenience.h"
14
#include "rocksdb/utilities/customizable_util.h"
15
#include "rocksdb/utilities/object_registry.h"
16
#include "rocksdb/utilities/options_type.h"
17
#include "table/plain/plain_table_builder.h"
18
#include "table/plain/plain_table_reader.h"
19
#include "util/string_util.h"
20
21
namespace ROCKSDB_NAMESPACE {
22
static std::unordered_map<std::string, OptionTypeInfo> plain_table_type_info = {
23
    {"user_key_len",
24
     {offsetof(struct PlainTableOptions, user_key_len), OptionType::kUInt32T,
25
      OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
26
    {"bloom_bits_per_key",
27
     {offsetof(struct PlainTableOptions, bloom_bits_per_key), OptionType::kInt,
28
      OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
29
    {"hash_table_ratio",
30
     {offsetof(struct PlainTableOptions, hash_table_ratio), OptionType::kDouble,
31
      OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
32
    {"index_sparseness",
33
     {offsetof(struct PlainTableOptions, index_sparseness), OptionType::kSizeT,
34
      OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
35
    {"huge_page_tlb_size",
36
     {offsetof(struct PlainTableOptions, huge_page_tlb_size),
37
      OptionType::kSizeT, OptionVerificationType::kNormal,
38
      OptionTypeFlags::kNone}},
39
    {"encoding_type",
40
     {offsetof(struct PlainTableOptions, encoding_type),
41
      OptionType::kEncodingType, OptionVerificationType::kNormal,
42
      OptionTypeFlags::kNone}},
43
    {"full_scan_mode",
44
     {offsetof(struct PlainTableOptions, full_scan_mode), OptionType::kBoolean,
45
      OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
46
    {"store_index_in_file",
47
     {offsetof(struct PlainTableOptions, store_index_in_file),
48
      OptionType::kBoolean, OptionVerificationType::kNormal,
49
      OptionTypeFlags::kNone}},
50
};
51
52
PlainTableFactory::PlainTableFactory(const PlainTableOptions& options)
53
0
    : table_options_(options) {
54
0
  RegisterOptions(&table_options_, &plain_table_type_info);
55
0
}
56
57
Status PlainTableFactory::NewTableReader(
58
    const ReadOptions& /*ro*/, const TableReaderOptions& table_reader_options,
59
    std::unique_ptr<RandomAccessFileReader>&& file, uint64_t file_size,
60
    std::unique_ptr<TableReader>* table,
61
0
    bool /*prefetch_index_and_filter_in_cache*/) const {
62
0
  return PlainTableReader::Open(
63
0
      table_reader_options.ioptions, table_reader_options.env_options,
64
0
      table_reader_options.internal_comparator, std::move(file), file_size,
65
0
      table, table_options_.bloom_bits_per_key, table_options_.hash_table_ratio,
66
0
      table_options_.index_sparseness, table_options_.huge_page_tlb_size,
67
0
      table_options_.full_scan_mode, table_reader_options.immortal,
68
0
      table_reader_options.prefix_extractor.get());
69
0
}
70
71
TableBuilder* PlainTableFactory::NewTableBuilder(
72
    const TableBuilderOptions& table_builder_options,
73
0
    WritableFileWriter* file) const {
74
  // Ignore the skip_filters flag. PlainTable format is optimized for small
75
  // in-memory dbs. The skip_filters optimization is not useful for plain
76
  // tables
77
  //
78
0
  return new PlainTableBuilder(
79
0
      table_builder_options.ioptions, table_builder_options.moptions,
80
0
      table_builder_options.internal_tbl_prop_coll_factories,
81
0
      table_builder_options.column_family_id,
82
0
      table_builder_options.level_at_creation, file,
83
0
      table_options_.user_key_len, table_options_.encoding_type,
84
0
      table_options_.index_sparseness, table_options_.bloom_bits_per_key,
85
0
      table_builder_options.column_family_name, 6,
86
0
      table_options_.huge_page_tlb_size, table_options_.hash_table_ratio,
87
0
      table_options_.store_index_in_file, table_builder_options.db_id,
88
0
      table_builder_options.db_session_id, table_builder_options.cur_file_num);
89
0
}
90
91
0
std::string PlainTableFactory::GetPrintableOptions() const {
92
0
  std::string ret;
93
0
  ret.reserve(20000);
94
0
  const int kBufferSize = 200;
95
0
  char buffer[kBufferSize];
96
97
0
  snprintf(buffer, kBufferSize, "  user_key_len: %u\n",
98
0
           table_options_.user_key_len);
99
0
  ret.append(buffer);
100
0
  snprintf(buffer, kBufferSize, "  bloom_bits_per_key: %d\n",
101
0
           table_options_.bloom_bits_per_key);
102
0
  ret.append(buffer);
103
0
  snprintf(buffer, kBufferSize, "  hash_table_ratio: %lf\n",
104
0
           table_options_.hash_table_ratio);
105
0
  ret.append(buffer);
106
0
  snprintf(buffer, kBufferSize, "  index_sparseness: %" ROCKSDB_PRIszt "\n",
107
0
           table_options_.index_sparseness);
108
0
  ret.append(buffer);
109
0
  snprintf(buffer, kBufferSize, "  huge_page_tlb_size: %" ROCKSDB_PRIszt "\n",
110
0
           table_options_.huge_page_tlb_size);
111
0
  ret.append(buffer);
112
0
  snprintf(buffer, kBufferSize, "  encoding_type: %d\n",
113
0
           table_options_.encoding_type);
114
0
  ret.append(buffer);
115
0
  snprintf(buffer, kBufferSize, "  full_scan_mode: %d\n",
116
0
           table_options_.full_scan_mode);
117
0
  ret.append(buffer);
118
0
  snprintf(buffer, kBufferSize, "  store_index_in_file: %d\n",
119
0
           table_options_.store_index_in_file);
120
0
  ret.append(buffer);
121
0
  return ret;
122
0
}
123
124
Status GetPlainTableOptionsFromString(const ConfigOptions& config_options,
125
                                      const PlainTableOptions& table_options,
126
                                      const std::string& opts_str,
127
0
                                      PlainTableOptions* new_table_options) {
128
0
  std::unordered_map<std::string, std::string> opts_map;
129
0
  Status s = StringToMap(opts_str, &opts_map);
130
0
  if (!s.ok()) {
131
0
    return s;
132
0
  }
133
134
0
  s = GetPlainTableOptionsFromMap(config_options, table_options, opts_map,
135
0
                                  new_table_options);
136
  // Translate any errors (NotFound, NotSupported, to InvalidArgument
137
0
  if (s.ok() || s.IsInvalidArgument()) {
138
0
    return s;
139
0
  } else {
140
0
    return Status::InvalidArgument(s.getState());
141
0
  }
142
0
}
143
144
static int RegisterBuiltinMemTableRepFactory(ObjectLibrary& library,
145
2
                                             const std::string& /*arg*/) {
146
  // The MemTableRepFactory built-in classes will be either a class
147
  // (VectorRepFactory) or a nickname (vector), followed optionally by ":#",
148
  // where # is the "size" of the factory.
149
10
  auto AsPattern = [](const std::string& name, const std::string& alt) {
150
10
    auto pattern = ObjectLibrary::PatternEntry(name, true);
151
10
    pattern.AnotherName(alt);
152
10
    pattern.AddNumber(":");
153
10
    return pattern;
154
10
  };
155
2
  library.AddFactory<MemTableRepFactory>(
156
2
      AsPattern(VectorRepFactory::kClassName(), VectorRepFactory::kNickName()),
157
2
      [](const std::string& uri, std::unique_ptr<MemTableRepFactory>* guard,
158
2
         std::string* /*errmsg*/) {
159
0
        auto colon = uri.find(':');
160
0
        if (colon != std::string::npos) {
161
0
          size_t count = ParseSizeT(uri.substr(colon + 1));
162
0
          guard->reset(new VectorRepFactory(count));
163
0
        } else {
164
0
          guard->reset(new VectorRepFactory());
165
0
        }
166
0
        return guard->get();
167
0
      });
168
2
  library.AddFactory<MemTableRepFactory>(
169
2
      AsPattern(SkipListFactory::kClassName(), SkipListFactory::kNickName()),
170
2
      [](const std::string& uri, std::unique_ptr<MemTableRepFactory>* guard,
171
107k
         std::string* /*errmsg*/) {
172
107k
        auto colon = uri.find(':');
173
107k
        if (colon != std::string::npos) {
174
0
          size_t lookahead = ParseSizeT(uri.substr(colon + 1));
175
0
          guard->reset(new SkipListFactory(lookahead));
176
107k
        } else {
177
107k
          guard->reset(new SkipListFactory());
178
107k
        }
179
107k
        return guard->get();
180
107k
      });
181
2
  library.AddFactory<MemTableRepFactory>(
182
2
      AsPattern("HashLinkListRepFactory", "hash_linkedlist"),
183
2
      [](const std::string& uri, std::unique_ptr<MemTableRepFactory>* guard,
184
2
         std::string* /*errmsg*/) {
185
        // Expecting format: hash_linkedlist:<hash_bucket_count>
186
0
        auto colon = uri.find(':');
187
0
        if (colon != std::string::npos) {
188
0
          size_t hash_bucket_count = ParseSizeT(uri.substr(colon + 1));
189
0
          guard->reset(NewHashLinkListRepFactory(hash_bucket_count));
190
0
        } else {
191
0
          guard->reset(NewHashLinkListRepFactory());
192
0
        }
193
0
        return guard->get();
194
0
      });
195
2
  library.AddFactory<MemTableRepFactory>(
196
2
      AsPattern("HashSkipListRepFactory", "prefix_hash"),
197
2
      [](const std::string& uri, std::unique_ptr<MemTableRepFactory>* guard,
198
2
         std::string* /*errmsg*/) {
199
        // Expecting format: prefix_hash:<hash_bucket_count>
200
0
        auto colon = uri.find(':');
201
0
        if (colon != std::string::npos) {
202
0
          size_t hash_bucket_count = ParseSizeT(uri.substr(colon + 1));
203
0
          guard->reset(NewHashSkipListRepFactory(hash_bucket_count));
204
0
        } else {
205
0
          guard->reset(NewHashSkipListRepFactory());
206
0
        }
207
0
        return guard->get();
208
0
      });
209
2
  library.AddFactory<MemTableRepFactory>(
210
2
      AsPattern("SortedHashRepFactory", "sorted_hash"),
211
2
      [](const std::string& uri, std::unique_ptr<MemTableRepFactory>* guard,
212
2
         std::string* /*errmsg*/) {
213
        // Expecting format: sorted_hash:<bucket_count>. Without a count,
214
        // bucket_count must come from the options string and is validated
215
        // when the column family is opened.
216
0
        auto colon = uri.find(':');
217
0
        if (colon != std::string::npos) {
218
0
          size_t hash_bucket_count = ParseSizeT(uri.substr(colon + 1));
219
0
          guard->reset(NewSortedHashRepFactory(hash_bucket_count));
220
0
        } else {
221
0
          guard->reset(NewSortedHashRepFactory(0));
222
0
        }
223
0
        return guard->get();
224
0
      });
225
2
  library.AddFactory<MemTableRepFactory>(
226
2
      "cuckoo",
227
2
      [](const std::string& /*uri*/,
228
2
         std::unique_ptr<MemTableRepFactory>* /*guard*/, std::string* errmsg) {
229
0
        *errmsg = "cuckoo hash memtable is not supported anymore.";
230
0
        return nullptr;
231
0
      });
232
233
2
  size_t num_types;
234
2
  return static_cast<int>(library.GetFactoryCount(&num_types));
235
2
}
236
237
Status GetMemTableRepFactoryFromString(
238
0
    const std::string& opts_str, std::unique_ptr<MemTableRepFactory>* result) {
239
0
  ConfigOptions config_options;
240
0
  config_options.ignore_unsupported_options = false;
241
0
  config_options.ignore_unknown_options = false;
242
0
  return MemTableRepFactory::CreateFromString(config_options, opts_str, result);
243
0
}
244
245
Status MemTableRepFactory::CreateFromString(
246
    const ConfigOptions& config_options, const std::string& value,
247
107k
    std::unique_ptr<MemTableRepFactory>* result) {
248
107k
  static std::once_flag once;
249
107k
  std::call_once(once, [&]() {
250
2
    RegisterBuiltinMemTableRepFactory(*(ObjectLibrary::Default().get()), "");
251
2
  });
252
107k
  std::string id;
253
107k
  std::unordered_map<std::string, std::string> opt_map;
254
107k
  Status status = Customizable::GetOptionsMap(config_options, result->get(),
255
107k
                                              value, &id, &opt_map);
256
107k
  if (!status.ok()) {  // GetOptionsMap failed
257
0
    return status;
258
107k
  } else if (value.empty()) {
259
    // No Id and no options.  Clear the object
260
0
    result->reset();
261
0
    return Status::OK();
262
107k
  } else if (id.empty()) {  // We have no Id but have options.  Not good
263
0
    return Status::NotSupported("Cannot reset object ", id);
264
107k
  } else {
265
107k
    status = NewUniqueObject<MemTableRepFactory>(config_options, id, opt_map,
266
107k
                                                 result);
267
107k
  }
268
107k
  return status;
269
107k
}
270
271
Status MemTableRepFactory::CreateFromString(
272
    const ConfigOptions& config_options, const std::string& value,
273
107k
    std::shared_ptr<MemTableRepFactory>* result) {
274
107k
  std::unique_ptr<MemTableRepFactory> factory;
275
107k
  Status s = CreateFromString(config_options, value, &factory);
276
107k
  if (factory && s.ok()) {
277
107k
    result->reset(factory.release());
278
107k
  }
279
107k
  return s;
280
107k
}
281
282
Status GetPlainTableOptionsFromMap(
283
    const ConfigOptions& config_options, const PlainTableOptions& table_options,
284
    const std::unordered_map<std::string, std::string>& opts_map,
285
0
    PlainTableOptions* new_table_options) {
286
0
  assert(new_table_options);
287
0
  PlainTableFactory ptf(table_options);
288
0
  Status s = ptf.ConfigureFromMap(config_options, opts_map);
289
0
  if (s.ok()) {
290
0
    *new_table_options = *(ptf.GetOptions<PlainTableOptions>());
291
0
  } else {
292
    // Restore "new_options" to the default "base_options".
293
0
    *new_table_options = table_options;
294
0
  }
295
0
  return s;
296
0
}
297
298
0
TableFactory* NewPlainTableFactory(const PlainTableOptions& options) {
299
0
  return new PlainTableFactory(options);
300
0
}
301
302
const std::string PlainTablePropertyNames::kEncodingType =
303
    "rocksdb.plain.table.encoding.type";
304
305
const std::string PlainTablePropertyNames::kBloomVersion =
306
    "rocksdb.plain.table.bloom.version";
307
308
const std::string PlainTablePropertyNames::kNumBloomBlocks =
309
    "rocksdb.plain.table.bloom.numblocks";
310
311
}  // namespace ROCKSDB_NAMESPACE