0
static const int DEFAULT_MAX_POOL_SIZE = 20;
0
static const int DEFAULT_MAX_INSTANCES_PER_APP = 0;
0
static const int CLEANER_THREAD_STACK_SIZE = 1024 * 128;
0
+ static const unsigned int MAX_GET_ATTEMPTS = 10;
0
friend class ApplicationPoolServer;
0
condition activeOrMaxChanged;
0
unsigned int maxPerApp;
0
AppContainerList inactiveApps;
0
map<string, time_t> restartFileTimes;
0
// Shortcuts for instance variables in SharedData. Saves typing in get().
0
condition &activeOrMaxChanged;
0
+ unsigned int &waiting;
0
unsigned int &maxPerApp;
0
AppContainerList &inactiveApps;
0
map<string, time_t> &restartFileTimes;
0
map<string, unsigned int> &appInstanceCount;
0
+ * Verify that all the invariants are correct.
0
+ bool inline verifyState() {
0
+ // Invariant for _apps_.
0
+ ApplicationMap::const_iterator it;
0
+ for (it = apps.begin(); it != apps.end(); it++) {
0
+ AppContainerList *list = it->second.get();
0
+ P_ASSERT(!list->empty(), false, "List for '" << it->first << "' is nonempty.");
0
+ AppContainerList::const_iterator prev_lit;
0
+ AppContainerList::const_iterator lit;
0
+ prev_lit = list->begin();
0
+ for (; lit != list->end(); lit++) {
0
+ if ((*prev_lit)->sessions > 0) {
0
+ P_ASSERT((*lit)->sessions > 0, false,
0
+ "List for '" << it->first <<
0
+ "' is sorted from nonactive to active");
0
+ P_ASSERT(active <= count, false,
0
+ "active (" << active << ") < count (" << count << ")");
0
bool needsRestart(const string &appRoot) {
0
string restartFile(appRoot);
0
restartFile.append("/tmp/restart.txt");
0
if (it != apps.end()) {
0
list = it->second.get();
0
- if (list->front()->sessions == 0 || count >= max
0
- || ( maxPerApp != 0 && appInstanceCount[appRoot] >= maxPerApp )) {
0
+ if (list->front()->sessions == 0) {
0
container = list->front();
0
list->push_back(container);
0
inactiveApps.erase(container->ia_iterator);
0
+ } else if (count >= max || (
0
+ maxPerApp != 0 && appInstanceCount[appRoot] >= maxPerApp )
0
+ return make_pair(AppContainerPtr(), (AppContainerList *) 0);
0
container = ptr(new AppContainer());
0
container->app = spawnManager.spawn(appRoot,
0
data(new SharedData()),
0
+ waitingLock(data->waitingLock),
0
activeOrMaxChanged(data->activeOrMaxChanged),
0
+ waiting(data->waiting),
0
maxPerApp(data->maxPerApp),
0
inactiveApps(data->inactiveApps),
0
restartFileTimes(data->restartFileTimes),
0
max = DEFAULT_MAX_POOL_SIZE;
0
maxPerApp = DEFAULT_MAX_INSTANCES_PER_APP;
0
maxIdleTime = DEFAULT_MAX_IDLE_TIME;
0
cleanerThread = new thread(
0
const string &spawnMethod = "smart"
0
- const unsigned int MAX_ATTEMPTS = 5;
0
mutex::scoped_lock l(lock);
0
pair<AppContainerPtr, AppContainerList *> p(
0
spawnOrUseExisting(l, appRoot, lowerPrivilege, lowestUser,
0
AppContainerPtr &container(p.first);
0
AppContainerList &list(*p.second);
0
- container->lastUsed = time(NULL);
0
- container->sessions++;
0
- return container->app->connect(SessionCloseCallback(data, container));
0
- } catch (const exception &e) {
0
- container->sessions--;
0
- if (attempt == MAX_ATTEMPTS) {
0
- string message("Cannot connect to an existing application instance for '");
0
- message.append(appRoot);
0
- message.append("': ");
0
- const SystemException &syse = dynamic_cast<const SystemException &>(e);
0
- message.append(syse.sys());
0
- } catch (const bad_cast &) {
0
- message.append(e.what());
0
+ if (container != NULL) {
0
+ container->lastUsed = time(NULL);
0
+ container->sessions++;
0
+ P_ASSERT(verifyState(), Application::SessionPtr(),
0
+ "State is valid:\n" << toString(false));
0
+ return container->app->connect(SessionCloseCallback(data, container));
0
+ } catch (const exception &e) {
0
+ container->sessions--;
0
+ if (attempt == MAX_GET_ATTEMPTS) {
0
+ string message("Cannot connect to an existing "
0
+ "application instance for '");
0
+ message.append(appRoot);
0
+ message.append("': ");
0
+ const SystemException &syse = dynamic_cast<const SystemException &>(e);
0
+ message.append(syse.sys());
0
+ } catch (const bad_cast &) {
0
+ message.append(e.what());
0
+ throw IOException(message);
0
+ list.erase(container->iterator);
0
+ appInstanceCount.erase(appRoot);
0
+ P_ASSERT(verifyState(), Application::SessionPtr(), "State is valid.");
0
- throw IOException(message);
0
- list.erase(container->iterator);
0
- appInstanceCount.erase(appRoot);
0
+ if (container == NULL) {
0
+ if (attempt == MAX_GET_ATTEMPTS) {
0
+ throw BusyException("Cannot satisfy get() request.");
0
+ mutex::scoped_lock wl(waitingLock);
0
+ usleep(attempt * 20000);
0
+ mutex::scoped_lock wl(waitingLock);
0
// Never reached; shut up compiler warning
0
return Application::SessionPtr();
0
* Returns a textual description of the internal state of
0
* the application pool.
0
- virtual string toString() const {
0
- mutex::scoped_lock l(lock);
0
+ virtual string toString(bool lockMutex = true) const {
0
+ mutex::scoped_lock l(lock, lockMutex);
0
result << "----------- General information -----------" << endl;
0
result << "max = " << max << endl;
0
result << "count = " << count << endl;
0
result << "active = " << active << endl;
0
+ result << "waiting = " << waiting << endl;
0
result << "----------- Applications -----------" << endl;
Comments
No one has commented yet.