Commit d6f6bfa3 authored by Dominik Charousset's avatar Dominik Charousset Committed by Dominik Charousset

Allow task queues to drop items

parent 036fc630
......@@ -129,25 +129,25 @@ public:
/// Appends `ptr` to the queue.
/// @pre `ptr != nullptr`
void push_back(pointer ptr) noexcept {
bool push_back(pointer ptr) noexcept {
CAF_ASSERT(ptr != nullptr);
tail_.next->next = ptr;
tail_.next = ptr;
ptr->next = &tail_;
inc_total_task_size(*ptr);
return true;
}
/// Appends `ptr` to the queue.
/// @pre `ptr != nullptr`
void push_back(unique_pointer ptr) noexcept {
CAF_ASSERT(ptr != nullptr);
push_back(ptr.release());
bool push_back(unique_pointer ptr) noexcept {
return push_back(ptr.release());
}
/// Creates a new element from `xs...` and appends it.
template <class... Ts>
void emplace_back(Ts&&... xs) {
push_back(new value_type(std::forward<Ts>(xs)...));
bool emplace_back(Ts&&... xs) {
return push_back(new value_type(std::forward<Ts>(xs)...));
}
/// @private
......
......@@ -64,42 +64,63 @@ public:
return policy_;
}
void push_back(mapped_type* ptr) noexcept {
bool push_back(mapped_type* ptr) noexcept {
auto i = qs_.find(policy_.id_of(*ptr));
if (i != qs_.end()) {
i->second.push_back(ptr);
return true;
} else {
deleter_type d;
d(ptr);
return false;
}
}
void push_back(unique_pointer ptr) noexcept {
push_back(ptr.release());
bool push_back(unique_pointer ptr) noexcept {
return push_back(ptr.release());
}
template <class... Ts>
void emplace_back(Ts&&... xs) {
push_back(new mapped_type(std::forward<Ts>(xs)...));
bool emplace_back(Ts&&... xs) {
return push_back(new mapped_type(std::forward<Ts>(xs)...));
}
/// @private
template <class F>
struct new_round_helper {
const key_type& k;
queue_type& q;
F& f;
template <class... Ts>
auto operator()(Ts&&... xs)
-> decltype((std::declval<F&>())(std::declval<const key_type&>(),
std::declval<queue_type&>(),
std::forward<Ts>(xs)...)) {
return f(k, q, std::forward<Ts>(xs)...);
}
};
/// Run a new round with `quantum`, dispatching all tasks to `consumer`.
/// @returns `true` if at least one item was consumed, `false` otherwise.
template <class F>
bool new_round(long quantum,
F& f) noexcept(noexcept(f(std::declval<const key_type&>(),
std::declval<queue_type&>(),
std::declval<mapped_type&>()))) {
bool new_round(long quantum, F& f) {
bool result = false;
for (auto& kvp : qs_) {
auto g = [&](mapped_type& x) {
f(kvp.first, kvp.second, x);
};
result |= kvp.second.new_round(policy_.quantum(kvp.second, quantum), g);
new_round_helper<F> g{kvp.first, kvp.second, f};
result |= g.q.new_round(policy_.quantum(g.q, quantum), g);
}
if (!erase_list_.empty()) {
for (auto& k : erase_list_)
qs_.erase(k);
erase_list_.clear();
}
return result;
}
void erase_later(key_type k) {
erase_list_.emplace_back(std::move(k));
}
pointer peek() noexcept {
for (auto& kvp : qs_) {
auto ptr = kvp.second.peek();
......@@ -159,6 +180,9 @@ private:
/// Policy object for adjusting a quantum based on queue weight etc.
Policy policy_;
/// List of keys that are marked erased.
std::vector<key_type> erase_list_;
};
} // namespace intrusive
......
......@@ -68,17 +68,17 @@ public:
return policy_;
}
void push_back(mapped_type* ptr) noexcept {
push_back_recursion<0>(policy_.id_of(*ptr), ptr);
bool push_back(mapped_type* ptr) noexcept {
return push_back_recursion<0>(policy_.id_of(*ptr), ptr);
}
void push_back(unique_pointer ptr) noexcept {
push_back(ptr.release());
bool push_back(unique_pointer ptr) noexcept {
return push_back(ptr.release());
}
template <class... Ts>
void emplace_back(Ts&&... xs) {
push_back(new mapped_type(std::forward<Ts>(xs)...));
bool emplace_back(Ts&&... xs) {
return push_back(new mapped_type(std::forward<Ts>(xs)...));
}
/// Run a new round with `quantum`, dispatching all tasks to `consumer`.
......@@ -127,21 +127,34 @@ private:
// -- recursive helper functions ---------------------------------------------
template <size_t I>
detail::enable_if_t<I == num_queues>
detail::enable_if_t<I == num_queues, bool>
push_back_recursion(size_t, mapped_type*) noexcept {
// nop
return false;
}
template <size_t I>
detail::enable_if_t<I != num_queues>
detail::enable_if_t<I != num_queues, bool>
push_back_recursion(size_t pos, mapped_type* ptr) noexcept {
if (pos == I) {
auto& q = std::get<I>(qs_);
q.push_back(ptr);
} else {
push_back_recursion<I + 1>(pos, ptr);
return q.push_back(ptr);
}
}
return push_back_recursion<I + 1>(pos, ptr);
}
template <size_t I, class Queue, class F>
struct new_round_recursion_helper {
Queue& q;
F& f;
template <class... Ts>
auto operator()(Ts&&... xs)
-> decltype((std::declval<F&>())(std::declval<index<I>>(),
std::declval<Queue&>(),
std::forward<Ts>(xs)...)) {
index<I> id;
return f(id, q, std::forward<Ts>(xs)...);
}
};
template <size_t I, class F>
detail::enable_if_t<I == num_queues, int>
......@@ -153,10 +166,8 @@ private:
detail::enable_if_t<I != num_queues, int>
new_round_recursion(deficit_type quantum, F& f) {
auto& q = std::get<I>(qs_);
auto g = [&](mapped_type& x) {
index<I> id;
return f(id, q, x);
};
using q_type = typename std::decay<decltype(q)>::type;
new_round_recursion_helper<I, q_type, F> g{q, f};
if (q.new_round(policy_.quantum(q, quantum), g))
return 1 + new_round_recursion<I + 1>(quantum, f);
return 0 + new_round_recursion<I + 1>(quantum, f);
......
......@@ -85,10 +85,6 @@ struct inode_policy {
using queue_map_type = std::map<key_type, queue_type>;
static inline task_size_type task_size(const mapped_type&) {
return 1;
}
static inline key_type id_of(const inode& x) {
return x.value % 3;
}
......@@ -108,14 +104,13 @@ struct fixture {
inode_policy policy;
queue_type queue{policy};
void fill(queue_type&) {
// nop
int fill(queue_type&) {
return 0;
}
template <class T, class... Ts>
void fill(queue_type& q, T x, Ts... xs) {
q.emplace_back(x);
fill(q, xs...);
int fill(queue_type& q, T x, Ts... xs) {
return (q.emplace_back(x) ? 1 : 0) + fill(q, xs...);
}
std::string fetch(int quantum) {
......@@ -148,7 +143,7 @@ CAF_TEST(default_constructed) {
CAF_TEST(dropping) {
CAF_REQUIRE_EQUAL(queue.empty(), true);
fill(queue, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12);
CAF_REQUIRE_EQUAL(fill(queue, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12), 0);
CAF_REQUIRE_EQUAL(queue.empty(), true);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment