public
Description: Phusion Passenger (mod_rails)
Homepage: http://www.modrails.com/
Clone URL: git://github.com/FooBarWidget/passenger.git
Search Repo:
Click here to lend your support to: passenger and make a donation at www.pledgie.com !
- Fix some crasher bugs in DispatcherBucket.
- Fix wrong timeout calculation in DispatcherBucket.
- Add a DummyRequestHandler, which is probably the fastest possible 
request handler implementation. This, together with DummySpawnManager, 
allows one to benchmark the Apache module's performance.
FooBarWidget (author)
Sun Feb 03 05:02:03 -0800 2008
commit  4430bf4bf5b889828f311be186e7c9faa49aeecc
tree    193401ed6ea578a6938113b125f659c130b58986
parent  a3196e06dd1880d72a1c9c36903d80384b7f8ccd
...
57
58
59
60
61
62
63
...
65
66
67
68
69
70
71
...
57
58
59
 
60
61
62
...
64
65
66
 
67
68
69
0
@@ -57,7 +57,6 @@ public:
0
     if (reader != -1) {
0
       close(reader);
0
       reader = -1;
0
- P_TRACE("Application " << this << ": reader closed.");
0
     }
0
   }
0
   
0
@@ -65,7 +64,6 @@ public:
0
     if (writer != -1) {
0
       close(writer);
0
       writer = -1;
0
- P_TRACE("Application " << this << ": writer closed.");
0
     }
0
   }
0
 };
...
7
8
9
10
 
 
 
 
 
11
12
13
...
26
27
28
29
 
 
 
 
 
30
31
32
...
41
42
43
44
 
 
 
 
45
46
47
...
7
8
9
 
10
11
12
13
14
15
16
17
...
30
31
32
 
33
34
35
36
37
38
39
40
...
49
50
51
 
52
53
54
55
56
57
58
0
@@ -7,7 +7,11 @@
0
 #include <string>
0
 #include <map>
0
 
0
-#include "SpawnManager.h"
0
+#ifdef PASSENGER_USE_DUMMY_SPAWN_MANAGER
0
+ #include "DummySpawnManager.h"
0
+#else
0
+ #include "SpawnManager.h"
0
+#endif
0
 
0
 namespace Passenger {
0
 
0
@@ -26,7 +30,11 @@ class StandardApplicationPool: public ApplicationPool {
0
 private:
0
   typedef map<string, ApplicationPtr> ApplicationMap;
0
 
0
- SpawnManager spawnManager;
0
+ #ifdef PASSENGER_USE_DUMMY_SPAWN_MANAGER
0
+ DummySpawnManager spawnManager;
0
+ #else
0
+ SpawnManager spawnManager;
0
+ #endif
0
   ApplicationMap apps;
0
   mutex lock;
0
   bool threadSafe;
0
@@ -41,7 +49,10 @@ public:
0
    const string &logFile = "",
0
    const string &environment = "production",
0
    const string &rubyCommand = "ruby")
0
- : spawnManager(spawnManagerCommand, logFile, environment, rubyCommand) {
0
+ #ifndef PASSENGER_USE_DUMMY_SPAWN_MANAGER
0
+ : spawnManager(spawnManagerCommand, logFile, environment, rubyCommand)
0
+ #endif
0
+ {
0
     threadSafe = false;
0
   }
0
   
...
13
14
15
 
16
17
18
...
13
14
15
16
17
18
19
0
@@ -13,6 +13,7 @@
0
 #include <unistd.h>
0
 
0
 #include "ApplicationPool.h"
0
+#include "MessageChannel.h"
0
 #include "Exceptions.h"
0
 #include "Utils.h"
0
 
...
1
 
 
2
3
4
...
67
68
69
70
 
71
72
73
 
74
75
76
...
141
142
143
144
 
 
 
 
 
145
146
147
...
162
163
164
165
 
 
 
 
 
166
167
168
...
1
2
3
4
5
6
...
69
70
71
 
72
73
74
 
75
76
77
78
...
143
144
145
 
146
147
148
149
150
151
152
153
...
168
169
170
 
171
172
173
174
175
176
177
178
0
@@ -1,4 +1,6 @@
0
 #include <string>
0
+#include <algorithm>
0
+
0
 #include <poll.h>
0
 #include <errno.h>
0
 #include <unistd.h>
0
@@ -67,10 +69,10 @@ private:
0
           return errno_to_apr_status(errno);
0
         }
0
       }
0
-
0
+
0
       apr_time_t begin = apr_time_now();
0
       tmp = ::read(pipe, (char *) buffer + already_read, size - already_read);
