WriteBufferManager

内容是新的,但是没有整理,偷懒了啊

WriteBufferManager

class WriteBufferManager final {
 public:
  // Parameters:
  // _buffer_size: _buffer_size = 0 indicates no limit. Memory won't be capped.
  // memory_usage() won't be valid and ShouldFlush() will always return true.
  //
  // cache_: if `cache` is provided, we'll put dummy entries in the cache and
  // cost the memory allocated to the cache. It can be used even if _buffer_size
  // = 0.
  //
  // allow_stall: if set true, it will enable stalling of writes when
  // memory_usage() exceeds buffer_size. It will wait for flush to complete and
  // memory usage to drop down.
  explicit WriteBufferManager(size_t _buffer_size,
                              std::shared_ptr cache = {},
                              bool allow_stall = false);
  // No copying allowed
  WriteBufferManager(const WriteBufferManager&) = delete;
  WriteBufferManager& operator=(const WriteBufferManager&) = delete;

  ~WriteBufferManager();

  // Returns true if buffer_limit is passed to limit the total memory usage and
  // is greater than 0.
  bool enabled() const { return buffer_size() > 0; }

  // Returns true if pointer to cache is passed.
  bool cost_to_cache() const { return cache_res_mgr_ != nullptr; }

  // Returns the total memory used by memtables.
  // Only valid if enabled()
  size_t memory_usage() const {
    return memory_used_.load(std::memory_order_relaxed);
  }

  // Returns the total memory used by active memtables.
  size_t mutable_memtable_memory_usage() const {
    return memory_active_.load(std::memory_order_relaxed);
  }

  size_t dummy_entries_in_cache_usage() const;

  // Returns the buffer_size.
  size_t buffer_size() const {
    return buffer_size_.load(std::memory_order_relaxed);
  }

  void SetBufferSize(size_t new_size) {
    buffer_size_.store(new_size, std::memory_order_relaxed);
    mutable_limit_.store(new_size * 7 / 8, std::memory_order_relaxed);
    // Check if stall is active and can be ended.
    MaybeEndWriteStall();
  }

  // Below functions should be called by RocksDB internally.

  // Should only be called from write thread
  bool ShouldFlush() const {
    if (enabled()) {
      if (mutable_memtable_memory_usage() >
          mutable_limit_.load(std::memory_order_relaxed)) {
        return true;
      }
      size_t local_size = buffer_size();
      if (memory_usage() >= local_size &&
          mutable_memtable_memory_usage() >= local_size / 2) {
        // If the memory exceeds the buffer size, we trigger more aggressive
        // flush. But if already more than half memory is being flushed,
        // triggering more flush may not help. We will hold it instead.
        return true;
      }
    }
    return false;
  }

  // Returns true if total memory usage exceeded buffer_size.
  // We stall the writes untill memory_usage drops below buffer_size. When the
  // function returns true, all writer threads (including one checking this
  // condition) across all DBs will be stalled. Stall is allowed only if user
  // pass allow_stall = true during WriteBufferManager instance creation.
  //
  // Should only be called by RocksDB internally .
  bool ShouldStall() const {
    if (!allow_stall_ || !enabled()) {
      return false;
    }

    return IsStallActive() || IsStallThresholdExceeded();
  }

  // Returns true if stall is active.
  bool IsStallActive() const {
    return stall_active_.load(std::memory_order_relaxed);
  }

  // Returns true if stalling condition is met.
  bool IsStallThresholdExceeded() const {
    return memory_usage() >= buffer_size_;
  }

  void ReserveMem(size_t mem);

  // We are in the process of freeing `mem` bytes, so it is not considered
  // when checking the soft limit.
  void ScheduleFreeMem(size_t mem);

  void FreeMem(size_t mem);

  // Add the DB instance to the queue and block the DB.
  // Should only be called by RocksDB internally.
  void BeginWriteStall(StallInterface* wbm_stall);

  // If stall conditions have resolved, remove DB instances from queue and
  // signal them to continue.
  void MaybeEndWriteStall();

  void RemoveDBFromQueue(StallInterface* wbm_stall);

  const std::shared_ptr& GetCache() const { return cache_; }

 private:
  std::atomic buffer_size_;
  std::atomic mutable_limit_;
  std::atomic memory_used_;
  // Memory that hasn't been scheduled to free.
  std::atomic memory_active_;
  std::shared_ptr cache_;
  std::shared_ptr cache_res_mgr_;
  // Protects cache_res_mgr_
  std::mutex cache_res_mgr_mu_;

  std::list queue_;
  // Protects the queue_ and stall_active_.
  std::mutex mu_;
  bool allow_stall_;
  // Value should only be changed by BeginWriteStall() and MaybeEndWriteStall()
  // while holding mu_, but it can be read without a lock.
  std::atomic stall_active_;

