Coverage Report

Created: 2026-02-14 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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