#pragma once
#include <cstddef>
#include <deque>
#include "memory/allocator.h"
#include "port/mmap.h"
#include "rocksdb/env.h"
namespace ROCKSDB_NAMESPACE {
class Arena : public Allocator {
public:
Arena(const Arena&) = delete;
void operator=(const Arena&) = delete;
static constexpr size_t kInlineSize = 2048;
static constexpr size_t kMinBlockSize = 4096;
static constexpr size_t kMaxBlockSize = 2u << 30;
static constexpr unsigned kAlignUnit = alignof(std::max_align_t);
static_assert((kAlignUnit & (kAlignUnit - 1)) == 0,
"Pointer size should be power of 2");
explicit Arena(size_t block_size = kMinBlockSize,
AllocTracker* tracker = nullptr, size_t huge_page_size = 0);
~Arena();
char* Allocate(size_t bytes) override;
char* AllocateAligned(size_t bytes, size_t huge_page_size = 0,
Logger* logger = nullptr) override;
size_t ApproximateMemoryUsage() const {
return blocks_memory_ + blocks_.size() * sizeof(char*) -
alloc_bytes_remaining_;
}
size_t MemoryAllocatedBytes() const { return blocks_memory_; }
size_t AllocatedAndUnused() const { return alloc_bytes_remaining_; }
size_t IrregularBlockNum() const { return irregular_block_num; }
size_t BlockSize() const override { return kBlockSize; }
bool IsInInlineBlock() const {
return blocks_.empty() && huge_blocks_.empty();
}
static size_t OptimizeBlockSize(size_t block_size);
private:
alignas(std::max_align_t) char inline_block_[kInlineSize];
const size_t kBlockSize;
std::deque<std::unique_ptr<char[]>> blocks_;
std::deque<MemMapping> huge_blocks_;
size_t irregular_block_num = 0;
char* unaligned_alloc_ptr_ = nullptr;
char* aligned_alloc_ptr_ = nullptr;
size_t alloc_bytes_remaining_ = 0;
size_t hugetlb_size_ = 0;
char* AllocateFromHugePage(size_t bytes);
char* AllocateFallback(size_t bytes, bool aligned);
char* AllocateNewBlock(size_t block_bytes);
size_t blocks_memory_ = 0;
AllocTracker* tracker_;
};
inline char* Arena::Allocate(size_t bytes) {
assert(bytes > 0);
if (bytes <= alloc_bytes_remaining_) {
unaligned_alloc_ptr_ -= bytes;
alloc_bytes_remaining_ -= bytes;
return unaligned_alloc_ptr_;
}
return AllocateFallback(bytes, false );
}
template <typename T>
struct Destroyer {
void operator()(T* ptr) { ptr->~T(); }
};
template <typename T>
using ScopedArenaPtr = std::unique_ptr<T, Destroyer<T>>;
}