void Group::onSessionClose(const ProcessPtr &process, Session *session) { TRACE_POINT(); // Standard resource management boilerplate stuff... PoolPtr pool = getPool(); boost::unique_lock<boost::mutex> lock(pool->syncher); assert(process->isAlive()); assert(isAlive() || getLifeStatus() == SHUTTING_DOWN); P_TRACE(2, "Session closed for process " << process->inspect()); verifyInvariants(); UPDATE_TRACE_POINT(); /* Update statistics. */ process->sessionClosed(session); assert(process->getLifeStatus() == Process::ALIVE); assert(process->enabled == Process::ENABLED || process->enabled == Process::DISABLING || process->enabled == Process::DETACHED); if (process->enabled == Process::ENABLED) { pqueue.decrease(process->pqHandle, process->busyness()); } /* This group now has a process that's guaranteed to be not * totally busy. */ assert(!process->isTotallyBusy()); bool detachingBecauseOfMaxRequests = false; bool detachingBecauseCapacityNeeded = false; bool shouldDetach = ( detachingBecauseOfMaxRequests = ( options.maxRequests > 0 && process->processed >= options.maxRequests )) || ( detachingBecauseCapacityNeeded = ( process->sessions == 0 && getWaitlist.empty() && ( !pool->getWaitlist.empty() || anotherGroupIsWaitingForCapacity() ) ) ); bool shouldDisable = process->enabled == Process::DISABLING && process->sessions == 0 && enabledCount > 0; if (shouldDetach || shouldDisable) { vector<Callback> actions; if (shouldDetach) { if (detachingBecauseCapacityNeeded) { /* Someone might be trying to get() a session for a different * group that couldn't be spawned because of lack of pool capacity. * If this group isn't under sufficiently load (as apparent by the * checked conditions) then now's a good time to detach * this process or group in order to free capacity. */ P_DEBUG("Process " << process->inspect() << " is no longer totally " "busy; detaching it in order to make room in the pool"); } else { /* This process has processed its maximum number of requests, * so we detach it. */ P_DEBUG("Process " << process->inspect() << " has reached its maximum number of requests (" << options.maxRequests << "); detaching it"); } pool->detachProcessUnlocked(process, actions); } else { removeProcessFromList(process, disablingProcesses); addProcessToList(process, disabledProcesses); removeFromDisableWaitlist(process, DR_SUCCESS, actions); maybeInitiateOobw(process); } pool->fullVerifyInvariants(); lock.unlock(); runAllActions(actions); } else { // This could change process->enabled. maybeInitiateOobw(process); if (!getWaitlist.empty() && process->enabled == Process::ENABLED) { /* If there are clients on this group waiting for a process to * become available then call them now. */ UPDATE_TRACE_POINT(); // Already calls verifyInvariants(). assignSessionsToGetWaitersQuickly(lock); } } }
void Group::detachedProcessesCheckerMain(GroupPtr self) { TRACE_POINT(); PoolPtr pool = getPool(); Pool::DebugSupportPtr debug = pool->debugSupport; if (debug != NULL && debug->detachedProcessesChecker) { debug->debugger->send("About to start detached processes checker"); debug->messages->recv("Proceed with starting detached processes checker"); } boost::unique_lock<boost::mutex> lock(pool->syncher); while (true) { assert(detachedProcessesCheckerActive); if (getLifeStatus() == SHUT_DOWN || this_thread::interruption_requested()) { UPDATE_TRACE_POINT(); P_DEBUG("Stopping detached processes checker"); detachedProcessesCheckerActive = false; break; } UPDATE_TRACE_POINT(); if (!detachedProcesses.empty()) { P_TRACE(2, "Checking whether any of the " << detachedProcesses.size() << " detached processes have exited..."); ProcessList::iterator it = detachedProcesses.begin(); ProcessList::iterator end = detachedProcesses.end(); while (it != end) { const ProcessPtr process = *it; switch (process->getLifeStatus()) { case Process::ALIVE: if (process->canTriggerShutdown()) { P_DEBUG("Detached process " << process->inspect() << " has 0 active sessions now. Triggering shutdown."); process->triggerShutdown(); assert(process->getLifeStatus() == Process::SHUTDOWN_TRIGGERED); } it++; break; case Process::SHUTDOWN_TRIGGERED: if (process->canCleanup()) { P_DEBUG("Detached process " << process->inspect() << " has shut down. Cleaning up associated resources."); process->cleanup(); assert(process->getLifeStatus() == Process::DEAD); it++; removeProcessFromList(process, detachedProcesses); } else if (process->shutdownTimeoutExpired()) { P_WARN("Detached process " << process->inspect() << " didn't shut down within " PROCESS_SHUTDOWN_TIMEOUT_DISPLAY ". Forcefully killing it with SIGKILL."); kill(process->pid, SIGKILL); it++; } else { it++; } break; default: P_BUG("Unknown 'lifeStatus' state " << (int) process->getLifeStatus()); } } } UPDATE_TRACE_POINT(); if (detachedProcesses.empty()) { UPDATE_TRACE_POINT(); P_DEBUG("Stopping detached processes checker"); detachedProcessesCheckerActive = false; vector<Callback> actions; if (shutdownCanFinish()) { UPDATE_TRACE_POINT(); finishShutdown(actions); } verifyInvariants(); verifyExpensiveInvariants(); lock.unlock(); UPDATE_TRACE_POINT(); runAllActions(actions); break; } else { UPDATE_TRACE_POINT(); verifyInvariants(); verifyExpensiveInvariants(); } // Not all processes can be shut down yet. Sleep for a while unless // someone wakes us up. UPDATE_TRACE_POINT(); detachedProcessesCheckerCond.timed_wait(lock, posix_time::milliseconds(100)); } }
void SuperGroup::realDoInitialize(const Options &options, unsigned int generation) { vector<ComponentInfo> componentInfos; vector<ComponentInfo>::const_iterator it; ExceptionPtr exception; P_TRACE(2, "Initializing SuperGroup " << inspect() << " in the background..."); try { componentInfos = loadComponentInfos(options); } catch (const tracable_exception &e) { exception = copyException(e); } if (componentInfos.empty() && exception == NULL) { string message = "The directory " + options.appRoot + " does not seem to contain a web application."; exception = boost::make_shared<SpawnException>( message, message, false); } PoolPtr pool = getPool(); Pool::DebugSupportPtr debug = pool->debugSupport; vector<Callback> actions; { if (debug != NULL && debug->superGroup) { debug->debugger->send("About to finish SuperGroup initialization"); debug->messages->recv("Proceed with initializing SuperGroup"); } boost::unique_lock<boost::mutex> lock(getPoolSyncher(pool)); this_thread::disable_interruption di; this_thread::disable_syscall_interruption dsi; NOT_EXPECTING_EXCEPTIONS(); if (OXT_UNLIKELY(getPool() == NULL || generation != this->generation)) { return; } P_TRACE(2, "Initialization of SuperGroup " << inspect() << " almost done; grabbed lock"); assert(state == INITIALIZING); verifyInvariants(); if (componentInfos.empty()) { /* Somehow initialization failed. Maybe something has deleted * the supergroup files while we're working. */ assert(exception != NULL); setState(DESTROYED); actions.reserve(getWaitlist.size()); while (!getWaitlist.empty()) { const GetWaiter &waiter = getWaitlist.front(); actions.push_back(boost::bind(waiter.callback, SessionPtr(), exception)); getWaitlist.pop_front(); } } else { for (it = componentInfos.begin(); it != componentInfos.end(); it++) { const ComponentInfo &info = *it; GroupPtr group = boost::make_shared<Group>(shared_from_this(), options, info); groups.push_back(group); if (info.isDefault) { defaultGroup = group.get(); } } setState(READY); assignGetWaitlistToGroups(actions); } verifyInvariants(); P_TRACE(2, "Done initializing SuperGroup " << inspect()); } this_thread::disable_interruption di; this_thread::disable_syscall_interruption dsi; runAllActions(actions); runInitializationHooks(); }
int infix2postfix(const std::string &query, std::vector<std::string> &result) { char buffer[4096]; result.clear(); char ch; int len = 0; for (size_t i = 0; i < query.length(); ++i) { ch = query.at(i); if (::isspace(ch) == 0) { if (!is_valid_trigger_char(ch)) { P_WARNING("invalid char[%c] in query[%s]", ch, query.c_str()); return -1; } buffer[len++] = ch; if (len >= int(sizeof(buffer))) { P_WARNING("too long query[%s]", query.c_str()); return -1; } } } buffer[len] = '\0'; P_TRACE("clean query[%s]", buffer); int start = -1; int last_token = 0; std::stack<char> op_stack; for (int i = 0; i < len; ) { ch = buffer[i]; if (ch >= '0' && ch <= '9') { start = i++; while (i < len) { ch = buffer[i]; if (ch >= '0' && ch <= '9') { ++i; } else break; } result.push_back(std::string(buffer + start, i - start)); P_TRACE("get token[%s]", result[result.size() - 1].c_str()); last_token = 1; } else if (ch == '(') { if (last_token == 1) { P_WARNING("invalid operator '('"); return -1; } op_stack.push(ch); P_TRACE("meet operator '('"); last_token = 0; ++i; } else if (ch == ')') { if (last_token != 1) { P_WARNING("invalid operator ')', has nothing in ()"); return -1; } P_TRACE("meet operator ')'"); bool matched = false; while (op_stack.size() > 0) { char op = op_stack.top(); op_stack.pop(); if (op == '(') { matched = true; break; } result.push_back(std::string(&op, 1)); P_TRACE("push back operator[%c]", op); } if (!matched) { P_WARNING("unmatched operator ')'"); return -1; } last_token = 1; ++i; } else { if (last_token != 1) { P_WARNING("operator '%c' must has left value", ch); return -1; } P_TRACE("meet operator[%c]", ch); while (op_stack.size() > 0) { char op = op_stack.top(); if (op == '(') { break; } if (g_operator_priority[uint8_t(op)] > g_operator_priority[uint8_t(ch)]) { break; } op_stack.pop(); result.push_back(std::string(&op, 1)); P_TRACE("push back operator[%c]", op); } op_stack.push(ch); last_token = 2; ++i; } } while (op_stack.size() > 0) { char op = op_stack.top(); if (op == '(') { P_WARNING("unmatched operator '('"); return -1; } op_stack.pop(); result.push_back(std::string(&op, 1)); P_TRACE("push back operator[%c]", op); } P_TRACE("parsed query[%s] ok", query.c_str()); for (size_t i = 0; i < result.size(); ++i) { P_TRACE("parsed tokens[%03d]: %s", int(i), result[i].c_str()); } return 0; }