Passenger: Passenger::ApplicationPoolServer Class Reference

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

Multi-process usage support for ApplicationPool. More...

`#include <ApplicationPoolServer.h>`

List of all members.

## 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.

## 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());

           // 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);
       }

## Implementation notes

### Separate server executable

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 the usage of threads in the ApplicationPool server, the Apache VM size would go way up. This gave people the (wrong) impression that Passenger uses a lot of memory, or that it leaks memory.
- Although it's not entirely confirmed, we suspect that it caused heap fragmentation as well. Apache allocates lots and lots of small objects on the heap, and ApplicationPool server isn't exactly helping. This too gave people the (wrong) impression that Passenger leaks memory.
- It would unnecessarily bloat the VM size of Apache worker processes.
- We had to resort to all kinds of tricks to make sure that fork()ing a process doesn't result in file descriptor leaks.
- Despite everything, there was still a small chance that file descriptor leaks would occur, and this could not be fixed. The reason for this is that the Apache control process may call fork() right after the ApplicationPool server has established a new connection with a client.

Because of these problems, it was decided to split the ApplicationPool server to a separate executable. This comes with no performance hit.

### Anonymous server socket

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.

## Constructor & Destructor Documentation

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.

Parameters:

  | 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.

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.

## 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.

Note:
  All methods of the returned ApplicationPool object may throw SystemException, IOException or boost::thread_interrupted.

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, 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().

The documentation for this class was generated from the following file:

- ApplicationPoolServer.h