Replace dynamic_cast<>
Summary: Replace dynamic_cast<> so that users can choose to build with RTTI off, so that they can save several bytes per object, and get tiny more memory available. Some nontrivial changes: 1. Add Comparator::GetRootComparator() to get around the internal comparator hack 2. Add the two experiemental functions to DB 3. Add TableFactory::GetOptionString() to avoid unnecessary casting to get the option string 4. Since 3 is done, move the parsing option functions for table factory to table factory files too, to be symmetric. Closes https://github.com/facebook/rocksdb/pull/2645 Differential Revision: D5502723 Pulled By: siying fbshipit-source-id: fd13cec5601cf68a554d87bfcf056f2ffa5fbf7c
This commit is contained in:
parent
e85f2c64cb
commit
21696ba502
@ -2,6 +2,7 @@
|
||||
## Unreleased
|
||||
### New Features
|
||||
* Add Iterator::Refresh(), which allows users to update the iterator state so that they can avoid some initialization costs of recreating iterators.
|
||||
* Replace dynamic_cast<> (except unit test) so people can choose to build with RTTI off. With make, release mode is by default built with -fno-rtti and debug mode is built without it. Users can override it by setting USE_RTTI=0 or 1.
|
||||
|
||||
## 5.7.0 (07/13/2017)
|
||||
### Public API Change
|
||||
|
12
Makefile
12
Makefile
@ -101,7 +101,19 @@ endif
|
||||
ifeq ($(DEBUG_LEVEL),0)
|
||||
OPT += -DNDEBUG
|
||||
DISABLE_WARNING_AS_ERROR=1
|
||||
|
||||
ifneq ($(USE_RTTI), 1)
|
||||
CXXFLAGS += -fno-rtti
|
||||
else
|
||||
CXXFLAGS += -DROCKSDB_USE_RTTI
|
||||
endif
|
||||
else
|
||||
ifneq ($(USE_RTTI), 0)
|
||||
CXXFLAGS += -DROCKSDB_USE_RTTI
|
||||
else
|
||||
CXXFLAGS += -fno-rtti
|
||||
endif
|
||||
|
||||
$(warning Warning: Compiling in debug mode. Don't use the resulting binary in production)
|
||||
endif
|
||||
|
||||
|
5
cache/clock_cache.cc
vendored
5
cache/clock_cache.cc
vendored
@ -27,6 +27,11 @@ std::shared_ptr<Cache> NewClockCache(size_t capacity, int num_shard_bits,
|
||||
#include <atomic>
|
||||
#include <deque>
|
||||
|
||||
// "tbb/concurrent_hash_map.h" requires RTTI if exception is enabled.
|
||||
// Disable it so users can chooose to disable RTTI.
|
||||
#ifndef ROCKSDB_USE_RTTI
|
||||
#define TBB_USE_EXCEPTIONS 0
|
||||
#endif
|
||||
#include "tbb/concurrent_hash_map.h"
|
||||
|
||||
#include "cache/sharded_cache.h"
|
||||
|
@ -9,16 +9,18 @@
|
||||
#include "rocksdb/convenience.h"
|
||||
|
||||
#include "db/db_impl.h"
|
||||
#include "util/cast_util.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
void CancelAllBackgroundWork(DB* db, bool wait) {
|
||||
(dynamic_cast<DBImpl*>(db->GetRootDB()))->CancelAllBackgroundWork(wait);
|
||||
(static_cast_with_check<DBImpl, DB>(db->GetRootDB()))
|
||||
->CancelAllBackgroundWork(wait);
|
||||
}
|
||||
|
||||
Status DeleteFilesInRange(DB* db, ColumnFamilyHandle* column_family,
|
||||
const Slice* begin, const Slice* end) {
|
||||
return (dynamic_cast<DBImpl*>(db->GetRootDB()))
|
||||
return (static_cast_with_check<DBImpl, DB>(db->GetRootDB()))
|
||||
->DeleteFilesInRange(column_family, begin, end);
|
||||
}
|
||||
|
||||
|
@ -235,11 +235,11 @@ class DBImpl : public DB {
|
||||
ColumnFamilyHandle* column_family,
|
||||
ColumnFamilyMetaData* metadata) override;
|
||||
|
||||
// experimental API
|
||||
Status SuggestCompactRange(ColumnFamilyHandle* column_family,
|
||||
const Slice* begin, const Slice* end);
|
||||
const Slice* begin, const Slice* end) override;
|
||||
|
||||
Status PromoteL0(ColumnFamilyHandle* column_family, int target_level);
|
||||
Status PromoteL0(ColumnFamilyHandle* column_family,
|
||||
int target_level) override;
|
||||
|
||||
// Similar to Write() but will call the callback once on the single write
|
||||
// thread to determine whether it is safe to perform the write.
|
||||
|
@ -157,6 +157,9 @@ class InternalKeyComparator : public Comparator {
|
||||
|
||||
int Compare(const InternalKey& a, const InternalKey& b) const;
|
||||
int Compare(const ParsedInternalKey& a, const ParsedInternalKey& b) const;
|
||||
virtual const Comparator* GetRootComparator() const override {
|
||||
return user_comparator_->GetRootComparator();
|
||||
}
|
||||
};
|
||||
|
||||
// Modules in this directory should keep internal keys wrapped inside
|
||||
|
@ -14,20 +14,18 @@ namespace experimental {
|
||||
|
||||
Status SuggestCompactRange(DB* db, ColumnFamilyHandle* column_family,
|
||||
const Slice* begin, const Slice* end) {
|
||||
auto dbimpl = dynamic_cast<DBImpl*>(db);
|
||||
if (dbimpl == nullptr) {
|
||||
return Status::InvalidArgument("Didn't recognize DB object");
|
||||
if (db == nullptr) {
|
||||
return Status::InvalidArgument("DB is empty");
|
||||
}
|
||||
|
||||
return dbimpl->SuggestCompactRange(column_family, begin, end);
|
||||
return db->SuggestCompactRange(column_family, begin, end);
|
||||
}
|
||||
|
||||
Status PromoteL0(DB* db, ColumnFamilyHandle* column_family, int target_level) {
|
||||
auto dbimpl = dynamic_cast<DBImpl*>(db);
|
||||
if (dbimpl == nullptr) {
|
||||
if (db == nullptr) {
|
||||
return Status::InvalidArgument("Didn't recognize DB object");
|
||||
}
|
||||
return dbimpl->PromoteL0(column_family, target_level);
|
||||
return db->PromoteL0(column_family, target_level);
|
||||
}
|
||||
|
||||
#else // ROCKSDB_LITE
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/options.h"
|
||||
#include "rocksdb/write_batch.h"
|
||||
#include "util/cast_util.h"
|
||||
#include "util/coding.h"
|
||||
#include "util/file_reader_writer.h"
|
||||
#include "util/filename.h"
|
||||
@ -273,8 +274,8 @@ namespace {
|
||||
struct CompareLogByPointer {
|
||||
bool operator()(const std::unique_ptr<LogFile>& a,
|
||||
const std::unique_ptr<LogFile>& b) {
|
||||
LogFileImpl* a_impl = dynamic_cast<LogFileImpl*>(a.get());
|
||||
LogFileImpl* b_impl = dynamic_cast<LogFileImpl*>(b.get());
|
||||
LogFileImpl* a_impl = static_cast_with_check<LogFileImpl, LogFile>(a.get());
|
||||
LogFileImpl* b_impl = static_cast_with_check<LogFileImpl, LogFile>(b.get());
|
||||
return *a_impl < *b_impl;
|
||||
}
|
||||
};
|
||||
|
4
env/mock_env.cc
vendored
4
env/mock_env.cc
vendored
@ -11,6 +11,7 @@
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include "port/sys_time.h"
|
||||
#include "util/cast_util.h"
|
||||
#include "util/murmurhash.h"
|
||||
#include "util/random.h"
|
||||
#include "util/rate_limiter.h"
|
||||
@ -711,7 +712,8 @@ Status MockEnv::LockFile(const std::string& fname, FileLock** flock) {
|
||||
}
|
||||
|
||||
Status MockEnv::UnlockFile(FileLock* flock) {
|
||||
std::string fn = dynamic_cast<MockEnvFileLock*>(flock)->FileName();
|
||||
std::string fn =
|
||||
static_cast_with_check<MockEnvFileLock, FileLock>(flock)->FileName();
|
||||
{
|
||||
MutexLock lock(&mutex_);
|
||||
if (file_map_.find(fn) != file_map_.end()) {
|
||||
|
@ -8,6 +8,10 @@ ifndef DISABLE_JEMALLOC
|
||||
PLATFORM_CXXFLAGS += $(JEMALLOC_INCLUDE)
|
||||
endif
|
||||
|
||||
ifneq ($(USE_RTTI), 1)
|
||||
CXXFLAGS += -fno-rtti
|
||||
endif
|
||||
|
||||
.PHONY: clean librocksdb
|
||||
|
||||
all: simple_example column_families_example compact_files_example c_simple_example optimistic_transaction_example transaction_example compaction_filter_example options_file_example
|
||||
|
@ -59,7 +59,11 @@ int main() {
|
||||
|
||||
MyFilter filter;
|
||||
|
||||
system("rm -rf /tmp/rocksmergetest");
|
||||
int ret = system("rm -rf /tmp/rocksmergetest");
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error deleting /tmp/rocksmergetest, code: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
rocksdb::Options options;
|
||||
options.create_if_missing = true;
|
||||
options.merge_operator.reset(new MyMerge);
|
||||
|
@ -64,6 +64,10 @@ class Comparator {
|
||||
// Simple comparator implementations may return with *key unchanged,
|
||||
// i.e., an implementation of this method that does nothing is correct.
|
||||
virtual void FindShortSuccessor(std::string* key) const = 0;
|
||||
|
||||
// if it is a wrapped comparator, may return the root one.
|
||||
// return itself it is not wrapped.
|
||||
virtual const Comparator* GetRootComparator() const { return this; }
|
||||
};
|
||||
|
||||
// Return a builtin comparator that uses lexicographic byte-wise
|
||||
|
@ -1097,6 +1097,17 @@ class DB {
|
||||
virtual Status GetPropertiesOfTablesInRange(
|
||||
ColumnFamilyHandle* column_family, const Range* range, std::size_t n,
|
||||
TablePropertiesCollection* props) = 0;
|
||||
|
||||
virtual Status SuggestCompactRange(ColumnFamilyHandle* column_family,
|
||||
const Slice* begin, const Slice* end) {
|
||||
return Status::NotSupported("SuggestCompactRange() is not implemented.");
|
||||
}
|
||||
|
||||
virtual Status PromoteL0(ColumnFamilyHandle* column_family,
|
||||
int target_level) {
|
||||
return Status::NotSupported("PromoteL0() is not implemented.");
|
||||
}
|
||||
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
// Needed for StackableDB
|
||||
|
@ -467,6 +467,12 @@ class TableFactory {
|
||||
// RocksDB prints configurations at DB Open().
|
||||
virtual std::string GetPrintableTableOptions() const = 0;
|
||||
|
||||
virtual Status GetOptionString(std::string* opt_string,
|
||||
const std::string& delimiter) const {
|
||||
return Status::NotSupported(
|
||||
"The table factory doesn't implement GetOptionString().");
|
||||
}
|
||||
|
||||
// Returns the raw pointer of the table options that is used by this
|
||||
// TableFactory, or nullptr if this function is not supported.
|
||||
// Since the return value is a raw pointer, the TableFactory owns the
|
||||
|
@ -350,6 +350,17 @@ class StackableDB : public DB {
|
||||
return db_->GetUpdatesSince(seq_number, iter, read_options);
|
||||
}
|
||||
|
||||
virtual Status SuggestCompactRange(ColumnFamilyHandle* column_family,
|
||||
const Slice* begin,
|
||||
const Slice* end) override {
|
||||
return db_->SuggestCompactRange(column_family, begin, end);
|
||||
}
|
||||
|
||||
virtual Status PromoteL0(ColumnFamilyHandle* column_family,
|
||||
int target_level) override {
|
||||
return db_->PromoteL0(column_family, target_level);
|
||||
}
|
||||
|
||||
virtual ColumnFamilyHandle* DefaultColumnFamily() const override {
|
||||
return db_->DefaultColumnFamily();
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "port/port.h"
|
||||
#include "util/cast_util.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
@ -255,7 +256,8 @@ void HistogramImpl::Add(uint64_t value) {
|
||||
|
||||
void HistogramImpl::Merge(const Histogram& other) {
|
||||
if (strcmp(Name(), other.Name()) == 0) {
|
||||
Merge(dynamic_cast<const HistogramImpl&>(other));
|
||||
Merge(
|
||||
*static_cast_with_check<const HistogramImpl, const Histogram>(&other));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "monitoring/histogram_windowing.h"
|
||||
#include "monitoring/histogram.h"
|
||||
#include "util/cast_util.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@ -64,7 +65,9 @@ void HistogramWindowingImpl::Add(uint64_t value){
|
||||
|
||||
void HistogramWindowingImpl::Merge(const Histogram& other) {
|
||||
if (strcmp(Name(), other.Name()) == 0) {
|
||||
Merge(dynamic_cast<const HistogramWindowingImpl&>(other));
|
||||
Merge(
|
||||
*static_cast_with_check<const HistogramWindowingImpl, const Histogram>(
|
||||
&other));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "rocksdb/table.h"
|
||||
#include "table/block_based_table_factory.h"
|
||||
#include "table/plain_table_factory.h"
|
||||
#include "util/cast_util.h"
|
||||
#include "util/string_util.h"
|
||||
|
||||
namespace rocksdb {
|
||||
@ -303,6 +304,7 @@ bool ParseSliceTransform(
|
||||
// SliceTransforms here.
|
||||
return false;
|
||||
}
|
||||
} // anonymouse namespace
|
||||
|
||||
bool ParseOptionHelper(char* opt_address, const OptionType& opt_type,
|
||||
const std::string& value) {
|
||||
@ -383,8 +385,6 @@ bool ParseOptionHelper(char* opt_address, const OptionType& opt_type,
|
||||
return true;
|
||||
}
|
||||
|
||||
} // anonymouse namespace
|
||||
|
||||
bool SerializeSingleOptionHelper(const char* opt_address,
|
||||
const OptionType opt_type,
|
||||
std::string* value) {
|
||||
@ -466,12 +466,14 @@ bool SerializeSingleOptionHelper(const char* opt_address,
|
||||
// Since the user-specified comparator will be wrapped by
|
||||
// InternalKeyComparator, we should persist the user-specified one
|
||||
// instead of InternalKeyComparator.
|
||||
const auto* internal_comparator =
|
||||
dynamic_cast<const InternalKeyComparator*>(*ptr);
|
||||
if (internal_comparator != nullptr) {
|
||||
*value = internal_comparator->user_comparator()->Name();
|
||||
if (*ptr == nullptr) {
|
||||
*value = kNullptrString;
|
||||
} else {
|
||||
*value = *ptr ? (*ptr)->Name() : kNullptrString;
|
||||
const Comparator* root_comp = (*ptr)->GetRootComparator();
|
||||
if (root_comp == nullptr) {
|
||||
root_comp = (*ptr);
|
||||
}
|
||||
*value = root_comp->Name();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -693,8 +695,9 @@ Status ParseColumnFamilyOption(const std::string& name,
|
||||
if (name == "block_based_table_factory") {
|
||||
// Nested options
|
||||
BlockBasedTableOptions table_opt, base_table_options;
|
||||
auto block_based_table_factory = dynamic_cast<BlockBasedTableFactory*>(
|
||||
new_options->table_factory.get());
|
||||
BlockBasedTableFactory* block_based_table_factory =
|
||||
static_cast_with_check<BlockBasedTableFactory, TableFactory>(
|
||||
new_options->table_factory.get());
|
||||
if (block_based_table_factory != nullptr) {
|
||||
base_table_options = block_based_table_factory->table_options();
|
||||
}
|
||||
@ -708,8 +711,9 @@ Status ParseColumnFamilyOption(const std::string& name,
|
||||
} else if (name == "plain_table_factory") {
|
||||
// Nested options
|
||||
PlainTableOptions table_opt, base_table_options;
|
||||
auto plain_table_factory = dynamic_cast<PlainTableFactory*>(
|
||||
new_options->table_factory.get());
|
||||
PlainTableFactory* plain_table_factory =
|
||||
static_cast_with_check<PlainTableFactory, TableFactory>(
|
||||
new_options->table_factory.get());
|
||||
if (plain_table_factory != nullptr) {
|
||||
base_table_options = plain_table_factory->table_options();
|
||||
}
|
||||
@ -909,59 +913,6 @@ std::vector<CompressionType> GetSupportedCompressions() {
|
||||
return supported_compressions;
|
||||
}
|
||||
|
||||
bool SerializeSingleBlockBasedTableOption(
|
||||
std::string* opt_string, const BlockBasedTableOptions& bbt_options,
|
||||
const std::string& name, const std::string& delimiter) {
|
||||
auto iter = block_based_table_type_info.find(name);
|
||||
if (iter == block_based_table_type_info.end()) {
|
||||
return false;
|
||||
}
|
||||
auto& opt_info = iter->second;
|
||||
const char* opt_address =
|
||||
reinterpret_cast<const char*>(&bbt_options) + opt_info.offset;
|
||||
std::string value;
|
||||
bool result = SerializeSingleOptionHelper(opt_address, opt_info.type, &value);
|
||||
if (result) {
|
||||
*opt_string = name + "=" + value + delimiter;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Status GetStringFromBlockBasedTableOptions(
|
||||
std::string* opt_string, const BlockBasedTableOptions& bbt_options,
|
||||
const std::string& delimiter) {
|
||||
assert(opt_string);
|
||||
opt_string->clear();
|
||||
for (auto iter = block_based_table_type_info.begin();
|
||||
iter != block_based_table_type_info.end(); ++iter) {
|
||||
if (iter->second.verification == OptionVerificationType::kDeprecated) {
|
||||
// If the option is no longer used in rocksdb and marked as deprecated,
|
||||
// we skip it in the serialization.
|
||||
continue;
|
||||
}
|
||||
std::string single_output;
|
||||
bool result = SerializeSingleBlockBasedTableOption(
|
||||
&single_output, bbt_options, iter->first, delimiter);
|
||||
assert(result);
|
||||
if (result) {
|
||||
opt_string->append(single_output);
|
||||
}
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status GetStringFromTableFactory(std::string* opts_str, const TableFactory* tf,
|
||||
const std::string& delimiter) {
|
||||
const auto* bbtf = dynamic_cast<const BlockBasedTableFactory*>(tf);
|
||||
opts_str->clear();
|
||||
if (bbtf != nullptr) {
|
||||
return GetStringFromBlockBasedTableOptions(opts_str, bbtf->table_options(),
|
||||
delimiter);
|
||||
}
|
||||
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status ParseDBOption(const std::string& name,
|
||||
const std::string& org_value,
|
||||
DBOptions* new_options,
|
||||
@ -1003,242 +954,6 @@ Status ParseDBOption(const std::string& name,
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
std::string ParseBlockBasedTableOption(const std::string& name,
|
||||
const std::string& org_value,
|
||||
BlockBasedTableOptions* new_options,
|
||||
bool input_strings_escaped = false,
|
||||
bool ignore_unknown_options = false) {
|
||||
const std::string& value =
|
||||
input_strings_escaped ? UnescapeOptionString(org_value) : org_value;
|
||||
if (!input_strings_escaped) {
|
||||
// if the input string is not escaped, it means this function is
|
||||
// invoked from SetOptions, which takes the old format.
|
||||
if (name == "block_cache") {
|
||||
new_options->block_cache = NewLRUCache(ParseSizeT(value));
|
||||
return "";
|
||||
} else if (name == "block_cache_compressed") {
|
||||
new_options->block_cache_compressed = NewLRUCache(ParseSizeT(value));
|
||||
return "";
|
||||
} else if (name == "filter_policy") {
|
||||
// Expect the following format
|
||||
// bloomfilter:int:bool
|
||||
const std::string kName = "bloomfilter:";
|
||||
if (value.compare(0, kName.size(), kName) != 0) {
|
||||
return "Invalid filter policy name";
|
||||
}
|
||||
size_t pos = value.find(':', kName.size());
|
||||
if (pos == std::string::npos) {
|
||||
return "Invalid filter policy config, missing bits_per_key";
|
||||
}
|
||||
int bits_per_key =
|
||||
ParseInt(trim(value.substr(kName.size(), pos - kName.size())));
|
||||
bool use_block_based_builder =
|
||||
ParseBoolean("use_block_based_builder", trim(value.substr(pos + 1)));
|
||||
new_options->filter_policy.reset(
|
||||
NewBloomFilterPolicy(bits_per_key, use_block_based_builder));
|
||||
return "";
|
||||
}
|
||||
}
|
||||
const auto iter = block_based_table_type_info.find(name);
|
||||
if (iter == block_based_table_type_info.end()) {
|
||||
if (ignore_unknown_options) {
|
||||
return "";
|
||||
} else {
|
||||
return "Unrecognized option";
|
||||
}
|
||||
}
|
||||
const auto& opt_info = iter->second;
|
||||
if (opt_info.verification != OptionVerificationType::kDeprecated &&
|
||||
!ParseOptionHelper(reinterpret_cast<char*>(new_options) + opt_info.offset,
|
||||
opt_info.type, value)) {
|
||||
return "Invalid value";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string ParsePlainTableOptions(const std::string& name,
|
||||
const std::string& org_value,
|
||||
PlainTableOptions* new_options,
|
||||
bool input_strings_escaped = false,
|
||||
bool ignore_unknown_options = false) {
|
||||
const std::string& value =
|
||||
input_strings_escaped ? UnescapeOptionString(org_value) : org_value;
|
||||
const auto iter = plain_table_type_info.find(name);
|
||||
if (iter == plain_table_type_info.end()) {
|
||||
if (ignore_unknown_options) {
|
||||
return "";
|
||||
} else {
|
||||
return "Unrecognized option";
|
||||
}
|
||||
}
|
||||
const auto& opt_info = iter->second;
|
||||
if (opt_info.verification != OptionVerificationType::kDeprecated &&
|
||||
!ParseOptionHelper(reinterpret_cast<char*>(new_options) + opt_info.offset,
|
||||
opt_info.type, value)) {
|
||||
return "Invalid value";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
Status GetBlockBasedTableOptionsFromMap(
|
||||
const BlockBasedTableOptions& table_options,
|
||||
const std::unordered_map<std::string, std::string>& opts_map,
|
||||
BlockBasedTableOptions* new_table_options, bool input_strings_escaped,
|
||||
bool ignore_unknown_options) {
|
||||
assert(new_table_options);
|
||||
*new_table_options = table_options;
|
||||
for (const auto& o : opts_map) {
|
||||
auto error_message = ParseBlockBasedTableOption(
|
||||
o.first, o.second, new_table_options, input_strings_escaped,
|
||||
ignore_unknown_options);
|
||||
if (error_message != "") {
|
||||
const auto iter = block_based_table_type_info.find(o.first);
|
||||
if (iter == block_based_table_type_info.end() ||
|
||||
!input_strings_escaped || // !input_strings_escaped indicates
|
||||
// the old API, where everything is
|
||||
// parsable.
|
||||
(iter->second.verification != OptionVerificationType::kByName &&
|
||||
iter->second.verification !=
|
||||
OptionVerificationType::kByNameAllowNull &&
|
||||
iter->second.verification !=
|
||||
OptionVerificationType::kDeprecated)) {
|
||||
// Restore "new_options" to the default "base_options".
|
||||
*new_table_options = table_options;
|
||||
return Status::InvalidArgument("Can't parse BlockBasedTableOptions:",
|
||||
o.first + " " + error_message);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status GetBlockBasedTableOptionsFromString(
|
||||
const BlockBasedTableOptions& table_options,
|
||||
const std::string& opts_str,
|
||||
BlockBasedTableOptions* new_table_options) {
|
||||
std::unordered_map<std::string, std::string> opts_map;
|
||||
Status s = StringToMap(opts_str, &opts_map);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
return GetBlockBasedTableOptionsFromMap(table_options, opts_map,
|
||||
new_table_options);
|
||||
}
|
||||
|
||||
Status GetPlainTableOptionsFromMap(
|
||||
const PlainTableOptions& table_options,
|
||||
const std::unordered_map<std::string, std::string>& opts_map,
|
||||
PlainTableOptions* new_table_options, bool input_strings_escaped,
|
||||
bool ignore_unknown_options) {
|
||||
assert(new_table_options);
|
||||
*new_table_options = table_options;
|
||||
for (const auto& o : opts_map) {
|
||||
auto error_message = ParsePlainTableOptions(
|
||||
o.first, o.second, new_table_options, input_strings_escaped);
|
||||
if (error_message != "") {
|
||||
const auto iter = plain_table_type_info.find(o.first);
|
||||
if (iter == plain_table_type_info.end() ||
|
||||
!input_strings_escaped || // !input_strings_escaped indicates
|
||||
// the old API, where everything is
|
||||
// parsable.
|
||||
(iter->second.verification != OptionVerificationType::kByName &&
|
||||
iter->second.verification !=
|
||||
OptionVerificationType::kByNameAllowNull &&
|
||||
iter->second.verification !=
|
||||
OptionVerificationType::kDeprecated)) {
|
||||
// Restore "new_options" to the default "base_options".
|
||||
*new_table_options = table_options;
|
||||
return Status::InvalidArgument("Can't parse PlainTableOptions:",
|
||||
o.first + " " + error_message);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status GetPlainTableOptionsFromString(
|
||||
const PlainTableOptions& table_options,
|
||||
const std::string& opts_str,
|
||||
PlainTableOptions* new_table_options) {
|
||||
std::unordered_map<std::string, std::string> opts_map;
|
||||
Status s = StringToMap(opts_str, &opts_map);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
return GetPlainTableOptionsFromMap(table_options, opts_map,
|
||||
new_table_options);
|
||||
}
|
||||
|
||||
Status GetMemTableRepFactoryFromString(const std::string& opts_str,
|
||||
std::unique_ptr<MemTableRepFactory>* new_mem_factory) {
|
||||
std::vector<std::string> opts_list = StringSplit(opts_str, ':');
|
||||
size_t len = opts_list.size();
|
||||
|
||||
if (opts_list.size() <= 0 || opts_list.size() > 2) {
|
||||
return Status::InvalidArgument("Can't parse memtable_factory option ",
|
||||
opts_str);
|
||||
}
|
||||
|
||||
MemTableRepFactory* mem_factory = nullptr;
|
||||
|
||||
if (opts_list[0] == "skip_list") {
|
||||
// Expecting format
|
||||
// skip_list:<lookahead>
|
||||
if (2 == len) {
|
||||
size_t lookahead = ParseSizeT(opts_list[1]);
|
||||
mem_factory = new SkipListFactory(lookahead);
|
||||
} else if (1 == len) {
|
||||
mem_factory = new SkipListFactory();
|
||||
}
|
||||
} else if (opts_list[0] == "prefix_hash") {
|
||||
// Expecting format
|
||||
// prfix_hash:<hash_bucket_count>
|
||||
if (2 == len) {
|
||||
size_t hash_bucket_count = ParseSizeT(opts_list[1]);
|
||||
mem_factory = NewHashSkipListRepFactory(hash_bucket_count);
|
||||
} else if (1 == len) {
|
||||
mem_factory = NewHashSkipListRepFactory();
|
||||
}
|
||||
} else if (opts_list[0] == "hash_linkedlist") {
|
||||
// Expecting format
|
||||
// hash_linkedlist:<hash_bucket_count>
|
||||
if (2 == len) {
|
||||
size_t hash_bucket_count = ParseSizeT(opts_list[1]);
|
||||
mem_factory = NewHashLinkListRepFactory(hash_bucket_count);
|
||||
} else if (1 == len) {
|
||||
mem_factory = NewHashLinkListRepFactory();
|
||||
}
|
||||
} else if (opts_list[0] == "vector") {
|
||||
// Expecting format
|
||||
// vector:<count>
|
||||
if (2 == len) {
|
||||
size_t count = ParseSizeT(opts_list[1]);
|
||||
mem_factory = new VectorRepFactory(count);
|
||||
} else if (1 == len) {
|
||||
mem_factory = new VectorRepFactory();
|
||||
}
|
||||
} else if (opts_list[0] == "cuckoo") {
|
||||
// Expecting format
|
||||
// cuckoo:<write_buffer_size>
|
||||
if (2 == len) {
|
||||
size_t write_buffer_size = ParseSizeT(opts_list[1]);
|
||||
mem_factory= NewHashCuckooRepFactory(write_buffer_size);
|
||||
} else if (1 == len) {
|
||||
return Status::InvalidArgument("Can't parse memtable_factory option ",
|
||||
opts_str);
|
||||
}
|
||||
} else {
|
||||
return Status::InvalidArgument("Unrecognized memtable_factory option ",
|
||||
opts_str);
|
||||
}
|
||||
|
||||
if (mem_factory != nullptr){
|
||||
new_mem_factory->reset(mem_factory);
|
||||
}
|
||||
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status GetColumnFamilyOptionsFromMap(
|
||||
const ColumnFamilyOptions& base_options,
|
||||
const std::unordered_map<std::string, std::string>& opts_map,
|
||||
|
@ -60,9 +60,6 @@ Status GetTableFactoryFromMap(
|
||||
std::shared_ptr<TableFactory>* table_factory,
|
||||
bool ignore_unknown_options = false);
|
||||
|
||||
Status GetStringFromTableFactory(std::string* opts_str, const TableFactory* tf,
|
||||
const std::string& delimiter = "; ");
|
||||
|
||||
enum class OptionType {
|
||||
kBoolean,
|
||||
kInt,
|
||||
@ -580,109 +577,6 @@ static std::unordered_map<std::string, OptionTypeInfo> cf_options_type_info = {
|
||||
{offset_of(&ColumnFamilyOptions::compaction_pri),
|
||||
OptionType::kCompactionPri, OptionVerificationType::kNormal, false, 0}}};
|
||||
|
||||
static std::unordered_map<std::string, OptionTypeInfo>
|
||||
block_based_table_type_info = {
|
||||
/* currently not supported
|
||||
std::shared_ptr<Cache> block_cache = nullptr;
|
||||
std::shared_ptr<Cache> block_cache_compressed = nullptr;
|
||||
*/
|
||||
{"flush_block_policy_factory",
|
||||
{offsetof(struct BlockBasedTableOptions, flush_block_policy_factory),
|
||||
OptionType::kFlushBlockPolicyFactory, OptionVerificationType::kByName,
|
||||
false, 0}},
|
||||
{"cache_index_and_filter_blocks",
|
||||
{offsetof(struct BlockBasedTableOptions,
|
||||
cache_index_and_filter_blocks),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
|
||||
{"cache_index_and_filter_blocks_with_high_priority",
|
||||
{offsetof(struct BlockBasedTableOptions,
|
||||
cache_index_and_filter_blocks_with_high_priority),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
|
||||
{"pin_l0_filter_and_index_blocks_in_cache",
|
||||
{offsetof(struct BlockBasedTableOptions,
|
||||
pin_l0_filter_and_index_blocks_in_cache),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
|
||||
{"index_type",
|
||||
{offsetof(struct BlockBasedTableOptions, index_type),
|
||||
OptionType::kBlockBasedTableIndexType,
|
||||
OptionVerificationType::kNormal, false, 0}},
|
||||
{"hash_index_allow_collision",
|
||||
{offsetof(struct BlockBasedTableOptions, hash_index_allow_collision),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
|
||||
{"checksum",
|
||||
{offsetof(struct BlockBasedTableOptions, checksum),
|
||||
OptionType::kChecksumType, OptionVerificationType::kNormal, false,
|
||||
0}},
|
||||
{"no_block_cache",
|
||||
{offsetof(struct BlockBasedTableOptions, no_block_cache),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
|
||||
{"block_size",
|
||||
{offsetof(struct BlockBasedTableOptions, block_size),
|
||||
OptionType::kSizeT, OptionVerificationType::kNormal, false, 0}},
|
||||
{"block_size_deviation",
|
||||
{offsetof(struct BlockBasedTableOptions, block_size_deviation),
|
||||
OptionType::kInt, OptionVerificationType::kNormal, false, 0}},
|
||||
{"block_restart_interval",
|
||||
{offsetof(struct BlockBasedTableOptions, block_restart_interval),
|
||||
OptionType::kInt, OptionVerificationType::kNormal, false, 0}},
|
||||
{"index_block_restart_interval",
|
||||
{offsetof(struct BlockBasedTableOptions, index_block_restart_interval),
|
||||
OptionType::kInt, OptionVerificationType::kNormal, false, 0}},
|
||||
{"index_per_partition",
|
||||
{0, OptionType::kUInt64T, OptionVerificationType::kDeprecated, false,
|
||||
0}},
|
||||
{"metadata_block_size",
|
||||
{offsetof(struct BlockBasedTableOptions, metadata_block_size),
|
||||
OptionType::kUInt64T, OptionVerificationType::kNormal, false, 0}},
|
||||
{"partition_filters",
|
||||
{offsetof(struct BlockBasedTableOptions, partition_filters),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
|
||||
{"filter_policy",
|
||||
{offsetof(struct BlockBasedTableOptions, filter_policy),
|
||||
OptionType::kFilterPolicy, OptionVerificationType::kByName, false,
|
||||
0}},
|
||||
{"whole_key_filtering",
|
||||
{offsetof(struct BlockBasedTableOptions, whole_key_filtering),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
|
||||
{"skip_table_builder_flush",
|
||||
{0, OptionType::kBoolean, OptionVerificationType::kDeprecated, false,
|
||||
0}},
|
||||
{"format_version",
|
||||
{offsetof(struct BlockBasedTableOptions, format_version),
|
||||
OptionType::kUInt32T, OptionVerificationType::kNormal, false, 0}},
|
||||
{"verify_compression",
|
||||
{offsetof(struct BlockBasedTableOptions, verify_compression),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
|
||||
{"read_amp_bytes_per_bit",
|
||||
{offsetof(struct BlockBasedTableOptions, read_amp_bytes_per_bit),
|
||||
OptionType::kSizeT, OptionVerificationType::kNormal, false, 0}}};
|
||||
|
||||
static std::unordered_map<std::string, OptionTypeInfo> plain_table_type_info = {
|
||||
{"user_key_len",
|
||||
{offsetof(struct PlainTableOptions, user_key_len), OptionType::kUInt32T,
|
||||
OptionVerificationType::kNormal, false, 0}},
|
||||
{"bloom_bits_per_key",
|
||||
{offsetof(struct PlainTableOptions, bloom_bits_per_key), OptionType::kInt,
|
||||
OptionVerificationType::kNormal, false, 0}},
|
||||
{"hash_table_ratio",
|
||||
{offsetof(struct PlainTableOptions, hash_table_ratio), OptionType::kDouble,
|
||||
OptionVerificationType::kNormal, false, 0}},
|
||||
{"index_sparseness",
|
||||
{offsetof(struct PlainTableOptions, index_sparseness), OptionType::kSizeT,
|
||||
OptionVerificationType::kNormal, false, 0}},
|
||||
{"huge_page_tlb_size",
|
||||
{offsetof(struct PlainTableOptions, huge_page_tlb_size),
|
||||
OptionType::kSizeT, OptionVerificationType::kNormal, false, 0}},
|
||||
{"encoding_type",
|
||||
{offsetof(struct PlainTableOptions, encoding_type),
|
||||
OptionType::kEncodingType, OptionVerificationType::kByName, false, 0}},
|
||||
{"full_scan_mode",
|
||||
{offsetof(struct PlainTableOptions, full_scan_mode), OptionType::kBoolean,
|
||||
OptionVerificationType::kNormal, false, 0}},
|
||||
{"store_index_in_file",
|
||||
{offsetof(struct PlainTableOptions, store_index_in_file),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}}};
|
||||
|
||||
static std::unordered_map<std::string, CompressionType>
|
||||
compression_type_string_map = {
|
||||
{"kNoCompression", kNoCompression},
|
||||
@ -745,6 +639,12 @@ static std::unordered_map<std::string, InfoLogLevel> info_log_level_string_map =
|
||||
{"FATAL_LEVEL", InfoLogLevel::FATAL_LEVEL},
|
||||
{"HEADER_LEVEL", InfoLogLevel::HEADER_LEVEL}};
|
||||
|
||||
extern Status StringToMap(
|
||||
const std::string& opts_str,
|
||||
std::unordered_map<std::string, std::string>* opts_map);
|
||||
|
||||
extern bool ParseOptionHelper(char* opt_address, const OptionType& opt_type,
|
||||
const std::string& value);
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
} // namespace rocksdb
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "options/options_helper.h"
|
||||
#include "rocksdb/convenience.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "util/cast_util.h"
|
||||
#include "util/string_util.h"
|
||||
#include "util/sync_point.h"
|
||||
|
||||
@ -84,7 +85,8 @@ Status PersistRocksDBOptions(const DBOptions& db_opt,
|
||||
writable->Append("[" + opt_section_titles[kOptionSectionTableOptions] +
|
||||
tf->Name() + " \"" + EscapeOptionString(cf_names[i]) +
|
||||
"\"]\n ");
|
||||
s = GetStringFromTableFactory(&options_file_content, tf, "\n ");
|
||||
options_file_content.clear();
|
||||
s = tf->GetOptionString(&options_file_content, "\n ");
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
@ -507,6 +509,7 @@ namespace {
|
||||
bool AreEqualDoubles(const double a, const double b) {
|
||||
return (fabs(a - b) < 0.00001);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool AreEqualOptions(
|
||||
const char* opt1, const char* opt2, const OptionTypeInfo& type_info,
|
||||
@ -613,8 +616,6 @@ bool AreEqualOptions(
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Status RocksDBOptionsParser::VerifyRocksDBOptionsFromFile(
|
||||
const DBOptions& db_opt, const std::vector<std::string>& cf_names,
|
||||
const std::vector<ColumnFamilyOptions>& cf_opts,
|
||||
@ -762,59 +763,23 @@ Status RocksDBOptionsParser::VerifyCFOptions(
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status RocksDBOptionsParser::VerifyBlockBasedTableFactory(
|
||||
const BlockBasedTableFactory* base_tf,
|
||||
const BlockBasedTableFactory* file_tf,
|
||||
OptionsSanityCheckLevel sanity_check_level) {
|
||||
if ((base_tf != nullptr) != (file_tf != nullptr) &&
|
||||
sanity_check_level > kSanityLevelNone) {
|
||||
return Status::Corruption(
|
||||
"[RocksDBOptionsParser]: Inconsistent TableFactory class type");
|
||||
}
|
||||
if (base_tf == nullptr) {
|
||||
return Status::OK();
|
||||
}
|
||||
assert(file_tf != nullptr);
|
||||
|
||||
const auto& base_opt = base_tf->table_options();
|
||||
const auto& file_opt = file_tf->table_options();
|
||||
|
||||
for (auto& pair : block_based_table_type_info) {
|
||||
if (pair.second.verification == OptionVerificationType::kDeprecated) {
|
||||
// We skip checking deprecated variables as they might
|
||||
// contain random values since they might not be initialized
|
||||
continue;
|
||||
}
|
||||
if (BBTOptionSanityCheckLevel(pair.first) <= sanity_check_level) {
|
||||
if (!AreEqualOptions(reinterpret_cast<const char*>(&base_opt),
|
||||
reinterpret_cast<const char*>(&file_opt),
|
||||
pair.second, pair.first, nullptr)) {
|
||||
return Status::Corruption(
|
||||
"[RocksDBOptionsParser]: "
|
||||
"failed the verification on BlockBasedTableOptions::",
|
||||
pair.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status RocksDBOptionsParser::VerifyTableFactory(
|
||||
const TableFactory* base_tf, const TableFactory* file_tf,
|
||||
OptionsSanityCheckLevel sanity_check_level) {
|
||||
if (base_tf && file_tf) {
|
||||
if (sanity_check_level > kSanityLevelNone &&
|
||||
base_tf->Name() != file_tf->Name()) {
|
||||
std::string(base_tf->Name()) != std::string(file_tf->Name())) {
|
||||
return Status::Corruption(
|
||||
"[RocksDBOptionsParser]: "
|
||||
"failed the verification on TableFactory->Name()");
|
||||
}
|
||||
auto s = VerifyBlockBasedTableFactory(
|
||||
dynamic_cast<const BlockBasedTableFactory*>(base_tf),
|
||||
dynamic_cast<const BlockBasedTableFactory*>(file_tf),
|
||||
sanity_check_level);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
if (base_tf->Name() == BlockBasedTableFactory::kName) {
|
||||
return VerifyBlockBasedTableFactory(
|
||||
static_cast_with_check<const BlockBasedTableFactory,
|
||||
const TableFactory>(base_tf),
|
||||
static_cast_with_check<const BlockBasedTableFactory,
|
||||
const TableFactory>(file_tf),
|
||||
sanity_check_level);
|
||||
}
|
||||
// TODO(yhchiang): add checks for other table factory types
|
||||
} else {
|
||||
|
@ -38,6 +38,11 @@ Status PersistRocksDBOptions(const DBOptions& db_opt,
|
||||
const std::vector<ColumnFamilyOptions>& cf_opts,
|
||||
const std::string& file_name, Env* env);
|
||||
|
||||
extern bool AreEqualOptions(
|
||||
const char* opt1, const char* opt2, const OptionTypeInfo& type_info,
|
||||
const std::string& opt_name,
|
||||
const std::unordered_map<std::string, std::string>* opt_map);
|
||||
|
||||
class RocksDBOptionsParser {
|
||||
public:
|
||||
explicit RocksDBOptionsParser();
|
||||
@ -86,11 +91,6 @@ class RocksDBOptionsParser {
|
||||
const TableFactory* base_tf, const TableFactory* file_tf,
|
||||
OptionsSanityCheckLevel sanity_check_level = kSanityLevelExactMatch);
|
||||
|
||||
static Status VerifyBlockBasedTableFactory(
|
||||
const BlockBasedTableFactory* base_tf,
|
||||
const BlockBasedTableFactory* file_tf,
|
||||
OptionsSanityCheckLevel sanity_check_level);
|
||||
|
||||
static Status ExtraParserCheck(const RocksDBOptionsParser& input_parser);
|
||||
|
||||
protected:
|
||||
|
@ -889,11 +889,11 @@ TEST_F(OptionsTest, ConvertOptionsTest) {
|
||||
ASSERT_EQ(converted_opt.max_open_files, leveldb_opt.max_open_files);
|
||||
ASSERT_EQ(converted_opt.compression, leveldb_opt.compression);
|
||||
|
||||
std::shared_ptr<BlockBasedTableFactory> table_factory =
|
||||
std::dynamic_pointer_cast<BlockBasedTableFactory>(
|
||||
converted_opt.table_factory);
|
||||
std::shared_ptr<TableFactory> tb_guard = converted_opt.table_factory;
|
||||
BlockBasedTableFactory* table_factory =
|
||||
dynamic_cast<BlockBasedTableFactory*>(converted_opt.table_factory.get());
|
||||
|
||||
ASSERT_TRUE(table_factory.get() != nullptr);
|
||||
ASSERT_TRUE(table_factory != nullptr);
|
||||
|
||||
const BlockBasedTableOptions table_opt = table_factory->table_options();
|
||||
|
||||
@ -1278,6 +1278,11 @@ TEST_F(OptionsParserTest, DumpAndParse) {
|
||||
Random rnd(302);
|
||||
test::RandomInitDBOptions(&base_db_opt, &rnd);
|
||||
base_db_opt.db_log_dir += "/#odd #but #could #happen #path #/\\\\#OMG";
|
||||
|
||||
BlockBasedTableOptions special_bbto;
|
||||
special_bbto.cache_index_and_filter_blocks = true;
|
||||
special_bbto.block_size = 999999;
|
||||
|
||||
for (int c = 0; c < num_cf; ++c) {
|
||||
ColumnFamilyOptions cf_opt;
|
||||
Random cf_rnd(0xFB + c);
|
||||
@ -1287,6 +1292,8 @@ TEST_F(OptionsParserTest, DumpAndParse) {
|
||||
}
|
||||
if (c < 3) {
|
||||
cf_opt.table_factory.reset(test::RandomTableFactory(&rnd, c));
|
||||
} else if (c == 4) {
|
||||
cf_opt.table_factory.reset(NewBlockBasedTableFactory(special_bbto));
|
||||
}
|
||||
base_cf_opts.emplace_back(cf_opt);
|
||||
}
|
||||
@ -1298,6 +1305,15 @@ TEST_F(OptionsParserTest, DumpAndParse) {
|
||||
RocksDBOptionsParser parser;
|
||||
ASSERT_OK(parser.Parse(kOptionsFileName, env_.get()));
|
||||
|
||||
// Make sure block-based table factory options was deserialized correctly
|
||||
std::shared_ptr<TableFactory> ttf = (*parser.cf_opts())[4].table_factory;
|
||||
ASSERT_EQ(BlockBasedTableFactory::kName, std::string(ttf->Name()));
|
||||
const BlockBasedTableOptions& parsed_bbto =
|
||||
static_cast<BlockBasedTableFactory*>(ttf.get())->table_options();
|
||||
ASSERT_EQ(special_bbto.block_size, parsed_bbto.block_size);
|
||||
ASSERT_EQ(special_bbto.cache_index_and_filter_blocks,
|
||||
parsed_bbto.cache_index_and_filter_blocks);
|
||||
|
||||
ASSERT_OK(RocksDBOptionsParser::VerifyRocksDBOptionsFromFile(
|
||||
base_db_opt, cf_names, base_cf_opts, kOptionsFileName, env_.get()));
|
||||
|
||||
|
@ -13,12 +13,15 @@
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "options/options_helper.h"
|
||||
#include "port/port.h"
|
||||
#include "rocksdb/flush_block_policy.h"
|
||||
#include "rocksdb/cache.h"
|
||||
#include "rocksdb/convenience.h"
|
||||
#include "rocksdb/flush_block_policy.h"
|
||||
#include "table/block_based_table_builder.h"
|
||||
#include "table/block_based_table_reader.h"
|
||||
#include "table/format.h"
|
||||
#include "util/string_util.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
@ -201,15 +204,203 @@ std::string BlockBasedTableFactory::GetPrintableTableOptions() const {
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
namespace {
|
||||
bool SerializeSingleBlockBasedTableOption(
|
||||
std::string* opt_string, const BlockBasedTableOptions& bbt_options,
|
||||
const std::string& name, const std::string& delimiter) {
|
||||
auto iter = block_based_table_type_info.find(name);
|
||||
if (iter == block_based_table_type_info.end()) {
|
||||
return false;
|
||||
}
|
||||
auto& opt_info = iter->second;
|
||||
const char* opt_address =
|
||||
reinterpret_cast<const char*>(&bbt_options) + opt_info.offset;
|
||||
std::string value;
|
||||
bool result = SerializeSingleOptionHelper(opt_address, opt_info.type, &value);
|
||||
if (result) {
|
||||
*opt_string = name + "=" + value + delimiter;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Status BlockBasedTableFactory::GetOptionString(
|
||||
std::string* opt_string, const std::string& delimiter) const {
|
||||
assert(opt_string);
|
||||
opt_string->clear();
|
||||
for (auto iter = block_based_table_type_info.begin();
|
||||
iter != block_based_table_type_info.end(); ++iter) {
|
||||
if (iter->second.verification == OptionVerificationType::kDeprecated) {
|
||||
// If the option is no longer used in rocksdb and marked as deprecated,
|
||||
// we skip it in the serialization.
|
||||
continue;
|
||||
}
|
||||
std::string single_output;
|
||||
bool result = SerializeSingleBlockBasedTableOption(
|
||||
&single_output, table_options_, iter->first, delimiter);
|
||||
assert(result);
|
||||
if (result) {
|
||||
opt_string->append(single_output);
|
||||
}
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
#else
|
||||
Status BlockBasedTableFactory::GetOptionString(
|
||||
std::string* opt_string, const std::string& delimiter) const {
|
||||
return Status::OK();
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
const BlockBasedTableOptions& BlockBasedTableFactory::table_options() const {
|
||||
return table_options_;
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
namespace {
|
||||
std::string ParseBlockBasedTableOption(const std::string& name,
|
||||
const std::string& org_value,
|
||||
BlockBasedTableOptions* new_options,
|
||||
bool input_strings_escaped = false,
|
||||
bool ignore_unknown_options = false) {
|
||||
const std::string& value =
|
||||
input_strings_escaped ? UnescapeOptionString(org_value) : org_value;
|
||||
if (!input_strings_escaped) {
|
||||
// if the input string is not escaped, it means this function is
|
||||
// invoked from SetOptions, which takes the old format.
|
||||
if (name == "block_cache") {
|
||||
new_options->block_cache = NewLRUCache(ParseSizeT(value));
|
||||
return "";
|
||||
} else if (name == "block_cache_compressed") {
|
||||
new_options->block_cache_compressed = NewLRUCache(ParseSizeT(value));
|
||||
return "";
|
||||
} else if (name == "filter_policy") {
|
||||
// Expect the following format
|
||||
// bloomfilter:int:bool
|
||||
const std::string kName = "bloomfilter:";
|
||||
if (value.compare(0, kName.size(), kName) != 0) {
|
||||
return "Invalid filter policy name";
|
||||
}
|
||||
size_t pos = value.find(':', kName.size());
|
||||
if (pos == std::string::npos) {
|
||||
return "Invalid filter policy config, missing bits_per_key";
|
||||
}
|
||||
int bits_per_key =
|
||||
ParseInt(trim(value.substr(kName.size(), pos - kName.size())));
|
||||
bool use_block_based_builder =
|
||||
ParseBoolean("use_block_based_builder", trim(value.substr(pos + 1)));
|
||||
new_options->filter_policy.reset(
|
||||
NewBloomFilterPolicy(bits_per_key, use_block_based_builder));
|
||||
return "";
|
||||
}
|
||||
}
|
||||
const auto iter = block_based_table_type_info.find(name);
|
||||
if (iter == block_based_table_type_info.end()) {
|
||||
if (ignore_unknown_options) {
|
||||
return "";
|
||||
} else {
|
||||
return "Unrecognized option";
|
||||
}
|
||||
}
|
||||
const auto& opt_info = iter->second;
|
||||
if (opt_info.verification != OptionVerificationType::kDeprecated &&
|
||||
!ParseOptionHelper(reinterpret_cast<char*>(new_options) + opt_info.offset,
|
||||
opt_info.type, value)) {
|
||||
return "Invalid value";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Status GetBlockBasedTableOptionsFromString(
|
||||
const BlockBasedTableOptions& table_options, const std::string& opts_str,
|
||||
BlockBasedTableOptions* new_table_options) {
|
||||
std::unordered_map<std::string, std::string> opts_map;
|
||||
Status s = StringToMap(opts_str, &opts_map);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
|
||||
return GetBlockBasedTableOptionsFromMap(table_options, opts_map,
|
||||
new_table_options);
|
||||
}
|
||||
|
||||
Status GetBlockBasedTableOptionsFromMap(
|
||||
const BlockBasedTableOptions& table_options,
|
||||
const std::unordered_map<std::string, std::string>& opts_map,
|
||||
BlockBasedTableOptions* new_table_options, bool input_strings_escaped,
|
||||
bool ignore_unknown_options) {
|
||||
assert(new_table_options);
|
||||
*new_table_options = table_options;
|
||||
for (const auto& o : opts_map) {
|
||||
auto error_message = ParseBlockBasedTableOption(
|
||||
o.first, o.second, new_table_options, input_strings_escaped,
|
||||
ignore_unknown_options);
|
||||
if (error_message != "") {
|
||||
const auto iter = block_based_table_type_info.find(o.first);
|
||||
if (iter == block_based_table_type_info.end() ||
|
||||
!input_strings_escaped || // !input_strings_escaped indicates
|
||||
// the old API, where everything is
|
||||
// parsable.
|
||||
(iter->second.verification != OptionVerificationType::kByName &&
|
||||
iter->second.verification !=
|
||||
OptionVerificationType::kByNameAllowNull &&
|
||||
iter->second.verification != OptionVerificationType::kDeprecated)) {
|
||||
// Restore "new_options" to the default "base_options".
|
||||
*new_table_options = table_options;
|
||||
return Status::InvalidArgument("Can't parse BlockBasedTableOptions:",
|
||||
o.first + " " + error_message);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status VerifyBlockBasedTableFactory(
|
||||
const BlockBasedTableFactory* base_tf,
|
||||
const BlockBasedTableFactory* file_tf,
|
||||
OptionsSanityCheckLevel sanity_check_level) {
|
||||
if ((base_tf != nullptr) != (file_tf != nullptr) &&
|
||||
sanity_check_level > kSanityLevelNone) {
|
||||
return Status::Corruption(
|
||||
"[RocksDBOptionsParser]: Inconsistent TableFactory class type");
|
||||
}
|
||||
if (base_tf == nullptr) {
|
||||
return Status::OK();
|
||||
}
|
||||
assert(file_tf != nullptr);
|
||||
|
||||
const auto& base_opt = base_tf->table_options();
|
||||
const auto& file_opt = file_tf->table_options();
|
||||
|
||||
for (auto& pair : block_based_table_type_info) {
|
||||
if (pair.second.verification == OptionVerificationType::kDeprecated) {
|
||||
// We skip checking deprecated variables as they might
|
||||
// contain random values since they might not be initialized
|
||||
continue;
|
||||
}
|
||||
if (BBTOptionSanityCheckLevel(pair.first) <= sanity_check_level) {
|
||||
if (!AreEqualOptions(reinterpret_cast<const char*>(&base_opt),
|
||||
reinterpret_cast<const char*>(&file_opt),
|
||||
pair.second, pair.first, nullptr)) {
|
||||
return Status::Corruption(
|
||||
"[RocksDBOptionsParser]: "
|
||||
"failed the verification on BlockBasedTableOptions::",
|
||||
pair.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
TableFactory* NewBlockBasedTableFactory(
|
||||
const BlockBasedTableOptions& _table_options) {
|
||||
return new BlockBasedTableFactory(_table_options);
|
||||
}
|
||||
|
||||
const std::string BlockBasedTableFactory::kName = "BlockBasedTable";
|
||||
const std::string BlockBasedTablePropertyNames::kIndexType =
|
||||
"rocksdb.block.based.table.index.type";
|
||||
const std::string BlockBasedTablePropertyNames::kWholeKeyFiltering =
|
||||
|
@ -13,9 +13,11 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "db/dbformat.h"
|
||||
#include "options/options_helper.h"
|
||||
#include "options/options_parser.h"
|
||||
#include "rocksdb/flush_block_policy.h"
|
||||
#include "rocksdb/table.h"
|
||||
#include "db/dbformat.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
@ -31,7 +33,7 @@ class BlockBasedTableFactory : public TableFactory {
|
||||
|
||||
~BlockBasedTableFactory() {}
|
||||
|
||||
const char* Name() const override { return "BlockBasedTable"; }
|
||||
const char* Name() const override { return kName.c_str(); }
|
||||
|
||||
Status NewTableReader(
|
||||
const TableReaderOptions& table_reader_options,
|
||||
@ -49,12 +51,17 @@ class BlockBasedTableFactory : public TableFactory {
|
||||
|
||||
std::string GetPrintableTableOptions() const override;
|
||||
|
||||
Status GetOptionString(std::string* opt_string,
|
||||
const std::string& delimiter) const override;
|
||||
|
||||
const BlockBasedTableOptions& table_options() const;
|
||||
|
||||
void* GetOptions() override { return &table_options_; }
|
||||
|
||||
bool IsDeleteRangeSupported() const override { return true; }
|
||||
|
||||
static const std::string kName;
|
||||
|
||||
private:
|
||||
BlockBasedTableOptions table_options_;
|
||||
};
|
||||
@ -64,4 +71,87 @@ extern const std::string kHashIndexPrefixesMetadataBlock;
|
||||
extern const std::string kPropTrue;
|
||||
extern const std::string kPropFalse;
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
extern Status VerifyBlockBasedTableFactory(
|
||||
const BlockBasedTableFactory* base_tf,
|
||||
const BlockBasedTableFactory* file_tf,
|
||||
OptionsSanityCheckLevel sanity_check_level);
|
||||
|
||||
static std::unordered_map<std::string, OptionTypeInfo>
|
||||
block_based_table_type_info = {
|
||||
/* currently not supported
|
||||
std::shared_ptr<Cache> block_cache = nullptr;
|
||||
std::shared_ptr<Cache> block_cache_compressed = nullptr;
|
||||
*/
|
||||
{"flush_block_policy_factory",
|
||||
{offsetof(struct BlockBasedTableOptions, flush_block_policy_factory),
|
||||
OptionType::kFlushBlockPolicyFactory, OptionVerificationType::kByName,
|
||||
false, 0}},
|
||||
{"cache_index_and_filter_blocks",
|
||||
{offsetof(struct BlockBasedTableOptions,
|
||||
cache_index_and_filter_blocks),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
|
||||
{"cache_index_and_filter_blocks_with_high_priority",
|
||||
{offsetof(struct BlockBasedTableOptions,
|
||||
cache_index_and_filter_blocks_with_high_priority),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
|
||||
{"pin_l0_filter_and_index_blocks_in_cache",
|
||||
{offsetof(struct BlockBasedTableOptions,
|
||||
pin_l0_filter_and_index_blocks_in_cache),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
|
||||
{"index_type",
|
||||
{offsetof(struct BlockBasedTableOptions, index_type),
|
||||
OptionType::kBlockBasedTableIndexType,
|
||||
OptionVerificationType::kNormal, false, 0}},
|
||||
{"hash_index_allow_collision",
|
||||
{offsetof(struct BlockBasedTableOptions, hash_index_allow_collision),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
|
||||
{"checksum",
|
||||
{offsetof(struct BlockBasedTableOptions, checksum),
|
||||
OptionType::kChecksumType, OptionVerificationType::kNormal, false,
|
||||
0}},
|
||||
{"no_block_cache",
|
||||
{offsetof(struct BlockBasedTableOptions, no_block_cache),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
|
||||
{"block_size",
|
||||
{offsetof(struct BlockBasedTableOptions, block_size),
|
||||
OptionType::kSizeT, OptionVerificationType::kNormal, false, 0}},
|
||||
{"block_size_deviation",
|
||||
{offsetof(struct BlockBasedTableOptions, block_size_deviation),
|
||||
OptionType::kInt, OptionVerificationType::kNormal, false, 0}},
|
||||
{"block_restart_interval",
|
||||
{offsetof(struct BlockBasedTableOptions, block_restart_interval),
|
||||
OptionType::kInt, OptionVerificationType::kNormal, false, 0}},
|
||||
{"index_block_restart_interval",
|
||||
{offsetof(struct BlockBasedTableOptions, index_block_restart_interval),
|
||||
OptionType::kInt, OptionVerificationType::kNormal, false, 0}},
|
||||
{"index_per_partition",
|
||||
{0, OptionType::kUInt64T, OptionVerificationType::kDeprecated, false,
|
||||
0}},
|
||||
{"metadata_block_size",
|
||||
{offsetof(struct BlockBasedTableOptions, metadata_block_size),
|
||||
OptionType::kUInt64T, OptionVerificationType::kNormal, false, 0}},
|
||||
{"partition_filters",
|
||||
{offsetof(struct BlockBasedTableOptions, partition_filters),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
|
||||
{"filter_policy",
|
||||
{offsetof(struct BlockBasedTableOptions, filter_policy),
|
||||
OptionType::kFilterPolicy, OptionVerificationType::kByName, false,
|
||||
0}},
|
||||
{"whole_key_filtering",
|
||||
{offsetof(struct BlockBasedTableOptions, whole_key_filtering),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
|
||||
{"skip_table_builder_flush",
|
||||
{0, OptionType::kBoolean, OptionVerificationType::kDeprecated, false,
|
||||
0}},
|
||||
{"format_version",
|
||||
{offsetof(struct BlockBasedTableOptions, format_version),
|
||||
OptionType::kUInt32T, OptionVerificationType::kNormal, false, 0}},
|
||||
{"verify_compression",
|
||||
{offsetof(struct BlockBasedTableOptions, verify_compression),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
|
||||
{"read_amp_bytes_per_bit",
|
||||
{offsetof(struct BlockBasedTableOptions, read_amp_bytes_per_bit),
|
||||
OptionType::kSizeT, OptionVerificationType::kNormal, false, 0}}};
|
||||
#endif // !ROCKSDB_LITE
|
||||
} // namespace rocksdb
|
||||
|
@ -76,6 +76,11 @@ class CuckooTableFactory : public TableFactory {
|
||||
|
||||
void* GetOptions() override { return &table_options_; }
|
||||
|
||||
Status GetOptionString(std::string* opt_string,
|
||||
const std::string& delimiter) const override {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
private:
|
||||
CuckooTableOptions table_options_;
|
||||
};
|
||||
|
@ -5,12 +5,15 @@
|
||||
#ifndef ROCKSDB_LITE
|
||||
#include "table/plain_table_factory.h"
|
||||
|
||||
#include <memory>
|
||||
#include <stdint.h>
|
||||
#include <memory>
|
||||
#include "db/dbformat.h"
|
||||
#include "options/options_helper.h"
|
||||
#include "port/port.h"
|
||||
#include "rocksdb/convenience.h"
|
||||
#include "table/plain_table_builder.h"
|
||||
#include "table/plain_table_reader.h"
|
||||
#include "port/port.h"
|
||||
#include "util/string_util.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
@ -81,6 +84,143 @@ const PlainTableOptions& PlainTableFactory::table_options() const {
|
||||
return table_options_;
|
||||
}
|
||||
|
||||
Status GetPlainTableOptionsFromString(const PlainTableOptions& table_options,
|
||||
const std::string& opts_str,
|
||||
PlainTableOptions* new_table_options) {
|
||||
std::unordered_map<std::string, std::string> opts_map;
|
||||
Status s = StringToMap(opts_str, &opts_map);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
return GetPlainTableOptionsFromMap(table_options, opts_map,
|
||||
new_table_options);
|
||||
}
|
||||
|
||||
Status GetMemTableRepFactoryFromString(
|
||||
const std::string& opts_str,
|
||||
std::unique_ptr<MemTableRepFactory>* new_mem_factory) {
|
||||
std::vector<std::string> opts_list = StringSplit(opts_str, ':');
|
||||
size_t len = opts_list.size();
|
||||
|
||||
if (opts_list.size() <= 0 || opts_list.size() > 2) {
|
||||
return Status::InvalidArgument("Can't parse memtable_factory option ",
|
||||
opts_str);
|
||||
}
|
||||
|
||||
MemTableRepFactory* mem_factory = nullptr;
|
||||
|
||||
if (opts_list[0] == "skip_list") {
|
||||
// Expecting format
|
||||
// skip_list:<lookahead>
|
||||
if (2 == len) {
|
||||
size_t lookahead = ParseSizeT(opts_list[1]);
|
||||
mem_factory = new SkipListFactory(lookahead);
|
||||
} else if (1 == len) {
|
||||
mem_factory = new SkipListFactory();
|
||||
}
|
||||
} else if (opts_list[0] == "prefix_hash") {
|
||||
// Expecting format
|
||||
// prfix_hash:<hash_bucket_count>
|
||||
if (2 == len) {
|
||||
size_t hash_bucket_count = ParseSizeT(opts_list[1]);
|
||||
mem_factory = NewHashSkipListRepFactory(hash_bucket_count);
|
||||
} else if (1 == len) {
|
||||
mem_factory = NewHashSkipListRepFactory();
|
||||
}
|
||||
} else if (opts_list[0] == "hash_linkedlist") {
|
||||
// Expecting format
|
||||
// hash_linkedlist:<hash_bucket_count>
|
||||
if (2 == len) {
|
||||
size_t hash_bucket_count = ParseSizeT(opts_list[1]);
|
||||
mem_factory = NewHashLinkListRepFactory(hash_bucket_count);
|
||||
} else if (1 == len) {
|
||||
mem_factory = NewHashLinkListRepFactory();
|
||||
}
|
||||
} else if (opts_list[0] == "vector") {
|
||||
// Expecting format
|
||||
// vector:<count>
|
||||
if (2 == len) {
|
||||
size_t count = ParseSizeT(opts_list[1]);
|
||||
mem_factory = new VectorRepFactory(count);
|
||||
} else if (1 == len) {
|
||||
mem_factory = new VectorRepFactory();
|
||||
}
|
||||
} else if (opts_list[0] == "cuckoo") {
|
||||
// Expecting format
|
||||
// cuckoo:<write_buffer_size>
|
||||
if (2 == len) {
|
||||
size_t write_buffer_size = ParseSizeT(opts_list[1]);
|
||||
mem_factory = NewHashCuckooRepFactory(write_buffer_size);
|
||||
} else if (1 == len) {
|
||||
return Status::InvalidArgument("Can't parse memtable_factory option ",
|
||||
opts_str);
|
||||
}
|
||||
} else {
|
||||
return Status::InvalidArgument("Unrecognized memtable_factory option ",
|
||||
opts_str);
|
||||
}
|
||||
|
||||
if (mem_factory != nullptr) {
|
||||
new_mem_factory->reset(mem_factory);
|
||||
}
|
||||
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
std::string ParsePlainTableOptions(const std::string& name,
|
||||
const std::string& org_value,
|
||||
PlainTableOptions* new_options,
|
||||
bool input_strings_escaped = false,
|
||||
bool ignore_unknown_options = false) {
|
||||
const std::string& value =
|
||||
input_strings_escaped ? UnescapeOptionString(org_value) : org_value;
|
||||
const auto iter = plain_table_type_info.find(name);
|
||||
if (iter == plain_table_type_info.end()) {
|
||||
if (ignore_unknown_options) {
|
||||
return "";
|
||||
} else {
|
||||
return "Unrecognized option";
|
||||
}
|
||||
}
|
||||
const auto& opt_info = iter->second;
|
||||
if (opt_info.verification != OptionVerificationType::kDeprecated &&
|
||||
!ParseOptionHelper(reinterpret_cast<char*>(new_options) + opt_info.offset,
|
||||
opt_info.type, value)) {
|
||||
return "Invalid value";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
Status GetPlainTableOptionsFromMap(
|
||||
const PlainTableOptions& table_options,
|
||||
const std::unordered_map<std::string, std::string>& opts_map,
|
||||
PlainTableOptions* new_table_options, bool input_strings_escaped,
|
||||
bool ignore_unknown_options) {
|
||||
assert(new_table_options);
|
||||
*new_table_options = table_options;
|
||||
for (const auto& o : opts_map) {
|
||||
auto error_message = ParsePlainTableOptions(
|
||||
o.first, o.second, new_table_options, input_strings_escaped);
|
||||
if (error_message != "") {
|
||||
const auto iter = plain_table_type_info.find(o.first);
|
||||
if (iter == plain_table_type_info.end() ||
|
||||
!input_strings_escaped || // !input_strings_escaped indicates
|
||||
// the old API, where everything is
|
||||
// parsable.
|
||||
(iter->second.verification != OptionVerificationType::kByName &&
|
||||
iter->second.verification !=
|
||||
OptionVerificationType::kByNameAllowNull &&
|
||||
iter->second.verification != OptionVerificationType::kDeprecated)) {
|
||||
// Restore "new_options" to the default "base_options".
|
||||
*new_table_options = table_options;
|
||||
return Status::InvalidArgument("Can't parse PlainTableOptions:",
|
||||
o.first + " " + error_message);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
extern TableFactory* NewPlainTableFactory(const PlainTableOptions& options) {
|
||||
return new PlainTableFactory(options);
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "options/options_helper.h"
|
||||
#include "rocksdb/options.h"
|
||||
#include "rocksdb/table.h"
|
||||
|
||||
@ -170,9 +171,40 @@ class PlainTableFactory : public TableFactory {
|
||||
|
||||
void* GetOptions() override { return &table_options_; }
|
||||
|
||||
Status GetOptionString(std::string* opt_string,
|
||||
const std::string& delimiter) const override {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
private:
|
||||
PlainTableOptions table_options_;
|
||||
};
|
||||
|
||||
static std::unordered_map<std::string, OptionTypeInfo> plain_table_type_info = {
|
||||
{"user_key_len",
|
||||
{offsetof(struct PlainTableOptions, user_key_len), OptionType::kUInt32T,
|
||||
OptionVerificationType::kNormal, false, 0}},
|
||||
{"bloom_bits_per_key",
|
||||
{offsetof(struct PlainTableOptions, bloom_bits_per_key), OptionType::kInt,
|
||||
OptionVerificationType::kNormal, false, 0}},
|
||||
{"hash_table_ratio",
|
||||
{offsetof(struct PlainTableOptions, hash_table_ratio), OptionType::kDouble,
|
||||
OptionVerificationType::kNormal, false, 0}},
|
||||
{"index_sparseness",
|
||||
{offsetof(struct PlainTableOptions, index_sparseness), OptionType::kSizeT,
|
||||
OptionVerificationType::kNormal, false, 0}},
|
||||
{"huge_page_tlb_size",
|
||||
{offsetof(struct PlainTableOptions, huge_page_tlb_size),
|
||||
OptionType::kSizeT, OptionVerificationType::kNormal, false, 0}},
|
||||
{"encoding_type",
|
||||
{offsetof(struct PlainTableOptions, encoding_type),
|
||||
OptionType::kEncodingType, OptionVerificationType::kByName, false, 0}},
|
||||
{"full_scan_mode",
|
||||
{offsetof(struct PlainTableOptions, full_scan_mode), OptionType::kBoolean,
|
||||
OptionVerificationType::kNormal, false, 0}},
|
||||
{"store_index_in_file",
|
||||
{offsetof(struct PlainTableOptions, store_index_in_file),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}}};
|
||||
|
||||
} // namespace rocksdb
|
||||
#endif // ROCKSDB_LITE
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
@ -57,6 +58,7 @@
|
||||
#include "rocksdb/utilities/transaction.h"
|
||||
#include "rocksdb/utilities/transaction_db.h"
|
||||
#include "rocksdb/write_batch.h"
|
||||
#include "util/cast_util.h"
|
||||
#include "util/compression.h"
|
||||
#include "util/crc32c.h"
|
||||
#include "util/mutexlock.h"
|
||||
@ -2551,7 +2553,9 @@ void VerifyDBFromDB(std::string& truth_db_name) {
|
||||
}
|
||||
if (FLAGS_simcache_size >= 0) {
|
||||
fprintf(stdout, "SIMULATOR CACHE STATISTICS:\n%s\n",
|
||||
std::dynamic_pointer_cast<SimCache>(cache_)->ToString().c_str());
|
||||
static_cast_with_check<SimCache, Cache>(cache_.get())
|
||||
->ToString()
|
||||
.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "table/scoped_arena_iterator.h"
|
||||
#include "tools/ldb_cmd_impl.h"
|
||||
#include "tools/sst_dump_tool_imp.h"
|
||||
#include "util/cast_util.h"
|
||||
#include "util/coding.h"
|
||||
#include "util/filename.h"
|
||||
#include "util/stderr_logger.h"
|
||||
@ -1493,8 +1494,7 @@ void DBDumperCommand::DoDumpCommand() {
|
||||
if (max_keys == 0)
|
||||
break;
|
||||
if (is_db_ttl_) {
|
||||
TtlIterator* it_ttl = dynamic_cast<TtlIterator*>(iter);
|
||||
assert(it_ttl);
|
||||
TtlIterator* it_ttl = static_cast_with_check<TtlIterator, Iterator>(iter);
|
||||
rawtime = it_ttl->timestamp();
|
||||
if (rawtime < ttl_start || rawtime >= ttl_end) {
|
||||
continue;
|
||||
@ -2291,8 +2291,7 @@ void ScanCommand::DoCommand() {
|
||||
it->Valid() && (!end_key_specified_ || it->key().ToString() < end_key_);
|
||||
it->Next()) {
|
||||
if (is_db_ttl_) {
|
||||
TtlIterator* it_ttl = dynamic_cast<TtlIterator*>(it);
|
||||
assert(it_ttl);
|
||||
TtlIterator* it_ttl = static_cast_with_check<TtlIterator, Iterator>(it);
|
||||
int rawtime = it_ttl->timestamp();
|
||||
if (rawtime < ttl_start || rawtime >= ttl_end) {
|
||||
continue;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <inttypes.h>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
@ -42,8 +43,6 @@
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
using std::dynamic_pointer_cast;
|
||||
|
||||
SstFileReader::SstFileReader(const std::string& file_path,
|
||||
bool verify_checksum,
|
||||
bool output_hex)
|
||||
@ -115,18 +114,13 @@ Status SstFileReader::NewTableReader(
|
||||
unique_ptr<TableReader>* table_reader) {
|
||||
// We need to turn off pre-fetching of index and filter nodes for
|
||||
// BlockBasedTable
|
||||
shared_ptr<BlockBasedTableFactory> block_table_factory =
|
||||
dynamic_pointer_cast<BlockBasedTableFactory>(options_.table_factory);
|
||||
|
||||
if (block_table_factory) {
|
||||
return block_table_factory->NewTableReader(
|
||||
if (BlockBasedTableFactory::kName == options_.table_factory->Name()) {
|
||||
return options_.table_factory->NewTableReader(
|
||||
TableReaderOptions(ioptions_, soptions_, internal_comparator_,
|
||||
/*skip_filters=*/false),
|
||||
std::move(file_), file_size, &table_reader_, /*enable_prefetch=*/false);
|
||||
}
|
||||
|
||||
assert(!block_table_factory);
|
||||
|
||||
// For all other factory implementation
|
||||
return options_.table_factory->NewTableReader(
|
||||
TableReaderOptions(ioptions_, soptions_, internal_comparator_),
|
||||
|
19
util/cast_util.h
Normal file
19
util/cast_util.h
Normal file
@ -0,0 +1,19 @@
|
||||
// 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).
|
||||
|
||||
namespace rocksdb {
|
||||
// The helper function to assert the move from dynamic_cast<> to
|
||||
// static_cast<> is correct. This function is to deal with legacy code.
|
||||
// It is not recommanded to add new code to issue class casting. The preferred
|
||||
// solution is to implement the functionality without a need of casting.
|
||||
template <class DestClass, class SrcClass>
|
||||
inline DestClass* static_cast_with_check(SrcClass* x) {
|
||||
DestClass* ret = static_cast<DestClass*>(x);
|
||||
#ifdef ROCKSDB_USE_RTTI
|
||||
assert(ret == dynamic_cast<DestClass*>(x));
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
} // namespace rocksdb
|
@ -23,6 +23,7 @@
|
||||
#include "table/block_based_table_builder.h"
|
||||
#include "table/block_builder.h"
|
||||
#include "table/meta_blocks.h"
|
||||
#include "util/cast_util.h"
|
||||
#include "util/crc32c.h"
|
||||
#include "util/file_reader_writer.h"
|
||||
#include "util/filename.h"
|
||||
@ -199,7 +200,8 @@ BlobDBImpl::BlobDBImpl(const std::string& dbname,
|
||||
open_p1_done_(false),
|
||||
debug_level_(0) {
|
||||
const BlobDBOptionsImpl* options_impl =
|
||||
dynamic_cast<const BlobDBOptionsImpl*>(&blob_db_options);
|
||||
static_cast_with_check<const BlobDBOptionsImpl, const BlobDBOptions>(
|
||||
&blob_db_options);
|
||||
if (options_impl) {
|
||||
bdb_options_ = *options_impl;
|
||||
}
|
||||
@ -215,12 +217,7 @@ Status BlobDBImpl::LinkToBaseDB(DB* db) {
|
||||
db_ = db;
|
||||
|
||||
// the Base DB in-itself can be a stackable DB
|
||||
StackableDB* sdb = dynamic_cast<StackableDB*>(db_);
|
||||
if (sdb) {
|
||||
db_impl_ = dynamic_cast<DBImpl*>(sdb->GetBaseDB());
|
||||
} else {
|
||||
db_impl_ = dynamic_cast<DBImpl*>(db);
|
||||
}
|
||||
db_impl_ = static_cast_with_check<DBImpl, DB>(db_->GetRootDB());
|
||||
|
||||
env_ = db_->GetEnv();
|
||||
|
||||
@ -249,7 +246,7 @@ BlobDBOptions BlobDBImpl::GetBlobDBOptions() const { return bdb_options_; }
|
||||
|
||||
BlobDBImpl::BlobDBImpl(DB* db, const BlobDBOptions& blob_db_options)
|
||||
: BlobDB(db),
|
||||
db_impl_(dynamic_cast<DBImpl*>(db)),
|
||||
db_impl_(static_cast_with_check<DBImpl, DB>(db)),
|
||||
opt_db_(new OptimisticTransactionDBImpl(db, false)),
|
||||
wo_set_(false),
|
||||
bdb_options_(blob_db_options),
|
||||
@ -268,10 +265,9 @@ BlobDBImpl::BlobDBImpl(DB* db, const BlobDBOptions& blob_db_options)
|
||||
total_blob_space_(0) {
|
||||
assert(db_impl_ != nullptr);
|
||||
const BlobDBOptionsImpl* options_impl =
|
||||
dynamic_cast<const BlobDBOptionsImpl*>(&blob_db_options);
|
||||
if (options_impl) {
|
||||
bdb_options_ = *options_impl;
|
||||
}
|
||||
static_cast_with_check<const BlobDBOptionsImpl, const BlobDBOptions>(
|
||||
&blob_db_options);
|
||||
bdb_options_ = *options_impl;
|
||||
|
||||
if (!bdb_options_.blob_dir.empty())
|
||||
blob_dir_ = (bdb_options_.path_relative)
|
||||
@ -1752,8 +1748,8 @@ Status BlobDBImpl::GCFileAndUpdateLSM(const std::shared_ptr<BlobFile>& bfptr,
|
||||
gcstats->deleted_size += record.GetBlobSize();
|
||||
if (first_gc) continue;
|
||||
|
||||
Transaction* txn = static_cast<OptimisticTransactionDB*>(opt_db_.get())
|
||||
->BeginTransaction(write_options_);
|
||||
Transaction* txn = opt_db_->BeginTransaction(
|
||||
write_options_, OptimisticTransactionOptions(), nullptr);
|
||||
txn->Delete(cfh, record.Key());
|
||||
Status s1 = txn->Commit();
|
||||
// chances that this DELETE will fail is low. If it fails, it would be
|
||||
@ -1817,8 +1813,8 @@ Status BlobDBImpl::GCFileAndUpdateLSM(const std::shared_ptr<BlobFile>& bfptr,
|
||||
newfile->file_size_ += BlobLogRecord::kHeaderSize + record.Key().size() +
|
||||
record.Blob().size() + BlobLogRecord::kFooterSize;
|
||||
|
||||
Transaction* txn = static_cast<OptimisticTransactionDB*>(opt_db_.get())
|
||||
->BeginTransaction(write_options_);
|
||||
Transaction* txn = opt_db_->BeginTransaction(
|
||||
write_options_, OptimisticTransactionOptions(), nullptr);
|
||||
txn->Put(cfh, record.Key(), index_entry);
|
||||
Status s1 = txn->Commit();
|
||||
// chances that this Put will fail is low. If it fails, it would be because
|
||||
|
@ -51,11 +51,9 @@ void ColumnAwareEncodingReader::InitTableReader(const std::string& file_path) {
|
||||
|
||||
options_.comparator = &internal_comparator_;
|
||||
options_.table_factory = std::make_shared<BlockBasedTableFactory>();
|
||||
shared_ptr<BlockBasedTableFactory> block_table_factory =
|
||||
std::dynamic_pointer_cast<BlockBasedTableFactory>(options_.table_factory);
|
||||
|
||||
std::unique_ptr<TableReader> table_reader;
|
||||
block_table_factory->NewTableReader(
|
||||
options_.table_factory->NewTableReader(
|
||||
TableReaderOptions(ioptions_, soptions_, internal_comparator_,
|
||||
/*skip_filters=*/false),
|
||||
std::move(file_), file_size, &table_reader, /*enable_prefetch=*/false);
|
||||
|
@ -100,28 +100,34 @@ class DummyTableFactory : public TableFactory {
|
||||
DummyTableFactory() {}
|
||||
virtual ~DummyTableFactory() {}
|
||||
|
||||
virtual const char* Name() const { return "DummyTableFactory"; }
|
||||
virtual const char* Name() const override { return "DummyTableFactory"; }
|
||||
|
||||
virtual Status NewTableReader(const TableReaderOptions& table_reader_options,
|
||||
unique_ptr<RandomAccessFileReader>&& file,
|
||||
uint64_t file_size,
|
||||
unique_ptr<TableReader>* table_reader,
|
||||
bool prefetch_index_and_filter_in_cache) const {
|
||||
virtual Status NewTableReader(
|
||||
const TableReaderOptions& table_reader_options,
|
||||
unique_ptr<RandomAccessFileReader>&& file, uint64_t file_size,
|
||||
unique_ptr<TableReader>* table_reader,
|
||||
bool prefetch_index_and_filter_in_cache) const override {
|
||||
return Status::NotSupported();
|
||||
}
|
||||
|
||||
virtual TableBuilder* NewTableBuilder(
|
||||
const TableBuilderOptions& table_builder_options,
|
||||
uint32_t column_family_id, WritableFileWriter* file) const {
|
||||
uint32_t column_family_id, WritableFileWriter* file) const override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual Status SanitizeOptions(const DBOptions& db_opts,
|
||||
const ColumnFamilyOptions& cf_opts) const {
|
||||
virtual Status SanitizeOptions(
|
||||
const DBOptions& db_opts,
|
||||
const ColumnFamilyOptions& cf_opts) const override {
|
||||
return Status::NotSupported();
|
||||
}
|
||||
|
||||
virtual std::string GetPrintableTableOptions() const { return ""; }
|
||||
virtual std::string GetPrintableTableOptions() const override { return ""; }
|
||||
|
||||
Status GetOptionString(std::string* opt_string,
|
||||
const std::string& delimiter) const override {
|
||||
return Status::OK();
|
||||
}
|
||||
};
|
||||
|
||||
class DummyMergeOperator : public MergeOperator {
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/status.h"
|
||||
#include "rocksdb/utilities/optimistic_transaction_db.h"
|
||||
#include "util/cast_util.h"
|
||||
#include "util/string_util.h"
|
||||
#include "utilities/transactions/transaction_util.h"
|
||||
|
||||
@ -62,13 +63,7 @@ Status OptimisticTransactionImpl::Commit() {
|
||||
// check whether this transaction is safe to be committed.
|
||||
OptimisticTransactionCallback callback(this);
|
||||
|
||||
DBImpl* db_impl = dynamic_cast<DBImpl*>(db_->GetRootDB());
|
||||
if (db_impl == nullptr) {
|
||||
// This should only happen if we support creating transactions from
|
||||
// a StackableDB and someone overrides GetRootDB().
|
||||
return Status::InvalidArgument(
|
||||
"DB::GetRootDB() returned an unexpected DB class");
|
||||
}
|
||||
DBImpl* db_impl = static_cast_with_check<DBImpl, DB>(db_->GetRootDB());
|
||||
|
||||
Status s = db_impl->WriteWithCallback(
|
||||
write_options_, GetWriteBatch()->GetWriteBatch(), &callback);
|
||||
@ -122,8 +117,7 @@ Status OptimisticTransactionImpl::TryLock(ColumnFamilyHandle* column_family,
|
||||
Status OptimisticTransactionImpl::CheckTransactionForConflicts(DB* db) {
|
||||
Status result;
|
||||
|
||||
assert(dynamic_cast<DBImpl*>(db) != nullptr);
|
||||
auto db_impl = reinterpret_cast<DBImpl*>(db);
|
||||
auto db_impl = static_cast_with_check<DBImpl, DB>(db);
|
||||
|
||||
// Since we are on the write thread and do not want to block other writers,
|
||||
// we will do a cache-only conflict check. This can result in TryAgain
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/options.h"
|
||||
#include "rocksdb/utilities/transaction_db.h"
|
||||
#include "util/cast_util.h"
|
||||
#include "utilities/transactions/transaction_db_mutex_impl.h"
|
||||
#include "utilities/transactions/transaction_impl.h"
|
||||
|
||||
@ -23,7 +24,7 @@ namespace rocksdb {
|
||||
TransactionDBImpl::TransactionDBImpl(DB* db,
|
||||
const TransactionDBOptions& txn_db_options)
|
||||
: TransactionDB(db),
|
||||
db_impl_(dynamic_cast<DBImpl*>(db)),
|
||||
db_impl_(static_cast_with_check<DBImpl, DB>(db)),
|
||||
txn_db_options_(txn_db_options),
|
||||
lock_mgr_(this, txn_db_options_.num_stripes, txn_db_options.max_num_locks,
|
||||
txn_db_options_.custom_mutex_factory
|
||||
@ -52,7 +53,7 @@ TransactionDBImpl::TransactionDBImpl(DB* db,
|
||||
TransactionDBImpl::TransactionDBImpl(StackableDB* db,
|
||||
const TransactionDBOptions& txn_db_options)
|
||||
: TransactionDB(db),
|
||||
db_impl_(dynamic_cast<DBImpl*>(db->GetRootDB())),
|
||||
db_impl_(static_cast_with_check<DBImpl, DB>(db->GetRootDB())),
|
||||
txn_db_options_(txn_db_options),
|
||||
lock_mgr_(this, txn_db_options_.num_stripes, txn_db_options.max_num_locks,
|
||||
txn_db_options_.custom_mutex_factory
|
||||
@ -371,8 +372,7 @@ Status TransactionDBImpl::Write(const WriteOptions& opts, WriteBatch* updates) {
|
||||
Transaction* txn = BeginInternalTransaction(opts);
|
||||
txn->DisableIndexing();
|
||||
|
||||
assert(dynamic_cast<TransactionImpl*>(txn) != nullptr);
|
||||
auto txn_impl = reinterpret_cast<TransactionImpl*>(txn);
|
||||
auto txn_impl = static_cast_with_check<TransactionImpl, Transaction>(txn);
|
||||
|
||||
// Since commitBatch sorts the keys before locking, concurrent Write()
|
||||
// operations will not cause a deadlock.
|
||||
@ -412,8 +412,7 @@ bool TransactionDBImpl::TryStealingExpiredTransactionLocks(
|
||||
void TransactionDBImpl::ReinitializeTransaction(
|
||||
Transaction* txn, const WriteOptions& write_options,
|
||||
const TransactionOptions& txn_options) {
|
||||
assert(dynamic_cast<TransactionImpl*>(txn) != nullptr);
|
||||
auto txn_impl = reinterpret_cast<TransactionImpl*>(txn);
|
||||
auto txn_impl = static_cast_with_check<TransactionImpl, Transaction>(txn);
|
||||
|
||||
txn_impl->Reinitialize(this, write_options, txn_options);
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "rocksdb/snapshot.h"
|
||||
#include "rocksdb/status.h"
|
||||
#include "rocksdb/utilities/transaction_db.h"
|
||||
#include "util/cast_util.h"
|
||||
#include "util/string_util.h"
|
||||
#include "util/sync_point.h"
|
||||
#include "utilities/transactions/transaction_db_impl.h"
|
||||
@ -46,10 +47,9 @@ TransactionImpl::TransactionImpl(TransactionDB* txn_db,
|
||||
lock_timeout_(0),
|
||||
deadlock_detect_(false),
|
||||
deadlock_detect_depth_(0) {
|
||||
txn_db_impl_ = dynamic_cast<TransactionDBImpl*>(txn_db);
|
||||
assert(txn_db_impl_);
|
||||
db_impl_ = dynamic_cast<DBImpl*>(txn_db->GetRootDB());
|
||||
assert(db_impl_);
|
||||
txn_db_impl_ =
|
||||
static_cast_with_check<TransactionDBImpl, TransactionDB>(txn_db);
|
||||
db_impl_ = static_cast_with_check<DBImpl, DB>(txn_db->GetRootDB());
|
||||
Initialize(txn_options);
|
||||
}
|
||||
|
||||
@ -526,8 +526,7 @@ Status TransactionImpl::ValidateSnapshot(ColumnFamilyHandle* column_family,
|
||||
|
||||
*new_seqno = seq;
|
||||
|
||||
assert(dynamic_cast<DBImpl*>(db_) != nullptr);
|
||||
auto db_impl = reinterpret_cast<DBImpl*>(db_);
|
||||
auto db_impl = static_cast_with_check<DBImpl, DB>(db_);
|
||||
|
||||
ColumnFamilyHandle* cfh =
|
||||
column_family ? column_family : db_impl->DefaultColumnFamily();
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include "rocksdb/slice.h"
|
||||
#include "rocksdb/utilities/transaction_db_mutex.h"
|
||||
#include "util/cast_util.h"
|
||||
#include "util/murmurhash.h"
|
||||
#include "util/sync_point.h"
|
||||
#include "util/thread_local.h"
|
||||
@ -112,8 +113,9 @@ TransactionLockMgr::TransactionLockMgr(
|
||||
max_num_locks_(max_num_locks),
|
||||
lock_maps_cache_(new ThreadLocalPtr(&UnrefLockMapsCache)),
|
||||
mutex_factory_(mutex_factory) {
|
||||
txn_db_impl_ = dynamic_cast<TransactionDBImpl*>(txn_db);
|
||||
assert(txn_db_impl_);
|
||||
assert(txn_db);
|
||||
txn_db_impl_ =
|
||||
static_cast_with_check<TransactionDBImpl, TransactionDB>(txn_db);
|
||||
}
|
||||
|
||||
TransactionLockMgr::~TransactionLockMgr() {}
|
||||
|
Loading…
Reference in New Issue
Block a user