public
Description: Phusion Passenger (mod_rails)
Homepage: http://www.modrails.com/
Clone URL: git://github.com/FooBarWidget/passenger.git
Click here to lend your support to: passenger and make a donation at www.pledgie.com !
Improve documentation and error handling.
Hongli Lai (Phusion) (author)
Mon Apr 28 02:22:09 -0700 2008
commit  94dccffb7ffc4f6925db763264bbb52913a84aa9
tree    e4c1b7c1aade71535cd7e645300a9e2fa30deee9
parent  4ef9966d9ff38582ef5b276fdafbff84b033af31
...
39
40
41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
43
44
...
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
0
@@ -39,6 +39,85 @@ using namespace std;
0
 using namespace boost;
0
 
0
 
0
+/**
0
+ * Multi-process usage support for ApplicationPool.
0
+ *
0
+ * ApplicationPoolServer implements a client/server architecture for ApplicationPool.
0
+ * This allows one to use ApplicationPool in a multi-process environment (unlike
0
+ * StandardApplicationPool). The cache/pool data is stored in the server. Different
0
+ * processes can then access the pool through the server.
0
+ *
0
+ * ApplicationPoolServer itself does not inherit ApplicationPool. Instead, it returns
0
+ * an ApplicationPool object via the connect() call. For example:
0
+ * @code
0
+ * // Create an ApplicationPoolServer.
0
+ * ApplicationPoolServer server(...);
0
+ *
0
+ * // Now fork a child process, like Apache's prefork MPM eventually will.
0
+ * pid_t pid = fork();
0
+ * if (pid == 0) {
0
+ * // Child process
0
+ *
0
+ * // Connect to the server. After connection, we have an ApplicationPool
0
+ * // object!
0
+ * ApplicationPoolPtr pool(server.connect());
0
+ *
0
+ * // We don't need to connect to the server anymore, so we detach from it.
0
+ * // This frees up some resources, such as file descriptors.
0
+ * server.detach();
0
+ *
0
+ * ApplicationPool::SessionPtr session(pool->get("/home/webapps/foo"));
0
+ * do_something_with(session);
0
+ *
0
+ * _exit(0);
0
+ * } else {
0
+ * // Parent process
0
+ * waitpid(pid, NULL, 0);
0
+ * }
0
+ * @endcode
0
+ *
0
+ * <h2>Implementation notes</h2>
0
+ *
0
+ * <h3>Separate server executable</h3>
0
+ * The actual server is implemented in ApplicationPoolServerExecutable.cpp, this class is
0
+ * just a convenience class for starting/stopping the server executable and connecting
0
+ * to it.
0
+ *
0
+ * In the past, the server logic itself was implemented in this class. This implies that
0
+ * the ApplicationPool server ran inside the Apache process. This presented us with several
0
+ * problems:
0
+ * - Because of the usage of threads in the ApplicationPool server, the Apache VM size would
0
+ * go way up. This gave people the (wrong) impression that Passenger uses a lot of memory,
0
+ * or that it leaks memory.
0
+ * - Although it's not entirely confirmed, we suspect that it caused heap fragmentation as
0
+ * well. Apache allocates lots and lots of small objects on the heap, and ApplicationPool
0
+ * server isn't exactly helping. This too gave people the (wrong) impression that
0
+ * Passenger leaks memory.
0
+ * - It would unnecessarily bloat the VM size of Apache worker processes.
0
+ * - We had to resort to all kinds of tricks to make sure that fork()ing a process doesn't
0
+ * result in file descriptor leaks.
0
+ * - Despite everything, there was still a small chance that file descriptor leaks would
0
+ * occur, and this could not be fixed. The reason for this is that the Apache control
0
+ * process may call fork() right after the ApplicationPool server has established a new
0
+ * connection with a client.
0
+ *
0
+ * Because of these problems, it was decided to split the ApplicationPool server to a
0
+ * separate executable. This comes with no performance hit.
0
+ *
0
+ * <h3>Anonymous server socket</h3>
0
+ * Notice that ApplicationPoolServer does do not use TCP sockets at all, or even named Unix
0
+ * sockets, despite being a server that can handle multiple clients! So ApplicationPoolServer
0
+ * will expose no open ports or temporary Unix socket files. Only child processes are able
0
+ * to use the ApplicationPoolServer.
0
+ *
0
+ * This is implemented through anonymous Unix sockets (<tt>socketpair()</tt>) and file descriptor
0
+ * passing. It allows one to emulate <tt>accept()</tt>. ApplicationPoolServer is connected to
0
+ * the server executable through a Unix socket pair. connect() sends a connect request to the
0
+ * server through that socket. The server will then create a new socket pair, and pass one of
0
+ * them back. This new socket pair represents the newly established connection.
0
+ *
0
+ * @ingroup Support
0
+ */
0
 class ApplicationPoolServer {
0
 private:
0
   /**
...
18
19
20
 
 
 
 
 
 
 
 
 
 
 
21
22
23
...
263
264
265
 
266
267
268
...
279
280
281
282
 
283
284
285
...
361
362
363
364
365
 
 
 
 
 
 
 
 
 
 
 
366
367
368
...
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
...
274
275
276
277
278
279
280
...
291
292
293
 
294
295
296
297
...
373
374
375
 
 
376
377
378
379
380
381
382
383
384
385
386
387
388
389
0
@@ -18,6 +18,17 @@
0
 #ifndef _PASSENGER_APPLICATION_POOL_SERVER_EXECUTABLE_H_
0
 #define _PASSENGER_APPLICATION_POOL_SERVER_EXECUTABLE_H_
0
 
0
+/*
0
+ * This is the ApplicationPool server executable. See the ApplicationPoolServer
0
+ * class for background information.
0
+ *
0
+ * Each client is handled by a seperate thread. This is necessary because we use
0
+ * StandardApplicationPool, and the current algorithm for StandardApplicationPool::get()
0
+ * can block (in the case that the spawning limit has been exceeded). While it is
0
+ * possible to get around this problem without using threads, a thread-based implementation
0
+ * is easier to write.
0
+ */
0
+
0
 #include <boost/shared_ptr.hpp>
0
 #include <boost/weak_ptr.hpp>
0
 #include <boost/bind.hpp>
0
@@ -263,6 +274,7 @@ public:
0
   /**
0
    * Create a new Client object.
0
    *
0
+ * @param the_server The Server object that this Client belongs to.
0
    * @param connection The connection to the ApplicationPool client.
0
    *
0
    * @note
0
@@ -279,7 +291,7 @@ public:
0
   /**
0
    * Start the thread for handling the connection with this client.
0
    *
0
- * @param The iterator of this Client object inside the server's
0
+ * @param self The iterator of this Client object inside the server's
0
    * <tt>clients</tt> set. This is used to remove itself from
0
    * the <tt>clients</tt> set once the client has closed the
0
    * connection.
0
@@ -361,8 +373,17 @@ Server::start() {
0
 
0
 int
0
 main(int argc, char *argv[]) {
0
- Server server(SERVER_SOCKET_FD, argv[1], argv[2], argv[3], argv[4], argv[5]);
0
- return server.start();
0
+ try {
0
+ Server server(SERVER_SOCKET_FD, argv[1], argv[2], argv[3], argv[4], argv[5]);
0
+ return server.start();
0
+ } catch (const exception &e) {
0
+ fprintf(stderr, "*** An unexpected error occured in the Passenger "
0
+ "ApplicationPool server:\n%s\n",
0
+ e.what());
0
+ fflush(stderr);
0
+ abort();
0
+ return 1;
0
+ }
0
 }
0
 
0
 #endif /* _PASSENGER_APPLICATION_POOL_SERVER_EXECUTABLE_H_ */

Comments

    No one has commented yet.