dirty_memory_manager: move region_group::allocating_function and related classes to new class allocation_queue

region_group currently fulfills two roles: in one role, when instantiated
as dirty_memory_manager::_virtual_region_group, it is responsible
for holding functions that allocate memtable memory (writes) and only
allowing them to run when enough dirty memory has been flushed from other
memtables. The other role, when instantiated as
dirty_memory_manager::_real_region_group, is to provide a hard stop when
the total amount of dirty memory exceeds the limit, since the other limit
is only estimated.

We want to simplify the whole thing, which means not using the same class
for two different roles (or rather, we can use it for both roles if we
simplify the internals significantly).

As a first step towards clarifying what functionality is used in what
role, move some classes related to holding allocating functions to a new
class allocation_queue. We will gradually move move content there, reducing
the amount of role confusion in region_group.

Type aliases are added to reduce churn.
This commit is contained in:
Avi Kivity
2022-09-11 16:53:46 +03:00
parent d21d2cdb3e
commit 71493c2539
2 changed files with 25 additions and 15 deletions

View File

@@ -187,7 +187,7 @@ void region_group::update(ssize_t delta) {
}
}
void region_group::on_request_expiry::operator()(std::unique_ptr<allocating_function>& func) noexcept {
void allocation_queue::on_request_expiry::operator()(std::unique_ptr<allocating_function>& func) noexcept {
func->fail(std::make_exception_ptr(blocked_requests_timed_out_error{_name}));
}

View File

@@ -115,20 +115,8 @@ public:
}
};
// Groups regions for the purpose of statistics. Can be nested.
// Interfaces to regions via region_listener
class region_group : public region_listener {
static region_group_reclaimer no_reclaimer;
using region_heap = dirty_memory_manager_logalloc::region_heap;
region_group* _parent = nullptr;
size_t _total_memory = 0;
region_group_reclaimer& _reclaimer;
region_group* _subgroup = nullptr;
region_heap _regions;
class allocation_queue {
public:
struct allocating_function {
virtual ~allocating_function() = default;
virtual void allocate() = 0;
@@ -169,6 +157,28 @@ class region_group : public region_listener {
explicit on_request_expiry(sstring name) : _name(std::move(name)) {}
void operator()(std::unique_ptr<allocating_function>&) noexcept;
};
};
// Groups regions for the purpose of statistics. Can be nested.
// Interfaces to regions via region_listener
class region_group : public region_listener {
static region_group_reclaimer no_reclaimer;
using region_heap = dirty_memory_manager_logalloc::region_heap;
region_group* _parent = nullptr;
size_t _total_memory = 0;
region_group_reclaimer& _reclaimer;
region_group* _subgroup = nullptr;
region_heap _regions;
using allocating_function = allocation_queue::allocating_function;
template <typename Func>
using concrete_allocating_function = allocation_queue::concrete_allocating_function<Func>;
using on_request_expiry = allocation_queue::on_request_expiry;
// It is a more common idiom to just hold the promises in the circular buffer and make them
// ready. However, in the time between the promise being made ready and the function execution,