Take the 2008 Git User's Survey and help out! [ hide ]

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 !
The request handler will be left in an inconsistent state if Apache dies 
during the middle of sending headers. This commit contains the beginning 
of an attempt to fix that, but it'll probably be easier to drop persistent 
pipe connections all together.
FooBarWidget (author)
Sun Feb 03 08:53:49 -0800 2008
commit  16e0de8a283d66d69be67997d26cbcbe609b73d2
tree    71c169c249722108ad7589834ee9556ba862edc2
parent  b39e6c012f6a10af78e61068b2367e74271fc975
...
11
12
13
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
16
 
 
 
 
17
18
19
 
 
 
20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
22
23
24
25
 
 
 
26
27
28
29
30
31
 
 
 
32
33
34
35
36
37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
39
40
...
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
...
11
12
13
 
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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
...
135
136
137
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
139
140
0
@@ -11,30 +11,113 @@ namespace Passenger {
0
 using namespace std;
0
 using namespace boost;
0
 
0
-// TODO: write better documentation
0
+/**
0
+ * Represents a single instance of a Ruby on Rails application, as spawned by
0
+ * SpawnManager. An Application can handle one CGI request at a time, through its
0
+ * two communication channels: reader and writer.
0
+ *
0
+ * Application is supposed to be used as follows:
0
+ * 1. The web server first opens the Application, thereby telling the Application
0
+ * that the web server wants to establish a new CGI session. Application
0
+ * will return a lock, which the web server must hold onto.
0
+ * 2. The web server sends the CGI request data through the Application's
0
+ * writer channel.
0
+ * 3. The web server reads the HTTP response from the Application's reader channel,
0
+ * and forwarding that to the web browser.
0
+ * 4. The web server destroys the previously obtained lock.
0
+ * 5. The web server closes the Application, thereby ending the CGI session.
0
+ *
0
+ * An Application can be reopened after it has been closed.
0
+ *
0
+ * Example:
0
+ * @code
0
+ * // Create a new Application.
0
+ * ApplicationPtr app(some_function_which_returns_an_application());
0
+ * // Open a new CGI session, and save the lock.
0
+ * Application::LockPtr lock(app->openSession());
0
+ *
0
+ * // Process request and response.
0
+ * send_cgi_headers_to(app->getWriter());
0
+ * response = read_response_from(app->getReader());
0
+ * process_response(response);
0
+ *
0
+ * // Now we're done. *First* we destroy the lock!
0
+ * lock = Application::LockPtr();
0
+ * // And *then* we close the session.
0
+ * app->closeSession();
0
+ * @endcode
0
+ *
0
+ * <h2>About open/close
0
+ */
0
 class Application {
0
 private:
0
+ struct LockData {
0
+ bool locked;
0
+ };
0
+
0
   string appRoot;
0
   pid_t pid;
0
   int reader, writer;
0
+ bool opened;
0
+ shared_ptr<LockData> lockData;
0
+
0
 public:
0
+ class Lock {
0
+ private:
0
+ friend class Application;
0
+ shared_ptr<LockData> data;
0
+
0
+ Lock(shared_ptr<LockData> data) {
0
+ this->data = data;
0
+ }
0
+
0
+ public:
0
+ Lock() {}
0
+
0
+ ~Lock() {
0
+ if (data != NULL) {
0
+ data->locked = false;
0
+ }
0
+ P_TRACE("Unlocked!");
0
+ }
0
+ };
0
+
0
+ typedef shared_ptr<Lock> LockPtr;
0
+
0
   Application(const string &theAppRoot, pid_t pid, int reader, int writer) {
0
     appRoot = theAppRoot;
0
     this->pid = pid;
0
     this->reader = reader;
0
     this->writer = writer;
0
+ opened = false;
0
+ lockData = ptr(new LockData());
0
+ lockData->locked = false;
0
     P_TRACE("Application " << this << ": created.");
0
   }
0
   
0
- ~Application() {
0
- closeReader();
0
- closeWriter();
0
+ virtual ~Application() {
0
+ close(reader);
0
+ close(writer);
0
     P_TRACE("Application " << this << ": destroyed.");
0
   }
0
   
0
- void detachCommunicationChannels() {
0
- reader = -1;
0
- writer = -1;
0
+ LockPtr openSession() {
0
+ opened = true;
0
+ lockData->locked = true;
0
+ return ptr(new Lock(lockData));
0
+ }
0
+
0
+ void closeSession() {
0
+ opened = false;
0
+ P_TRACE("Closed!");
0
+ }
0
+
0
+ bool isOpen() const {
0
+ return opened;
0
+ }
0
+
0
+ bool hasError() const {
0
+ return opened && !lockData->locked;
0
   }
0
   
0
   string getAppRoot() const {
0
@@ -52,20 +135,6 @@ public:
0
   int getWriter() const {
0
     return writer;
0
   }
0
-
0
- void closeReader() {
0
- if (reader != -1) {
0
- close(reader);
0
- reader = -1;
0
- }
0
- }
0
-
0
- void closeWriter() {
0
- if (writer != -1) {
0
- close(writer);
0
- writer = -1;
0
- }
0
- }
0
 };
0
 
0
 typedef shared_ptr<Application> ApplicationPtr;
...
22
23
24
25
 
 
26
27
28
...
39
40
41
42
43
44
45
46
47
48
49
...
61
62
63
64
65
 
 
66
67
68
...
72
73
74
 
 
 
 
75
76
 
77
78
79
...
22
23
24
 
25
26
27
28
29
...
40
41
42
 
 
 
 
 
43
44
45
...
57
58
59
 
 
60
61
62
63
64
...
68
69
70
71
72
73
74
75
 
76
77
78
79
0
@@ -22,7 +22,8 @@ class ApplicationPool {
0
 public:
0
   virtual ~ApplicationPool() {};
0
   
0
- virtual ApplicationPtr get(const string &appRoot, const string &user = "", const string &group = "") = 0;
0
+ virtual pair<ApplicationPtr, Application::LockPtr>
0
+ get(const string &appRoot, const string &user = "", const string &group = "") = 0;
0
 };
0
 
0
 // TODO: document this
0
@@ -39,11 +40,6 @@ private:
0
   mutex lock;
0
   bool threadSafe;
0
   
0
- string normalizePath(const string &path) {
0
- // TODO
0
- return path;
0
- }
0
-
0
 public:
0
   StandardApplicationPool(const string &spawnManagerCommand,
0
    const string &logFile = "",
0
@@ -61,8 +57,8 @@ public:
0
   }
0
   
0
   // TODO: improve algorithm
0
- virtual ApplicationPtr get(const string &appRoot, const string &user = "", const string &group = "") {
0
- string normalizedAppRoot(normalizePath(appRoot));
0
+ virtual pair<ApplicationPtr, Application::LockPtr>
0
+ get(const string &appRoot, const string &user = "", const string &group = "") {
0
     ApplicationPtr app;
0
     mutex::scoped_lock l(lock, threadSafe);
0
     
0
@@ -72,8 +68,12 @@ public:
0
       apps[appRoot] = app;
0
     } else {
0
       app = it->second;
0
+ if (app->hasError()) {
0
+ app = spawnManager.spawn(appRoot, user, group);
0
+ apps[appRoot] = app;
0
+ }
0
     }
0
- return app;
0
+ return make_pair(app, app->openSession());
0
   }
0
 };
0
 
...
29
30
31
32
 
33
34
35
...
119
120
121
 
122
123
124
...
137
138
139
 
140
141
142
143
 
 
 
144
145
146
...
179
180
181
182
 
 
183
184
185
...
196
197
198
 
199
200
201
...
29
30
31
 
32
33
34
35
...
119
120
121
122
123
124
125
...
138
139
140
141
142
143
144
145
146
147
148
149
150
151
...
184
185
186
 
187
188
189
190
191
...
202
203
204
205
206
207
208
0
@@ -29,7 +29,7 @@ static const apr_bucket_type_t bucket_type_dispatcher = {
0
   apr_bucket_copy_notimpl
0
 };
0
 
0
-
0
+static bool x = false;
0
 class DispatcherBucket {
0
 private:
0
   apr_status_t
0
@@ -119,6 +119,7 @@ private:
0
   
0
 public:
0
   ApplicationPtr app;
0
+ Application::LockPtr lock;
0
   int pipe;
0
   apr_interval_time_t timeout;
0
   
0
@@ -137,10 +138,14 @@ public:
0
     }
0
     
0
     result = read_chunk_size(chunk_size, current_timeout);
0
+ if (x) { result = APR_EBADF; x = !x; }
0
     if (result == APR_EOF || (result == APR_SUCCESS && chunk_size == 0)) {
0
       P_TRACE("DispatcherBucket " << this << ": EOF");
0
       b = apr_bucket_immortal_make(b, "", 0);
0
       *str = (const char *) b->data;
0
+ x = true;
0
+ lock = Application::LockPtr();
0
+ app->closeSession();
0
       return APR_SUCCESS;
0
     } else if (result != APR_SUCCESS) {
0
       char buf[1024];
0
@@ -179,7 +184,8 @@ public:
0
 };
0
 
0
 apr_bucket *
0
-dispatcher_bucket_create(apr_pool_t *pool, ApplicationPtr app, apr_interval_time_t timeout, apr_bucket_alloc_t *list) {
0
+dispatcher_bucket_create(apr_pool_t *pool, ApplicationPtr app, Application::LockPtr lock,
0
+ apr_interval_time_t timeout, apr_bucket_alloc_t *list) {
0
   apr_bucket *b;
0
   DispatcherBucket *data;
0
 
0
@@ -196,6 +202,7 @@ dispatcher_bucket_create(apr_pool_t *pool, ApplicationPtr app, apr_interval_time
0
 
0
   data = new DispatcherBucket();
0
   data->app = app;
0
+ data->lock = lock;
0
   data->pipe = app->getReader();
0
   data->timeout = timeout;
0
   b->data = data;
...
10
11
12
13
 
 
14
15
16
...
10
11
12
 
13
14
15
16
17
0
@@ -10,7 +10,8 @@
0
 #include <apr_buckets.h>
0
 #include "Application.h"
0
 
0
-apr_bucket *dispatcher_bucket_create(apr_pool_t *pool, Passenger::ApplicationPtr app,
0
+apr_bucket *dispatcher_bucket_create(apr_pool_t *pool,
0
+ Passenger::ApplicationPtr app, Passenger::Application::LockPtr lock,
0
   apr_interval_time_t timeout, apr_bucket_alloc_t *list);
0
 
0
 #endif /* _DISPATCHER_BUCKET_H_ */
...
22
23
24
25
 
 
26
27
28
...
33
34
35
36
 
37
38
39
...
217
218
219
220
221
 
 
222
223
224
...
226
227
228
229
230
 
 
 
231
232
233
...
271
272
273
274
275
276
 
 
 
 
277
278
279
 
280
281
282
...
22
23
24
 
25
26
27
28
29
...
34
35
36
 
37
38
39
40
...
218
219
220
 
 
221
222
223
224
225
...
227
228
229
 
 
230
231
232
233
234
235
...
273
274
275
 
 
 
276
277
278
279
280
281
 
282
283
284
285
0
@@ -22,7 +22,8 @@
0
 #include "Types.h"
0
 #include "Utils.h"
0
 #include "DispatcherBucket.h"
0
-#include "ApplicationPoolClientServer.h"
0
+//#include "ApplicationPoolClientServer.h"
0
+#include "ApplicationPool.h"
0
 #include "MessageChannel.h"
0
 
0
 using namespace std;
0
@@ -33,7 +34,7 @@ extern "C" module AP_MODULE_DECLARE_DATA rails_module;
0
 
0
 class Hooks {
0
 private:
0
- ApplicationPoolServerPtr applicationPoolServer;
0
+ //ApplicationPoolServerPtr applicationPoolServer;
0
   ApplicationPoolPtr applicationPool;
0
   
0
   RailsConfig *getConfig(request_rec *r) {
0
@@ -217,8 +218,8 @@ public:
0
     initDebugging();
0
     P_DEBUG("Initializing mod_passenger.");
0
     ap_add_version_component(pconf, "Phusion_Passenger/" PASSENGER_VERSION);
0
- const char *spawnManagerCommand = "/home/hongli/Projects/mod_rails/lib/mod_rails/spawn_manager.rb";
0
- applicationPoolServer = ptr(new ApplicationPoolServer(spawnManagerCommand, "", "production"));
0
+ //const char *spawnManagerCommand = "/home/hongli/Projects/mod_rails/lib/mod_rails/spawn_manager.rb";
0
+ //applicationPoolServer = ptr(new ApplicationPoolServer(spawnManagerCommand, "", "production"));
0
   }
0
   
0
   ~Hooks() {
0
@@ -226,8 +227,9 @@ public:
0
   }
0
   
0
   void initChild(apr_pool_t *pchild, server_rec *s) {
0
- applicationPool = applicationPoolServer->connect();
0
- applicationPoolServer->detach();
0
+ //applicationPool = applicationPoolServer->connect();
0
+ //applicationPoolServer->detach();
0
+ applicationPool = ptr(new StandardApplicationPool(""));
0
   }
0
   
0
   int handleRequest(request_rec *r) {
0
@@ -271,12 +273,13 @@ public:
0
       apr_bucket *b;
0
       
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
+ pair<ApplicationPtr, Application::LockPtr> p(applicationPool->get(string(railsDir) + "/.."));
0
+ Application &app(*p.first);
0
+ P_TRACE("Connected to application: reader FD = " << app.getReader() << ", writer FD = " << app.getWriter());
0
+ sendHeaders(r, app.getWriter());
0
 
0
       bb = apr_brigade_create(r->connection->pool, r->connection->bucket_alloc);
0
- b = dispatcher_bucket_create(r->pool, app,
0
+ b = dispatcher_bucket_create(r->pool, p.first, p.second,
0
         r->server->timeout, r->connection->bucket_alloc);
0
       APR_BRIGADE_INSERT_TAIL(bb, b);
0
 

Comments

    No one has commented yet.