Deprecate CompactionFilterV2
Summary: It has been around for a while and it looks like it never found any uses in the wild. It's also complicating our compaction_job code quite a bit. We're deprecating it in 3.13, but will put it back in 3.14 if we actually find users that need this feature. Test Plan: make check Reviewers: noetzli, yhchiang, sdong Reviewed By: sdong Subscribers: dhruba, leveldb Differential Revision: https://reviews.facebook.net/D42405
This commit is contained in:
parent
1d20fa9d0f
commit
a96fcd09b7
@ -6,6 +6,7 @@
|
||||
* Deprecated WriteOptions::timeout_hint_us. We no longer support write timeout. If you really need this option, talk to us and we might consider returning it.
|
||||
* Deprecated purge_redundant_kvs_while_flush option.
|
||||
* Removed BackupEngine::NewBackupEngine() and NewReadOnlyBackupEngine() that were deprecated in RocksDB 3.8. Please use BackupEngine::Open() instead.
|
||||
* Deprecated Compaction Filter V2. We are not aware of any existing use-cases. If you use this filter, your compile will break with RocksDB 3.13. Please let us know if you use it and we'll put it back in RocksDB 3.14.
|
||||
|
||||
## 3.12.0 (7/2/2015)
|
||||
### New Features
|
||||
|
140
db/c.cc
140
db/c.cc
@ -39,8 +39,6 @@ using rocksdb::ColumnFamilyHandle;
|
||||
using rocksdb::ColumnFamilyOptions;
|
||||
using rocksdb::CompactionFilter;
|
||||
using rocksdb::CompactionFilterFactory;
|
||||
using rocksdb::CompactionFilterV2;
|
||||
using rocksdb::CompactionFilterFactoryV2;
|
||||
using rocksdb::CompactionFilterContext;
|
||||
using rocksdb::CompactionOptionsFIFO;
|
||||
using rocksdb::Comparator;
|
||||
@ -172,99 +170,6 @@ struct rocksdb_compactionfilterfactory_t : public CompactionFilterFactory {
|
||||
virtual const char* Name() const override { return (*name_)(state_); }
|
||||
};
|
||||
|
||||
struct rocksdb_compactionfilterv2_t : public CompactionFilterV2 {
|
||||
void* state_;
|
||||
void (*destructor_)(void*);
|
||||
const char* (*name_)(void*);
|
||||
void (*filter_)(void*, int level, size_t num_keys,
|
||||
const char* const* keys_list, const size_t* keys_list_sizes,
|
||||
const char* const* existing_values_list, const size_t* existing_values_list_sizes,
|
||||
char** new_values_list, size_t* new_values_list_sizes,
|
||||
unsigned char* to_delete_list);
|
||||
|
||||
virtual ~rocksdb_compactionfilterv2_t() {
|
||||
(*destructor_)(state_);
|
||||
}
|
||||
|
||||
virtual const char* Name() const override { return (*name_)(state_); }
|
||||
|
||||
virtual std::vector<bool> Filter(
|
||||
int level, const SliceVector& keys, const SliceVector& existing_values,
|
||||
std::vector<std::string>* new_values,
|
||||
std::vector<bool>* values_changed) const override {
|
||||
// Make a vector pointing to the underlying key data.
|
||||
size_t num_keys = keys.size();
|
||||
std::vector<const char*> keys_list(num_keys);
|
||||
std::vector<size_t> keys_list_sizes(num_keys);
|
||||
for (size_t i = 0; i < num_keys; ++i) {
|
||||
keys_list[i] = keys[i].data();
|
||||
keys_list_sizes[i] = keys[i].size();
|
||||
}
|
||||
// Make a vector pointing to the underlying value data.
|
||||
std::vector<const char*> existing_values_list(num_keys);
|
||||
std::vector<size_t> existing_values_list_sizes(num_keys);
|
||||
for (size_t i = 0; i < num_keys; ++i) {
|
||||
existing_values_list[i] = existing_values[i].data();
|
||||
existing_values_list_sizes[i] = existing_values[i].size();
|
||||
}
|
||||
// Make a vector which will accept newly-allocated char* arrays
|
||||
// which we will take ownership of and assign to strings in new_values.
|
||||
new_values->clear();
|
||||
std::vector<char*> new_values_list(num_keys);
|
||||
std::vector<size_t> new_values_list_sizes(num_keys);
|
||||
// Resize values_changed to hold all keys.
|
||||
values_changed->resize(num_keys);
|
||||
// Make a vector for bools indicating a value should be deleted
|
||||
// on compaction (true) or maintained (false).
|
||||
std::vector<unsigned char> to_delete_list(num_keys);
|
||||
|
||||
(*filter_)(
|
||||
state_, level, num_keys, &keys_list[0], &keys_list_sizes[0],
|
||||
&existing_values_list[0], &existing_values_list_sizes[0],
|
||||
&new_values_list[0], &new_values_list_sizes[0], &to_delete_list[0]);
|
||||
|
||||
// Now, we transfer any changed values, setting values_changed and
|
||||
// initializing new_values in the event a value changed.
|
||||
std::vector<bool> to_delete(num_keys);
|
||||
for (size_t i = 0; i < num_keys; ++i) {
|
||||
to_delete[i] = to_delete_list[i];
|
||||
(*values_changed)[i] = new_values_list[i] != nullptr;
|
||||
if ((*values_changed)[i]) {
|
||||
new_values->push_back(std::string(new_values_list[i], new_values_list_sizes[i]));
|
||||
free(new_values_list[i]);
|
||||
}
|
||||
}
|
||||
return to_delete;
|
||||
}
|
||||
};
|
||||
|
||||
struct rocksdb_compactionfilterfactoryv2_t : public CompactionFilterFactoryV2 {
|
||||
void* state_;
|
||||
void (*destructor_)(void*);
|
||||
const char* (*name_)(void*);
|
||||
rocksdb_compactionfilterv2_t* (*create_compaction_filter_v2_)(
|
||||
void* state, const rocksdb_compactionfiltercontext_t* context);
|
||||
|
||||
rocksdb_compactionfilterfactoryv2_t(const SliceTransform* prefix_extractor)
|
||||
: CompactionFilterFactoryV2(prefix_extractor) {
|
||||
}
|
||||
|
||||
virtual ~rocksdb_compactionfilterfactoryv2_t() {
|
||||
(*destructor_)(state_);
|
||||
}
|
||||
|
||||
virtual const char* Name() const override { return (*name_)(state_); }
|
||||
|
||||
virtual std::unique_ptr<CompactionFilterV2> CreateCompactionFilterV2(
|
||||
const CompactionFilterContext& context) override {
|
||||
struct rocksdb_compactionfiltercontext_t c_context;
|
||||
c_context.rep.is_full_compaction = context.is_full_compaction;
|
||||
c_context.rep.is_manual_compaction = context.is_manual_compaction;
|
||||
return std::unique_ptr<CompactionFilterV2>(
|
||||
(*create_compaction_filter_v2_)(state_, &c_context));
|
||||
}
|
||||
};
|
||||
|
||||
struct rocksdb_comparator_t : public Comparator {
|
||||
void* state_;
|
||||
void (*destructor_)(void*);
|
||||
@ -1490,11 +1395,6 @@ void rocksdb_options_set_merge_operator(
|
||||
opt->rep.merge_operator = std::shared_ptr<MergeOperator>(merge_operator);
|
||||
}
|
||||
|
||||
void rocksdb_options_set_compaction_filter_factory_v2(
|
||||
rocksdb_options_t* opt,
|
||||
rocksdb_compactionfilterfactoryv2_t* compaction_filter_factory_v2) {
|
||||
opt->rep.compaction_filter_factory_v2 = std::shared_ptr<CompactionFilterFactoryV2>(compaction_filter_factory_v2);
|
||||
}
|
||||
|
||||
void rocksdb_options_set_create_if_missing(
|
||||
rocksdb_options_t* opt, unsigned char v) {
|
||||
@ -2007,46 +1907,6 @@ void rocksdb_compactionfilterfactory_destroy(
|
||||
delete factory;
|
||||
}
|
||||
|
||||
rocksdb_compactionfilterv2_t* rocksdb_compactionfilterv2_create(
|
||||
void* state,
|
||||
void (*destructor)(void*),
|
||||
void (*filter)(void*, int level, size_t num_keys,
|
||||
const char* const* keys_list, const size_t* keys_list_sizes,
|
||||
const char* const* existing_values_list, const size_t* existing_values_list_sizes,
|
||||
char** new_values_list, size_t* new_values_list_sizes,
|
||||
unsigned char* to_delete_list),
|
||||
const char* (*name)(void*)) {
|
||||
rocksdb_compactionfilterv2_t* result = new rocksdb_compactionfilterv2_t;
|
||||
result->state_ = state;
|
||||
result->destructor_ = destructor;
|
||||
result->filter_ = filter;
|
||||
result->name_ = name;
|
||||
return result;
|
||||
}
|
||||
|
||||
void rocksdb_compactionfilterv2_destroy(rocksdb_compactionfilterv2_t* filter) {
|
||||
delete filter;
|
||||
}
|
||||
|
||||
rocksdb_compactionfilterfactoryv2_t* rocksdb_compactionfilterfactoryv2_create(
|
||||
void* state,
|
||||
rocksdb_slicetransform_t* prefix_extractor,
|
||||
void (*destructor)(void*),
|
||||
rocksdb_compactionfilterv2_t* (*create_compaction_filter_v2)(
|
||||
void* state, const rocksdb_compactionfiltercontext_t* context),
|
||||
const char* (*name)(void*)) {
|
||||
rocksdb_compactionfilterfactoryv2_t* result = new rocksdb_compactionfilterfactoryv2_t(prefix_extractor);
|
||||
result->state_ = state;
|
||||
result->destructor_ = destructor;
|
||||
result->create_compaction_filter_v2_ = create_compaction_filter_v2;
|
||||
result->name_ = name;
|
||||
return result;
|
||||
}
|
||||
|
||||
void rocksdb_compactionfilterfactoryv2_destroy(rocksdb_compactionfilterfactoryv2_t* factory) {
|
||||
delete factory;
|
||||
}
|
||||
|
||||
rocksdb_comparator_t* rocksdb_comparator_create(
|
||||
void* state,
|
||||
void (*destructor)(void*),
|
||||
|
117
db/c_test.c
117
db/c_test.c
@ -251,79 +251,6 @@ static rocksdb_t* CheckCompaction(rocksdb_t* db, rocksdb_options_t* options,
|
||||
return db;
|
||||
}
|
||||
|
||||
// Custom compaction filter V2.
|
||||
static void CompactionFilterV2Destroy(void* arg) { }
|
||||
static const char* CompactionFilterV2Name(void* arg) {
|
||||
return "TestCompactionFilterV2";
|
||||
}
|
||||
static void CompactionFilterV2Filter(
|
||||
void* arg, int level, size_t num_keys,
|
||||
const char* const* keys_list, const size_t* keys_list_sizes,
|
||||
const char* const* existing_values_list, const size_t* existing_values_list_sizes,
|
||||
char** new_values_list, size_t* new_values_list_sizes,
|
||||
unsigned char* to_delete_list) {
|
||||
size_t i;
|
||||
for (i = 0; i < num_keys; i++) {
|
||||
// If any value is "gc", it's removed.
|
||||
if (existing_values_list_sizes[i] == 2 && memcmp(existing_values_list[i], "gc", 2) == 0) {
|
||||
to_delete_list[i] = 1;
|
||||
} else if (existing_values_list_sizes[i] == 6 && memcmp(existing_values_list[i], "gc all", 6) == 0) {
|
||||
// If any value is "gc all", all keys are removed.
|
||||
size_t j;
|
||||
for (j = 0; j < num_keys; j++) {
|
||||
to_delete_list[j] = 1;
|
||||
}
|
||||
return;
|
||||
} else if (existing_values_list_sizes[i] == 6 && memcmp(existing_values_list[i], "change", 6) == 0) {
|
||||
// If value is "change", set changed value to "changed".
|
||||
size_t len;
|
||||
len = strlen("changed");
|
||||
new_values_list[i] = malloc(len);
|
||||
memcpy(new_values_list[i], "changed", len);
|
||||
new_values_list_sizes[i] = len;
|
||||
} else {
|
||||
// Otherwise, no keys are removed.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Custom prefix extractor for compaction filter V2 which extracts first 3 characters.
|
||||
static void CFV2PrefixExtractorDestroy(void* arg) { }
|
||||
static char* CFV2PrefixExtractorTransform(void* arg, const char* key, size_t length, size_t* dst_length) {
|
||||
// Verify keys are maximum length 4; this verifies fix for a
|
||||
// prior bug which was passing the RocksDB-encoded key with
|
||||
// logical timestamp suffix instead of parsed user key.
|
||||
if (length > 4) {
|
||||
fprintf(stderr, "%s:%d: %s: key %s is not user key\n", __FILE__, __LINE__, phase, key);
|
||||
abort();
|
||||
}
|
||||
*dst_length = length < 3 ? length : 3;
|
||||
return (char*)key;
|
||||
}
|
||||
static unsigned char CFV2PrefixExtractorInDomain(void* state, const char* key, size_t length) {
|
||||
return 1;
|
||||
}
|
||||
static unsigned char CFV2PrefixExtractorInRange(void* state, const char* key, size_t length) {
|
||||
return 1;
|
||||
}
|
||||
static const char* CFV2PrefixExtractorName(void* state) {
|
||||
return "TestCFV2PrefixExtractor";
|
||||
}
|
||||
|
||||
// Custom compaction filter factory V2.
|
||||
static void CompactionFilterFactoryV2Destroy(void* arg) {
|
||||
rocksdb_slicetransform_destroy((rocksdb_slicetransform_t*)arg);
|
||||
}
|
||||
static const char* CompactionFilterFactoryV2Name(void* arg) {
|
||||
return "TestCompactionFilterFactoryV2";
|
||||
}
|
||||
static rocksdb_compactionfilterv2_t* CompactionFilterFactoryV2Create(
|
||||
void* state, const rocksdb_compactionfiltercontext_t* context) {
|
||||
return rocksdb_compactionfilterv2_create(state, CompactionFilterV2Destroy,
|
||||
CompactionFilterV2Filter,
|
||||
CompactionFilterV2Name);
|
||||
}
|
||||
|
||||
// Custom merge operator
|
||||
static void MergeOperatorDestroy(void* arg) { }
|
||||
static const char* MergeOperatorName(void* arg) {
|
||||
@ -722,50 +649,6 @@ int main(int argc, char** argv) {
|
||||
rocksdb_options_destroy(options_with_filter_factory);
|
||||
}
|
||||
|
||||
StartPhase("compaction_filter_v2");
|
||||
{
|
||||
rocksdb_compactionfilterfactoryv2_t* factory;
|
||||
rocksdb_slicetransform_t* prefix_extractor;
|
||||
prefix_extractor = rocksdb_slicetransform_create(
|
||||
NULL, CFV2PrefixExtractorDestroy, CFV2PrefixExtractorTransform,
|
||||
CFV2PrefixExtractorInDomain, CFV2PrefixExtractorInRange,
|
||||
CFV2PrefixExtractorName);
|
||||
factory = rocksdb_compactionfilterfactoryv2_create(
|
||||
prefix_extractor, prefix_extractor, CompactionFilterFactoryV2Destroy,
|
||||
CompactionFilterFactoryV2Create, CompactionFilterFactoryV2Name);
|
||||
// Create new database
|
||||
rocksdb_close(db);
|
||||
rocksdb_destroy_db(options, dbname, &err);
|
||||
rocksdb_options_set_compaction_filter_factory_v2(options, factory);
|
||||
db = rocksdb_open(options, dbname, &err);
|
||||
CheckNoError(err);
|
||||
// Only foo2 is GC'd, foo3 is changed.
|
||||
rocksdb_put(db, woptions, "foo1", 4, "no gc", 5, &err);
|
||||
CheckNoError(err);
|
||||
rocksdb_put(db, woptions, "foo2", 4, "gc", 2, &err);
|
||||
CheckNoError(err);
|
||||
rocksdb_put(db, woptions, "foo3", 4, "change", 6, &err);
|
||||
CheckNoError(err);
|
||||
// All bars are GC'd.
|
||||
rocksdb_put(db, woptions, "bar1", 4, "no gc", 5, &err);
|
||||
CheckNoError(err);
|
||||
rocksdb_put(db, woptions, "bar2", 4, "gc all", 6, &err);
|
||||
CheckNoError(err);
|
||||
rocksdb_put(db, woptions, "bar3", 4, "no gc", 5, &err);
|
||||
CheckNoError(err);
|
||||
// Compact the DB to garbage collect.
|
||||
rocksdb_compact_range(db, NULL, 0, NULL, 0);
|
||||
|
||||
// Verify foo entries.
|
||||
CheckGet(db, roptions, "foo1", "no gc");
|
||||
CheckGet(db, roptions, "foo2", NULL);
|
||||
CheckGet(db, roptions, "foo3", "changed");
|
||||
// Verify bar entries were all deleted.
|
||||
CheckGet(db, roptions, "bar1", NULL);
|
||||
CheckGet(db, roptions, "bar2", NULL);
|
||||
CheckGet(db, roptions, "bar3", NULL);
|
||||
}
|
||||
|
||||
StartPhase("merge_operator");
|
||||
{
|
||||
rocksdb_mergeoperator_t* merge_operator;
|
||||
|
@ -160,8 +160,7 @@ bool Compaction::IsTrivialMove() const {
|
||||
|
||||
if (is_manual_compaction_ &&
|
||||
(cfd_->ioptions()->compaction_filter != nullptr ||
|
||||
cfd_->ioptions()->compaction_filter_factory != nullptr ||
|
||||
cfd_->ioptions()->compaction_filter_factory_v2 != nullptr)) {
|
||||
cfd_->ioptions()->compaction_filter_factory != nullptr)) {
|
||||
// This is a manual compaction and we have a compaction filter that should
|
||||
// be executed, we cannot do a trivial move
|
||||
return false;
|
||||
@ -376,18 +375,4 @@ std::unique_ptr<CompactionFilter> Compaction::CreateCompactionFilter() const {
|
||||
context);
|
||||
}
|
||||
|
||||
std::unique_ptr<CompactionFilterV2>
|
||||
Compaction::CreateCompactionFilterV2() const {
|
||||
if (!cfd_->ioptions()->compaction_filter_factory_v2) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CompactionFilterContext context;
|
||||
context.is_full_compaction = is_full_compaction_;
|
||||
context.is_manual_compaction = is_manual_compaction_;
|
||||
return
|
||||
cfd_->ioptions()->compaction_filter_factory_v2->CreateCompactionFilterV2(
|
||||
context);
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
|
@ -30,7 +30,6 @@ class Version;
|
||||
class ColumnFamilyData;
|
||||
class VersionStorageInfo;
|
||||
class CompactionFilter;
|
||||
class CompactionFilterV2;
|
||||
|
||||
// A Compaction encapsulates information about a compaction.
|
||||
class Compaction {
|
||||
@ -195,9 +194,6 @@ class Compaction {
|
||||
// Create a CompactionFilter from compaction_filter_factory
|
||||
std::unique_ptr<CompactionFilter> CreateCompactionFilter() const;
|
||||
|
||||
// Create a CompactionFilterV2 from compaction_filter_factory_v2
|
||||
std::unique_ptr<CompactionFilterV2> CreateCompactionFilterV2() const;
|
||||
|
||||
private:
|
||||
// mark (or clear) all files that are being compacted
|
||||
void MarkFilesBeingCompacted(bool mark_as_compacted);
|
||||
|
@ -84,102 +84,8 @@ struct CompactionJob::CompactionState {
|
||||
num_input_records(0),
|
||||
num_output_records(0) {}
|
||||
|
||||
std::vector<std::string> key_str_buf_;
|
||||
std::vector<std::string> existing_value_str_buf_;
|
||||
// new_value_buf_ will only be appended if a value changes
|
||||
std::vector<std::string> new_value_buf_;
|
||||
// if values_changed_buf_[i] is true
|
||||
// new_value_buf_ will add a new entry with the changed value
|
||||
std::vector<bool> value_changed_buf_;
|
||||
// to_delete_buf_[i] is true iff key_buf_[i] is deleted
|
||||
std::vector<bool> to_delete_buf_;
|
||||
|
||||
std::vector<std::string> other_key_str_buf_;
|
||||
std::vector<std::string> other_value_str_buf_;
|
||||
|
||||
std::vector<Slice> combined_key_buf_;
|
||||
std::vector<Slice> combined_value_buf_;
|
||||
|
||||
std::string cur_prefix_;
|
||||
|
||||
uint64_t num_input_records;
|
||||
uint64_t num_output_records;
|
||||
|
||||
// Buffers the kv-pair that will be run through compaction filter V2
|
||||
// in the future.
|
||||
void BufferKeyValueSlices(const Slice& key, const Slice& value) {
|
||||
key_str_buf_.emplace_back(key.ToString());
|
||||
existing_value_str_buf_.emplace_back(value.ToString());
|
||||
}
|
||||
|
||||
// Buffers the kv-pair that will not be run through compaction filter V2
|
||||
// in the future.
|
||||
void BufferOtherKeyValueSlices(const Slice& key, const Slice& value) {
|
||||
other_key_str_buf_.emplace_back(key.ToString());
|
||||
other_value_str_buf_.emplace_back(value.ToString());
|
||||
}
|
||||
|
||||
// Add a kv-pair to the combined buffer
|
||||
void AddToCombinedKeyValueSlices(const Slice& key, const Slice& value) {
|
||||
// The real strings are stored in the batch buffers
|
||||
combined_key_buf_.emplace_back(key);
|
||||
combined_value_buf_.emplace_back(value);
|
||||
}
|
||||
|
||||
// Merging the two buffers
|
||||
void MergeKeyValueSliceBuffer(const InternalKeyComparator* comparator) {
|
||||
size_t i = 0;
|
||||
size_t j = 0;
|
||||
size_t total_size = key_str_buf_.size() + other_key_str_buf_.size();
|
||||
combined_key_buf_.reserve(total_size);
|
||||
combined_value_buf_.reserve(total_size);
|
||||
|
||||
while (i + j < total_size) {
|
||||
int comp_res = 0;
|
||||
if (i < key_str_buf_.size() && j < other_key_str_buf_.size()) {
|
||||
comp_res = comparator->Compare(key_str_buf_[i], other_key_str_buf_[j]);
|
||||
} else if (i >= key_str_buf_.size() && j < other_key_str_buf_.size()) {
|
||||
comp_res = 1;
|
||||
} else if (j >= other_key_str_buf_.size() && i < key_str_buf_.size()) {
|
||||
comp_res = -1;
|
||||
}
|
||||
if (comp_res > 0) {
|
||||
AddToCombinedKeyValueSlices(other_key_str_buf_[j],
|
||||
other_value_str_buf_[j]);
|
||||
j++;
|
||||
} else if (comp_res < 0) {
|
||||
AddToCombinedKeyValueSlices(key_str_buf_[i],
|
||||
existing_value_str_buf_[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CleanupBatchBuffer() {
|
||||
to_delete_buf_.clear();
|
||||
key_str_buf_.clear();
|
||||
existing_value_str_buf_.clear();
|
||||
new_value_buf_.clear();
|
||||
value_changed_buf_.clear();
|
||||
|
||||
to_delete_buf_.shrink_to_fit();
|
||||
key_str_buf_.shrink_to_fit();
|
||||
existing_value_str_buf_.shrink_to_fit();
|
||||
new_value_buf_.shrink_to_fit();
|
||||
value_changed_buf_.shrink_to_fit();
|
||||
|
||||
other_key_str_buf_.clear();
|
||||
other_value_str_buf_.clear();
|
||||
other_key_str_buf_.shrink_to_fit();
|
||||
other_value_str_buf_.shrink_to_fit();
|
||||
}
|
||||
|
||||
void CleanupMergedBuffer() {
|
||||
combined_key_buf_.clear();
|
||||
combined_value_buf_.clear();
|
||||
combined_key_buf_.shrink_to_fit();
|
||||
combined_value_buf_.shrink_to_fit();
|
||||
}
|
||||
};
|
||||
|
||||
CompactionJob::CompactionJob(
|
||||
@ -271,8 +177,6 @@ void CompactionJob::ReportStartedCompaction(
|
||||
void CompactionJob::Prepare() {
|
||||
AutoThreadOperationStageUpdater stage_updater(
|
||||
ThreadStatus::STAGE_COMPACTION_PREPARE);
|
||||
compact_->CleanupBatchBuffer();
|
||||
compact_->CleanupMergedBuffer();
|
||||
|
||||
// Generate file_levels_ for compaction berfore making Iterator
|
||||
ColumnFamilyData* cfd __attribute__((unused)) =
|
||||
@ -316,18 +220,8 @@ Status CompactionJob::Run() {
|
||||
versions_->MakeInputIterator(compact_->compaction));
|
||||
input->SeekToFirst();
|
||||
|
||||
std::unique_ptr<CompactionFilterV2> compaction_filter_from_factory_v2 =
|
||||
compact_->compaction->CreateCompactionFilterV2();
|
||||
auto compaction_filter_v2 = compaction_filter_from_factory_v2.get();
|
||||
|
||||
Status status;
|
||||
int64_t imm_micros = 0; // Micros spent doing imm_ compactions
|
||||
if (!compaction_filter_v2) {
|
||||
status = ProcessKeyValueCompaction(&imm_micros, input.get(), false);
|
||||
} else {
|
||||
status = ProcessPrefixBatches(cfd, &imm_micros, input.get(),
|
||||
compaction_filter_v2);
|
||||
}
|
||||
auto status = ProcessKeyValueCompaction(&imm_micros, input.get());
|
||||
|
||||
if (status.ok() &&
|
||||
(shutting_down_->load(std::memory_order_acquire) || cfd->IsDropped())) {
|
||||
@ -418,141 +312,10 @@ void CompactionJob::Install(Status* status,
|
||||
CleanupCompaction(*status);
|
||||
}
|
||||
|
||||
Status CompactionJob::ProcessPrefixBatches(
|
||||
ColumnFamilyData* cfd,
|
||||
int64_t* imm_micros,
|
||||
Iterator* input,
|
||||
CompactionFilterV2* compaction_filter_v2) {
|
||||
// temp_backup_input always point to the start of the current buffer
|
||||
// temp_backup_input = backup_input;
|
||||
// iterate through input,
|
||||
// 1) buffer ineligible keys and value keys into 2 separate buffers;
|
||||
// 2) send value_buffer to compaction filter and alternate the values;
|
||||
// 3) merge value_buffer with ineligible_value_buffer;
|
||||
// 4) run the modified "compaction" using the old for loop.
|
||||
ParsedInternalKey ikey;
|
||||
Status status;
|
||||
bool prefix_initialized = false;
|
||||
shared_ptr<Iterator> backup_input(
|
||||
versions_->MakeInputIterator(compact_->compaction));
|
||||
backup_input->SeekToFirst();
|
||||
uint64_t total_filter_time = 0;
|
||||
while (backup_input->Valid() &&
|
||||
!shutting_down_->load(std::memory_order_acquire) &&
|
||||
!cfd->IsDropped()) {
|
||||
// FLUSH preempts compaction
|
||||
// TODO(icanadi) this currently only checks if flush is necessary on
|
||||
// compacting column family. we should also check if flush is necessary on
|
||||
// other column families, too
|
||||
|
||||
imm_micros += yield_callback_();
|
||||
|
||||
Slice key = backup_input->key();
|
||||
Slice value = backup_input->value();
|
||||
|
||||
if (!ParseInternalKey(key, &ikey)) {
|
||||
// log error
|
||||
Log(InfoLogLevel::WARN_LEVEL, db_options_.info_log,
|
||||
"[%s] [JOB %d] Failed to parse key: %s", cfd->GetName().c_str(),
|
||||
job_id_, key.ToString().c_str());
|
||||
continue;
|
||||
} else {
|
||||
const SliceTransform* transformer =
|
||||
cfd->ioptions()->compaction_filter_factory_v2->GetPrefixExtractor();
|
||||
const auto key_prefix = transformer->Transform(ikey.user_key);
|
||||
if (!prefix_initialized) {
|
||||
compact_->cur_prefix_ = key_prefix.ToString();
|
||||
prefix_initialized = true;
|
||||
}
|
||||
// If the prefix remains the same, keep buffering
|
||||
if (key_prefix.compare(Slice(compact_->cur_prefix_)) == 0) {
|
||||
// Apply the compaction filter V2 to all the kv pairs sharing
|
||||
// the same prefix
|
||||
if (ikey.type == kTypeValue &&
|
||||
(visible_at_tip_ || ikey.sequence > latest_snapshot_)) {
|
||||
// Buffer all keys sharing the same prefix for CompactionFilterV2
|
||||
// Iterate through keys to check prefix
|
||||
compact_->BufferKeyValueSlices(key, value);
|
||||
} else {
|
||||
// buffer ineligible keys
|
||||
compact_->BufferOtherKeyValueSlices(key, value);
|
||||
}
|
||||
backup_input->Next();
|
||||
continue;
|
||||
// finish changing values for eligible keys
|
||||
} else {
|
||||
// Now prefix changes, this batch is done.
|
||||
// Call compaction filter on the buffered values to change the value
|
||||
if (compact_->key_str_buf_.size() > 0) {
|
||||
uint64_t time = 0;
|
||||
CallCompactionFilterV2(compaction_filter_v2, &time);
|
||||
total_filter_time += time;
|
||||
}
|
||||
compact_->cur_prefix_ = key_prefix.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
// Merge this batch of data (values + ineligible keys)
|
||||
compact_->MergeKeyValueSliceBuffer(&cfd->internal_comparator());
|
||||
|
||||
// Done buffering for the current prefix. Spit it out to disk
|
||||
// Now just iterate through all the kv-pairs
|
||||
status = ProcessKeyValueCompaction(imm_micros, input, true);
|
||||
|
||||
if (!status.ok()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// After writing the kv-pairs, we can safely remove the reference
|
||||
// to the string buffer and clean them up
|
||||
compact_->CleanupBatchBuffer();
|
||||
compact_->CleanupMergedBuffer();
|
||||
// Buffer the key that triggers the mismatch in prefix
|
||||
if (ikey.type == kTypeValue &&
|
||||
(visible_at_tip_ || ikey.sequence > latest_snapshot_)) {
|
||||
compact_->BufferKeyValueSlices(key, value);
|
||||
} else {
|
||||
compact_->BufferOtherKeyValueSlices(key, value);
|
||||
}
|
||||
backup_input->Next();
|
||||
if (!backup_input->Valid()) {
|
||||
// If this is the single last value, we need to merge it.
|
||||
if (compact_->key_str_buf_.size() > 0) {
|
||||
uint64_t time = 0;
|
||||
CallCompactionFilterV2(compaction_filter_v2, &time);
|
||||
total_filter_time += time;
|
||||
}
|
||||
compact_->MergeKeyValueSliceBuffer(&cfd->internal_comparator());
|
||||
|
||||
status = ProcessKeyValueCompaction(imm_micros, input, true);
|
||||
if (!status.ok()) {
|
||||
break;
|
||||
}
|
||||
|
||||
compact_->CleanupBatchBuffer();
|
||||
compact_->CleanupMergedBuffer();
|
||||
}
|
||||
} // done processing all prefix batches
|
||||
// finish the last batch
|
||||
if (status.ok()) {
|
||||
if (compact_->key_str_buf_.size() > 0) {
|
||||
uint64_t time = 0;
|
||||
CallCompactionFilterV2(compaction_filter_v2, &time);
|
||||
total_filter_time += time;
|
||||
}
|
||||
compact_->MergeKeyValueSliceBuffer(&cfd->internal_comparator());
|
||||
status = ProcessKeyValueCompaction(imm_micros, input, true);
|
||||
}
|
||||
RecordTick(stats_, FILTER_OPERATION_TOTAL_TIME, total_filter_time);
|
||||
return status;
|
||||
}
|
||||
|
||||
Status CompactionJob::ProcessKeyValueCompaction(int64_t* imm_micros,
|
||||
Iterator* input,
|
||||
bool is_compaction_v2) {
|
||||
Iterator* input) {
|
||||
AutoThreadOperationStageUpdater stage_updater(
|
||||
ThreadStatus::STAGE_COMPACTION_PROCESS_KV);
|
||||
size_t combined_idx = 0;
|
||||
Status status;
|
||||
std::string compaction_filter_value;
|
||||
ParsedInternalKey ikey;
|
||||
@ -599,26 +362,8 @@ Status CompactionJob::ProcessKeyValueCompaction(int64_t* imm_micros,
|
||||
// on other column families, too
|
||||
(*imm_micros) += yield_callback_();
|
||||
|
||||
Slice key;
|
||||
Slice value;
|
||||
// If is_compaction_v2 is on, kv-pairs are reset to the prefix batch.
|
||||
// This prefix batch should contain results after calling
|
||||
// compaction_filter_v2.
|
||||
//
|
||||
// If is_compaction_v2 is off, this function will go through all the
|
||||
// kv-pairs in input.
|
||||
if (!is_compaction_v2) {
|
||||
key = input->key();
|
||||
value = input->value();
|
||||
} else {
|
||||
if (combined_idx >= compact_->combined_key_buf_.size()) {
|
||||
break;
|
||||
}
|
||||
key = compact_->combined_key_buf_[combined_idx];
|
||||
value = compact_->combined_value_buf_[combined_idx];
|
||||
|
||||
++combined_idx;
|
||||
}
|
||||
Slice key = input->key();
|
||||
Slice value = input->value();
|
||||
|
||||
if (compaction_job_stats_ != nullptr) {
|
||||
compaction_job_stats_->total_input_raw_key_bytes +=
|
||||
@ -660,7 +405,7 @@ Status CompactionJob::ProcessKeyValueCompaction(int64_t* imm_micros,
|
||||
last_sequence_for_key = kMaxSequenceNumber;
|
||||
visible_in_snapshot = kMaxSequenceNumber;
|
||||
// apply the compaction filter to the first occurrence of the user key
|
||||
if (compaction_filter && !is_compaction_v2 && ikey.type == kTypeValue &&
|
||||
if (compaction_filter && ikey.type == kTypeValue &&
|
||||
(visible_at_tip_ || ikey.sequence > latest_snapshot_)) {
|
||||
// If the user has specified a compaction filter and the sequence
|
||||
// number is greater than any external snapshot, then invoke the
|
||||
@ -738,11 +483,8 @@ Status CompactionJob::ProcessKeyValueCompaction(int64_t* imm_micros,
|
||||
// object to minimize change to the existing flow. Turn out this
|
||||
// logic could also be nicely re-used for memtable flush purge
|
||||
// optimization in BuildTable.
|
||||
int steps = 0;
|
||||
merge.MergeUntil(input, prev_snapshot, bottommost_level_,
|
||||
db_options_.statistics.get(), &steps, env_);
|
||||
// Skip the Merge ops
|
||||
combined_idx = combined_idx - 1 + steps;
|
||||
db_options_.statistics.get(), nullptr, env_);
|
||||
|
||||
current_entry_is_merging = true;
|
||||
if (merge.IsSuccess()) {
|
||||
@ -899,70 +641,6 @@ void CompactionJob::RecordDroppedKeys(
|
||||
}
|
||||
}
|
||||
|
||||
void CompactionJob::CallCompactionFilterV2(
|
||||
CompactionFilterV2* compaction_filter_v2, uint64_t* time) {
|
||||
if (compact_ == nullptr || compaction_filter_v2 == nullptr) {
|
||||
return;
|
||||
}
|
||||
AutoThreadOperationStageUpdater stage_updater(
|
||||
ThreadStatus::STAGE_COMPACTION_FILTER_V2);
|
||||
|
||||
// Assemble slice vectors for user keys and existing values.
|
||||
// We also keep track of our parsed internal key structs because
|
||||
// we may need to access the sequence number in the event that
|
||||
// keys are garbage collected during the filter process.
|
||||
std::vector<ParsedInternalKey> ikey_buf;
|
||||
std::vector<Slice> user_key_buf;
|
||||
std::vector<Slice> existing_value_buf;
|
||||
|
||||
for (const auto& key : compact_->key_str_buf_) {
|
||||
ParsedInternalKey ikey;
|
||||
ParseInternalKey(Slice(key), &ikey);
|
||||
ikey_buf.emplace_back(ikey);
|
||||
user_key_buf.emplace_back(ikey.user_key);
|
||||
}
|
||||
for (const auto& value : compact_->existing_value_str_buf_) {
|
||||
existing_value_buf.emplace_back(Slice(value));
|
||||
}
|
||||
|
||||
// If the user has specified a compaction filter and the sequence
|
||||
// number is greater than any external snapshot, then invoke the
|
||||
// filter.
|
||||
// If the return value of the compaction filter is true, replace
|
||||
// the entry with a delete marker.
|
||||
StopWatchNano timer(env_, stats_ != nullptr);
|
||||
compact_->to_delete_buf_ = compaction_filter_v2->Filter(
|
||||
compact_->compaction->level(), user_key_buf, existing_value_buf,
|
||||
&compact_->new_value_buf_, &compact_->value_changed_buf_);
|
||||
*time = timer.ElapsedNanos();
|
||||
// new_value_buf_.size() <= to_delete__buf_.size(). "=" iff all
|
||||
// kv-pairs in this compaction run needs to be deleted.
|
||||
assert(compact_->to_delete_buf_.size() == compact_->key_str_buf_.size());
|
||||
assert(compact_->to_delete_buf_.size() ==
|
||||
compact_->existing_value_str_buf_.size());
|
||||
assert(compact_->value_changed_buf_.empty() ||
|
||||
compact_->to_delete_buf_.size() ==
|
||||
compact_->value_changed_buf_.size());
|
||||
|
||||
int new_value_idx = 0;
|
||||
for (unsigned int i = 0; i < compact_->to_delete_buf_.size(); ++i) {
|
||||
if (compact_->to_delete_buf_[i]) {
|
||||
// update the string buffer directly
|
||||
// the Slice buffer points to the updated buffer
|
||||
UpdateInternalKey(&compact_->key_str_buf_[i], ikey_buf[i].sequence,
|
||||
kTypeDeletion);
|
||||
|
||||
// no value associated with delete
|
||||
compact_->existing_value_str_buf_[i].clear();
|
||||
RecordTick(stats_, COMPACTION_KEY_DROP_USER);
|
||||
} else if (!compact_->value_changed_buf_.empty() &&
|
||||
compact_->value_changed_buf_[i]) {
|
||||
compact_->existing_value_str_buf_[i] =
|
||||
compact_->new_value_buf_[new_value_idx++];
|
||||
}
|
||||
} // for
|
||||
}
|
||||
|
||||
Status CompactionJob::FinishCompactionOutputFile(const Status& input_status) {
|
||||
AutoThreadOperationStageUpdater stage_updater(
|
||||
ThreadStatus::STAGE_COMPACTION_SYNC_FILE);
|
||||
|
@ -83,23 +83,15 @@ class CompactionJob {
|
||||
// update the thread status for starting a compaction.
|
||||
void ReportStartedCompaction(Compaction* compaction);
|
||||
void AllocateCompactionOutputFileNumbers();
|
||||
// Processes batches of keys with the same prefixes. This is used for
|
||||
// CompactionFilterV2.
|
||||
Status ProcessPrefixBatches(ColumnFamilyData* cfd,
|
||||
int64_t* imm_micros,
|
||||
Iterator* input,
|
||||
CompactionFilterV2* compaction_filter_v2);
|
||||
// Call compaction filter if is_compaction_v2 is not true. Then iterate
|
||||
// through input and compact the kv-pairs
|
||||
Status ProcessKeyValueCompaction(int64_t* imm_micros, Iterator* input,
|
||||
bool is_compaction_v2);
|
||||
|
||||
// Call compaction filter. Then iterate through input and compact the
|
||||
// kv-pairs
|
||||
Status ProcessKeyValueCompaction(int64_t* imm_micros, Iterator* input);
|
||||
|
||||
Status WriteKeyValue(const Slice& key, const Slice& value,
|
||||
const ParsedInternalKey& ikey,
|
||||
const Status& input_status);
|
||||
// Call compaction_filter_v2->Filter() on kv-pairs in compact
|
||||
void CallCompactionFilterV2(CompactionFilterV2* compaction_filter_v2,
|
||||
uint64_t* time);
|
||||
|
||||
Status FinishCompactionOutputFile(const Status& input_status);
|
||||
Status InstallCompactionResults(InstrumentedMutex* db_mutex,
|
||||
const MutableCFOptions& mutable_cf_options);
|
||||
|
@ -538,310 +538,6 @@ TEST_F(DBTestCompactionFilter, CompactionFilterContextManual) {
|
||||
}
|
||||
}
|
||||
|
||||
class KeepFilterV2 : public CompactionFilterV2 {
|
||||
public:
|
||||
virtual std::vector<bool> Filter(int level,
|
||||
const SliceVector& keys,
|
||||
const SliceVector& existing_values,
|
||||
std::vector<std::string>* new_values,
|
||||
std::vector<bool>* values_changed)
|
||||
const override {
|
||||
cfilter_count++;
|
||||
std::vector<bool> ret;
|
||||
new_values->clear();
|
||||
values_changed->clear();
|
||||
for (unsigned int i = 0; i < keys.size(); ++i) {
|
||||
values_changed->push_back(false);
|
||||
ret.push_back(false);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
virtual const char* Name() const override {
|
||||
return "KeepFilterV2";
|
||||
}
|
||||
};
|
||||
|
||||
class DeleteFilterV2 : public CompactionFilterV2 {
|
||||
public:
|
||||
virtual std::vector<bool> Filter(int level,
|
||||
const SliceVector& keys,
|
||||
const SliceVector& existing_values,
|
||||
std::vector<std::string>* new_values,
|
||||
std::vector<bool>* values_changed)
|
||||
const override {
|
||||
cfilter_count++;
|
||||
new_values->clear();
|
||||
values_changed->clear();
|
||||
std::vector<bool> ret;
|
||||
for (unsigned int i = 0; i < keys.size(); ++i) {
|
||||
values_changed->push_back(false);
|
||||
ret.push_back(true);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
virtual const char* Name() const override {
|
||||
return "DeleteFilterV2";
|
||||
}
|
||||
};
|
||||
|
||||
class ChangeFilterV2 : public CompactionFilterV2 {
|
||||
public:
|
||||
virtual std::vector<bool> Filter(int level,
|
||||
const SliceVector& keys,
|
||||
const SliceVector& existing_values,
|
||||
std::vector<std::string>* new_values,
|
||||
std::vector<bool>* values_changed)
|
||||
const override {
|
||||
std::vector<bool> ret;
|
||||
new_values->clear();
|
||||
values_changed->clear();
|
||||
for (unsigned int i = 0; i < keys.size(); ++i) {
|
||||
values_changed->push_back(true);
|
||||
new_values->push_back(NEW_VALUE);
|
||||
ret.push_back(false);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
virtual const char* Name() const override {
|
||||
return "ChangeFilterV2";
|
||||
}
|
||||
};
|
||||
|
||||
class KeepFilterFactoryV2 : public CompactionFilterFactoryV2 {
|
||||
public:
|
||||
explicit KeepFilterFactoryV2(const SliceTransform* prefix_extractor)
|
||||
: CompactionFilterFactoryV2(prefix_extractor) { }
|
||||
|
||||
virtual std::unique_ptr<CompactionFilterV2>
|
||||
CreateCompactionFilterV2(
|
||||
const CompactionFilterContext& context) override {
|
||||
return std::unique_ptr<CompactionFilterV2>(new KeepFilterV2());
|
||||
}
|
||||
|
||||
virtual const char* Name() const override {
|
||||
return "KeepFilterFactoryV2";
|
||||
}
|
||||
};
|
||||
|
||||
class DeleteFilterFactoryV2 : public CompactionFilterFactoryV2 {
|
||||
public:
|
||||
explicit DeleteFilterFactoryV2(const SliceTransform* prefix_extractor)
|
||||
: CompactionFilterFactoryV2(prefix_extractor) { }
|
||||
|
||||
virtual std::unique_ptr<CompactionFilterV2>
|
||||
CreateCompactionFilterV2(
|
||||
const CompactionFilterContext& context) override {
|
||||
return std::unique_ptr<CompactionFilterV2>(new DeleteFilterV2());
|
||||
}
|
||||
|
||||
virtual const char* Name() const override {
|
||||
return "DeleteFilterFactoryV2";
|
||||
}
|
||||
};
|
||||
|
||||
class ChangeFilterFactoryV2 : public CompactionFilterFactoryV2 {
|
||||
public:
|
||||
explicit ChangeFilterFactoryV2(const SliceTransform* prefix_extractor)
|
||||
: CompactionFilterFactoryV2(prefix_extractor) { }
|
||||
|
||||
virtual std::unique_ptr<CompactionFilterV2>
|
||||
CreateCompactionFilterV2(
|
||||
const CompactionFilterContext& context) override {
|
||||
return std::unique_ptr<CompactionFilterV2>(new ChangeFilterV2());
|
||||
}
|
||||
|
||||
virtual const char* Name() const override {
|
||||
return "ChangeFilterFactoryV2";
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(DBTestCompactionFilter, CompactionFilterV2) {
|
||||
Options options = CurrentOptions();
|
||||
options.num_levels = 3;
|
||||
options.max_mem_compaction_level = 0;
|
||||
// extract prefix
|
||||
std::unique_ptr<const SliceTransform> prefix_extractor;
|
||||
prefix_extractor.reset(NewFixedPrefixTransform(8));
|
||||
|
||||
options.compaction_filter_factory_v2
|
||||
= std::make_shared<KeepFilterFactoryV2>(prefix_extractor.get());
|
||||
// In a testing environment, we can only flush the application
|
||||
// compaction filter buffer using universal compaction
|
||||
option_config_ = kUniversalCompaction;
|
||||
options.compaction_style = (rocksdb::CompactionStyle)1;
|
||||
Reopen(options);
|
||||
|
||||
// Write 100K keys, these are written to a few files in L0.
|
||||
const std::string value(10, 'x');
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
char key[100];
|
||||
snprintf(key, sizeof(key), "B%08d%010d", i , i);
|
||||
Put(key, value);
|
||||
}
|
||||
|
||||
dbfull()->TEST_FlushMemTable();
|
||||
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr);
|
||||
dbfull()->TEST_CompactRange(1, nullptr, nullptr);
|
||||
|
||||
ASSERT_EQ(NumSortedRuns(0), 1);
|
||||
|
||||
// All the files are in the lowest level.
|
||||
int count = 0;
|
||||
int total = 0;
|
||||
{
|
||||
Arena arena;
|
||||
ScopedArenaIterator iter(dbfull()->TEST_NewInternalIterator(&arena));
|
||||
iter->SeekToFirst();
|
||||
ASSERT_OK(iter->status());
|
||||
while (iter->Valid()) {
|
||||
ParsedInternalKey ikey(Slice(), 0, kTypeValue);
|
||||
ikey.sequence = -1;
|
||||
ASSERT_EQ(ParseInternalKey(iter->key(), &ikey), true);
|
||||
total++;
|
||||
if (ikey.sequence != 0) {
|
||||
count++;
|
||||
}
|
||||
iter->Next();
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_EQ(total, 100000);
|
||||
// 1 snapshot only. Since we are using universal compacton,
|
||||
// the sequence no is cleared for better compression
|
||||
ASSERT_EQ(count, 1);
|
||||
|
||||
// create a new database with the compaction
|
||||
// filter in such a way that it deletes all keys
|
||||
options.compaction_filter_factory_v2 =
|
||||
std::make_shared<DeleteFilterFactoryV2>(prefix_extractor.get());
|
||||
options.create_if_missing = true;
|
||||
DestroyAndReopen(options);
|
||||
|
||||
// write all the keys once again.
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
char key[100];
|
||||
snprintf(key, sizeof(key), "B%08d%010d", i, i);
|
||||
Put(key, value);
|
||||
}
|
||||
|
||||
dbfull()->TEST_FlushMemTable();
|
||||
ASSERT_NE(NumTableFilesAtLevel(0), 0);
|
||||
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr);
|
||||
dbfull()->TEST_CompactRange(1, nullptr, nullptr);
|
||||
ASSERT_EQ(NumTableFilesAtLevel(1), 0);
|
||||
|
||||
// Scan the entire database to ensure that nothing is left
|
||||
Iterator* iter = db_->NewIterator(ReadOptions());
|
||||
iter->SeekToFirst();
|
||||
count = 0;
|
||||
while (iter->Valid()) {
|
||||
count++;
|
||||
iter->Next();
|
||||
}
|
||||
|
||||
ASSERT_EQ(count, 0);
|
||||
delete iter;
|
||||
}
|
||||
|
||||
TEST_F(DBTestCompactionFilter, CompactionFilterV2WithValueChange) {
|
||||
Options options = CurrentOptions();
|
||||
options.num_levels = 3;
|
||||
options.max_mem_compaction_level = 0;
|
||||
std::unique_ptr<const SliceTransform> prefix_extractor;
|
||||
prefix_extractor.reset(NewFixedPrefixTransform(8));
|
||||
options.compaction_filter_factory_v2 =
|
||||
std::make_shared<ChangeFilterFactoryV2>(prefix_extractor.get());
|
||||
// In a testing environment, we can only flush the application
|
||||
// compaction filter buffer using universal compaction
|
||||
option_config_ = kUniversalCompaction;
|
||||
options.compaction_style = (rocksdb::CompactionStyle)1;
|
||||
options = CurrentOptions(options);
|
||||
Reopen(options);
|
||||
|
||||
// Write 100K+1 keys, these are written to a few files
|
||||
// in L0. We do this so that the current snapshot points
|
||||
// to the 100001 key.The compaction filter is not invoked
|
||||
// on keys that are visible via a snapshot because we
|
||||
// anyways cannot delete it.
|
||||
const std::string value(10, 'x');
|
||||
for (int i = 0; i < 100001; i++) {
|
||||
char key[100];
|
||||
snprintf(key, sizeof(key), "B%08d%010d", i, i);
|
||||
Put(key, value);
|
||||
}
|
||||
|
||||
// push all files to lower levels
|
||||
dbfull()->TEST_FlushMemTable();
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr);
|
||||
dbfull()->TEST_CompactRange(1, nullptr, nullptr);
|
||||
|
||||
// verify that all keys now have the new value that
|
||||
// was set by the compaction process.
|
||||
for (int i = 0; i < 100001; i++) {
|
||||
char key[100];
|
||||
snprintf(key, sizeof(key), "B%08d%010d", i, i);
|
||||
std::string newvalue = Get(key);
|
||||
ASSERT_EQ(newvalue.compare(NEW_VALUE), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DBTestCompactionFilter, CompactionFilterV2NULLPrefix) {
|
||||
Options options = CurrentOptions();
|
||||
options.num_levels = 3;
|
||||
options.max_mem_compaction_level = 0;
|
||||
std::unique_ptr<const SliceTransform> prefix_extractor;
|
||||
prefix_extractor.reset(NewFixedPrefixTransform(8));
|
||||
options.compaction_filter_factory_v2 =
|
||||
std::make_shared<ChangeFilterFactoryV2>(prefix_extractor.get());
|
||||
// In a testing environment, we can only flush the application
|
||||
// compaction filter buffer using universal compaction
|
||||
option_config_ = kUniversalCompaction;
|
||||
options.compaction_style = (rocksdb::CompactionStyle)1;
|
||||
Reopen(options);
|
||||
|
||||
// Write 100K+1 keys, these are written to a few files
|
||||
// in L0. We do this so that the current snapshot points
|
||||
// to the 100001 key.The compaction filter is not invoked
|
||||
// on keys that are visible via a snapshot because we
|
||||
// anyways cannot delete it.
|
||||
const std::string value(10, 'x');
|
||||
char first_key[100];
|
||||
snprintf(first_key, sizeof(first_key), "%s0000%010d", "NULL", 1);
|
||||
Put(first_key, value);
|
||||
for (int i = 1; i < 100000; i++) {
|
||||
char key[100];
|
||||
snprintf(key, sizeof(key), "%08d%010d", i, i);
|
||||
Put(key, value);
|
||||
}
|
||||
|
||||
char last_key[100];
|
||||
snprintf(last_key, sizeof(last_key), "%s0000%010d", "NULL", 2);
|
||||
Put(last_key, value);
|
||||
|
||||
// push all files to lower levels
|
||||
dbfull()->TEST_FlushMemTable();
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr);
|
||||
|
||||
// verify that all keys now have the new value that
|
||||
// was set by the compaction process.
|
||||
std::string newvalue = Get(first_key);
|
||||
ASSERT_EQ(newvalue.compare(NEW_VALUE), 0);
|
||||
newvalue = Get(last_key);
|
||||
ASSERT_EQ(newvalue.compare(NEW_VALUE), 0);
|
||||
for (int i = 1; i < 100000; i++) {
|
||||
char key[100];
|
||||
snprintf(key, sizeof(key), "%08d%010d", i, i);
|
||||
newvalue = Get(key);
|
||||
ASSERT_EQ(newvalue.compare(NEW_VALUE), 0);
|
||||
}
|
||||
}
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
#if !(defined NDEBUG) || !defined(OS_WIN)
|
||||
rocksdb::port::InstallStackTraceHandler();
|
||||
|
@ -1446,8 +1446,7 @@ Status DBImpl::CompactRange(const CompactRangeOptions& options,
|
||||
} else if (options.bottommost_level_compaction ==
|
||||
BottommostLevelCompaction::kIfHaveCompactionFilter &&
|
||||
cfd->ioptions()->compaction_filter == nullptr &&
|
||||
cfd->ioptions()->compaction_filter_factory == nullptr &&
|
||||
cfd->ioptions()->compaction_filter_factory_v2 == nullptr) {
|
||||
cfd->ioptions()->compaction_filter_factory == nullptr) {
|
||||
// Skip bottommost level compaction since we dont have
|
||||
// compaction filter
|
||||
continue;
|
||||
|
@ -80,10 +80,6 @@ typedef struct rocksdb_compactionfiltercontext_t
|
||||
rocksdb_compactionfiltercontext_t;
|
||||
typedef struct rocksdb_compactionfilterfactory_t
|
||||
rocksdb_compactionfilterfactory_t;
|
||||
typedef struct rocksdb_compactionfilterv2_t
|
||||
rocksdb_compactionfilterv2_t;
|
||||
typedef struct rocksdb_compactionfilterfactoryv2_t
|
||||
rocksdb_compactionfilterfactoryv2_t;
|
||||
typedef struct rocksdb_comparator_t rocksdb_comparator_t;
|
||||
typedef struct rocksdb_env_t rocksdb_env_t;
|
||||
typedef struct rocksdb_fifo_compaction_options_t rocksdb_fifo_compaction_options_t;
|
||||
@ -494,9 +490,6 @@ extern ROCKSDB_LIBRARY_API void rocksdb_options_set_compaction_filter(
|
||||
rocksdb_options_t*, rocksdb_compactionfilter_t*);
|
||||
extern ROCKSDB_LIBRARY_API void rocksdb_options_set_compaction_filter_factory(
|
||||
rocksdb_options_t*, rocksdb_compactionfilterfactory_t*);
|
||||
extern ROCKSDB_LIBRARY_API void
|
||||
rocksdb_options_set_compaction_filter_factory_v2(
|
||||
rocksdb_options_t*, rocksdb_compactionfilterfactoryv2_t*);
|
||||
extern ROCKSDB_LIBRARY_API void rocksdb_options_set_comparator(
|
||||
rocksdb_options_t*, rocksdb_comparator_t*);
|
||||
extern ROCKSDB_LIBRARY_API void rocksdb_options_set_merge_operator(
|
||||
@ -740,36 +733,6 @@ rocksdb_compactionfilterfactory_create(
|
||||
extern ROCKSDB_LIBRARY_API void rocksdb_compactionfilterfactory_destroy(
|
||||
rocksdb_compactionfilterfactory_t*);
|
||||
|
||||
/* Compaction Filter V2 */
|
||||
|
||||
extern ROCKSDB_LIBRARY_API rocksdb_compactionfilterv2_t*
|
||||
rocksdb_compactionfilterv2_create(
|
||||
void* state, void (*destructor)(void*),
|
||||
// num_keys specifies the number of array entries in every *list parameter.
|
||||
// New values added to the new_values_list should be malloc'd and will be
|
||||
// freed by the caller. Specify true in the to_delete_list to remove an
|
||||
// entry during compaction; false to keep it.
|
||||
void (*filter)(void*, int level, size_t num_keys,
|
||||
const char* const* keys_list, const size_t* keys_list_sizes,
|
||||
const char* const* existing_values_list,
|
||||
const size_t* existing_values_list_sizes,
|
||||
char** new_values_list, size_t* new_values_list_sizes,
|
||||
unsigned char* to_delete_list),
|
||||
const char* (*name)(void*));
|
||||
extern void rocksdb_compactionfilterv2_destroy(rocksdb_compactionfilterv2_t*);
|
||||
|
||||
/* Compaction Filter Factory V2 */
|
||||
|
||||
extern ROCKSDB_LIBRARY_API rocksdb_compactionfilterfactoryv2_t*
|
||||
rocksdb_compactionfilterfactoryv2_create(
|
||||
void* state, rocksdb_slicetransform_t* prefix_extractor,
|
||||
void (*destructor)(void*),
|
||||
rocksdb_compactionfilterv2_t* (*create_compaction_filter_v2)(
|
||||
void*, const rocksdb_compactionfiltercontext_t* context),
|
||||
const char* (*name)(void*));
|
||||
extern ROCKSDB_LIBRARY_API void rocksdb_compactionfilterfactoryv2_destroy(
|
||||
rocksdb_compactionfilterfactoryv2_t*);
|
||||
|
||||
/* Comparator */
|
||||
|
||||
extern ROCKSDB_LIBRARY_API rocksdb_comparator_t* rocksdb_comparator_create(
|
||||
|
@ -35,8 +35,6 @@ struct ImmutableCFOptions {
|
||||
|
||||
CompactionFilterFactory* compaction_filter_factory;
|
||||
|
||||
CompactionFilterFactoryV2* compaction_filter_factory_v2;
|
||||
|
||||
bool inplace_update_support;
|
||||
|
||||
UpdateStatus (*inplace_callback)(char* existing_value,
|
||||
|
@ -213,11 +213,9 @@ struct ColumnFamilyOptions {
|
||||
// Default: nullptr
|
||||
std::shared_ptr<CompactionFilterFactory> compaction_filter_factory;
|
||||
|
||||
// Version TWO of the compaction_filter_factory
|
||||
// It supports rolling compaction
|
||||
//
|
||||
// Default: nullptr
|
||||
std::shared_ptr<CompactionFilterFactoryV2> compaction_filter_factory_v2;
|
||||
// This is deprecated. Talk to us if you depend on
|
||||
// compaction_filter_factory_v2 and we'll put it back
|
||||
// std::shared_ptr<CompactionFilterFactoryV2> compaction_filter_factory_v2;
|
||||
|
||||
// -------------------
|
||||
// Parameters that affect performance
|
||||
|
@ -67,7 +67,6 @@ struct ThreadStatus {
|
||||
STAGE_COMPACTION_PREPARE,
|
||||
STAGE_COMPACTION_RUN,
|
||||
STAGE_COMPACTION_PROCESS_KV,
|
||||
STAGE_COMPACTION_FILTER_V2,
|
||||
STAGE_COMPACTION_INSTALL,
|
||||
STAGE_COMPACTION_SYNC_FILE,
|
||||
STAGE_PICK_MEMTABLES_TO_FLUSH,
|
||||
|
@ -44,7 +44,6 @@ ImmutableCFOptions::ImmutableCFOptions(const Options& options)
|
||||
merge_operator(options.merge_operator.get()),
|
||||
compaction_filter(options.compaction_filter),
|
||||
compaction_filter_factory(options.compaction_filter_factory.get()),
|
||||
compaction_filter_factory_v2(options.compaction_filter_factory_v2.get()),
|
||||
inplace_update_support(options.inplace_update_support),
|
||||
inplace_callback(options.inplace_callback),
|
||||
info_log(options.info_log.get()),
|
||||
@ -79,7 +78,6 @@ ColumnFamilyOptions::ColumnFamilyOptions()
|
||||
merge_operator(nullptr),
|
||||
compaction_filter(nullptr),
|
||||
compaction_filter_factory(nullptr),
|
||||
compaction_filter_factory_v2(nullptr),
|
||||
write_buffer_size(4 << 20),
|
||||
max_write_buffer_number(2),
|
||||
min_write_buffer_number_to_merge(1),
|
||||
@ -132,7 +130,6 @@ ColumnFamilyOptions::ColumnFamilyOptions(const Options& options)
|
||||
merge_operator(options.merge_operator),
|
||||
compaction_filter(options.compaction_filter),
|
||||
compaction_filter_factory(options.compaction_filter_factory),
|
||||
compaction_filter_factory_v2(options.compaction_filter_factory_v2),
|
||||
write_buffer_size(options.write_buffer_size),
|
||||
max_write_buffer_number(options.max_write_buffer_number),
|
||||
min_write_buffer_number_to_merge(
|
||||
@ -383,9 +380,6 @@ void ColumnFamilyOptions::Dump(Logger* log) const {
|
||||
compaction_filter ? compaction_filter->Name() : "None");
|
||||
Warn(log, " Options.compaction_filter_factory: %s",
|
||||
compaction_filter_factory ? compaction_filter_factory->Name() : "None");
|
||||
Warn(log, " Options.compaction_filter_factory_v2: %s",
|
||||
compaction_filter_factory_v2 ? compaction_filter_factory_v2->Name()
|
||||
: "None");
|
||||
Warn(log, " Options.memtable_factory: %s", memtable_factory->Name());
|
||||
Warn(log, " Options.table_factory: %s", table_factory->Name());
|
||||
Warn(log, " table_factory options: %s",
|
||||
|
@ -61,8 +61,6 @@ static OperationStageInfo global_op_stage_table[] = {
|
||||
"CompactionJob::Run"},
|
||||
{ThreadStatus::STAGE_COMPACTION_PROCESS_KV,
|
||||
"CompactionJob::ProcessKeyValueCompaction"},
|
||||
{ThreadStatus::STAGE_COMPACTION_FILTER_V2,
|
||||
"CompactionJob::CallCompactionFilterV2"},
|
||||
{ThreadStatus::STAGE_COMPACTION_INSTALL,
|
||||
"CompactionJob::Install"},
|
||||
{ThreadStatus::STAGE_COMPACTION_SYNC_FILE,
|
||||
|
Loading…
x
Reference in New Issue
Block a user