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 // Copyright (c) 2011 The LevelDB Authors. All rights reserved. 7 // Use of this source code is governed by a BSD-style license that can be 8 // found in the LICENSE file. See the AUTHORS file for names of contributors. 9 10 #pragma once 11 12 #include "rocksdb/env.h" 13 #include "rocksdb/statistics.h" 14 15 namespace ROCKSDB_NAMESPACE { 16 17 class RateLimiter { 18 public: 19 enum class OpType { 20 // Limitation: we currently only invoke Request() with OpType::kRead for 21 // compactions when DBOptions::new_table_reader_for_compaction_inputs is set 22 kRead, 23 kWrite, 24 }; 25 enum class Mode { 26 kReadsOnly, 27 kWritesOnly, 28 kAllIo, 29 }; 30 31 // For API compatibility, default to rate-limiting writes only. mode_(mode)32 explicit RateLimiter(Mode mode = Mode::kWritesOnly) : mode_(mode) {} 33 ~RateLimiter()34 virtual ~RateLimiter() {} 35 36 // This API allows user to dynamically change rate limiter's bytes per second. 37 // REQUIRED: bytes_per_second > 0 38 virtual void SetBytesPerSecond(int64_t bytes_per_second) = 0; 39 40 // Deprecated. New RateLimiter derived classes should override 41 // Request(const int64_t, const Env::IOPriority, Statistics*) or 42 // Request(const int64_t, const Env::IOPriority, Statistics*, OpType) 43 // instead. 44 // 45 // Request for token for bytes. If this request can not be satisfied, the call 46 // is blocked. Caller is responsible to make sure 47 // bytes <= GetSingleBurstBytes() Request(const int64_t,const Env::IOPriority)48 virtual void Request(const int64_t /*bytes*/, const Env::IOPriority /*pri*/) { 49 assert(false); 50 } 51 52 // Request for token for bytes and potentially update statistics. If this 53 // request can not be satisfied, the call is blocked. Caller is responsible to 54 // make sure bytes <= GetSingleBurstBytes(). Request(const int64_t bytes,const Env::IOPriority pri,Statistics *)55 virtual void Request(const int64_t bytes, const Env::IOPriority pri, 56 Statistics* /* stats */) { 57 // For API compatibility, default implementation calls the older API in 58 // which statistics are unsupported. 59 Request(bytes, pri); 60 } 61 62 // Requests token to read or write bytes and potentially updates statistics. 63 // 64 // If this request can not be satisfied, the call is blocked. Caller is 65 // responsible to make sure bytes <= GetSingleBurstBytes(). Request(const int64_t bytes,const Env::IOPriority pri,Statistics * stats,OpType op_type)66 virtual void Request(const int64_t bytes, const Env::IOPriority pri, 67 Statistics* stats, OpType op_type) { 68 if (IsRateLimited(op_type)) { 69 Request(bytes, pri, stats); 70 } 71 } 72 73 // Requests token to read or write bytes and potentially updates statistics. 74 // Takes into account GetSingleBurstBytes() and alignment (e.g., in case of 75 // direct I/O) to allocate an appropriate number of bytes, which may be less 76 // than the number of bytes requested. 77 virtual size_t RequestToken(size_t bytes, size_t alignment, 78 Env::IOPriority io_priority, Statistics* stats, 79 RateLimiter::OpType op_type); 80 81 // Max bytes can be granted in a single burst 82 virtual int64_t GetSingleBurstBytes() const = 0; 83 84 // Total bytes that go through rate limiter 85 virtual int64_t GetTotalBytesThrough( 86 const Env::IOPriority pri = Env::IO_TOTAL) const = 0; 87 88 // Total # of requests that go through rate limiter 89 virtual int64_t GetTotalRequests( 90 const Env::IOPriority pri = Env::IO_TOTAL) const = 0; 91 92 virtual int64_t GetBytesPerSecond() const = 0; 93 IsRateLimited(OpType op_type)94 virtual bool IsRateLimited(OpType op_type) { 95 if ((mode_ == RateLimiter::Mode::kWritesOnly && 96 op_type == RateLimiter::OpType::kRead) || 97 (mode_ == RateLimiter::Mode::kReadsOnly && 98 op_type == RateLimiter::OpType::kWrite)) { 99 return false; 100 } 101 return true; 102 } 103 104 protected: GetMode()105 Mode GetMode() { return mode_; } 106 107 private: 108 const Mode mode_; 109 }; 110 111 // Create a RateLimiter object, which can be shared among RocksDB instances to 112 // control write rate of flush and compaction. 113 // @rate_bytes_per_sec: this is the only parameter you want to set most of the 114 // time. It controls the total write rate of compaction and flush in bytes per 115 // second. Currently, RocksDB does not enforce rate limit for anything other 116 // than flush and compaction, e.g. write to WAL. 117 // @refill_period_us: this controls how often tokens are refilled. For example, 118 // when rate_bytes_per_sec is set to 10MB/s and refill_period_us is set to 119 // 100ms, then 1MB is refilled every 100ms internally. Larger value can lead to 120 // burstier writes while smaller value introduces more CPU overhead. 121 // The default should work for most cases. 122 // @fairness: RateLimiter accepts high-pri requests and low-pri requests. 123 // A low-pri request is usually blocked in favor of hi-pri request. Currently, 124 // RocksDB assigns low-pri to request from compaction and high-pri to request 125 // from flush. Low-pri requests can get blocked if flush requests come in 126 // continuously. This fairness parameter grants low-pri requests permission by 127 // 1/fairness chance even though high-pri requests exist to avoid starvation. 128 // You should be good by leaving it at default 10. 129 // @mode: Mode indicates which types of operations count against the limit. 130 // @auto_tuned: Enables dynamic adjustment of rate limit within the range 131 // `[rate_bytes_per_sec / 20, rate_bytes_per_sec]`, according to 132 // the recent demand for background I/O. 133 extern RateLimiter* NewGenericRateLimiter( 134 int64_t rate_bytes_per_sec, int64_t refill_period_us = 100 * 1000, 135 int32_t fairness = 10, 136 RateLimiter::Mode mode = RateLimiter::Mode::kWritesOnly, 137 bool auto_tuned = false); 138 139 } // namespace ROCKSDB_NAMESPACE 140