bool Group::pushGetWaiter(const Options &newOptions, const GetCallback &callback, boost::container::vector<Callback> &postLockActions) { if (OXT_LIKELY(!testOverflowRequestQueue() && (newOptions.maxRequestQueueSize == 0 || getWaitlist.size() < newOptions.maxRequestQueueSize))) { getWaitlist.push_back(GetWaiter( newOptions.copyAndPersist().detachFromUnionStationTransaction(), callback)); return true; } else { postLockActions.push_back(boost::bind(GetCallback::call, callback, SessionPtr(), boost::make_shared<RequestQueueFullException>(newOptions.maxRequestQueueSize))); HookScriptOptions hsOptions; if (prepareHookScriptOptions(hsOptions, "queue_full_error")) { // TODO <Feb 17, 2015] DK> should probably rate limit this, since we are already at heavy load postLockActions.push_back(boost::bind(runHookScripts, hsOptions)); } return false; } }
/** * Process all waiters on the getWaitlist. Call when capacity has become free. * This function assigns sessions to them by calling get() on the corresponding * Groups, or by creating more Groups, in so far the new capacity allows. */ void Pool::assignSessionsToGetWaiters(boost::container::vector<Callback> &postLockActions) { bool done = false; vector<GetWaiter>::iterator it, end = getWaitlist.end(); vector<GetWaiter> newWaitlist; for (it = getWaitlist.begin(); it != end && !done; it++) { GetWaiter &waiter = *it; Group *group = findMatchingGroup(waiter.options); if (group != NULL) { SessionPtr session = group->get(waiter.options, waiter.callback, postLockActions); if (session != NULL) { postLockActions.push_back(boost::bind(GetCallback::call, waiter.callback, session, ExceptionPtr())); } /* else: the callback has now been put in * the group's get wait list. */ } else if (!atFullCapacityUnlocked()) { createGroupAndAsyncGetFromIt(waiter.options, waiter.callback, postLockActions); } else { /* Still cannot satisfy this get request. Keep it on the get * wait list and try again later. */ newWaitlist.push_back(waiter); } } std::swap(getWaitlist, newWaitlist); }
/** One of the post lock actions can potentially perform a long-running * operation, so running them in a thread is advised. */ void Group::finishShutdown(boost::container::vector<Callback> &postLockActions) { TRACE_POINT(); #ifndef NDEBUG LifeStatus lifeStatus = (LifeStatus) this->lifeStatus.load(boost::memory_order_relaxed); P_ASSERT_EQ(lifeStatus, SHUTTING_DOWN); #endif P_DEBUG("Finishing shutdown of group " << info.name); if (shutdownCallback) { postLockActions.push_back(shutdownCallback); shutdownCallback = Callback(); } postLockActions.push_back(boost::bind(interruptAndJoinAllThreads, shared_from_this())); this->lifeStatus.store(SHUT_DOWN, boost::memory_order_seq_cst); selfPointer.reset(); }
void Pool::assignExceptionToGetWaiters(Queue &getWaitlist, const ExceptionPtr &exception, boost::container::vector<Callback> &postLockActions) { while (!getWaitlist.empty()) { postLockActions.push_back(boost::bind(GetCallback::call, getWaitlist.front().callback, SessionPtr(), exception)); getWaitlist.pop_front(); } }
/** * Must be called before destroying a Group. You can optionally provide a * callback so that you are notified when shutdown has finished. * * The caller is responsible for migrating waiters on the getWaitlist. * * One of the post lock actions can potentially perform a long-running * operation, so running them in a thread is advised. */ void Group::shutdown(const Callback &callback, boost::container::vector<Callback> &postLockActions) { assert(isAlive()); assert(getWaitlist.empty()); P_DEBUG("Begin shutting down group " << info.name); shutdownCallback = callback; detachAll(postLockActions); startCheckingDetachedProcesses(true); interruptableThreads.interrupt_all(); postLockActions.push_back(boost::bind(doCleanupSpawner, spawner)); spawner.reset(); selfPointer = shared_from_this(); assert(disableWaitlist.empty()); lifeStatus.store(SHUTTING_DOWN, boost::memory_order_seq_cst); }
void Group::assignSessionsToGetWaiters(boost::container::vector<Callback> &postLockActions) { unsigned int i = 0; bool done = false; while (!done && i < getWaitlist.size()) { const GetWaiter &waiter = getWaitlist[i]; RouteResult result = route(waiter.options); if (result.process != NULL) { postLockActions.push_back(boost::bind( GetCallback::call, waiter.callback, newSession(result.process), ExceptionPtr())); getWaitlist.erase(getWaitlist.begin() + i); } else { done = result.finished; if (!result.finished) { i++; } } } }
void Group::cleanupSpawner(boost::container::vector<Callback> &postLockActions) { assert(isAlive()); postLockActions.push_back(boost::bind(doCleanupSpawner, spawner)); }