class OpQueue {
public:
- // How many Ops are in the queue
- virtual unsigned length() const = 0;
// Ops of this class should be deleted immediately. If out isn't
// nullptr then items should be added to the front in
// front-to-back order. The typical strategy is to visit items in
min_cost(min_c)
{}
- unsigned length() const final {
+ unsigned length() const {
unsigned total = 0;
for (typename SubQueues::const_iterator i = queue.begin();
i != queue.end();
unsigned get_size() const {
return lp.size();
}
- unsigned filter_class(std::list<T>* out) {
- unsigned count = 0;
+ void filter_class(std::list<T>* out) {
for (Lit i = --lp.end();; --i) {
if (out) {
out->push_front(std::move(i->item));
}
i = lp.erase_and_dispose(i, DelItem<ListPair>());
- ++count;
if (i == lp.begin()) {
break;
}
}
- return count;
}
};
class SubQueue : public bi::set_base_hook<>
check_end();
return ret;
}
- unsigned filter_class(K& cl, std::list<T>* out) {
- unsigned count = 0;
+ void filter_class(K& cl, std::list<T>* out) {
Kit i = klasses.find(cl, MapKey<Klass, K>());
if (i != klasses.end()) {
- count = i->filter_class(out);
+ i->filter_class(out);
Kit tmp = klasses.erase_and_dispose(i, DelItem<Klass>());
if (next == i) {
next = tmp;
}
check_end();
}
+ }
+ // this is intended for unit tests and should be never used on hot paths
+ unsigned get_size_slow() const {
+ unsigned count = 0;
+ for (const auto& klass : klasses) {
+ count += klass.get_size();
+ }
return count;
}
void dump(ceph::Formatter *f) const {
unsigned total_prio;
unsigned max_cost;
public:
- unsigned size;
Queue() :
total_prio(0),
- max_cost(0),
- size(0) {
+ max_cost(0) {
}
~Queue() {
queues.clear_and_dispose(DelItem<SubQueue>());
}
bool empty() const {
- return !size;
+ return queues.empty();
}
void insert(unsigned p, K cl, unsigned cost, T&& item, bool front = false) {
typename SubQueues::insert_commit_data insert_data;
if (cost > max_cost) {
max_cost = cost;
}
- ++size;
}
T pop(bool strict = false) {
- --size;
Sit i = --queues.end();
if (strict) {
T ret = i->pop();
}
void filter_class(K& cl, std::list<T>* out) {
for (Sit i = queues.begin(); i != queues.end();) {
- size -= i->filter_class(cl, out);
+ i->filter_class(cl, out);
if (i->empty()) {
total_prio -= i->key;
i = queues.erase_and_dispose(i, DelItem<SubQueue>());
}
}
}
+ // this is intended for unit tests and should be never used on hot paths
+ unsigned get_size_slow() const {
+ unsigned count = 0;
+ for (const auto& queue : queues) {
+ count += queue.get_size_slow();
+ }
+ return count;
+ }
void dump(ceph::Formatter *f) const {
for (typename SubQueues::const_iterator i = queues.begin();
i != queues.end(); ++i) {
{
std::srand(time(0));
}
- unsigned length() const final {
- return strict.size + normal.size;
- }
void remove_by_class(K cl, std::list<T>* removed = 0) final {
strict.filter_class(cl, removed);
normal.filter_class(cl, removed);
}
bool empty() const final {
- return !(strict.size + normal.size);
+ return strict.empty() && normal.empty();
}
void enqueue_strict(K cl, unsigned p, T&& item) final {
strict.insert(p, cl, 0, std::move(item));
normal.insert(p, cl, cost, std::move(item), true);
}
T dequeue() override {
- ceph_assert(strict.size + normal.size > 0);
+ ceph_assert(!empty());
if (!strict.empty()) {
return strict.pop(true);
}
return normal.pop();
}
+ unsigned get_size_slow() {
+ return strict.get_size_slow() + normal.get_size_slow();
+ }
void dump(ceph::Formatter *f) const override {
f->open_array_section("high_queues");
strict.dump(f);
Classes q;
unsigned tokens, max_tokens;
- int64_t size;
+ int64_t size; // XXX: this is only for the sake of dump().
typename Classes::iterator cur;
}
void dump(ceph::Formatter *f) const {
- f->dump_int("size", size);
+ f->dump_int("size", length());
f->dump_int("num_keys", q.size());
}
};
// empty
}
- unsigned length() const override final {
+ // XXX: used only by the unitest?
+ unsigned length() const {
unsigned total = 0;
total += queue_front.size();
total += queue.request_count();
const crimson::dmclock::ClientInfo* op_class_client_info_f(const InnerClient& client);
- inline unsigned length() const override final {
- return queue.length();
- }
-
// Ops of this priority should be deleted immediately
inline void remove_by_class(Client cl,
std::list<Request> *out) override final {
const crimson::dmclock::ClientInfo*
op_class_client_info_f(const osd_op_type_t& op_type);
- inline unsigned length() const override final {
- return queue.length();
- }
-
// Ops of this priority should be deleted immediately
inline void remove_by_class(Client cl,
std::list<Request> *out) override final {
TEST_F(WeightedPriorityQueueTest, wpq_size){
WQ wq(0, 0);
EXPECT_TRUE(wq.empty());
- EXPECT_EQ(0u, wq.length());
+ EXPECT_EQ(0u, wq.get_size_slow());
// Test the strict queue size.
for (unsigned i = 1; i < 5; ++i) {
wq.enqueue_strict(Klass(i),i, std::make_tuple(i, i, i));
EXPECT_FALSE(wq.empty());
- EXPECT_EQ(i, wq.length());
+ EXPECT_EQ(i, wq.get_size_slow());
}
// Test the normal queue size.
for (unsigned i = 5; i < 10; ++i) {
wq.enqueue(Klass(i), i, i, std::make_tuple(i, i, i));
EXPECT_FALSE(wq.empty());
- EXPECT_EQ(i, wq.length());
+ EXPECT_EQ(i, wq.get_size_slow());
}
// Test that as both queues are emptied
// the size is correct.
for (unsigned i = 8; i >0; --i) {
wq.dequeue();
EXPECT_FALSE(wq.empty());
- EXPECT_EQ(i, wq.length());
+ EXPECT_EQ(i, wq.get_size_slow());
}
wq.dequeue();
EXPECT_TRUE(wq.empty());
- EXPECT_EQ(0u, wq.length());
+ EXPECT_EQ(0u, wq.get_size_slow());
}
TEST_F(WeightedPriorityQueueTest, wpq_test_static) {
wq.remove_by_class(k, &wq_removed);
// Check that the right ops were removed.
EXPECT_EQ(num_to_remove, wq_removed.size());
- EXPECT_EQ(num_items - num_to_remove, wq.length());
+ EXPECT_EQ(num_items - num_to_remove, wq.get_size_slow());
for (Removed::iterator it = wq_removed.begin();
it != wq_removed.end(); ++it) {
EXPECT_EQ(k, std::get<1>(*it));