MXS-1754 Use std::multimap instead of std::priority_queue

When canceling, a DelayedCall instance must be removed from the
collection holding all delayed calls. Consequently priority_queue
cannot be used as it 1) does not provide access to the underlying
collection and 2) the underlying collection (vector or deque)
is a bad choise if items in the middle needs to be removed.
This commit is contained in:
Johan Wikman
2018-04-20 10:28:27 +03:00
parent a84e369a97
commit cb3a98dee8
2 changed files with 18 additions and 17 deletions

View File

@ -13,9 +13,8 @@
*/ */
#include <maxscale/cppdefs.hh> #include <maxscale/cppdefs.hh>
#include <map>
#include <memory> #include <memory>
#include <queue>
#include <vector>
#include <maxscale/platform.h> #include <maxscale/platform.h>
#include <maxscale/session.h> #include <maxscale/session.h>
#include <maxscale/utils.hh> #include <maxscale/utils.hh>
@ -1298,7 +1297,7 @@ private:
}; };
typedef DelegatingTimer<Worker> PrivateTimer; typedef DelegatingTimer<Worker> PrivateTimer;
typedef std::priority_queue<DelayedCall*, std::vector<DelayedCall*>, LaterAt> DelayedCalls; typedef std::multimap<int64_t, DelayedCall*> DelayedCalls;
STATISTICS m_statistics; /*< Worker statistics. */ STATISTICS m_statistics; /*< Worker statistics. */
MessageQueue* m_pQueue; /*< The message queue of the worker. */ MessageQueue* m_pQueue; /*< The message queue of the worker. */
@ -1311,7 +1310,6 @@ private:
Load m_load; /*< The worker load. */ Load m_load; /*< The worker load. */
PrivateTimer* m_pTimer; /*< The worker's own timer. */ PrivateTimer* m_pTimer; /*< The worker's own timer. */
DelayedCalls m_delayed_calls; /*< Current delayed calls. */ DelayedCalls m_delayed_calls; /*< Current delayed calls. */
uint64_t m_last_delayed_call; /*< When was the last delayed call made. */
}; };
} }

View File

@ -1133,12 +1133,13 @@ void Worker::tick()
vector<DelayedCall*> repeating_calls; vector<DelayedCall*> repeating_calls;
DelayedCall* pDelayed_call; auto i = m_delayed_calls.begin();
while (!m_delayed_calls.empty() && (m_delayed_calls.top()->at() <= now)) while ((i != m_delayed_calls.end()) && (i->first <= now))
{ {
pDelayed_call = m_delayed_calls.top(); DelayedCall* pDelayed_call = i->second;
m_delayed_calls.pop();
m_delayed_calls.erase(i++);
if (pDelayed_call->call(Worker::Call::EXECUTE)) if (pDelayed_call->call(Worker::Call::EXECUTE))
{ {
@ -1152,7 +1153,9 @@ void Worker::tick()
for (auto i = repeating_calls.begin(); i != repeating_calls.end(); ++i) for (auto i = repeating_calls.begin(); i != repeating_calls.end(); ++i)
{ {
m_delayed_calls.push(*i); DelayedCall* pCall = *i;
m_delayed_calls.insert(std::make_pair(pCall->at(), pCall));
} }
adjust_timer(); adjust_timer();
@ -1164,18 +1167,18 @@ void Worker::add_delayed_call(DelayedCall* pDelayed_call)
if (!m_delayed_calls.empty()) if (!m_delayed_calls.empty())
{ {
DelayedCall* pTop = m_delayed_calls.top(); DelayedCall* pFirst = m_delayed_calls.begin()->second;
if (pDelayed_call->at() < pTop->at()) if (pDelayed_call->at() > pFirst->at())
{ {
// If the added delayed call needs to be called sooner // If the added delayed call needs to be called later
// than the top-most delayed call, then we must adjust // than the first delayed call, then we do not need to
// the timer. // adjust the timer.
adjust = true; adjust = false;
} }
} }
m_delayed_calls.push(pDelayed_call); m_delayed_calls.insert(std::make_pair(pDelayed_call->at(), pDelayed_call));
if (adjust) if (adjust)
{ {
@ -1187,7 +1190,7 @@ void Worker::adjust_timer()
{ {
if (!m_delayed_calls.empty()) if (!m_delayed_calls.empty())
{ {
DelayedCall* pNext_call = m_delayed_calls.top(); DelayedCall* pNext_call = m_delayed_calls.begin()->second;
uint64_t now = get_current_time_ms(); uint64_t now = get_current_time_ms();
int64_t delay = pNext_call->at() - now; int64_t delay = pNext_call->at() - now;