Skip to content
59 changes: 47 additions & 12 deletions be/src/vec/common/arena.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,20 +84,22 @@ class Arena : private boost::noncopyable {
size_t used() const { return pos - begin; }
};

size_t growth_factor;
size_t linear_growth_threshold;
size_t growth_factor = 2;
size_t linear_growth_threshold = 128 * 1024 * 1024;

/// Last contiguous chunk of memory.
Chunk* head = nullptr;
size_t size_in_bytes;
size_t size_in_bytes = 0;
size_t _initial_size = 4096;
// The memory used by all chunks, excluding head.
size_t _used_size_no_head;
size_t _used_size_no_head = 0;

static size_t round_up_to_page_size(size_t s) { return (s + 4096 - 1) / 4096 * 4096; }

/// If chunks size is less than 'linear_growth_threshold', then use exponential growth, otherwise - linear growth
/// (to not allocate too much excessive memory).
size_t next_size(size_t min_next_size) const {
size_t next_size(size_t min_next_size) {
DCHECK(head != nullptr);
size_t size_after_grow = 0;

if (head->size() < linear_growth_threshold) {
Expand All @@ -120,12 +122,20 @@ class Arena : private boost::noncopyable {
}

/// Add next contiguous chunk of memory with size not less than specified.
void NO_INLINE add_chunk(size_t min_size) {
void NO_INLINE _add_chunk(size_t min_size) {
DCHECK(head != nullptr);
_used_size_no_head += head->used();
head = new Chunk(next_size(min_size + pad_right), head);
size_in_bytes += head->size();
}

void _init_head_if_needed() {
if (UNLIKELY(head == nullptr)) {
head = new Chunk(_initial_size, nullptr);
size_in_bytes += head->size();
}
}

friend class ArenaAllocator;
template <size_t>
friend class AlignedArenaAllocator;
Expand All @@ -135,15 +145,18 @@ class Arena : private boost::noncopyable {
size_t linear_growth_threshold_ = 128 * 1024 * 1024)
: growth_factor(growth_factor_),
linear_growth_threshold(linear_growth_threshold_),
head(new Chunk(initial_size_, nullptr)),
size_in_bytes(head->size()),
_initial_size(initial_size_),
_used_size_no_head(0) {}

~Arena() { delete head; }

/// Get piece of memory, without alignment.
char* alloc(size_t size) {
if (UNLIKELY(head->pos + size > head->end)) add_chunk(size);
_init_head_if_needed();

if (UNLIKELY(head->pos + size > head->end)) {
_add_chunk(size);
}

char* res = head->pos;
head->pos += size;
Expand All @@ -153,6 +166,8 @@ class Arena : private boost::noncopyable {

/// Get piece of memory with alignment
char* aligned_alloc(size_t size, size_t alignment) {
_init_head_if_needed();

do {
void* head_pos = head->pos;
size_t space = head->end - head->pos;
Expand All @@ -165,7 +180,7 @@ class Arena : private boost::noncopyable {
return res;
}

add_chunk(size + alignment);
_add_chunk(size + alignment);
} while (true);
}

Expand All @@ -180,6 +195,8 @@ class Arena : private boost::noncopyable {
* the allocation it intended to roll back was indeed the last one.
*/
void* rollback(size_t size) {
DCHECK(head != nullptr);

head->pos -= size;
ASAN_POISON_MEMORY_REGION(head->pos, size + pad_right);
return head->pos;
Expand Down Expand Up @@ -208,6 +225,8 @@ class Arena : private boost::noncopyable {
return result;
}

DCHECK(head != nullptr);

// Extend an existing memory range with 'additional_bytes'.

// This method only works for extending the last allocation. For lack of
Expand Down Expand Up @@ -291,6 +310,10 @@ class Arena : private boost::noncopyable {
* and only 128M can be reused when you apply for 4G memory again.
*/
void clear() {
if (head == nullptr) {
return;
}

if (head->prev) {
delete head->prev;
head->prev = nullptr;
Expand All @@ -303,9 +326,21 @@ class Arena : private boost::noncopyable {
/// Size of chunks in bytes.
size_t size() const { return size_in_bytes; }

size_t used_size() const { return _used_size_no_head + head->used(); }
size_t used_size() const {
if (head == nullptr) {
return _used_size_no_head;
}

return _used_size_no_head + head->used();
}

size_t remaining_space_in_current_chunk() const {
if (head == nullptr) {
return 0;
}

size_t remaining_space_in_current_chunk() const { return head->remaining(); }
return head->remaining();
}
};

using ArenaPtr = std::shared_ptr<Arena>;
Expand Down