0
- timeout -= apr_time_now() - begin;
0
+ timeout = max((apr_time_t) 0, timeout - (apr_time_now() - begin));
0
       if (tmp > 0) {
0
         // Data has been read.
0
         already_read += tmp;
0
@@ -141,7 +143,11 @@ public:
0
       *str = (const char *) b->data;
0
       return APR_SUCCESS;
0
     } else if (result != APR_SUCCESS) {
0
- P_TRACE("DispatcherBucket " << this << ": APR error " << result);
0
+ char buf[1024];
0
+ P_TRACE("DispatcherBucket " << this << ": APR error " << result
0
+ << ": " << apr_strerror(result, buf, sizeof(buf)));
0
+ b = apr_bucket_immortal_make(b, "", 0);
0
+ *str = (const char *) b->data;
0
       return result;
0
     }
0
 
0
@@ -162,7 +168,11 @@ public:
0
       *str = (const char *) b->data;
0
       return APR_SUCCESS;
0
     } else {
0
- P_TRACE("DispatcherBucket " << this << ": APR error " << result);
0
+ char buf[1024];
0
+ P_TRACE("DispatcherBucket " << this << ": APR error " << result
0
+ << ": " << apr_strerror(result, buf, sizeof(buf)));
0
+ b = apr_bucket_immortal_make(b, "", 0);
0
+ *str = (const char *) b->data;
0
       return result;
0
     }
0
   }
0
...
260
261
262
 
 
 
 
 
 
263
264
265
266
267
 
268
269
270
...
279
280
281
 
 
282
283
284
...
260
261
262
263
264
265
266
267
268
269
270
271
272
 
273
274
275
276
...
285
286
287
288
289
290
291
292
0
@@ -260,11 +260,17 @@ public:
0
       return httpStatus;
0
     } */
0
     
