Skip to content

Commit b9d65f5

Browse files
Cheng Changfacebook-github-bot
authored andcommitted
Trigger compaction in CompactOnDeletionCollector based on deletion ratio (facebook#6806)
Summary: In level compaction, if the total size (even if compensated after taking account of the deletions) of a level hasn't exceeded the limit, but there are lots of deletion entries in some SST files of the level, these files should also be good candidates for compaction. Otherwise, queries for the deleted keys might be slow because they need to go over all the tombstones. This PR adds an option `deletion_ratio` to the factory of `CompactOnDeletionCollector` to configure it to trigger compaction when the ratio of tombstones >= `deletion_ratio`. Pull Request resolved: facebook#6806 Test Plan: Added new unit test in `compact_on_deletion_collector_test.cc`. make compact_on_deletion_collector_test && ./compact_on_deletion_collector_test Reviewed By: ajkr Differential Revision: D21511981 Pulled By: cheng-chang fbshipit-source-id: 65a9d0150e8c9c00337787686475252e4535a3e1
1 parent d790e60 commit b9d65f5

File tree

4 files changed

+175
-77
lines changed

4 files changed

+175
-77
lines changed

include/rocksdb/utilities/table_properties_collectors.h

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ namespace ROCKSDB_NAMESPACE {
1414

1515
// A factory of a table property collector that marks a SST
1616
// file as need-compaction when it observe at least "D" deletion
17-
// entries in any "N" consecutive entires.
17+
// entries in any "N" consecutive entires or the ratio of tombstone
18+
// entries in the whole file >= the specified deletion ratio.
1819
class CompactOnDeletionCollectorFactory
1920
: public TablePropertiesCollectorFactory {
2021
public:
@@ -34,6 +35,13 @@ class CompactOnDeletionCollectorFactory
3435
deletion_trigger_.store(deletion_trigger);
3536
}
3637

38+
// Change deletion ratio.
39+
// @param deletion_ratio, if <= 0 or > 1, disable triggering compaction
40+
// based on deletion ratio.
41+
void SetDeletionRatio(double deletion_ratio) {
42+
deletion_ratio_.store(deletion_ratio);
43+
}
44+
3745
const char* Name() const override {
3846
return "CompactOnDeletionCollector";
3947
}
@@ -43,34 +51,45 @@ class CompactOnDeletionCollectorFactory
4351
private:
4452
friend std::shared_ptr<CompactOnDeletionCollectorFactory>
4553
NewCompactOnDeletionCollectorFactory(size_t sliding_window_size,
46-
size_t deletion_trigger);
54+
size_t deletion_trigger,
55+
double deletion_ratio);
4756
// A factory of a table property collector that marks a SST
4857
// file as need-compaction when it observe at least "D" deletion
49-
// entries in any "N" consecutive entires.
58+
// entries in any "N" consecutive entires, or the ratio of tombstone
59+
// entries >= deletion_ratio.
5060
//
5161
// @param sliding_window_size "N"
5262
// @param deletion_trigger "D"
63+
// @param deletion_ratio, if <= 0 or > 1, disable triggering compaction
64+
// based on deletion ratio.
5365
CompactOnDeletionCollectorFactory(size_t sliding_window_size,
54-
size_t deletion_trigger)
66+
size_t deletion_trigger,
67+
double deletion_ratio)
5568
: sliding_window_size_(sliding_window_size),
56-
deletion_trigger_(deletion_trigger) {}
69+
deletion_trigger_(deletion_trigger),
70+
deletion_ratio_(deletion_ratio) {}
5771

5872
std::atomic<size_t> sliding_window_size_;
5973
std::atomic<size_t> deletion_trigger_;
74+
std::atomic<double> deletion_ratio_;
6075
};
6176

6277
// Creates a factory of a table property collector that marks a SST
6378
// file as need-compaction when it observe at least "D" deletion
64-
// entries in any "N" consecutive entires.
79+
// entries in any "N" consecutive entires, or the ratio of tombstone
80+
// entries >= deletion_ratio.
6581
//
6682
// @param sliding_window_size "N". Note that this number will be
6783
// round up to the smallest multiple of 128 that is no less
6884
// than the specified size.
6985
// @param deletion_trigger "D". Note that even when "N" is changed,
7086
// the specified number for "D" will not be changed.
87+
// @param deletion_ratio, if <= 0 or > 1, disable triggering compaction
88+
// based on deletion ratio. Disabled by default.
7189
extern std::shared_ptr<CompactOnDeletionCollectorFactory>
7290
NewCompactOnDeletionCollectorFactory(size_t sliding_window_size,
73-
size_t deletion_trigger);
91+
size_t deletion_trigger,
92+
double deletion_ratio = 0);
7493
} // namespace ROCKSDB_NAMESPACE
7594

