#include <ApplicationPoolServer.h>
Public Member Functions | |
ApplicationPoolServer (const string &serverExecutable, const string &spawnServerCommand, const string &logFile="", 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, thereby telling it that we don't want to connect to it anymore. |
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()); // We don't need to connect to the server anymore, so we detach from it. // This frees up some resources, such as 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); }
The actual server is implemented in ApplicationPoolServerExecutable.cpp, this class is just a convenience class for starting/stopping the server executable and connecting to it.
In the past, the server logic itself was implemented in this class. This implies that the ApplicationPool server ran inside the Apache process. This presented us with several problems:
Because of these problems, it was decided to split the ApplicationPool server to a separate executable. This comes with no performance hit.
Notice that ApplicationPoolServer does do not use TCP sockets at all, or even named Unix sockets, despite 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()
. ApplicationPoolServer is connected to the server executable through a Unix socket pair. connect() sends a connect request to the server through that socket. The server will then create a new socket pair, and pass one of them back. This new socket pair represents the newly established connection.
Passenger::ApplicationPoolServer::ApplicationPoolServer | ( | const string & | serverExecutable, | |
const string & | spawnServerCommand, | |||
const string & | logFile = "" , |
|||
const string & | rubyCommand = "ruby" , |
|||
const string & | user = "" | |||
) | [inline] |
Create a new ApplicationPoolServer object.
serverExecutable | The filename of the ApplicationPool server executable to use. | |
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. | |
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. |
SystemException | An error occured while trying to setup the spawn server or the server socket. | |
IOException | The specified log file could not be opened. |
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.
ApplicationPoolPtr pool = server.connect(); Application::SessionPtr session1 = pool->get(...); Application::SessionPtr session2 = pool->get(...);
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(...);
SystemException | Something went wrong. | |
IOException | Something went wrong. |
void Passenger::ApplicationPoolServer::detach | ( | ) | [inline] |
Detach the server, thereby telling it that we don't want to connect to it anymore.
This frees up some resources in the current process, such as file descriptors.
This method is particularily useful to Apache worker processes that have just established a connection with the ApplicationPool server. Any sessions that are opened prior to calling detach(), will keep working even after a detach().
This method may only be called once. The ApplicationPoolServer object will become unusable once detach() has been called, so call connect() before calling detach().