  void ReserveMemWithCache(size_t mem);
  void FreeMemWithCache(size_t mem);
};

问题

1、如何使用WriteBufferManager

SanitizeOptions:
    result.write_buffer_manager.reset(
        new WriteBufferManager(result.db_write_buffer_size));
        
MemTable::MemTable(const InternalKeyComparator& cmp,
                   const ImmutableOptions& ioptions,
                   const MutableCFOptions& mutable_cf_options,
                   WriteBufferManager* write_buffer_manager,
                   SequenceNumber latest_seq, uint32_t column_family_id)
                   
class AllocTracker {
 public:
  explicit AllocTracker(WriteBufferManager* write_buffer_manager);
  
void AllocTracker::Allocate(size_t bytes) {
  assert(write_buffer_manager_ != nullptr);
  if (write_buffer_manager_->enabled() ||
      write_buffer_manager_->cost_to_cache()) {
    bytes_allocated_.fetch_add(bytes, std::memory_order_relaxed);
    write_buffer_manager_->ReserveMem(bytes);
  }
}

2、WriteBufferManager 和 max_write_buffer_number 的关系

没什么关系,是两个不相关的内容

if (num_unflushed_memtables >= mutable_cf_options.max_write_buffer_number) {

3、WriteBufferManager 和 write_buffer_size 的关系

没什么关系,是两个不相关的内容

DBImpl::SwitchMemtable:
    const auto preallocate_block_size =
      GetWalPreallocateBlockSize(mutable_cf_options.write_buffer_size)
      
    io_s = CreateWAL(new_log_number, recycle_log_number, preallocate_block_size,
                     &new_log);
                     

MemTable::MemTable(const InternalKeyComparator& cmp,
                   const ImmutableOptions& ioptions,
                   const MutableCFOptions& mutable_cf_options,
                   WriteBufferManager* write_buffer_manager,
                   SequenceNumber latest_seq, uint32_t column_family_id)
    : comparator_(cmp),
      moptions_(ioptions, mutable_cf_options),
      refs_(0),
      kArenaBlockSize(OptimizeBlockSize(moptions_.arena_block_size)),
      mem_tracker_(write_buffer_manager),
      arena_(moptions_.arena_block_size,
             (write_buffer_manager != nullptr &&
              (write_buffer_manager->enabled() ||
               write_buffer_manager->cost_to_cache()))
                 ? &mem_tracker_
                 : nullptr,
             mutable_cf_options.memtable_huge_page_size),
      table_(ioptions.memtable_factory->CreateMemTableRep(
          comparator_, &arena_, mutable_cf_options.prefix_extractor.get(),
          ioptions.logger, column_family_id)),
      range_del_table_(SkipListFactory().CreateMemTableRep(
          comparator_, &arena_, nullptr /* transform */, ioptions.logger,
          column_family_id)),
      is_range_del_table_empty_(true),
      data_size_(0),
      num_entries_(0),
      num_deletes_(0),
      write_buffer_size_(mutable_cf_options.write_buffer_size),
      

AllocTracker::Allocate->WriteBufferManager::ReserveMem->WriteBufferManager::ReserveMemWithCache->cache_res_mgr_->UpdateCacheReservation

4、WriteBufferManager 如何控制内存

对内存没有硬性限制,通过ShouldFlush,判断是否需要操作释放内存

DBImpl::PreprocessWrite->if (UNLIKELY(status.ok() && write_buffer_manager_->ShouldFlush()))

5、总结 memtable 如何使用 WriteBufferManager 相关的接口

不是直接使用的,是通过MemTable构造函数中 "table_(ioptions.memtable_factory->CreateMemTableRep("使用arena_, arena_ 使用mem_tracker_, mem_tracker_ 使用write_buffer_manager,实现的

skiplist 如何使用的 WriteBufferManager

using MemtableSkipList = SkipList;

如何设置默认memtable

MemTableRepFactory
MemTable::MemTable->table_(ioptions.memtable_factory->CreateMemTableRep

SkipListFactory().CreateMemTableRep->SkipListRep
class SkipListRep : public MemTableRep

MemTable::Add->(table->InsertKeyValue)->MemTableRep::InsertKeyValue->SkipListRep::InsertKey->SkipListRep::Insert->InlineSkipList::Insert->InlineSkipList::Insert->

MemTableRep::InsertKeyValue->MemTableRep::EncodeKeyValue->Allocate->(allocator_->Allocate)->

待处理问题

1、总结自己实现一个类似skiplist需要适配哪些接口

skiplist适配过程

InlineSkipList
SkipListRep
SkipListFactory::CreateMemTableRep

class SkipListFactory : public MemTableRepFactory

你可能感兴趣的:(WriteBufferManager)