Project

General

Profile

Actions

Bug #12444

closed

WorkQueue.cc: unintended behavior for ThreadPool::drain()?

Added by Krzysztof Kosinski over 8 years ago. Updated almost 7 years ago.

Status:
Rejected
Priority:
Normal
Assignee:
Category:
-
Target version:
-
% Done:

0%

Source:
other
Tags:
Backport:
Regression:
No
Severity:
3 - minor
Reviewed:
Affected Versions:
ceph-qa-suite:
Pull request ID:
Crash signature (v1):
Crash signature (v2):

Description

ThreadPool::drain() contains this condition:

while (processing || (wq != NULL && !wq->_empty()))
  _wait_cond.Wait(_lock);

This will wait until no threads are processing (which only happens when all queues are empty), AND the queue given by wq is empty (if wq is not NULL). However, as far as I can tell, the intent of the API seems to be that drain(wq) should only wait until the queue given in the parameter is empty, since otherwise passing a work queue which is already added to the thread pool (as seen in e.g. WorkQueue::drain()) is equivalent to passing NULL. Therefore the correct condition seems to be:

while (processing && (wq == NULL || wq->_empty()))
  _wait_cond.Wait(_lock);

Am I missing something here?

Actions #1

Updated by Kefu Chai over 8 years ago

  • Status changed from New to 12

Krzysztof,

thanks for pointing this out. I think you are right. the existing ThreadPool::drain(wq) will wait until all the work queues added to this pool are empty if the thread pool, which renders the wq parameter useless.

i will run some qa suite against the patch proposed by you. and see how it works.

Actions #2

Updated by Kefu Chai over 8 years ago

  • Assignee set to Kefu Chai
Actions #3

Updated by Krzysztof Kosinski over 8 years ago

I looked at the condition I wrote again and it seems like it's wrong, should actually be:

while (processing && (wq == NULL || !wq->_empty()))
_wait_cond.Wait(_lock);

(Missing `!` before `wq->_empty()`)

Better yet, use an explicit `if`, because we end up with double negatives and the condition becomes very confusing:

if (wq != NULL) {
while(!wq->_empty())
_wait_cond.Wait(_lock);
} else {
while(processing)
_wait_cond.Wait(_lock);
}
Actions #4

Updated by Greg Farnum almost 7 years ago

Kefu, ever look at this?

Without much context I think the condition is correct as originally written: we keep waiting while there is an in-flight op, and if we got a specific WorkQueue, we wait until that workqueue is drained.

Actions #5

Updated by Kefu Chai almost 7 years ago

greg, i will revisit this ticket tmr.

Actions #6

Updated by Kefu Chai almost 7 years ago

no, once the specific wq is drained. ThreadPool::drain() should return, but in current implementation, the loop won't stop until processing is false, which means it will stop only if none job is being processed and wq is drained.

Actions #7

Updated by Greg Farnum almost 7 years ago

Yeah, but I don't think we can avoid that — processing is a count of how many threads are currently doing one of the THreadPool's ops. We don't have a per-WorkQueue equivalent, so any in-flight op might belong to the WorkQueue we're waiting on, which means we need to wait for it.

It does seem like we might need to draw a bit more of a distinction here though, since _draining won't stop a thread from doing other work. So there's an issue, but the proposed code definitely isn't the solution — it's not waiting when there are items in the WorkQueue. ;)

Actions #8

Updated by Kefu Chai almost 7 years ago

  • Status changed from 12 to Rejected

Greg, i concur with you aside from following statement:

it's not waiting when there are items in the WorkQueue. ;)

IMHO, it should be

it's not waiting when there are in-flight ops which might belong to the WorkQueue.

anyway, i am closing this ticket. as

We don't have a per-WorkQueue equivalent

Actions

Also available in: Atom PDF