Passenger: PoolOptions.h Source File

- Main Page
- Modules
- Classes
- Files

- File List

# PoolOptions.h

    00001 /*
    00002  *  Phusion Passenger - http://www.modrails.com/
    00003  *  Copyright (C) 2008  Phusion
    00004  *
    00005  *  Phusion Passenger is a trademark of Hongli Lai & Ninh Bui.
    00006  *
    00007  *  This program is free software; you can redistribute it and/or modify
    00008  *  it under the terms of the GNU General Public License as published by
    00009  *  the Free Software Foundation; version 2 of the License.
    00010  *
    00011  *  This program is distributed in the hope that it will be useful,
    00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    00014  *  GNU General Public License for more details.
    00015  *
    00016  *  You should have received a copy of the GNU General Public License along
    00017  *  with this program; if not, write to the Free Software Foundation, Inc.,
    00018  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    00019  */
    00020 #ifndef _PASSENGER_SPAWN_OPTIONS_H_
    00021 #define _PASSENGER_SPAWN_OPTIONS_H_
    00022
    00023 #include <string>
    00024 #include "Utils.h"
    00025
    00026 namespace Passenger {
    00027
    00028 using namespace std;
    00029
    00030 /**
    00031  * This struct encapsulates information for ApplicationPool::get() and for
    00032  * SpawnManager::spawn(), such as which application is to be spawned.
    00033  *
    00034  * <h2>Notes on privilege lowering support</h2>
    00035  *
    00036  * If <tt>lowerPrivilege</tt> is true, then it will be attempt to
    00037  * switch the spawned application instance to the user who owns the
    00038  * application's <tt>config/environment.rb</tt>, and to the default
    00039  * group of that user.
    00040  *
    00041  * If that user doesn't exist on the system, or if that user is root,
    00042  * then it will be attempted to switch to the username given by
    00043  * <tt>lowestUser</tt> (and to the default group of that user).
    00044  * If <tt>lowestUser</tt> doesn't exist either, or if switching user failed
    00045  * (because the spawn server process does not have the privilege to do so),
    00046  * then the application will be spawned anyway, without reporting an error.
    00047  *
    00048  * It goes without saying that lowering privilege is only possible if
    00049  * the spawn server is running as root (and thus, by induction, that
    00050  * Phusion Passenger and Apache's control process are also running as root).
    00051  * Note that if Apache is listening on port 80, then its control process must
    00052  * be running as root. See "doc/Security of user switching.txt" for
    00053  * a detailed explanation.
    00054  */
    00055 struct PoolOptions {
    00056         /**
    00057          * The root directory of the application to spawn. In case of a Ruby on Rails
    00058          * application, this is the folder that contains 'app/', 'public/', 'config/',
    00059          * etc. This must be a valid directory, but the path does not have to be absolute.
    00060          */
    00061         string appRoot;
    00062
    00063         /** Whether to lower the application's privileges. */
    00064         bool lowerPrivilege;
    00065
    00066         /**
    00067          * The user to fallback to if lowering privilege fails.
    00068          */
    00069         string lowestUser;
    00070
    00071         /**
    00072          * The RAILS_ENV/RACK_ENV environment that should be used. May not be an
    00073          * empty string.
    00074          */
    00075         string environment;
    00076
    00077         /**
    00078          * The spawn method to use. Either "smart" or "conservative". See the Ruby
    00079          * class <tt>SpawnManager</tt> for details.
    00080          */
    00081         string spawnMethod;
    00082
    00083         /** The application type. Either "rails", "rack" or "wsgi". */
    00084         string appType;
    00085
    00086         /**
    00087          * The idle timeout, in seconds, of Rails framework spawners.
    00088          * A timeout of 0 means that the framework spawner should never idle timeout. A timeout
    00089          * of -1 means that the default timeout value should be used.
    00090          *
    00091          * For more details about Rails framework spawners, please
    00092          * read the documentation on the Railz::FrameworkSpawner
    00093          * Ruby class.
    00094          */
    00095         long frameworkSpawnerTimeout;
    00096
    00097         /**
    00098          * The idle timeout, in seconds, of Rails application spawners.
    00099          * A timeout of 0 means that the application spawner should never idle timeout. A timeout
    00100          * of -1 means that the default timeout value should be used.
    00101          *
    00102          * For more details about Rails application spawners, please
    00103          * read the documentation on the Railz::ApplicationSpawner
    00104          * Ruby class.
    00105          */
    00106         long appSpawnerTimeout;
    00107
    00108         /**
    00109          * The maximum number of requests that the spawned application may process
    00110          * before exiting. A value of 0 means unlimited.
    00111          */
    00112         unsigned long maxRequests;
    00113
    00114         /**
    00115          * The maximum amount of memory (in MB) the spawned application may use.
    00116          * A value of 0 means unlimited.
    00117          */
    00118         unsigned long memoryLimit;
    00119
    00120         /**
    00121          * Whether to use a global queue instead of a per-backend process
    00122          * queue. This option is only used by ApplicationPool::get().
    00123          *
    00124          * If enabled, when all backend processes are active, get() will
    00125          * wait until there's at least one backend process that's idle, instead
    00126          * of queuing the request into a random process's private queue.
    00127          * This is especially useful if a website has one or more long-running
    00128          * requests.
    00129          */
    00130         bool useGlobalQueue;
    00131
    00132         /**
    00133          * A throttling rate for file stats. When set to a non-zero value N,
    00134          * restart.txt and other files which are usually stat()ted on every
    00135          * ApplicationPool::get() call will be stat()ed at most every N seconds.
    00136          */
    00137         unsigned long statThrottleRate;
    00138
    00139         /**
    00140          * The directory which contains restart.txt and always_restart.txt.
    00141          * An empty string means that the default directory should be used.
    00142          */
    00143         string restartDir;
    00144
    00145         /**
    00146          * Creates a new PoolOptions object with the default values filled in.
    00147          * One must still set appRoot manually, after having used this constructor.
    00148          */
    00149         PoolOptions() {
    00150                 lowerPrivilege = true;
    00151                 lowestUser     = "nobody";
    00152                 environment    = "production";
    00153                 spawnMethod    = "smart";
    00154                 appType        = "rails";
    00155                 frameworkSpawnerTimeout = -1;
    00156                 appSpawnerTimeout       = -1;
    00157                 maxRequests    = 0;
    00158                 memoryLimit    = 0;
    00159                 useGlobalQueue = false;
    00160                 statThrottleRate        = 0;
    00161         }
    00162
    00163         /**
    00164          * Creates a new PoolOptions object with the given values.
    00165          */
    00166         PoolOptions(const string &appRoot,
    00167                 bool lowerPrivilege       = true,
    00168                 const string &lowestUser  = "nobody",
    00169                 const string &environment = "production",
    00170                 const string &spawnMethod = "smart",
    00171                 const string &appType     = "rails",
    00172                 long frameworkSpawnerTimeout = -1,
    00173                 long appSpawnerTimeout       = -1,
    00174                 unsigned long maxRequests    = 0,
    00175                 unsigned long memoryLimit    = 0,
    00176                 bool useGlobalQueue          = false,
    00177                 unsigned long statThrottleRate = 0,
    00178                 const string &restartDir  = ""
    00179         ) {
    00180                 this->appRoot        = appRoot;
    00181                 this->lowerPrivilege = lowerPrivilege;
    00182                 this->lowestUser     = lowestUser;
    00183                 this->environment    = environment;
    00184                 this->spawnMethod    = spawnMethod;
    00185                 this->appType        = appType;
    00186                 this->frameworkSpawnerTimeout = frameworkSpawnerTimeout;
    00187                 this->appSpawnerTimeout       = appSpawnerTimeout;
    00188                 this->maxRequests    = maxRequests;
    00189                 this->memoryLimit    = memoryLimit;
    00190                 this->useGlobalQueue = useGlobalQueue;
    00191                 this->statThrottleRate        = statThrottleRate;
    00192                 this->restartDir     = restartDir;
    00193         }
    00194
    00195         /**
    00196          * Creates a new PoolOptions object from the given string vector.
    00197          * This vector contains information that's written to by toVector().
    00198          *
    00199          * For example:
    00200          * @code
    00201          *   PoolOptions options(...);
    00202          *   vector<string> vec;
    00203          *
    00204          *   vec.push_back("my");
    00205          *   vec.push_back("data");
    00206          *   options.toVector(vec);  // PoolOptions information will start at index 2.
    00207          *
    00208          *   PoolOptions copy(vec, 2);
    00209          * @endcode
    00210          *
    00211          * @param vec The vector containing spawn options information.
    00212          * @param startIndex The index in vec at which the information starts.
    00213          */
    00214         PoolOptions(const vector<string> &vec, unsigned int startIndex = 0) {
    00215                 appRoot        = vec[startIndex + 1];
    00216                 lowerPrivilege = vec[startIndex + 3] == "true";
    00217                 lowestUser     = vec[startIndex + 5];
    00218                 environment    = vec[startIndex + 7];
    00219                 spawnMethod    = vec[startIndex + 9];
    00220                 appType        = vec[startIndex + 11];
    00221                 frameworkSpawnerTimeout = atol(vec[startIndex + 13]);
    00222                 appSpawnerTimeout       = atol(vec[startIndex + 15]);
    00223                 maxRequests    = atol(vec[startIndex + 17]);
    00224                 memoryLimit    = atol(vec[startIndex + 19]);
    00225                 useGlobalQueue = vec[startIndex + 21] == "true";
    00226                 statThrottleRate = atol(vec[startIndex + 23]);
    00227                 restartDir     = vec[startIndex + 25];
    00228         }
    00229
    00230         /**
    00231          * Append the information in this PoolOptions object to the given
    00232          * string vector. The resulting array could, for example, be used
    00233          * as a message to be sent to the spawn server.
    00234          */
    00235         void toVector(vector<string> &vec) const {
    00236                 if (vec.capacity() < vec.size() + 10) {
    00237                         vec.reserve(vec.size() + 10);
    00238                 }
    00239                 appendKeyValue (vec, "app_root",        appRoot);
    00240                 appendKeyValue (vec, "lower_privilege", lowerPrivilege ? "true" : "false");
    00241                 appendKeyValue (vec, "lowest_user",     lowestUser);
    00242                 appendKeyValue (vec, "environment",     environment);
    00243                 appendKeyValue (vec, "spawn_method",    spawnMethod);
    00244                 appendKeyValue (vec, "app_type",        appType);
    00245                 appendKeyValue2(vec, "framework_spawner_timeout", frameworkSpawnerTimeout);
    00246                 appendKeyValue2(vec, "app_spawner_timeout",       appSpawnerTimeout);
    00247                 appendKeyValue3(vec, "max_requests",    maxRequests);
    00248                 appendKeyValue3(vec, "memory_limit",    memoryLimit);
    00249                 appendKeyValue (vec, "use_global_queue", useGlobalQueue ? "true" : "false");
    00250                 appendKeyValue3(vec, "stat_throttle_rate", statThrottleRate);
    00251                 appendKeyValue (vec, "restart_dir",     restartDir);
    00252         }
    00253
    00254 private:
    00255         static inline void
    00256         appendKeyValue(vector<string> &vec, const char *key, const string &value) {
    00257                 vec.push_back(key);
    00258                 vec.push_back(const_cast<string &>(value));
    00259         }
    00260
    00261         static inline void
    00262         appendKeyValue(vector<string> &vec, const char *key, const char *value) {
    00263                 vec.push_back(key);
    00264                 vec.push_back(value);
    00265         }
    00266
    00267         static inline void
    00268         appendKeyValue2(vector<string> &vec, const char *key, long value) {
    00269                 vec.push_back(key);
    00270                 vec.push_back(toString(value));
    00271         }
    00272
    00273         static inline void
    00274         appendKeyValue3(vector<string> &vec, const char *key, unsigned long value) {
    00275                 vec.push_back(key);
    00276                 vec.push_back(toString(value));
    00277         }
    00278 };
    00279
    00280 } // namespace Passenger
    00281
    00282 #endif /* _PASSENGER_SPAWN_OPTIONS_H_ */
    00283