| // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
| // This source code is licensed under both the GPLv2 (found in the |
| // COPYING file in the root directory) and Apache 2.0 License |
| // (found in the LICENSE.Apache file in the root directory). |
| // |
| // Copyright (c) 2011 The LevelDB Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. See the AUTHORS file for names of contributors. |
| |
| #pragma once |
| |
| #include "rocksdb/env.h" |
| #include "rocksdb/statistics.h" |
| |
| namespace rocksdb { |
| |
| class RateLimiter { |
| public: |
| enum class OpType { |
| // Limitation: we currently only invoke Request() with OpType::kRead for |
| // compactions when DBOptions::new_table_reader_for_compaction_inputs is set |
| kRead, |
| kWrite, |
| }; |
| enum class Mode { |
| kReadsOnly, |
| kWritesOnly, |
| kAllIo, |
| }; |
| |
| // For API compatibility, default to rate-limiting writes only. |
| explicit RateLimiter(Mode mode = Mode::kWritesOnly) : mode_(mode) {} |
| |
| virtual ~RateLimiter() {} |
| |
| // This API allows user to dynamically change rate limiter's bytes per second. |
| // REQUIRED: bytes_per_second > 0 |
| virtual void SetBytesPerSecond(int64_t bytes_per_second) = 0; |
| |
| // Deprecated. New RateLimiter derived classes should override |
| // Request(const int64_t, const Env::IOPriority, Statistics*) or |
| // Request(const int64_t, const Env::IOPriority, Statistics*, OpType) |
| // instead. |
| // |
| // Request for token for bytes. If this request can not be satisfied, the call |
| // is blocked. Caller is responsible to make sure |
| // bytes <= GetSingleBurstBytes() |
| virtual void Request(const int64_t bytes, const Env::IOPriority pri) { |
| assert(false); |
| } |
| |
| // Request for token for bytes and potentially update statistics. If this |
| // request can not be satisfied, the call is blocked. Caller is responsible to |
| // make sure bytes <= GetSingleBurstBytes(). |
| virtual void Request(const int64_t bytes, const Env::IOPriority pri, |
| Statistics* /* stats */) { |
| // For API compatibility, default implementation calls the older API in |
| // which statistics are unsupported. |
| Request(bytes, pri); |
| } |
| |
| // Requests token to read or write bytes and potentially updates statistics. |
| // |
| // If this request can not be satisfied, the call is blocked. Caller is |
| // responsible to make sure bytes <= GetSingleBurstBytes(). |
| virtual void Request(const int64_t bytes, const Env::IOPriority pri, |
| Statistics* stats, OpType op_type) { |
| if (IsRateLimited(op_type)) { |
| Request(bytes, pri, stats); |
| } |
| } |
| |
| // Requests token to read or write bytes and potentially updates statistics. |
| // Takes into account GetSingleBurstBytes() and alignment (e.g., in case of |
| // direct I/O) to allocate an appropriate number of bytes, which may be less |
| // than the number of bytes requested. |
| virtual size_t RequestToken(size_t bytes, size_t alignment, |
| Env::IOPriority io_priority, Statistics* stats, |
| RateLimiter::OpType op_type); |
| |
| // Max bytes can be granted in a single burst |
| virtual int64_t GetSingleBurstBytes() const = 0; |
| |
| // Total bytes that go though rate limiter |
| virtual int64_t GetTotalBytesThrough( |
| const Env::IOPriority pri = Env::IO_TOTAL) const = 0; |
| |
| // Total # of requests that go though rate limiter |
| virtual int64_t GetTotalRequests( |
| const Env::IOPriority pri = Env::IO_TOTAL) const = 0; |
| |
| virtual int64_t GetBytesPerSecond() const = 0; |
| |
| virtual bool IsRateLimited(OpType op_type) { |
| if ((mode_ == RateLimiter::Mode::kWritesOnly && |
| op_type == RateLimiter::OpType::kRead) || |
| (mode_ == RateLimiter::Mode::kReadsOnly && |
| op_type == RateLimiter::OpType::kWrite)) { |
| return false; |
| } |
| return true; |
| } |
| |
| protected: |
| Mode GetMode() { return mode_; } |
| |
| private: |
| const Mode mode_; |
| }; |
| |
| // Create a RateLimiter object, which can be shared among RocksDB instances to |
| // control write rate of flush and compaction. |
| // @rate_bytes_per_sec: this is the only parameter you want to set most of the |
| // time. It controls the total write rate of compaction and flush in bytes per |
| // second. Currently, RocksDB does not enforce rate limit for anything other |
| // than flush and compaction, e.g. write to WAL. |
| // @refill_period_us: this controls how often tokens are refilled. For example, |
| // when rate_bytes_per_sec is set to 10MB/s and refill_period_us is set to |
| // 100ms, then 1MB is refilled every 100ms internally. Larger value can lead to |
| // burstier writes while smaller value introduces more CPU overhead. |
| // The default should work for most cases. |
| // @fairness: RateLimiter accepts high-pri requests and low-pri requests. |
| // A low-pri request is usually blocked in favor of hi-pri request. Currently, |
| // RocksDB assigns low-pri to request from compaction and high-pri to request |
| // from flush. Low-pri requests can get blocked if flush requests come in |
| // continuously. This fairness parameter grants low-pri requests permission by |
| // 1/fairness chance even though high-pri requests exist to avoid starvation. |
| // You should be good by leaving it at default 10. |
| // @mode: Mode indicates which types of operations count against the limit. |
| extern RateLimiter* NewGenericRateLimiter( |
| int64_t rate_bytes_per_sec, int64_t refill_period_us = 100 * 1000, |
| int32_t fairness = 10, |
| RateLimiter::Mode mode = RateLimiter::Mode::kWritesOnly); |
| |
| } // namespace rocksdb |