/src/rocksdb/table/block_based/flush_block_policy.cc
Line | Count | Source |
1 | | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
2 | | // This source code is licensed under both the GPLv2 (found in the |
3 | | // COPYING file in the root directory) and Apache 2.0 License |
4 | | // (found in the LICENSE.Apache file in the root directory). |
5 | | |
6 | | #include "rocksdb/flush_block_policy.h" |
7 | | |
8 | | #include <cassert> |
9 | | #include <mutex> |
10 | | |
11 | | #include "rocksdb/options.h" |
12 | | #include "rocksdb/slice.h" |
13 | | #include "rocksdb/utilities/customizable_util.h" |
14 | | #include "table/block_based/block_based_table_reader.h" |
15 | | #include "table/block_based/block_builder.h" |
16 | | #include "table/block_based/flush_block_policy_impl.h" |
17 | | #include "table/format.h" |
18 | | |
19 | | namespace ROCKSDB_NAMESPACE { |
20 | | |
21 | | // Flush block by size |
22 | | class FlushBlockBySizePolicy : public RetargetableFlushBlockPolicy { |
23 | | public: |
24 | | // @params block_size: Approximate size of user data packed per |
25 | | // block. |
26 | | // @params block_size_deviation: This is used to close a block before it |
27 | | // reaches the configured |
28 | | FlushBlockBySizePolicy(const uint64_t block_size, |
29 | | const uint64_t block_size_deviation, const bool align, |
30 | | const BlockBuilder& data_block_builder) |
31 | 8.06k | : RetargetableFlushBlockPolicy(data_block_builder), |
32 | 8.06k | block_size_(block_size), |
33 | | block_size_deviation_limit_( |
34 | 8.06k | ((block_size * (100 - block_size_deviation)) + 99) / 100), |
35 | 8.06k | align_(align) {} |
36 | | |
37 | 8.90k | bool Update(const Slice& key, const Slice& value) override { |
38 | | // it makes no sense to flush when the data block is empty |
39 | 8.90k | if (data_block_builder_->empty()) { |
40 | 8.05k | return false; |
41 | 8.05k | } |
42 | | |
43 | 843 | auto curr_size = data_block_builder_->CurrentSizeEstimate(); |
44 | | |
45 | | // Do flush if one of the below two conditions is true: |
46 | | // 1) if the current estimated size already exceeds the block size, |
47 | | // 2) block_size_deviation is set and the estimated size after appending |
48 | | // the kv will exceed the block size and the current size is under the |
49 | | // the deviation. |
50 | 843 | return curr_size >= block_size_ || BlockAlmostFull(key, value); |
51 | 8.90k | } |
52 | | |
53 | | private: |
54 | 842 | bool BlockAlmostFull(const Slice& key, const Slice& value) const { |
55 | 842 | if (block_size_deviation_limit_ == 0) { |
56 | 0 | return false; |
57 | 0 | } |
58 | | |
59 | 842 | const auto curr_size = data_block_builder_->CurrentSizeEstimate(); |
60 | 842 | auto estimated_size_after = |
61 | 842 | data_block_builder_->EstimateSizeAfterKV(key, value); |
62 | | |
63 | 842 | if (align_) { |
64 | 0 | estimated_size_after += BlockBasedTable::kBlockTrailerSize; |
65 | 0 | return estimated_size_after > block_size_; |
66 | 0 | } |
67 | | |
68 | 842 | return estimated_size_after > block_size_ && |
69 | 1 | curr_size > block_size_deviation_limit_; |
70 | 842 | } |
71 | | |
72 | | const uint64_t block_size_; |
73 | | const uint64_t block_size_deviation_limit_; |
74 | | const bool align_; |
75 | | }; |
76 | | |
77 | | FlushBlockPolicy* FlushBlockBySizePolicyFactory::NewFlushBlockPolicy( |
78 | | const BlockBasedTableOptions& table_options, |
79 | 8.06k | const BlockBuilder& data_block_builder) const { |
80 | 8.06k | return new FlushBlockBySizePolicy( |
81 | 8.06k | table_options.block_size, table_options.block_size_deviation, |
82 | 8.06k | table_options.block_align, data_block_builder); |
83 | 8.06k | } |
84 | | |
85 | | std::unique_ptr<RetargetableFlushBlockPolicy> NewFlushBlockBySizePolicy( |
86 | | const uint64_t size, const int deviation, |
87 | 0 | const BlockBuilder& data_block_builder) { |
88 | 0 | return std::make_unique<FlushBlockBySizePolicy>(size, deviation, false, |
89 | 0 | data_block_builder); |
90 | 0 | } |
91 | | |
92 | | FlushBlockPolicy* FlushBlockBySizePolicyFactory::NewFlushBlockPolicy( |
93 | | const uint64_t size, const int deviation, |
94 | 0 | const BlockBuilder& data_block_builder) { |
95 | 0 | return NewFlushBlockBySizePolicy(size, deviation, data_block_builder) |
96 | 0 | .release(); |
97 | 0 | } |
98 | | |
99 | | static int RegisterFlushBlockPolicyFactories(ObjectLibrary& library, |
100 | 2 | const std::string& /*arg*/) { |
101 | 2 | library.AddFactory<FlushBlockPolicyFactory>( |
102 | 2 | FlushBlockBySizePolicyFactory::kClassName(), |
103 | 2 | [](const std::string& /*uri*/, |
104 | 2 | std::unique_ptr<FlushBlockPolicyFactory>* guard, |
105 | 55.0k | std::string* /* errmsg */) { |
106 | 55.0k | guard->reset(new FlushBlockBySizePolicyFactory()); |
107 | 55.0k | return guard->get(); |
108 | 55.0k | }); |
109 | 2 | library.AddFactory<FlushBlockPolicyFactory>( |
110 | 2 | FlushBlockEveryKeyPolicyFactory::kClassName(), |
111 | 2 | [](const std::string& /*uri*/, |
112 | 2 | std::unique_ptr<FlushBlockPolicyFactory>* guard, |
113 | 2 | std::string* /* errmsg */) { |
114 | 0 | guard->reset(new FlushBlockEveryKeyPolicyFactory()); |
115 | 0 | return guard->get(); |
116 | 0 | }); |
117 | 2 | return 2; |
118 | 2 | } |
119 | | |
120 | | FlushBlockBySizePolicyFactory::FlushBlockBySizePolicyFactory() |
121 | 324k | : FlushBlockPolicyFactory() {} |
122 | | |
123 | | Status FlushBlockPolicyFactory::CreateFromString( |
124 | | const ConfigOptions& config_options, const std::string& value, |
125 | 55.0k | std::shared_ptr<FlushBlockPolicyFactory>* factory) { |
126 | 55.0k | static std::once_flag once; |
127 | 55.0k | std::call_once(once, [&]() { |
128 | 2 | RegisterFlushBlockPolicyFactories(*(ObjectLibrary::Default().get()), ""); |
129 | 2 | }); |
130 | | |
131 | 55.0k | if (value.empty()) { |
132 | 0 | factory->reset(new FlushBlockBySizePolicyFactory()); |
133 | 0 | return Status::OK(); |
134 | 55.0k | } else { |
135 | 55.0k | return LoadSharedObject<FlushBlockPolicyFactory>(config_options, value, |
136 | 55.0k | factory); |
137 | 55.0k | } |
138 | 55.0k | } |
139 | | } // namespace ROCKSDB_NAMESPACE |