Add a way for us to place jobs with a concurrency limit.

The main use case is having all threads stuck in ledgerData, fighting each other.
This commit is contained in:
JoelKatz
2013-07-13 19:02:35 -07:00
parent 2ce293ec85
commit 5b2d5e8428
6 changed files with 76 additions and 20 deletions

View File

@@ -31,6 +31,11 @@ JobQueue::JobQueue (boost::asio::io_service& svc)
}
void JobQueue::addJob (JobType type, const std::string& name, const FUNCTION_TYPE<void (Job&)>& jobFunc)
{
addLimitJob(type, name, 0, jobFunc);
}
void JobQueue::addLimitJob (JobType type, const std::string& name, int limit, const FUNCTION_TYPE<void (Job&)>& jobFunc)
{
assert (type != jtINVALID);
@@ -39,7 +44,7 @@ void JobQueue::addJob (JobType type, const std::string& name, const FUNCTION_TYP
if (type != jtCLIENT) // FIXME: Workaround incorrect client shutdown ordering
assert (mThreadCount != 0); // do not add jobs to a queue with no threads
mJobSet.insert (Job (type, name, ++mLastJob, mJobLoads[type], jobFunc));
mJobSet.insert (Job (type, name, limit, ++mLastJob, mJobLoads[type], jobFunc));
++mJobCounts[type].first;
mJobCond.notify_one ();
}
@@ -232,6 +237,37 @@ void JobQueue::setThreadCount (int c, bool const standaloneMode)
mJobCond.notify_one (); // in case we sucked up someone else's signal
}
bool JobQueue::getJob(Job& job)
{
if (mJobSet.empty() || mShuttingDown)
return false;
std::set<Job>::iterator it = mJobSet.begin ();
while (1)
{
// Are we out of jobs?
if (it == mJobSet.end())
return false;
// Does this job have no limit?
if (it->getLimit() == 0)
break;
// Is this job category below the limit?
if (mJobCounts[it->getType()].second < it->getLimit())
break;
// Try the next job, if any
++it;
}
job = *it;
mJobSet.erase (it);
return true;
}
// do jobs until asked to stop
void JobQueue::threadEntry ()
{
@@ -239,27 +275,32 @@ void JobQueue::threadEntry ()
while (1)
{
JobType type;
setCallingThreadName ("waiting");
while (mJobSet.empty () && !mShuttingDown)
{
mJobCond.wait (sl);
}
if (mJobSet.empty ())
break;
JobType type;
std::set<Job>::iterator it = mJobSet.begin ();
{
Job job (*it);
mJobSet.erase (it);
Job job;
while (!getJob(job))
{
if (mShuttingDown)
{
--mThreadCount;
mJobCond.notify_all();
return;
}
mJobCond.wait (sl);
}
type = job.getType ();
-- (mJobCounts[type].first);
if (type == jtDEATH)
break;
{
--mThreadCount;
mJobCond.notify_all();
return;
}
++ (mJobCounts[type].second);
sl.unlock ();
@@ -267,12 +308,10 @@ void JobQueue::threadEntry ()
WriteLog (lsTRACE, JobQueue) << "Doing " << Job::toString (type) << " job";
job.doJob ();
} // must destroy job without holding lock
sl.lock ();
-- (mJobCounts[type].second);
}
--mThreadCount;
mJobCond.notify_all ();
}
// vim:ts=4