0
+ /*
0
+ * TODO: fix these bugs:
0
+ * - If the request handler dies, it does not get removed from the application pool. It should.
0
+ * - If Apache dies, then the request handler's protocol state is left in an inconsistent state.
0
+ */
0
+
0
     try {
0
       apr_bucket_brigade *bb;
0
       apr_bucket *b;
0
       
0
- P_DEBUG("Processing HTTP request on process " << getpid() << ": " << r->uri);
0
+ P_DEBUG("Processing HTTP request: " << r->uri);
0
       ApplicationPtr app(applicationPool->get(string(railsDir) + "/.."));
0
       P_TRACE("Connected to application: reader FD = " << app->getReader() << ", writer FD = " << app->getWriter());
0
       sendHeaders(r, app->getWriter());
0
@@ -279,6 +285,8 @@ public:
0
 
0
       ap_scan_script_header_err_brigade(r, bb, NULL);
0
       ap_pass_brigade(r->output_filters, bb);
0
+
0
+ P_TRACE("Dispatcher brigade passed to output filters");
0
 
0
       return OK;
0
     } catch (const exception &e) {
0
...
1
2
3
4
 
5
6
7
...
1
2
3
 
4
5
6
7
0
@@ -1,7 +1,7 @@
0
 APXS=apxs2
0
 APACHECTL=apache2ctl
0
 CXX=g++
0
-CXXFLAGS=-Wall -fPIC -g -DPASSENGER_DEBUG `pkg-config --cflags apr-1 apr-util-1` `$(APXS) -q CFLAGS` -I`$(APXS) -q INCLUDEDIR`
0
+CXXFLAGS=-Wall -fPIC -g -DPASSENGER_DEBUG -DPASSENGER_USE_DUMMY_SPAWN_MANAGER `pkg-config --cflags apr-1 apr-util-1` `$(APXS) -q CFLAGS` -I`$(APXS) -q INCLUDEDIR`
0
 OBJECTS=Configuration.o Hooks.o DispatcherBucket.o Utils.o
0
 LIBTOOL_OBJECTS=Configuration.o,Hooks.o,DispatcherBucket.o,Utils.o
0
 
...
21
22
23
24
25
 
26
27
 
 
 
 
 
 
 
 
 
28
29
30
...
32
33
34
 
35
36
37
 
 
 
 
 
38
39
40
...
43
44
45
46
47
48
49
50
51
 
 
 
 
 
 
 
 
52
53
54
...
56
57
58
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
60
61
...
86
87
88
89
 
90
91
92
...
123
124
125
126
 
127
128
129
...
149
150
151
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
153
154
...
21
22
23
 
 
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
...
40
41
42
43
44
45
 
46
47
48
49
50
51
52
53
...
56
57
58
 
 
 
 
 
 
59
60
61
62
63
64
65
66
67
68
69
...
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
...
120
121
122
 
123
124
125
126
...
157
158
159
 
160
161
162
163
...
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
0
@@ -21,10 +21,18 @@ using namespace std;
0
 
0
 /**
0
  * This class provides convenience methods for:
0
- * - sending and receiving discrete messages over a file descriptor.
0
- * A message is just a list of strings.
0
+ * - sending and receiving messages over a file descriptor.
0
  * - file descriptor passing over a Unix socket.
0
  *
0
+ * There are two kinds of messages:
0
+ * - Array messages. These are just a list of strings, and the message
0
+ * itself has a specific length. The contained strings may not
0
+ * contain NUL characters ('\0').
0
+ * - Scalar messages. These are byte strings which may contain arbitrary
0
+ * binary data. Scalar messages also have a specific length.
0
+ * The protocol is designed to be low overhead, easy to implement and
0
+ * easy to parse.
0
+ *
0
  * MessageChannel is to be wrapped around a file descriptor. For example:
0
  * @code
0
  * int p[2];
0
@@ -32,9 +40,14 @@ using namespace std;
0
  * MessageChannel channel1(p[0]);
0
  * MessageChannel channel2(p[1]);
0
  *
0
+ * // Send an array message.
0
  * channel2.write("hello", "world !!", NULL);
0
  * list<string> args;
0
- * channel1.read(args); // args now contains { "hello", "world !!" }
0
+ * channel1.read(args); // args now contains { "hello", "world !!" }
0
+ *
0
+ * // Send a scalar message.
0
+ * channel2.writeScalar("some long string which can contain arbitrary binary data");
0
+ * string str = channel1.readScalar();
0
  * @endcode
0
  *
0
  * The life time of a MessageChannel is independent from that of the
0
@@ -43,12 +56,14 @@ using namespace std;
0
  * if you want to close the file descriptor.
0
  *
0
  * @note I/O operations are not buffered.
0
- * @note Be careful with mixing the sending/receiving of messages file
0
- * descriptor passing. These operations have stream properties.
0
- * Suppose you first send a message, then pass a file descriptor.
0
- * If the other side of the communication channel first tries to
0
- * receive a file descriptor, and then tries to receive a message,
0
- * then bad things will happen.
0
+ * @note Be careful with mixing the sending/receiving of array messages,
0
+ * scalar messages and file descriptors. If you send a collection of any
0
+ * of these in a specific order, then the receiving side must receive them
0
+ * in the exact some order. So suppose you first send a message, then a
0
+ * file descriptor, then a scalar, then the receiving side must first
0
+ * receive a message, then a file descriptor, then a scalar. If the
0
+ * receiving side does things in the wrong order then bad things will
0
+ * happen.
0
  * @note MessageChannel is thread-safe.
0
  */
0
 class MessageChannel {
0
@@ -56,6 +71,25 @@ private:
0
   const static char DELIMITER = '\0';
0
   int fd;
0
 
0
+ void writeLength(unsigned short len) {
0
+ uint16_t l;
0
+ ssize_t ret;
0
+ unsigned int written;
0
+
0
+ l = htons(len);
0
+ written = 0;
0
+ do {
0
+ do {
0
+ ret = ::write(fd, (char *) &l + written, sizeof(l) - written);
0
+ } while (ret == -1 && errno == EINTR);
0
+ if (ret == -1) {
0
+ throw SystemException("write() failed", errno);
0
+ } else {
0
+ written += ret;
0
+ }
0
+ } while (written < sizeof(l));
0
+ }
0
+
0
 public:
0
   /**
0
    * Construct a new MessageChannel with no underlying file descriptor.
0
@@ -86,7 +120,7 @@ public:
0
   }
0
 
0
   /**
0
- * Send the message, which consists of the given elements, over the underlying
0
+ * Send an array message, which consists of the given elements, over the underlying
0
    * file descriptor.
0
    *
0
    * @throws SystemException An error occured while writing the data to the file descriptor.
0
@@ -123,7 +157,7 @@ public:
0
   }
0
   
0
   /**
0
- * Send the message, which consists of the given strings, over the underlying
0
+ * Send an array message, which consists of the given strings, over the underlying
0
    * file descriptor.
0
    *
0
    * @param name The first element of the message to send.
0
@@ -149,6 +183,27 @@ public:
0
     write(args);
0
   }
0
   
0
+ void writeScalar(const string &str) {
0
+ writeScalar(str.c_str(), str.size());
0
+ }
0
+
0
+ void writeScalar(const char *data, unsigned short size) {
0
+ writeLength(size);
0
+
0
+ ssize_t ret;
0
+ unsigned int written = 0;
0
+ do {
0
+ do {
0
+ ret = ::write(fd, data + written, size - written);
0
+ } while (ret == -1 && errno == EINTR);
0
+ if (ret == -1) {
0
+ throw SystemException("write() failed", errno);
0
+ } else {
0
+ written += ret;
0
+ }
0
+ } while (written < size);
0
+ }
0
+
0
   /**
0
    * Pass a file descriptor. This only works if the underlying file
0
    * descriptor is a Unix socket.

Comments

    No one has commented yet.