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();
}
Exemple #4
0
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;
}