mirror of
https://github.com/facebook/rocksdb.git
synced 2024-11-25 22:44:05 +00:00
defd97bc9d
Summary: add a new CF option `paranoid_memory_checks` that allows additional data integrity validations during read/scan. Currently, skiplist-based memtable will validate the order of keys visited. Further data validation can be added in different layers. The option will be opt-in due to performance overhead. The motivation for this feature is for services where data correctness is critical and want to detect in-memory corruption earlier. For a corrupted memtable key, this feature can help to detect it during during reads instead of during flush with existing protections (OutputValidator that verifies key order or per kv checksum). See internally linked task for more context. Pull Request resolved: https://github.com/facebook/rocksdb/pull/12889 Test Plan: * new unit test added for paranoid_memory_checks=true. * existing unit test for paranoid_memory_checks=false. * enable in stress test. Performance Benchmark: we check for performance regression in read path where data is in memtable only. For each benchmark, the script was run at the same time for main and this PR: * Memtable-only randomread ops/sec: ``` (for I in $(seq 1 50);do ./db_bench --benchmarks=fillseq,readrandom --write_buffer_size=268435456 --writes=250000 --num=250000 --reads=500000 --seed=1723056275 2>&1 | grep "readrandom"; done;) | awk '{ t += $5; c++; print } END { print 1.0 * t / c }'; Main: 608146 PR with paranoid_memory_checks=false: 607727 (- %0.07) PR with paranoid_memory_checks=true: 521889 (-%14.2) ``` * Memtable-only sequential scan ops/sec: ``` (for I in $(seq 1 50); do ./db_bench--benchmarks=fillseq,readseq[-X10] --write_buffer_size=268435456 --num=1000000 --seed=1723056275 2>1 | grep "\[AVG 10 runs\]"; done;) | awk '{ t += $6; c++; print; } END { printf "%.0f\n", 1.0 * t / c }'; Main: 9180077 PR with paranoid_memory_checks=false: 9536241 (+%3.8) PR with paranoid_memory_checks=true: 7653934 (-%16.6) ``` * Memtable-only reverse scan ops/sec: ``` (for I in $(seq 1 20); do ./db_bench --benchmarks=fillseq,readreverse[-X10] --write_buffer_size=268435456 --num=1000000 --seed=1723056275 2>1 | grep "\[AVG 10 runs\]"; done;) | awk '{ t += $6; c++; print; } END { printf "%.0f\n", 1.0 * t / c }'; Main: 1285719 PR with integrity_checks=false: 1431626 (+%11.3) PR with integrity_checks=true: 811031 (-%36.9) ``` The `readrandom` benchmark shows no regression. The scanning benchmarks show improvement that I can't explain. Reviewed By: pdillinger Differential Revision: D60414267 Pulled By: cbi42 fbshipit-source-id: a70b0cbeea131f1a249a5f78f9dc3a62dacfaa91
1225 lines
57 KiB
C++
1225 lines
57 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/advanced_cache.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 {
|
|
|
|
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_compressed_bytes_per_kb",
|
|
{offsetof(struct CompressionOptions, max_compressed_bytes_per_kb),
|
|
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}},
|
|
{"checksum",
|
|
{offsetof(struct CompressionOptions, checksum), OptionType::kBoolean,
|
|
OptionVerificationType::kNormal, OptionTypeFlags::kMutable}},
|
|
};
|
|
|
|
static std::unordered_map<std::string, OptionTypeInfo>
|
|
file_temperature_age_type_info = {
|
|
{"temperature",
|
|
{offsetof(struct FileTemperatureAge, temperature),
|
|
OptionType::kTemperature, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"age",
|
|
{offsetof(struct FileTemperatureAge, age), OptionType::kUInt64T,
|
|
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}},
|
|
{"file_temperature_age_thresholds",
|
|
OptionTypeInfo::Vector<struct FileTemperatureAge>(
|
|
offsetof(struct CompactionOptionsFIFO,
|
|
file_temperature_age_thresholds),
|
|
OptionVerificationType::kNormal, OptionTypeFlags::kMutable,
|
|
OptionTypeInfo::Struct("file_temperature_age_thresholds",
|
|
&file_temperature_age_type_info, 0,
|
|
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}},
|
|
{"max_read_amp",
|
|
{offsetof(class CompactionOptionsUniversal, max_read_amp),
|
|
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",
|
|
{0, OptionType::kBoolean, OptionVerificationType::kDeprecated,
|
|
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",
|
|
{0, OptionType::kBoolean, OptionVerificationType::kDeprecated,
|
|
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}},
|
|
{"strict_max_successive_merges",
|
|
{offsetof(struct MutableCFOptions, strict_max_successive_merges),
|
|
OptionType::kBoolean, 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}},
|
|
{"default_write_temperature",
|
|
{offsetof(struct MutableCFOptions, default_write_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}},
|
|
{"bottommost_file_compaction_delay",
|
|
{offsetof(struct MutableCFOptions, bottommost_file_compaction_delay),
|
|
OptionType::kUInt32T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"uncache_aggressiveness",
|
|
{offsetof(struct MutableCFOptions, uncache_aggressiveness),
|
|
OptionType::kUInt32T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"block_protection_bytes_per_key",
|
|
{offsetof(struct MutableCFOptions, block_protection_bytes_per_key),
|
|
OptionType::kUInt8T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
{"paranoid_memory_checks",
|
|
{offsetof(struct MutableCFOptions, paranoid_memory_checks),
|
|
OptionType::kBoolean, 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
|
|
{"memtable_max_range_deletions",
|
|
{offsetof(struct MutableCFOptions, memtable_max_range_deletions),
|
|
OptionType::kUInt32T, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kMutable}},
|
|
|
|
};
|
|
|
|
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",
|
|
{0, OptionType::kBoolean, OptionVerificationType::kDeprecated,
|
|
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}},
|
|
{"default_temperature",
|
|
{offsetof(struct ImmutableCFOptions, default_temperature),
|
|
OptionType::kTemperature, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kCompareNever}},
|
|
{"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, nullptr}},
|
|
{"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, nullptr}},
|
|
{"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);
|
|
if (*ptr == nullptr) {
|
|
*value = kNullptrString;
|
|
} else if (opts.mutable_options_only) {
|
|
*value = "";
|
|
} else {
|
|
*value = (*ptr)->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);
|
|
}}},
|
|
{"persist_user_defined_timestamps",
|
|
{offsetof(struct ImmutableCFOptions, persist_user_defined_timestamps),
|
|
OptionType::kBoolean, OptionVerificationType::kNormal,
|
|
OptionTypeFlags::kCompareLoose}},
|
|
};
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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),
|
|
num_levels(cf_options.num_levels),
|
|
optimize_filters_for_hits(cf_options.optimize_filters_for_hits),
|
|
force_consistency_checks(cf_options.force_consistency_checks),
|
|
default_temperature(cf_options.default_temperature),
|
|
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),
|
|
persist_user_defined_timestamps(
|
|
cf_options.persist_user_defined_timestamps) {}
|
|
|
|
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, " strict_max_successive_merges: %d",
|
|
strict_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, " 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);
|
|
ROCKS_LOG_INFO(log, " paranoid_memory_checks: %d",
|
|
paranoid_memory_checks);
|
|
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, " 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);
|
|
ROCKS_LOG_INFO(log, " bottommost_file_compaction_delay: %" PRIu32,
|
|
bottommost_file_compaction_delay);
|
|
ROCKS_LOG_INFO(log, " uncache_aggressiveness: %" PRIu32,
|
|
uncache_aggressiveness);
|
|
|
|
// 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.max_read_amp: %d",
|
|
compaction_options_universal.max_read_amp);
|
|
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)) {}
|
|
|
|
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);
|
|
}
|
|
} // namespace ROCKSDB_NAMESPACE
|