Passenger::ApplicationPoolServer Class Reference
[Apache-independent support classes and function]

#include <ApplicationPoolClientServer.h>

List of all members.


Detailed Description

Multi-process usage support for ApplicationPool.

ApplicationPoolServer implements a client/server architecture for ApplicationPool. This allows one to use ApplicationPool in a multi-process environment (unlike StandardApplicationPool). The cache/pool data is stored in the server. Different processes can then access the pool through the server.

ApplicationPoolServer itself does not inherit ApplicationPool. Instead, it returns an ApplicationPool object via the connect() call. For example:

   // Create an ApplicationPoolServer.
   ApplicationPoolServer server(...);
   
   // Now fork a child process, like Apache's prefork MPM eventually will.
   pid_t pid = fork();
   if (pid == 0) {
       // Child process
       
       // Connect to the server. After connection, we have an ApplicationPool
       // object!
       ApplicationPoolPtr pool(server.connect());

       // The child process doesn't run a server (only the parent process does)
       // so we call detach to free the server resources (things like file
       // descriptors).
       server.detach();

       ApplicationPool::SessionPtr session(pool->get("/home/webapps/foo"));
       do_something_with(session);

       _exit(0);
   } else {
       // Parent process
       waitpid(pid, NULL, 0);
   }

Warning:
ApplicationPoolServer uses threads internally. Threads will disappear after a fork(), so ApplicationPoolServer will become usable as a server after a fork(). After a fork(), you can still call connect() (and, of course, detach()), but the same ApplicationPoolServer better still be running in the parent process. So in case of Apache with the prefork MPM, be sure to create an ApplicationPoolServer after Apache has daemonized.

Implementation notes

Notice that ApplicationPoolServer does do not use TCP sockets at all, or even named Unix sockets, depite being a server that can handle multiple clients! So ApplicationPoolServer will expose no open ports or temporary Unix socket files. Only child processes are able to use the ApplicationPoolServer.

This is implemented through anonymous Unix sockets (socketpair()) and file descriptor passing. It allows one to emulate accept(). During initialization, ApplicationPoolServer creates a pair of Unix sockets, one called serverSocket and the other called connectSocket. There is a thread which continuously listens on serverSocket for incoming data. The data itself is not important, because it only serves to wake up the thread. ApplicationPoolServer::connect() sends some data through connectSocket, which wakes up the server thread. The server thread will then create a pair of Unix sockets. One of them is passed through serverSocket. The other will be handled by a newly created client thread. So the socket that was passed through serverSocket is the client's connection to the server, while the other socket is the server's connection to the client.

Note that serverSocket and connectSocket are solely used for setting up new connections ala accept(). They are not used for any actual data. In fact, they cannot be used in any other way without some sort of inter-process synchronization mechanism, because all child processes are connected to the same serverSocket. In contrast, ApplicationPoolServer::connect() allows one to setup a private communicate channel between the server and the current child process.

Also note that each client is handled by a seperate thread. This is necessary because ApplicationPoolServer internally uses StandardApplicationPool, and the current algorithm for StandardApplicationPool::get() can block (in the case that the spawning limit has been exceeded). While it is possible to get around this problem without using threads, a thread-based implementation is easier to write.

Public Member Functions

 ApplicationPoolServer (const string &spawnServerCommand, const string &logFile="", const string &environment="production", const string &rubyCommand="ruby", const string &user="")
 Create a new ApplicationPoolServer object.
ApplicationPoolPtr connect ()
 Connects to the server and returns a usable ApplicationPool object.
void detach ()
 Detach the server by freeing up some server resources such as file descriptors.


Constructor & Destructor Documentation

Passenger::ApplicationPoolServer::ApplicationPoolServer ( const string &  spawnServerCommand,
const string &  logFile = "",
const string &  environment = "production",
const string &  rubyCommand = "ruby",
const string &  user = "" 
) [inline]

Create a new ApplicationPoolServer object.

Parameters:
spawnServerCommand The filename of the spawn server to use.
logFile Specify a log file that the spawn server should use. Messages on its standard output and standard error channels will be written to this log file. If an empty string is specified, no log file will be used, and the spawn server will use the same standard output/error channels as the current process.
environment The RAILS_ENV environment that all RoR applications should use. If an empty string is specified, the current value of the RAILS_ENV environment variable will be used.
rubyCommand The Ruby interpreter's command.
user The user that the spawn manager should run as. This parameter only has effect if the current process is running as root. If the empty string is given, or if the user is not a valid username, then the spawn manager will be run as the current user.
Exceptions:
SystemException An error occured while trying to setup the spawn server or the server socket.
IOException The specified log file could not be opened.
boost::thread_resource_error A threading resource could not be allocated or initialized.


Member Function Documentation

ApplicationPoolPtr Passenger::ApplicationPoolServer::connect (  )  [inline]

Connects to the server and returns a usable ApplicationPool object.

All cache/pool data of this ApplicationPool is actually stored on the server and shared with other clients, but that is totally transparent to the user of the ApplicationPool object.

Warning:
One may only use the returned ApplicationPool object for handling one session at a time. For example, don't do stuff like this:
   ApplicationPoolPtr pool = server.connect();
   Application::SessionPtr session1 = pool->get(...);
   Application::SessionPtr session2 = pool->get(...);
Otherwise, a deadlock can occur under certain circumstances.

Instead, one should call connect() multiple times:

   ApplicationPoolPtr pool1 = server.connect();
   Application::SessionPtr session1 = pool1->get(...);
   
   ApplicationPoolPtr pool2 = server.connect();
   Application::SessionPtr session2 = pool2->get(...);
Exceptions:
SystemException Something went wrong.
IOException Something went wrong.

void Passenger::ApplicationPoolServer::detach (  )  [inline]

Detach the server by freeing up some server resources such as file descriptors.

This should be called by child processes that wish to use a server, but do not run the server itself.

This method may only be called once. The ApplicationPoolServer object will become unusable once detach() has been called.

Warning:
Never call this method in the process in which this ApplicationPoolServer was created!


The documentation for this class was generated from the following file:
Generated on Wed May 7 20:28:19 2008 for Passenger by  doxygen 1.5.3