mirror of
https://github.com/facebook/rocksdb.git
synced 2024-11-27 11:43:49 +00:00
333abe9c55
Summary: When picking compaction input files, we sometimes stop picking a file that is fully included in the output key-range due to hitting max_compaction_bytes. Including these input files can potentially reduce WA at the expense of larger compactions. Larger compaction should be fine as files from input level are usually 10X smaller than files from output level. This PR adds a mutable CF option `ignore_max_compaction_bytes_for_input` that is enabled by default. We can remove this option once we are sure it is safe. Pull Request resolved: https://github.com/facebook/rocksdb/pull/10835 Test Plan: - CI, a unit test on max_compaction_bytes fails before turning this flag off. - Benchmark does not show much difference in WA: `./db_bench --benchmarks=fillrandom,waitforcompaction,stats,levelstats -max_background_jobs=12 -num=2000000000 -target_file_size_base=33554432 --write_buffer_size=33554432` ``` main: ** Compaction Stats [default] ** Level Files Size Score Read(GB) Rn(GB) Rnp1(GB) Write(GB) Wnew(GB) Moved(GB) W-Amp Rd(MB/s) Wr(MB/s) Comp(sec) CompMergeCPU(sec) Comp(cnt) Avg(sec) KeyIn KeyDrop Rblob(GB) Wblob(GB) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ L0 3/0 91.59 MB 0.8 70.9 0.0 70.9 200.8 129.9 0.0 1.5 25.2 71.2 2886.55 2463.45 9725 0.297 1093M 254K 0.0 0.0 L1 9/0 248.03 MB 1.0 392.0 129.8 262.2 391.7 129.5 0.0 3.0 69.0 68.9 5821.71 5536.90 804 7.241 6029M 5814K 0.0 0.0 L2 87/0 2.50 GB 1.0 537.0 128.5 408.5 533.8 125.2 0.7 4.2 69.5 69.1 7912.24 7323.70 4417 1.791 8299M 36M 0.0 0.0 L3 836/0 24.99 GB 1.0 616.9 118.3 498.7 594.5 95.8 5.2 5.0 66.9 64.5 9442.38 8490.28 4204 2.246 9749M 306M 0.0 0.0 L4 2355/0 62.95 GB 0.3 67.3 37.1 30.2 54.2 24.0 38.9 1.5 72.2 58.2 954.37 821.18 917 1.041 1076M 173M 0.0 0.0 Sum 3290/0 90.77 GB 0.0 1684.2 413.7 1270.5 1775.0 504.5 44.9 13.7 63.8 67.3 27017.25 24635.52 20067 1.346 26G 522M 0.0 0.0 Cumulative compaction: 1774.96 GB write, 154.29 MB/s write, 1684.19 GB read, 146.40 MB/s read, 27017.3 seconds This PR: ** Compaction Stats [default] ** Level Files Size Score Read(GB) Rn(GB) Rnp1(GB) Write(GB) Wnew(GB) Moved(GB) W-Amp Rd(MB/s) Wr(MB/s) Comp(sec) CompMergeCPU(sec) Comp(cnt) Avg(sec) KeyIn KeyDrop Rblob(GB) Wblob(GB) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ L0 3/0 45.71 MB 0.8 72.9 0.0 72.9 202.8 129.9 0.0 1.6 25.4 70.7 2938.16 2510.36 9741 0.302 1124M 265K 0.0 0.0 L1 8/0 234.54 MB 0.9 384.5 129.8 254.7 384.2 129.6 0.0 3.0 69.0 68.9 5708.08 5424.43 791 7.216 5913M 5753K 0.0 0.0 L2 84/0 2.47 GB 1.0 543.1 128.6 414.5 539.9 125.4 0.7 4.2 69.6 69.2 7989.31 7403.13 4418 1.808 8393M 36M 0.0 0.0 L3 839/0 24.96 GB 1.0 615.6 118.4 497.2 593.2 96.0 5.1 5.0 66.6 64.1 9471.23 8489.31 4193 2.259 9726M 306M 0.0 0.0 L4 2360/0 63.04 GB 0.3 67.6 37.3 30.3 54.4 24.1 38.9 1.5 71.5 57.6 967.30 827.99 907 1.066 1080M 173M 0.0 0.0 Sum 3294/0 90.75 GB 0.0 1683.8 414.2 1269.6 1774.5 504.9 44.8 13.7 63.7 67.1 27074.08 24655.22 20050 1.350 26G 522M 0.0 0.0 Cumulative compaction: 1774.52 GB write, 157.09 MB/s write, 1683.77 GB read, 149.06 MB/s read, 27074.1 seconds ``` Reviewed By: ajkr Differential Revision: D40518319 Pulled By: cbi42 fbshipit-source-id: f4ea614bc0ebefe007ffaf05bb9aec9a8ca25b60
1167 lines
54 KiB
C++
1167 lines
54 KiB
C++
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
|
// This source code is licensed under both the GPLv2 (found in the
|
|
// COPYING file in the root directory) and Apache 2.0 License
|
|
// (found in the LICENSE.Apache file in the root directory).
|
|
|
|
#include "options/cf_options.h"
|
|
|
|
#include <cassert>
|
|
#include <cinttypes>
|
|
#include <limits>
|
|
#include <string>
|
|
|
|
#include "logging/logging.h"
|
|
#include "options/configurable_helper.h"
|
|
#include "options/db_options.h"
|
|
#include "options/options_helper.h"
|
|
#include "options/options_parser.h"
|
|
#include "port/port.h"
|
|
#include "rocksdb/compaction_filter.h"
|
|
#include "rocksdb/concurrent_task_limiter.h"
|
|
#include "rocksdb/configurable.h"
|
|
#include "rocksdb/convenience.h"
|
|
#include "rocksdb/env.h"
|
|
#include "rocksdb/file_system.h"
|
|
#include "rocksdb/merge_operator.h"
|
|
#include "rocksdb/options.h"
|
|
#include "rocksdb/table.h"
|
|
#include "rocksdb/utilities/object_registry.h"
|
|
#include "rocksdb/utilities/options_type.h"
|
|
#include "util/cast_util.h"
|
|
|
|
// NOTE: in this file, many option flags that were deprecated
|
|
// and removed from the rest of the code have to be kept here
|
|
// and marked as kDeprecated in order to be able to read old
|
|
// OPTIONS files.
|
|
|
|
namespace ROCKSDB_NAMESPACE {
|
|
|
|
#ifndef ROCKSDB_LITE
|
|
static Status ParseCompressionOptions(const std::string& value,
|
|
const std::string& name,
|
|
CompressionOptions& compression_opts) {
|
|
const char kDelimiter = ':';
|
|
std::istringstream field_stream(value);
|
|
std::string field;
|
|
|
|
if (!std::getline(field_stream, field, kDelimiter)) {
|
|
return Status::InvalidArgument("unable to parse the specified CF option " +
|
|
name);
|
|
}
|
|
compression_opts.window_bits = ParseInt(field);
|
|
|
|
if (!std::getline(field_stream, field, kDelimiter)) {
|
|
return Status::InvalidArgument("unable to parse the specified CF option " +
|
|
name);
|
|
}
|
|
compression_opts.level = ParseInt(field);
|
|
|
|
if (!std::getline(field_stream, field, kDelimiter)) {
|
|
return Status::InvalidArgument("unable to parse the specified CF option " +
|
|
name);
|
|
}
|
|
compression_opts.strategy = ParseInt(field);
|
|
|
|
// max_dict_bytes is optional for backwards compatibility
|
|
if (!field_stream.eof()) {
|
|
if (!std::getline(field_stream, field, kDelimiter)) {
|
|
return Status::InvalidArgument(
|
|
"unable to parse the specified CF option " + name);
|
|
}
|
|
compression_opts.max_dict_bytes = ParseInt(field);
|
|
}
|
|
|
|
// zstd_max_train_bytes is optional for backwards compatibility
|
|
if (!field_stream.eof()) {
|
|
if (!std::getline(field_stream, field, kDelimiter)) {
|
|
return Status::InvalidArgument(
|
|
"unable to parse the specified CF option " + name);
|
|
}
|
|
compression_opts.zstd_max_train_bytes = ParseInt(field);
|
|
}
|
|
|
|
// parallel_threads is optional for backwards compatibility
|
|
if (!field_stream.eof()) {
|
|
if (!std::getline(field_stream, field, kDelimiter)) {
|
|
return Status::InvalidArgument(
|
|
"unable to parse the specified CF option " + name);
|
|
}
|
|
// Since parallel_threads comes before enabled but was added optionally
|
|
// later, we need to check if this is the final token (meaning it is the
|
|
// enabled bit), or if there are more tokens (meaning this one is
|
|
// parallel_threads).
|
|
if (!field_stream.eof()) {
|
|
compression_opts.parallel_threads = ParseInt(field);
|
|
} else {
|
|
// parallel_threads is not serialized with this format, but enabled is
|
|
compression_opts.enabled = ParseBoolean("", field);
|
|
}
|
|
}
|
|
|
|
// enabled is optional for backwards compatibility
|
|
if (!field_stream.eof()) {
|
|
if (!std::getline(field_stream, field, kDelimiter)) {
|
|
return Status::InvalidArgument(
|
|
"unable to parse the specified CF option " + name);
|
|
}
|
|
compression_opts.enabled = ParseBoolean("", field);
|
|
}
|
|
|
|
// max_dict_buffer_bytes is optional for backwards compatibility
|
|
if (!field_stream.eof()) {
|
|
if (!std::getline(field_stream, field, kDelimiter)) {
|
|
return Status::InvalidArgument(
|
|
"unable to parse the specified CF option " + name);
|
|
}
|
|
compression_opts.max_dict_buffer_bytes = ParseUint64(field);
|
|
}
|
|
|
|
// use_zstd_dict_trainer is optional for backwards compatibility
|
|
if (!field_stream.eof()) {
|
|
if (!std::getline(field_stream, field, kDelimiter)) {
|
|
return Status::InvalidArgument(
|
|
"unable to parse the specified CF option " + name);
|
|
}
|
|
compression_opts.use_zstd_dict_trainer = ParseBoolean("", field);
|
|
}
|
|
|
|
if (!field_stream.eof()) {
|
|
return Status::InvalidArgument("unable to parse the specified CF option " +
|
|
name);
|
|
}
|
|
return Status::OK();
|
|
}
|
|
|
|
const std::string kOptNameBMCompOpts = "bottommost_compression_opts";
|
|
const std::string kOptNameCompOpts = "compression_opts";
|
|
|
|
// OptionTypeInfo map for CompressionOptions
|
|
static std::unordered_map<std::string, OptionTypeInfo>
|
|
compression_options_type_info = {
|
|
{"window_bits",
|
|
{offsetof(struct CompressionOptions, window_bits), OptionType::kInt,
|
|
OptionVerificationType::kNormal, OptionTypeFlags::kMutable}},
|
|
{"level",
|
|
{offsetof(struct CompressionOptions, level), OptionType::kInt,
|
|
OptionVerificationType::kNormal, OptionTypeFlags::kMutable}},
|
|
{"strategy",
|
|
{offsetof(struct CompressionOptions, strategy), OptionType::kInt,
|
|
OptionVerificationType::kNormal, OptionTypeFlags::kMutable}},
|
|
{"max_dict_bytes",
|
|
{offsetof(struct CompressionOptions, max_dict_bytes), OptionType::kInt,
|
|
OptionVerificationType::kNormal, OptionTypeFlags::kMutable}},
|
|
{"zstd_max_train_bytes",
|
|
{offsetof(struct CompressionOptions, zstd_max_train_bytes),
|
|
OptionType::kUInt32T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"parallel_threads",
|
|
{offsetof(struct CompressionOptions, parallel_threads),
|
|
OptionType::kUInt32T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"enabled",
|
|
{offsetof(struct CompressionOptions, enabled), OptionType::kBoolean,
|
|
OptionVerificationType::kNormal, OptionTypeFlags::kMutable}},
|
|
{"max_dict_buffer_bytes",
|
|
{offsetof(struct CompressionOptions, max_dict_buffer_bytes),
|
|
OptionType::kUInt64T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"use_zstd_dict_trainer",
|
|
{offsetof(struct CompressionOptions, use_zstd_dict_trainer),
|
|
OptionType::kBoolean, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
};
|
|
|
|
static std::unordered_map<std::string, OptionTypeInfo>
|
|
fifo_compaction_options_type_info = {
|
|
{"max_table_files_size",
|
|
{offsetof(struct CompactionOptionsFIFO, max_table_files_size),
|
|
OptionType::kUInt64T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"age_for_warm",
|
|
{offsetof(struct CompactionOptionsFIFO, age_for_warm),
|
|
OptionType::kUInt64T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"ttl",
|
|
{0, OptionType::kUInt64T, OptionVerificationType::kDeprecated,
|
|
OptionTypeFlags::kNone}},
|
|
{"allow_compaction",
|
|
{offsetof(struct CompactionOptionsFIFO, allow_compaction),
|
|
OptionType::kBoolean, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
};
|
|
|
|
static std::unordered_map<std::string, OptionTypeInfo>
|
|
universal_compaction_options_type_info = {
|
|
{"size_ratio",
|
|
{offsetof(class CompactionOptionsUniversal, size_ratio),
|
|
OptionType::kUInt, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"min_merge_width",
|
|
{offsetof(class CompactionOptionsUniversal, min_merge_width),
|
|
OptionType::kUInt, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"max_merge_width",
|
|
{offsetof(class CompactionOptionsUniversal, max_merge_width),
|
|
OptionType::kUInt, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"max_size_amplification_percent",
|
|
{offsetof(class CompactionOptionsUniversal,
|
|
max_size_amplification_percent),
|
|
OptionType::kUInt, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"compression_size_percent",
|
|
{offsetof(class CompactionOptionsUniversal, compression_size_percent),
|
|
OptionType::kInt, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"stop_style",
|
|
{offsetof(class CompactionOptionsUniversal, stop_style),
|
|
OptionType::kCompactionStopStyle, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"incremental",
|
|
{offsetof(class CompactionOptionsUniversal, incremental),
|
|
OptionType::kBoolean, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"allow_trivial_move",
|
|
{offsetof(class CompactionOptionsUniversal, allow_trivial_move),
|
|
OptionType::kBoolean, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}}};
|
|
|
|
static std::unordered_map<std::string, OptionTypeInfo>
|
|
cf_mutable_options_type_info = {
|
|
{"report_bg_io_stats",
|
|
{offsetof(struct MutableCFOptions, report_bg_io_stats),
|
|
OptionType::kBoolean, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"disable_auto_compactions",
|
|
{offsetof(struct MutableCFOptions, disable_auto_compactions),
|
|
OptionType::kBoolean, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"filter_deletes",
|
|
{0, OptionType::kBoolean, OptionVerificationType::kDeprecated,
|
|
OptionTypeFlags::kMutable}},
|
|
{"check_flush_compaction_key_order",
|
|
{offsetof(struct MutableCFOptions, check_flush_compaction_key_order),
|
|
OptionType::kBoolean, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"paranoid_file_checks",
|
|
{offsetof(struct MutableCFOptions, paranoid_file_checks),
|
|
OptionType::kBoolean, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"verify_checksums_in_compaction",
|
|
{0, OptionType::kBoolean, OptionVerificationType::kDeprecated,
|
|
OptionTypeFlags::kMutable}},
|
|
{"soft_pending_compaction_bytes_limit",
|
|
{offsetof(struct MutableCFOptions,
|
|
soft_pending_compaction_bytes_limit),
|
|
OptionType::kUInt64T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"hard_pending_compaction_bytes_limit",
|
|
{offsetof(struct MutableCFOptions,
|
|
hard_pending_compaction_bytes_limit),
|
|
OptionType::kUInt64T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"hard_rate_limit",
|
|
{0, OptionType::kDouble, OptionVerificationType::kDeprecated,
|
|
OptionTypeFlags::kMutable}},
|
|
{"soft_rate_limit",
|
|
{0, OptionType::kDouble, OptionVerificationType::kDeprecated,
|
|
OptionTypeFlags::kMutable}},
|
|
{"max_compaction_bytes",
|
|
{offsetof(struct MutableCFOptions, max_compaction_bytes),
|
|
OptionType::kUInt64T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"ignore_max_compaction_bytes_for_input",
|
|
{offsetof(struct MutableCFOptions,
|
|
ignore_max_compaction_bytes_for_input),
|
|
OptionType::kBoolean, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"expanded_compaction_factor",
|
|
{0, OptionType::kInt, OptionVerificationType::kDeprecated,
|
|
OptionTypeFlags::kMutable}},
|
|
{"level0_file_num_compaction_trigger",
|
|
{offsetof(struct MutableCFOptions, level0_file_num_compaction_trigger),
|
|
OptionType::kInt, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"level0_slowdown_writes_trigger",
|
|
{offsetof(struct MutableCFOptions, level0_slowdown_writes_trigger),
|
|
OptionType::kInt, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"level0_stop_writes_trigger",
|
|
{offsetof(struct MutableCFOptions, level0_stop_writes_trigger),
|
|
OptionType::kInt, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"max_grandparent_overlap_factor",
|
|
{0, OptionType::kInt, OptionVerificationType::kDeprecated,
|
|
OptionTypeFlags::kMutable}},
|
|
{"max_write_buffer_number",
|
|
{offsetof(struct MutableCFOptions, max_write_buffer_number),
|
|
OptionType::kInt, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"source_compaction_factor",
|
|
{0, OptionType::kInt, OptionVerificationType::kDeprecated,
|
|
OptionTypeFlags::kMutable}},
|
|
{"target_file_size_multiplier",
|
|
{offsetof(struct MutableCFOptions, target_file_size_multiplier),
|
|
OptionType::kInt, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"arena_block_size",
|
|
{offsetof(struct MutableCFOptions, arena_block_size),
|
|
OptionType::kSizeT, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"inplace_update_num_locks",
|
|
{offsetof(struct MutableCFOptions, inplace_update_num_locks),
|
|
OptionType::kSizeT, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"max_successive_merges",
|
|
{offsetof(struct MutableCFOptions, max_successive_merges),
|
|
OptionType::kSizeT, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"memtable_huge_page_size",
|
|
{offsetof(struct MutableCFOptions, memtable_huge_page_size),
|
|
OptionType::kSizeT, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"memtable_prefix_bloom_huge_page_tlb_size",
|
|
{0, OptionType::kSizeT, OptionVerificationType::kDeprecated,
|
|
OptionTypeFlags::kMutable}},
|
|
{"write_buffer_size",
|
|
{offsetof(struct MutableCFOptions, write_buffer_size),
|
|
OptionType::kSizeT, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"memtable_prefix_bloom_bits",
|
|
{0, OptionType::kUInt32T, OptionVerificationType::kDeprecated,
|
|
OptionTypeFlags::kMutable}},
|
|
{"memtable_prefix_bloom_size_ratio",
|
|
{offsetof(struct MutableCFOptions, memtable_prefix_bloom_size_ratio),
|
|
OptionType::kDouble, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"memtable_prefix_bloom_probes",
|
|
{0, OptionType::kUInt32T, OptionVerificationType::kDeprecated,
|
|
OptionTypeFlags::kMutable}},
|
|
{"memtable_whole_key_filtering",
|
|
{offsetof(struct MutableCFOptions, memtable_whole_key_filtering),
|
|
OptionType::kBoolean, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"min_partial_merge_operands",
|
|
{0, OptionType::kUInt32T, OptionVerificationType::kDeprecated,
|
|
OptionTypeFlags::kMutable}},
|
|
{"max_bytes_for_level_base",
|
|
{offsetof(struct MutableCFOptions, max_bytes_for_level_base),
|
|
OptionType::kUInt64T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"snap_refresh_nanos",
|
|
{0, OptionType::kUInt64T, OptionVerificationType::kDeprecated,
|
|
OptionTypeFlags::kMutable}},
|
|
{"max_bytes_for_level_multiplier",
|
|
{offsetof(struct MutableCFOptions, max_bytes_for_level_multiplier),
|
|
OptionType::kDouble, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"max_bytes_for_level_multiplier_additional",
|
|
OptionTypeInfo::Vector<int>(
|
|
offsetof(struct MutableCFOptions,
|
|
max_bytes_for_level_multiplier_additional),
|
|
OptionVerificationType::kNormal, OptionTypeFlags::kMutable,
|
|
{0, OptionType::kInt})},
|
|
{"max_sequential_skip_in_iterations",
|
|
{offsetof(struct MutableCFOptions, max_sequential_skip_in_iterations),
|
|
OptionType::kUInt64T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"target_file_size_base",
|
|
{offsetof(struct MutableCFOptions, target_file_size_base),
|
|
OptionType::kUInt64T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"compression",
|
|
{offsetof(struct MutableCFOptions, compression),
|
|
OptionType::kCompressionType, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"prefix_extractor",
|
|
OptionTypeInfo::AsCustomSharedPtr<const SliceTransform>(
|
|
offsetof(struct MutableCFOptions, prefix_extractor),
|
|
OptionVerificationType::kByNameAllowNull,
|
|
(OptionTypeFlags::kMutable | OptionTypeFlags::kAllowNull))},
|
|
{"compaction_options_fifo",
|
|
OptionTypeInfo::Struct(
|
|
"compaction_options_fifo", &fifo_compaction_options_type_info,
|
|
offsetof(struct MutableCFOptions, compaction_options_fifo),
|
|
OptionVerificationType::kNormal, OptionTypeFlags::kMutable)
|
|
.SetParseFunc([](const ConfigOptions& opts,
|
|
const std::string& name, const std::string& value,
|
|
void* addr) {
|
|
// This is to handle backward compatibility, where
|
|
// compaction_options_fifo could be assigned a single scalar
|
|
// value, say, like "23", which would be assigned to
|
|
// max_table_files_size.
|
|
if (name == "compaction_options_fifo" &&
|
|
value.find("=") == std::string::npos) {
|
|
// Old format. Parse just a single uint64_t value.
|
|
auto options = static_cast<CompactionOptionsFIFO*>(addr);
|
|
options->max_table_files_size = ParseUint64(value);
|
|
return Status::OK();
|
|
} else {
|
|
return OptionTypeInfo::ParseStruct(
|
|
opts, "compaction_options_fifo",
|
|
&fifo_compaction_options_type_info, name, value, addr);
|
|
}
|
|
})},
|
|
{"compaction_options_universal",
|
|
OptionTypeInfo::Struct(
|
|
"compaction_options_universal",
|
|
&universal_compaction_options_type_info,
|
|
offsetof(struct MutableCFOptions, compaction_options_universal),
|
|
OptionVerificationType::kNormal, OptionTypeFlags::kMutable)},
|
|
{"ttl",
|
|
{offsetof(struct MutableCFOptions, ttl), OptionType::kUInt64T,
|
|
OptionVerificationType::kNormal, OptionTypeFlags::kMutable}},
|
|
{"periodic_compaction_seconds",
|
|
{offsetof(struct MutableCFOptions, periodic_compaction_seconds),
|
|
OptionType::kUInt64T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"bottommost_temperature",
|
|
{0, OptionType::kTemperature, OptionVerificationType::kDeprecated,
|
|
OptionTypeFlags::kMutable}},
|
|
{"last_level_temperature",
|
|
{offsetof(struct MutableCFOptions, last_level_temperature),
|
|
OptionType::kTemperature, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"enable_blob_files",
|
|
{offsetof(struct MutableCFOptions, enable_blob_files),
|
|
OptionType::kBoolean, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"min_blob_size",
|
|
{offsetof(struct MutableCFOptions, min_blob_size),
|
|
OptionType::kUInt64T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"blob_file_size",
|
|
{offsetof(struct MutableCFOptions, blob_file_size),
|
|
OptionType::kUInt64T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"blob_compression_type",
|
|
{offsetof(struct MutableCFOptions, blob_compression_type),
|
|
OptionType::kCompressionType, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"enable_blob_garbage_collection",
|
|
{offsetof(struct MutableCFOptions, enable_blob_garbage_collection),
|
|
OptionType::kBoolean, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"blob_garbage_collection_age_cutoff",
|
|
{offsetof(struct MutableCFOptions, blob_garbage_collection_age_cutoff),
|
|
OptionType::kDouble, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"blob_garbage_collection_force_threshold",
|
|
{offsetof(struct MutableCFOptions,
|
|
blob_garbage_collection_force_threshold),
|
|
OptionType::kDouble, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"blob_compaction_readahead_size",
|
|
{offsetof(struct MutableCFOptions, blob_compaction_readahead_size),
|
|
OptionType::kUInt64T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"blob_file_starting_level",
|
|
{offsetof(struct MutableCFOptions, blob_file_starting_level),
|
|
OptionType::kInt, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"prepopulate_blob_cache",
|
|
OptionTypeInfo::Enum<PrepopulateBlobCache>(
|
|
offsetof(struct MutableCFOptions, prepopulate_blob_cache),
|
|
&prepopulate_blob_cache_string_map, OptionTypeFlags::kMutable)},
|
|
{"sample_for_compression",
|
|
{offsetof(struct MutableCFOptions, sample_for_compression),
|
|
OptionType::kUInt64T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"bottommost_compression",
|
|
{offsetof(struct MutableCFOptions, bottommost_compression),
|
|
OptionType::kCompressionType, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"compression_per_level",
|
|
OptionTypeInfo::Vector<CompressionType>(
|
|
offsetof(struct MutableCFOptions, compression_per_level),
|
|
OptionVerificationType::kNormal, OptionTypeFlags::kMutable,
|
|
{0, OptionType::kCompressionType})},
|
|
{"experimental_mempurge_threshold",
|
|
{offsetof(struct MutableCFOptions, experimental_mempurge_threshold),
|
|
OptionType::kDouble, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"memtable_protection_bytes_per_key",
|
|
{offsetof(struct MutableCFOptions, memtable_protection_bytes_per_key),
|
|
OptionType::kUInt32T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{kOptNameCompOpts,
|
|
OptionTypeInfo::Struct(
|
|
kOptNameCompOpts, &compression_options_type_info,
|
|
offsetof(struct MutableCFOptions, compression_opts),
|
|
OptionVerificationType::kNormal,
|
|
(OptionTypeFlags::kMutable | OptionTypeFlags::kCompareNever),
|
|
[](const ConfigOptions& opts, const std::string& name,
|
|
const std::string& value, void* addr) {
|
|
// This is to handle backward compatibility, where
|
|
// compression_options was a ":" separated list.
|
|
if (name == kOptNameCompOpts &&
|
|
value.find("=") == std::string::npos) {
|
|
auto* compression = static_cast<CompressionOptions*>(addr);
|
|
return ParseCompressionOptions(value, name, *compression);
|
|
} else {
|
|
return OptionTypeInfo::ParseStruct(
|
|
opts, kOptNameCompOpts, &compression_options_type_info,
|
|
name, value, addr);
|
|
}
|
|
})},
|
|
{kOptNameBMCompOpts,
|
|
OptionTypeInfo::Struct(
|
|
kOptNameBMCompOpts, &compression_options_type_info,
|
|
offsetof(struct MutableCFOptions, bottommost_compression_opts),
|
|
OptionVerificationType::kNormal,
|
|
(OptionTypeFlags::kMutable | OptionTypeFlags::kCompareNever),
|
|
[](const ConfigOptions& opts, const std::string& name,
|
|
const std::string& value, void* addr) {
|
|
// This is to handle backward compatibility, where
|
|
// compression_options was a ":" separated list.
|
|
if (name == kOptNameBMCompOpts &&
|
|
value.find("=") == std::string::npos) {
|
|
auto* compression = static_cast<CompressionOptions*>(addr);
|
|
return ParseCompressionOptions(value, name, *compression);
|
|
} else {
|
|
return OptionTypeInfo::ParseStruct(
|
|
opts, kOptNameBMCompOpts, &compression_options_type_info,
|
|
name, value, addr);
|
|
}
|
|
})},
|
|
// End special case properties
|
|
};
|
|
|
|
static std::unordered_map<std::string, OptionTypeInfo>
|
|
cf_immutable_options_type_info = {
|
|
/* not yet supported
|
|
CompressionOptions compression_opts;
|
|
TablePropertiesCollectorFactories table_properties_collector_factories;
|
|
using TablePropertiesCollectorFactories =
|
|
std::vector<std::shared_ptr<TablePropertiesCollectorFactory>>;
|
|
UpdateStatus (*inplace_callback)(char* existing_value,
|
|
uint34_t* existing_value_size,
|
|
Slice delta_value,
|
|
std::string* merged_value);
|
|
std::vector<DbPath> cf_paths;
|
|
*/
|
|
{"compaction_measure_io_stats",
|
|
{0, OptionType::kBoolean, OptionVerificationType::kDeprecated,
|
|
OptionTypeFlags::kNone}},
|
|
{"purge_redundant_kvs_while_flush",
|
|
{0, OptionType::kBoolean, OptionVerificationType::kDeprecated,
|
|
OptionTypeFlags::kNone}},
|
|
{"inplace_update_support",
|
|
{offsetof(struct ImmutableCFOptions, inplace_update_support),
|
|
OptionType::kBoolean, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kNone}},
|
|
{"level_compaction_dynamic_level_bytes",
|
|
{offsetof(struct ImmutableCFOptions,
|
|
level_compaction_dynamic_level_bytes),
|
|
OptionType::kBoolean, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kNone}},
|
|
{"level_compaction_dynamic_file_size",
|
|
{offsetof(struct ImmutableCFOptions,
|
|
level_compaction_dynamic_file_size),
|
|
OptionType::kBoolean, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kNone}},
|
|
{"optimize_filters_for_hits",
|
|
{offsetof(struct ImmutableCFOptions, optimize_filters_for_hits),
|
|
OptionType::kBoolean, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kNone}},
|
|
{"force_consistency_checks",
|
|
{offsetof(struct ImmutableCFOptions, force_consistency_checks),
|
|
OptionType::kBoolean, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kNone}},
|
|
{"preclude_last_level_data_seconds",
|
|
{offsetof(struct ImmutableCFOptions, preclude_last_level_data_seconds),
|
|
OptionType::kUInt64T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kNone}},
|
|
{"preserve_internal_time_seconds",
|
|
{offsetof(struct ImmutableCFOptions, preserve_internal_time_seconds),
|
|
OptionType::kUInt64T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kNone}},
|
|
// Need to keep this around to be able to read old OPTIONS files.
|
|
{"max_mem_compaction_level",
|
|
{0, OptionType::kInt, OptionVerificationType::kDeprecated,
|
|
OptionTypeFlags::kNone}},
|
|
{"max_write_buffer_number_to_maintain",
|
|
{offsetof(struct ImmutableCFOptions,
|
|
max_write_buffer_number_to_maintain),
|
|
OptionType::kInt, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kNone, 0}},
|
|
{"max_write_buffer_size_to_maintain",
|
|
{offsetof(struct ImmutableCFOptions,
|
|
max_write_buffer_size_to_maintain),
|
|
OptionType::kInt64T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kNone}},
|
|
{"min_write_buffer_number_to_merge",
|
|
{offsetof(struct ImmutableCFOptions, min_write_buffer_number_to_merge),
|
|
OptionType::kInt, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kNone, 0}},
|
|
{"num_levels",
|
|
{offsetof(struct ImmutableCFOptions, num_levels), OptionType::kInt,
|
|
OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
|
|
{"bloom_locality",
|
|
{offsetof(struct ImmutableCFOptions, bloom_locality),
|
|
OptionType::kUInt32T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kNone}},
|
|
{"rate_limit_delay_max_milliseconds",
|
|
{0, OptionType::kUInt, OptionVerificationType::kDeprecated,
|
|
OptionTypeFlags::kNone}},
|
|
{"comparator",
|
|
OptionTypeInfo::AsCustomRawPtr<const Comparator>(
|
|
offsetof(struct ImmutableCFOptions, user_comparator),
|
|
OptionVerificationType::kByName, OptionTypeFlags::kCompareLoose)
|
|
.SetSerializeFunc(
|
|
// Serializes a Comparator
|
|
[](const ConfigOptions& opts, const std::string&,
|
|
const void* addr, std::string* value) {
|
|
// it's a const pointer of const Comparator*
|
|
const auto* ptr =
|
|
static_cast<const Comparator* const*>(addr);
|
|
// Since the user-specified comparator will be wrapped by
|
|
// InternalKeyComparator, we should persist the
|
|
// user-specified one instead of InternalKeyComparator.
|
|
if (*ptr == nullptr) {
|
|
*value = kNullptrString;
|
|
} else if (opts.mutable_options_only) {
|
|
*value = "";
|
|
} else {
|
|
const Comparator* root_comp = (*ptr)->GetRootComparator();
|
|
if (root_comp == nullptr) {
|
|
root_comp = (*ptr);
|
|
}
|
|
*value = root_comp->ToString(opts);
|
|
}
|
|
return Status::OK();
|
|
})},
|
|
{"memtable_insert_with_hint_prefix_extractor",
|
|
OptionTypeInfo::AsCustomSharedPtr<const SliceTransform>(
|
|
offsetof(struct ImmutableCFOptions,
|
|
memtable_insert_with_hint_prefix_extractor),
|
|
OptionVerificationType::kByNameAllowNull, OptionTypeFlags::kNone)},
|
|
{"memtable_factory",
|
|
{offsetof(struct ImmutableCFOptions, memtable_factory),
|
|
OptionType::kCustomizable, OptionVerificationType::kByName,
|
|
OptionTypeFlags::kShared,
|
|
[](const ConfigOptions& opts, const std::string&,
|
|
const std::string& value, void* addr) {
|
|
std::unique_ptr<MemTableRepFactory> factory;
|
|
auto* shared =
|
|
static_cast<std::shared_ptr<MemTableRepFactory>*>(addr);
|
|
Status s =
|
|
MemTableRepFactory::CreateFromString(opts, value, shared);
|
|
return s;
|
|
}}},
|
|
{"memtable",
|
|
{offsetof(struct ImmutableCFOptions, memtable_factory),
|
|
OptionType::kCustomizable, OptionVerificationType::kAlias,
|
|
OptionTypeFlags::kShared,
|
|
[](const ConfigOptions& opts, const std::string&,
|
|
const std::string& value, void* addr) {
|
|
std::unique_ptr<MemTableRepFactory> factory;
|
|
auto* shared =
|
|
static_cast<std::shared_ptr<MemTableRepFactory>*>(addr);
|
|
Status s =
|
|
MemTableRepFactory::CreateFromString(opts, value, shared);
|
|
return s;
|
|
}}},
|
|
{"table_factory",
|
|
OptionTypeInfo::AsCustomSharedPtr<TableFactory>(
|
|
offsetof(struct ImmutableCFOptions, table_factory),
|
|
OptionVerificationType::kByName,
|
|
(OptionTypeFlags::kCompareLoose |
|
|
OptionTypeFlags::kStringNameOnly |
|
|
OptionTypeFlags::kDontPrepare))},
|
|
{"block_based_table_factory",
|
|
{offsetof(struct ImmutableCFOptions, table_factory),
|
|
OptionType::kCustomizable, OptionVerificationType::kAlias,
|
|
OptionTypeFlags::kShared | OptionTypeFlags::kCompareLoose,
|
|
// Parses the input value and creates a BlockBasedTableFactory
|
|
[](const ConfigOptions& opts, const std::string& name,
|
|
const std::string& value, void* addr) {
|
|
BlockBasedTableOptions* old_opts = nullptr;
|
|
auto table_factory =
|
|
static_cast<std::shared_ptr<TableFactory>*>(addr);
|
|
if (table_factory->get() != nullptr) {
|
|
old_opts =
|
|
table_factory->get()->GetOptions<BlockBasedTableOptions>();
|
|
}
|
|
if (name == "block_based_table_factory") {
|
|
std::unique_ptr<TableFactory> new_factory;
|
|
if (old_opts != nullptr) {
|
|
new_factory.reset(NewBlockBasedTableFactory(*old_opts));
|
|
} else {
|
|
new_factory.reset(NewBlockBasedTableFactory());
|
|
}
|
|
Status s = new_factory->ConfigureFromString(opts, value);
|
|
if (s.ok()) {
|
|
table_factory->reset(new_factory.release());
|
|
}
|
|
return s;
|
|
} else if (old_opts != nullptr) {
|
|
return table_factory->get()->ConfigureOption(opts, name, value);
|
|
} else {
|
|
return Status::NotFound("Mismatched table option: ", name);
|
|
}
|
|
}}},
|
|
{"plain_table_factory",
|
|
{offsetof(struct ImmutableCFOptions, table_factory),
|
|
OptionType::kCustomizable, OptionVerificationType::kAlias,
|
|
OptionTypeFlags::kShared | OptionTypeFlags::kCompareLoose,
|
|
// Parses the input value and creates a PlainTableFactory
|
|
[](const ConfigOptions& opts, const std::string& name,
|
|
const std::string& value, void* addr) {
|
|
PlainTableOptions* old_opts = nullptr;
|
|
auto table_factory =
|
|
static_cast<std::shared_ptr<TableFactory>*>(addr);
|
|
if (table_factory->get() != nullptr) {
|
|
old_opts = table_factory->get()->GetOptions<PlainTableOptions>();
|
|
}
|
|
if (name == "plain_table_factory") {
|
|
std::unique_ptr<TableFactory> new_factory;
|
|
if (old_opts != nullptr) {
|
|
new_factory.reset(NewPlainTableFactory(*old_opts));
|
|
} else {
|
|
new_factory.reset(NewPlainTableFactory());
|
|
}
|
|
Status s = new_factory->ConfigureFromString(opts, value);
|
|
if (s.ok()) {
|
|
table_factory->reset(new_factory.release());
|
|
}
|
|
return s;
|
|
} else if (old_opts != nullptr) {
|
|
return table_factory->get()->ConfigureOption(opts, name, value);
|
|
} else {
|
|
return Status::NotFound("Mismatched table option: ", name);
|
|
}
|
|
}}},
|
|
{"table_properties_collectors",
|
|
OptionTypeInfo::Vector<
|
|
std::shared_ptr<TablePropertiesCollectorFactory>>(
|
|
offsetof(struct ImmutableCFOptions,
|
|
table_properties_collector_factories),
|
|
OptionVerificationType::kByName, OptionTypeFlags::kNone,
|
|
OptionTypeInfo::AsCustomSharedPtr<TablePropertiesCollectorFactory>(
|
|
0, OptionVerificationType::kByName, OptionTypeFlags::kNone))},
|
|
{"compaction_filter",
|
|
OptionTypeInfo::AsCustomRawPtr<const CompactionFilter>(
|
|
offsetof(struct ImmutableCFOptions, compaction_filter),
|
|
OptionVerificationType::kByName, OptionTypeFlags::kAllowNull)},
|
|
{"compaction_filter_factory",
|
|
OptionTypeInfo::AsCustomSharedPtr<CompactionFilterFactory>(
|
|
offsetof(struct ImmutableCFOptions, compaction_filter_factory),
|
|
OptionVerificationType::kByName, OptionTypeFlags::kAllowNull)},
|
|
{"merge_operator",
|
|
OptionTypeInfo::AsCustomSharedPtr<MergeOperator>(
|
|
offsetof(struct ImmutableCFOptions, merge_operator),
|
|
OptionVerificationType::kByNameAllowFromNull,
|
|
OptionTypeFlags::kCompareLoose | OptionTypeFlags::kAllowNull)},
|
|
{"compaction_style",
|
|
{offsetof(struct ImmutableCFOptions, compaction_style),
|
|
OptionType::kCompactionStyle, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kNone}},
|
|
{"compaction_pri",
|
|
{offsetof(struct ImmutableCFOptions, compaction_pri),
|
|
OptionType::kCompactionPri, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kNone}},
|
|
{"sst_partitioner_factory",
|
|
OptionTypeInfo::AsCustomSharedPtr<SstPartitionerFactory>(
|
|
offsetof(struct ImmutableCFOptions, sst_partitioner_factory),
|
|
OptionVerificationType::kByName, OptionTypeFlags::kAllowNull)},
|
|
{"blob_cache",
|
|
{offsetof(struct ImmutableCFOptions, blob_cache), OptionType::kUnknown,
|
|
OptionVerificationType::kNormal,
|
|
(OptionTypeFlags::kCompareNever | OptionTypeFlags::kDontSerialize),
|
|
// Parses the input value as a Cache
|
|
[](const ConfigOptions& opts, const std::string&,
|
|
const std::string& value, void* addr) {
|
|
auto* cache = static_cast<std::shared_ptr<Cache>*>(addr);
|
|
return Cache::CreateFromString(opts, value, cache);
|
|
}}},
|
|
};
|
|
|
|
const std::string OptionsHelper::kCFOptionsName = "ColumnFamilyOptions";
|
|
|
|
class ConfigurableMutableCFOptions : public Configurable {
|
|
public:
|
|
explicit ConfigurableMutableCFOptions(const MutableCFOptions& mcf) {
|
|
mutable_ = mcf;
|
|
RegisterOptions(&mutable_, &cf_mutable_options_type_info);
|
|
}
|
|
|
|
protected:
|
|
MutableCFOptions mutable_;
|
|
};
|
|
|
|
class ConfigurableCFOptions : public ConfigurableMutableCFOptions {
|
|
public:
|
|
ConfigurableCFOptions(const ColumnFamilyOptions& opts,
|
|
const std::unordered_map<std::string, std::string>* map)
|
|
: ConfigurableMutableCFOptions(MutableCFOptions(opts)),
|
|
immutable_(opts),
|
|
cf_options_(opts),
|
|
opt_map_(map) {
|
|
RegisterOptions(&immutable_, &cf_immutable_options_type_info);
|
|
}
|
|
|
|
protected:
|
|
Status ConfigureOptions(
|
|
const ConfigOptions& config_options,
|
|
const std::unordered_map<std::string, std::string>& opts_map,
|
|
std::unordered_map<std::string, std::string>* unused) override {
|
|
Status s = Configurable::ConfigureOptions(config_options, opts_map, unused);
|
|
if (s.ok()) {
|
|
UpdateColumnFamilyOptions(mutable_, &cf_options_);
|
|
UpdateColumnFamilyOptions(immutable_, &cf_options_);
|
|
s = PrepareOptions(config_options);
|
|
}
|
|
return s;
|
|
}
|
|
|
|
virtual const void* GetOptionsPtr(const std::string& name) const override {
|
|
if (name == OptionsHelper::kCFOptionsName) {
|
|
return &cf_options_;
|
|
} else {
|
|
return ConfigurableMutableCFOptions::GetOptionsPtr(name);
|
|
}
|
|
}
|
|
|
|
bool OptionsAreEqual(const ConfigOptions& config_options,
|
|
const OptionTypeInfo& opt_info,
|
|
const std::string& opt_name, const void* const this_ptr,
|
|
const void* const that_ptr,
|
|
std::string* mismatch) const override {
|
|
bool equals = opt_info.AreEqual(config_options, opt_name, this_ptr,
|
|
that_ptr, mismatch);
|
|
if (!equals && opt_info.IsByName()) {
|
|
if (opt_map_ == nullptr) {
|
|
equals = true;
|
|
} else {
|
|
const auto& iter = opt_map_->find(opt_name);
|
|
if (iter == opt_map_->end()) {
|
|
equals = true;
|
|
} else {
|
|
equals = opt_info.AreEqualByName(config_options, opt_name, this_ptr,
|
|
iter->second);
|
|
}
|
|
}
|
|
if (equals) { // False alarm, clear mismatch
|
|
*mismatch = "";
|
|
}
|
|
}
|
|
if (equals && opt_info.IsConfigurable() && opt_map_ != nullptr) {
|
|
const auto* this_config = opt_info.AsRawPointer<Configurable>(this_ptr);
|
|
if (this_config == nullptr) {
|
|
const auto& iter = opt_map_->find(opt_name);
|
|
// If the name exists in the map and is not empty/null,
|
|
// then the this_config should be set.
|
|
if (iter != opt_map_->end() && !iter->second.empty() &&
|
|
iter->second != kNullptrString) {
|
|
*mismatch = opt_name;
|
|
equals = false;
|
|
}
|
|
}
|
|
}
|
|
return equals;
|
|
}
|
|
|
|
private:
|
|
ImmutableCFOptions immutable_;
|
|
ColumnFamilyOptions cf_options_;
|
|
const std::unordered_map<std::string, std::string>* opt_map_;
|
|
};
|
|
|
|
std::unique_ptr<Configurable> CFOptionsAsConfigurable(
|
|
const MutableCFOptions& opts) {
|
|
std::unique_ptr<Configurable> ptr(new ConfigurableMutableCFOptions(opts));
|
|
return ptr;
|
|
}
|
|
std::unique_ptr<Configurable> CFOptionsAsConfigurable(
|
|
const ColumnFamilyOptions& opts,
|
|
const std::unordered_map<std::string, std::string>* opt_map) {
|
|
std::unique_ptr<Configurable> ptr(new ConfigurableCFOptions(opts, opt_map));
|
|
return ptr;
|
|
}
|
|
#endif // ROCKSDB_LITE
|
|
|
|
ImmutableCFOptions::ImmutableCFOptions() : ImmutableCFOptions(Options()) {}
|
|
|
|
ImmutableCFOptions::ImmutableCFOptions(const ColumnFamilyOptions& cf_options)
|
|
: compaction_style(cf_options.compaction_style),
|
|
compaction_pri(cf_options.compaction_pri),
|
|
user_comparator(cf_options.comparator),
|
|
internal_comparator(InternalKeyComparator(cf_options.comparator)),
|
|
merge_operator(cf_options.merge_operator),
|
|
compaction_filter(cf_options.compaction_filter),
|
|
compaction_filter_factory(cf_options.compaction_filter_factory),
|
|
min_write_buffer_number_to_merge(
|
|
cf_options.min_write_buffer_number_to_merge),
|
|
max_write_buffer_number_to_maintain(
|
|
cf_options.max_write_buffer_number_to_maintain),
|
|
max_write_buffer_size_to_maintain(
|
|
cf_options.max_write_buffer_size_to_maintain),
|
|
inplace_update_support(cf_options.inplace_update_support),
|
|
inplace_callback(cf_options.inplace_callback),
|
|
memtable_factory(cf_options.memtable_factory),
|
|
table_factory(cf_options.table_factory),
|
|
table_properties_collector_factories(
|
|
cf_options.table_properties_collector_factories),
|
|
bloom_locality(cf_options.bloom_locality),
|
|
level_compaction_dynamic_level_bytes(
|
|
cf_options.level_compaction_dynamic_level_bytes),
|
|
level_compaction_dynamic_file_size(
|
|
cf_options.level_compaction_dynamic_file_size),
|
|
num_levels(cf_options.num_levels),
|
|
optimize_filters_for_hits(cf_options.optimize_filters_for_hits),
|
|
force_consistency_checks(cf_options.force_consistency_checks),
|
|
preclude_last_level_data_seconds(
|
|
cf_options.preclude_last_level_data_seconds),
|
|
preserve_internal_time_seconds(cf_options.preserve_internal_time_seconds),
|
|
memtable_insert_with_hint_prefix_extractor(
|
|
cf_options.memtable_insert_with_hint_prefix_extractor),
|
|
cf_paths(cf_options.cf_paths),
|
|
compaction_thread_limiter(cf_options.compaction_thread_limiter),
|
|
sst_partitioner_factory(cf_options.sst_partitioner_factory),
|
|
blob_cache(cf_options.blob_cache) {}
|
|
|
|
ImmutableOptions::ImmutableOptions() : ImmutableOptions(Options()) {}
|
|
|
|
ImmutableOptions::ImmutableOptions(const Options& options)
|
|
: ImmutableOptions(options, options) {}
|
|
|
|
ImmutableOptions::ImmutableOptions(const DBOptions& db_options,
|
|
const ColumnFamilyOptions& cf_options)
|
|
: ImmutableDBOptions(db_options), ImmutableCFOptions(cf_options) {}
|
|
|
|
ImmutableOptions::ImmutableOptions(const DBOptions& db_options,
|
|
const ImmutableCFOptions& cf_options)
|
|
: ImmutableDBOptions(db_options), ImmutableCFOptions(cf_options) {}
|
|
|
|
ImmutableOptions::ImmutableOptions(const ImmutableDBOptions& db_options,
|
|
const ColumnFamilyOptions& cf_options)
|
|
: ImmutableDBOptions(db_options), ImmutableCFOptions(cf_options) {}
|
|
|
|
ImmutableOptions::ImmutableOptions(const ImmutableDBOptions& db_options,
|
|
const ImmutableCFOptions& cf_options)
|
|
: ImmutableDBOptions(db_options), ImmutableCFOptions(cf_options) {}
|
|
|
|
// Multiple two operands. If they overflow, return op1.
|
|
uint64_t MultiplyCheckOverflow(uint64_t op1, double op2) {
|
|
if (op1 == 0 || op2 <= 0) {
|
|
return 0;
|
|
}
|
|
if (std::numeric_limits<uint64_t>::max() / op1 < op2) {
|
|
return op1;
|
|
}
|
|
return static_cast<uint64_t>(op1 * op2);
|
|
}
|
|
|
|
// when level_compaction_dynamic_level_bytes is true and leveled compaction
|
|
// is used, the base level is not always L1, so precomupted max_file_size can
|
|
// no longer be used. Recompute file_size_for_level from base level.
|
|
uint64_t MaxFileSizeForLevel(const MutableCFOptions& cf_options,
|
|
int level, CompactionStyle compaction_style, int base_level,
|
|
bool level_compaction_dynamic_level_bytes) {
|
|
if (!level_compaction_dynamic_level_bytes || level < base_level ||
|
|
compaction_style != kCompactionStyleLevel) {
|
|
assert(level >= 0);
|
|
assert(level < (int)cf_options.max_file_size.size());
|
|
return cf_options.max_file_size[level];
|
|
} else {
|
|
assert(level >= 0 && base_level >= 0);
|
|
assert(level - base_level < (int)cf_options.max_file_size.size());
|
|
return cf_options.max_file_size[level - base_level];
|
|
}
|
|
}
|
|
|
|
size_t MaxFileSizeForL0MetaPin(const MutableCFOptions& cf_options) {
|
|
// We do not want to pin meta-blocks that almost certainly came from intra-L0
|
|
// or a former larger `write_buffer_size` value to avoid surprising users with
|
|
// pinned memory usage. We use a factor of 1.5 to account for overhead
|
|
// introduced during flush in most cases.
|
|
if (std::numeric_limits<size_t>::max() / 3 <
|
|
cf_options.write_buffer_size / 2) {
|
|
return std::numeric_limits<size_t>::max();
|
|
}
|
|
return cf_options.write_buffer_size / 2 * 3;
|
|
}
|
|
|
|
void MutableCFOptions::RefreshDerivedOptions(int num_levels,
|
|
CompactionStyle compaction_style) {
|
|
max_file_size.resize(num_levels);
|
|
for (int i = 0; i < num_levels; ++i) {
|
|
if (i == 0 && compaction_style == kCompactionStyleUniversal) {
|
|
max_file_size[i] = ULLONG_MAX;
|
|
} else if (i > 1) {
|
|
max_file_size[i] = MultiplyCheckOverflow(max_file_size[i - 1],
|
|
target_file_size_multiplier);
|
|
} else {
|
|
max_file_size[i] = target_file_size_base;
|
|
}
|
|
}
|
|
}
|
|
|
|
void MutableCFOptions::Dump(Logger* log) const {
|
|
// Memtable related options
|
|
ROCKS_LOG_INFO(log,
|
|
" write_buffer_size: %" ROCKSDB_PRIszt,
|
|
write_buffer_size);
|
|
ROCKS_LOG_INFO(log, " max_write_buffer_number: %d",
|
|
max_write_buffer_number);
|
|
ROCKS_LOG_INFO(log,
|
|
" arena_block_size: %" ROCKSDB_PRIszt,
|
|
arena_block_size);
|
|
ROCKS_LOG_INFO(log, " memtable_prefix_bloom_ratio: %f",
|
|
memtable_prefix_bloom_size_ratio);
|
|
ROCKS_LOG_INFO(log, " memtable_whole_key_filtering: %d",
|
|
memtable_whole_key_filtering);
|
|
ROCKS_LOG_INFO(log,
|
|
" memtable_huge_page_size: %" ROCKSDB_PRIszt,
|
|
memtable_huge_page_size);
|
|
ROCKS_LOG_INFO(log,
|
|
" max_successive_merges: %" ROCKSDB_PRIszt,
|
|
max_successive_merges);
|
|
ROCKS_LOG_INFO(log,
|
|
" inplace_update_num_locks: %" ROCKSDB_PRIszt,
|
|
inplace_update_num_locks);
|
|
ROCKS_LOG_INFO(log, " prefix_extractor: %s",
|
|
prefix_extractor == nullptr
|
|
? "nullptr"
|
|
: prefix_extractor->GetId().c_str());
|
|
ROCKS_LOG_INFO(log, " disable_auto_compactions: %d",
|
|
disable_auto_compactions);
|
|
ROCKS_LOG_INFO(log, " soft_pending_compaction_bytes_limit: %" PRIu64,
|
|
soft_pending_compaction_bytes_limit);
|
|
ROCKS_LOG_INFO(log, " hard_pending_compaction_bytes_limit: %" PRIu64,
|
|
hard_pending_compaction_bytes_limit);
|
|
ROCKS_LOG_INFO(log, " level0_file_num_compaction_trigger: %d",
|
|
level0_file_num_compaction_trigger);
|
|
ROCKS_LOG_INFO(log, " level0_slowdown_writes_trigger: %d",
|
|
level0_slowdown_writes_trigger);
|
|
ROCKS_LOG_INFO(log, " level0_stop_writes_trigger: %d",
|
|
level0_stop_writes_trigger);
|
|
ROCKS_LOG_INFO(log, " max_compaction_bytes: %" PRIu64,
|
|
max_compaction_bytes);
|
|
ROCKS_LOG_INFO(log, " ignore_max_compaction_bytes_for_input: %s",
|
|
ignore_max_compaction_bytes_for_input ? "true" : "false");
|
|
ROCKS_LOG_INFO(log, " target_file_size_base: %" PRIu64,
|
|
target_file_size_base);
|
|
ROCKS_LOG_INFO(log, " target_file_size_multiplier: %d",
|
|
target_file_size_multiplier);
|
|
ROCKS_LOG_INFO(log, " max_bytes_for_level_base: %" PRIu64,
|
|
max_bytes_for_level_base);
|
|
ROCKS_LOG_INFO(log, " max_bytes_for_level_multiplier: %f",
|
|
max_bytes_for_level_multiplier);
|
|
ROCKS_LOG_INFO(log, " ttl: %" PRIu64,
|
|
ttl);
|
|
ROCKS_LOG_INFO(log, " periodic_compaction_seconds: %" PRIu64,
|
|
periodic_compaction_seconds);
|
|
std::string result;
|
|
char buf[10];
|
|
for (const auto m : max_bytes_for_level_multiplier_additional) {
|
|
snprintf(buf, sizeof(buf), "%d, ", m);
|
|
result += buf;
|
|
}
|
|
if (result.size() >= 2) {
|
|
result.resize(result.size() - 2);
|
|
} else {
|
|
result = "";
|
|
}
|
|
|
|
ROCKS_LOG_INFO(log, "max_bytes_for_level_multiplier_additional: %s",
|
|
result.c_str());
|
|
ROCKS_LOG_INFO(log, " max_sequential_skip_in_iterations: %" PRIu64,
|
|
max_sequential_skip_in_iterations);
|
|
ROCKS_LOG_INFO(log, " check_flush_compaction_key_order: %d",
|
|
check_flush_compaction_key_order);
|
|
ROCKS_LOG_INFO(log, " paranoid_file_checks: %d",
|
|
paranoid_file_checks);
|
|
ROCKS_LOG_INFO(log, " report_bg_io_stats: %d",
|
|
report_bg_io_stats);
|
|
ROCKS_LOG_INFO(log, " compression: %d",
|
|
static_cast<int>(compression));
|
|
ROCKS_LOG_INFO(log,
|
|
" experimental_mempurge_threshold: %f",
|
|
experimental_mempurge_threshold);
|
|
|
|
// Universal Compaction Options
|
|
ROCKS_LOG_INFO(log, "compaction_options_universal.size_ratio : %d",
|
|
compaction_options_universal.size_ratio);
|
|
ROCKS_LOG_INFO(log, "compaction_options_universal.min_merge_width : %d",
|
|
compaction_options_universal.min_merge_width);
|
|
ROCKS_LOG_INFO(log, "compaction_options_universal.max_merge_width : %d",
|
|
compaction_options_universal.max_merge_width);
|
|
ROCKS_LOG_INFO(
|
|
log, "compaction_options_universal.max_size_amplification_percent : %d",
|
|
compaction_options_universal.max_size_amplification_percent);
|
|
ROCKS_LOG_INFO(log,
|
|
"compaction_options_universal.compression_size_percent : %d",
|
|
compaction_options_universal.compression_size_percent);
|
|
ROCKS_LOG_INFO(log, "compaction_options_universal.stop_style : %d",
|
|
compaction_options_universal.stop_style);
|
|
ROCKS_LOG_INFO(
|
|
log, "compaction_options_universal.allow_trivial_move : %d",
|
|
static_cast<int>(compaction_options_universal.allow_trivial_move));
|
|
ROCKS_LOG_INFO(log, "compaction_options_universal.incremental : %d",
|
|
static_cast<int>(compaction_options_universal.incremental));
|
|
|
|
// FIFO Compaction Options
|
|
ROCKS_LOG_INFO(log, "compaction_options_fifo.max_table_files_size : %" PRIu64,
|
|
compaction_options_fifo.max_table_files_size);
|
|
ROCKS_LOG_INFO(log, "compaction_options_fifo.allow_compaction : %d",
|
|
compaction_options_fifo.allow_compaction);
|
|
|
|
// Blob file related options
|
|
ROCKS_LOG_INFO(log, " enable_blob_files: %s",
|
|
enable_blob_files ? "true" : "false");
|
|
ROCKS_LOG_INFO(log, " min_blob_size: %" PRIu64,
|
|
min_blob_size);
|
|
ROCKS_LOG_INFO(log, " blob_file_size: %" PRIu64,
|
|
blob_file_size);
|
|
ROCKS_LOG_INFO(log, " blob_compression_type: %s",
|
|
CompressionTypeToString(blob_compression_type).c_str());
|
|
ROCKS_LOG_INFO(log, " enable_blob_garbage_collection: %s",
|
|
enable_blob_garbage_collection ? "true" : "false");
|
|
ROCKS_LOG_INFO(log, " blob_garbage_collection_age_cutoff: %f",
|
|
blob_garbage_collection_age_cutoff);
|
|
ROCKS_LOG_INFO(log, " blob_garbage_collection_force_threshold: %f",
|
|
blob_garbage_collection_force_threshold);
|
|
ROCKS_LOG_INFO(log, " blob_compaction_readahead_size: %" PRIu64,
|
|
blob_compaction_readahead_size);
|
|
ROCKS_LOG_INFO(log, " blob_file_starting_level: %d",
|
|
blob_file_starting_level);
|
|
ROCKS_LOG_INFO(log, " prepopulate_blob_cache: %s",
|
|
prepopulate_blob_cache == PrepopulateBlobCache::kFlushOnly
|
|
? "flush only"
|
|
: "disable");
|
|
ROCKS_LOG_INFO(log, " last_level_temperature: %d",
|
|
static_cast<int>(last_level_temperature));
|
|
}
|
|
|
|
MutableCFOptions::MutableCFOptions(const Options& options)
|
|
: MutableCFOptions(ColumnFamilyOptions(options)) {}
|
|
|
|
#ifndef ROCKSDB_LITE
|
|
Status GetMutableOptionsFromStrings(
|
|
const MutableCFOptions& base_options,
|
|
const std::unordered_map<std::string, std::string>& options_map,
|
|
Logger* /*info_log*/, MutableCFOptions* new_options) {
|
|
assert(new_options);
|
|
*new_options = base_options;
|
|
ConfigOptions config_options;
|
|
Status s = OptionTypeInfo::ParseType(
|
|
config_options, options_map, cf_mutable_options_type_info, new_options);
|
|
if (!s.ok()) {
|
|
*new_options = base_options;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
Status GetStringFromMutableCFOptions(const ConfigOptions& config_options,
|
|
const MutableCFOptions& mutable_opts,
|
|
std::string* opt_string) {
|
|
assert(opt_string);
|
|
opt_string->clear();
|
|
return OptionTypeInfo::SerializeType(
|
|
config_options, cf_mutable_options_type_info, &mutable_opts, opt_string);
|
|
}
|
|
#endif // ROCKSDB_LITE
|
|
} // namespace ROCKSDB_NAMESPACE
|