1
0
mirror of https://github.com/ceph/ceph synced 2024-12-24 04:14:07 +00:00

common/Finisher: simplify

The second _rval list was a dumb idea.  A vector of pairs is simpler
and more efficient.

Also, extend support to any container type.

Signed-off-by: Sage Weil <sage@redhat.com>
This commit is contained in:
Sage Weil 2017-09-13 11:50:32 -05:00
parent da7d071654
commit f46efeb47c
2 changed files with 20 additions and 36 deletions

View File

@ -50,11 +50,10 @@ void *Finisher::finisher_thread_entry()
/// Every time we are woken up, we process the queue until it is empty.
while (!finisher_queue.empty()) {
// To reduce lock contention, we swap out the queue to process.
// This way other threads can submit new contexts to complete while we are working.
vector<Context*> ls;
list<pair<Context*,int> > ls_rval;
// This way other threads can submit new contexts to complete
// while we are working.
vector<pair<Context*,int>> ls;
ls.swap(finisher_queue);
ls_rval.swap(finisher_queue_rval);
finisher_running = true;
finisher_lock.Unlock();
ldout(cct, 10) << "finisher_thread doing " << ls << dendl;
@ -65,21 +64,8 @@ void *Finisher::finisher_thread_entry()
}
// Now actually process the contexts.
for (vector<Context*>::iterator p = ls.begin();
p != ls.end();
++p) {
if (*p) {
(*p)->complete(0);
} else {
// When an item is NULL in the finisher_queue, it means
// we should instead process an item from finisher_queue_rval,
// which has a parameter for complete() other than zero.
// This preserves the order while saving some storage.
assert(!ls_rval.empty());
Context *c = ls_rval.front().first;
c->complete(ls_rval.front().second);
ls_rval.pop_front();
}
for (auto p : ls) {
p.first->complete(p.second);
}
ldout(cct, 10) << "finisher_thread done with " << ls << dendl;
ls.clear();

View File

@ -42,17 +42,12 @@ class Finisher {
bool finisher_stop; ///< Set when the finisher should stop.
bool finisher_running; ///< True when the finisher is currently executing contexts.
bool finisher_empty_wait; ///< True mean someone wait finisher empty.
/// Queue for contexts for which complete(0) will be called.
/// NULLs in this queue indicate that an item from finisher_queue_rval
/// should be completed in that place instead.
vector<Context*> finisher_queue;
vector<pair<Context*,int>> finisher_queue;
string thread_name;
/// Queue for contexts for which the complete function will be called
/// with a parameter other than 0.
list<pair<Context*,int> > finisher_queue_rval;
/// Performance counter for the finisher's queue length.
/// Only active for named finishers.
PerfCounters *logger;
@ -72,21 +67,20 @@ class Finisher {
if (finisher_queue.empty()) {
finisher_cond.Signal();
}
if (r) {
finisher_queue_rval.push_back(pair<Context*, int>(c, r));
finisher_queue.push_back(NULL);
} else
finisher_queue.push_back(c);
finisher_queue.push_back(make_pair(c, r));
if (logger)
logger->inc(l_finisher_queue_len);
finisher_lock.Unlock();
}
void queue(vector<Context*>& ls) {
void queue(list<Context*>& ls) {
finisher_lock.Lock();
if (finisher_queue.empty()) {
finisher_cond.Signal();
}
finisher_queue.insert(finisher_queue.end(), ls.begin(), ls.end());
for (auto i : ls) {
finisher_queue.push_back(make_pair(i, 0));
}
if (logger)
logger->inc(l_finisher_queue_len, ls.size());
finisher_lock.Unlock();
@ -97,18 +91,22 @@ class Finisher {
if (finisher_queue.empty()) {
finisher_cond.Signal();
}
finisher_queue.insert(finisher_queue.end(), ls.begin(), ls.end());
for (auto i : ls) {
finisher_queue.push_back(make_pair(i, 0));
}
if (logger)
logger->inc(l_finisher_queue_len, ls.size());
finisher_lock.Unlock();
ls.clear();
}
void queue(list<Context*>& ls) {
void queue(vector<Context*>& ls) {
finisher_lock.Lock();
if (finisher_queue.empty()) {
finisher_cond.Signal();
}
finisher_queue.insert(finisher_queue.end(), ls.begin(), ls.end());
for (auto i : ls) {
finisher_queue.push_back(make_pair(i, 0));
}
if (logger)
logger->inc(l_finisher_queue_len, ls.size());
finisher_lock.Unlock();