flush_block_policy.cc 5.0 KB

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