7695
#endif // !ROCKSDB_LITE

utilities/table_properties_collectors/compact_on_deletion_collector.cc

Lines changed: 54 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313
namespace ROCKSDB_NAMESPACE {
1414

1515
CompactOnDeletionCollector::CompactOnDeletionCollector(
16-
size_t sliding_window_size, size_t deletion_trigger)
16+
size_t sliding_window_size, size_t deletion_trigger, double deletion_ratio)
1717
: bucket_size_((sliding_window_size + kNumBuckets - 1) / kNumBuckets),
1818
current_bucket_(0),
1919
num_keys_in_current_bucket_(0),
2020
num_deletions_in_observation_window_(0),
2121
deletion_trigger_(deletion_trigger),
22+
deletion_ratio_(deletion_ratio),
23+
deletion_ratio_enabled_(deletion_ratio > 0 && deletion_ratio <= 1),
2224
need_compaction_(false),
2325
finished_(false) {
2426
memset(num_deletions_in_buckets_, 0, sizeof(size_t) * kNumBuckets);
@@ -35,7 +37,7 @@ Status CompactOnDeletionCollector::AddUserKey(const Slice& /*key*/,
3537
SequenceNumber /*seq*/,
3638
uint64_t /*file_size*/) {
3739
assert(!finished_);
38-
if (bucket_size_ == 0) {
40+
if (!bucket_size_ && !deletion_ratio_enabled_) {
3941
// This collector is effectively disabled
4042
return Status::OK();
4143
}
@@ -45,54 +47,76 @@ Status CompactOnDeletionCollector::AddUserKey(const Slice& /*key*/,
4547
return Status::OK();
4648
}
4749

48-
if (num_keys_in_current_bucket_ == bucket_size_) {
49-
// When the current bucket is full, advance the cursor of the
50-
// ring buffer to the next bucket.
51-
current_bucket_ = (current_bucket_ + 1) % kNumBuckets;
52-
53-
// Update the current count of observed deletion keys by excluding
54-
// the number of deletion keys in the oldest bucket in the
55-
// observation window.
56-
assert(num_deletions_in_observation_window_ >=
57-
num_deletions_in_buckets_[current_bucket_]);
58-
num_deletions_in_observation_window_ -=
59-
num_deletions_in_buckets_[current_bucket_];
60-
num_deletions_in_buckets_[current_bucket_] = 0;
61-
num_keys_in_current_bucket_ = 0;
50+
if (deletion_ratio_enabled_) {
51+
total_entries_++;
52+
if (type == kEntryDelete) {
53+
deletion_entries_++;
54+
}
6255
}
6356

64-
num_keys_in_current_bucket_++;
65-
if (type == kEntryDelete) {
66-
num_deletions_in_observation_window_++;
67-
num_deletions_in_buckets_[current_bucket_]++;
68-
if (num_deletions_in_observation_window_ >= deletion_trigger_) {
69-
need_compaction_ = true;
57+
if (bucket_size_) {
58+
if (num_keys_in_current_bucket_ == bucket_size_) {
59+
// When the current bucket is full, advance the cursor of the
60+
// ring buffer to the next bucket.
61+
current_bucket_ = (current_bucket_ + 1) % kNumBuckets;
62+
63+
// Update the current count of observed deletion keys by excluding
64+
// the number of deletion keys in the oldest bucket in the
65+
// observation window.
66+
assert(num_deletions_in_observation_window_ >=
67+
num_deletions_in_buckets_[current_bucket_]);
68+
num_deletions_in_observation_window_ -=
69+
num_deletions_in_buckets_[current_bucket_];
70+
num_deletions_in_buckets_[current_bucket_] = 0;
71+
num_keys_in_current_bucket_ = 0;
72+
}
73+
74+
num_keys_in_current_bucket_++;
75+
if (type == kEntryDelete) {
76+
num_deletions_in_observation_window_++;
77+
num_deletions_in_buckets_[current_bucket_]++;
78+
if (num_deletions_in_observation_window_ >= deletion_trigger_) {
79+
need_compaction_ = true;
80+
}
7081
}
7182
}
83+
84+
return Status::OK();
85+
}
86+
87+
Status CompactOnDeletionCollector::Finish(
88+
UserCollectedProperties* /*properties*/) {
89+
if (!need_compaction_ && deletion_ratio_enabled_ && total_entries_ > 0) {
90+
double ratio = static_cast<double>(deletion_entries_) / total_entries_;
91+
need_compaction_ = ratio >= deletion_ratio_;
92+
}
93+
finished_ = true;
7294
return Status::OK();
7395
}
7496

7597
TablePropertiesCollector*
7698
CompactOnDeletionCollectorFactory::CreateTablePropertiesCollector(
7799
TablePropertiesCollectorFactory::Context /*context*/) {
78-
return new CompactOnDeletionCollector(
79-
sliding_window_size_.load(), deletion_trigger_.load());
100+
return new CompactOnDeletionCollector(sliding_window_size_.load(),
101+
deletion_trigger_.load(),
102+
deletion_ratio_.load());
80103
}
81104

82105
std::string CompactOnDeletionCollectorFactory::ToString() const {
83106
std::ostringstream cfg;
84107
cfg << Name() << " (Sliding window size = " << sliding_window_size_.load()
85-
<< " Deletion trigger = " << deletion_trigger_.load() << ')';
108+
<< " Deletion trigger = " << deletion_trigger_.load()
109+
<< " Deletion ratio = " << deletion_ratio_.load() << ')';
86110
return cfg.str();
87111
}
88112

89113
std::shared_ptr<CompactOnDeletionCollectorFactory>
90-
NewCompactOnDeletionCollectorFactory(
91-
size_t sliding_window_size,
92-
size_t deletion_trigger) {
114+
NewCompactOnDeletionCollectorFactory(size_t sliding_window_size,
115+
size_t deletion_trigger,
116+
double deletion_ratio) {
93117
return std::shared_ptr<CompactOnDeletionCollectorFactory>(
94-
new CompactOnDeletionCollectorFactory(
95-
sliding_window_size, deletion_trigger));
118+
new CompactOnDeletionCollectorFactory(sliding_window_size,
119+
deletion_trigger, deletion_ratio));
96120
}
97121
} // namespace ROCKSDB_NAMESPACE
98122
#endif // !ROCKSDB_LITE

utilities/table_properties_collectors/compact_on_deletion_collector.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@ namespace ROCKSDB_NAMESPACE {
1111

1212
class CompactOnDeletionCollector : public TablePropertiesCollector {
1313
public:
14-
CompactOnDeletionCollector(
15-
size_t sliding_window_size,
16-
size_t deletion_trigger);
14+
CompactOnDeletionCollector(size_t sliding_window_size,
15+
size_t deletion_trigger, double deletion_raatio);
1716

1817
// AddUserKey() will be called when a new key/value pair is inserted into the
1918
// table.
@@ -28,10 +27,7 @@ class CompactOnDeletionCollector : public TablePropertiesCollector {
2827
// for writing the properties block.
2928
// @params properties User will add their collected statistics to
3029
// `properties`.
31-
virtual Status Finish(UserCollectedProperties* /*properties*/) override {
32-
finished_ = true;
33-
return Status::OK();
34-
}
30+
virtual Status Finish(UserCollectedProperties* /*properties*/) override;
3531

3632
// Return the human-readable properties, where the key is property name and
3733
// the value is the human-readable form of value.
@@ -64,6 +60,10 @@ class CompactOnDeletionCollector : public TablePropertiesCollector {
6460
size_t num_keys_in_current_bucket_;
6561
size_t num_deletions_in_observation_window_;
6662
size_t deletion_trigger_;
63+
const double deletion_ratio_;
64+
const bool deletion_ratio_enabled_;
65+
size_t total_entries_ = 0;
66+
size_t deletion_entries_ = 0;
6767
// true if the current SST file needs to be compacted.
6868
bool need_compaction_;
6969
bool finished_;

0 commit comments

Comments
 (0)