ry / ebb fork watch download tarball
public this repo is viewable by everyone
Description: web server
Homepage: http://ebb.rubyforge.org
Clone URL: git://github.com/ry/ebb.git
Experiemental threaded processing branch

Handles the 'wait' benchmark very well but slower with throughput.
Ryan Dahl (author)
2 months ago
commit  4780e2c81b44bf1b4f96f2ce064e6416024888cc
tree    330a130d337cb909c5b01855e20b8d0a76066202
parent  b88daa796c6eade49e1b15d38ca97aae66d76e8d
...
148
149
150
151
 
 
 
 
 
 
152
153
154
...
148
149
150
 
151
152
153
154
155
156
157
158
159
0
@@ -148,7 +148,12 @@ class ServerTest
0
     if r =~ /Complete requests:\s*(\d+)/
0
       requests_completed = $1.to_i
0
     end
0
- puts " #{rps} req/sec (#{requests_completed} completed)"
0
+ if r =~ /Failed requests:\s*(\d+)/
0
+ failed_requests = $1.to_i
0
+ else
0
+ raise "didn't get how many failed requests from ab"
0
+ end
0
+ puts " #{rps} req/sec (#{requests_completed} completed, #{failed_requests} failed)"
0
     
0
     {
0
       :server => @name,
...
9
10
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
...
9
10
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
0
@@ -9,105 +9,84 @@ module Ebb
0
   
0
   def self.start_server(app, options={})
0
     port = (options[:port] || 4001).to_i
0
-
0
- nworkers = options[:workers] || 1
0
- Client::BASE_ENV['rack.multithread'] = true if nworkers > 1
0
-
0
- # socket = options[:socket]
0
- # timeout = options[:timeout]
0
-
0
-
0
     FFI::server_listen_on_port(port)
0
     
0
- puts "Ebb listening at http://0.0.0.0:#{port}/ (#{nworkers} worker#{'s' if nworkers > 1})"
0
+ puts "Ebb listening at http://0.0.0.0:#{port}/"
0
     
0
     trap('INT') { @running = false }
0
     @running = true
0
     
0
- workers = ThreadGroup.new
0
- nworkers.times do
0
- thread = Thread.new do
0
- while @running
0
- FFI::server_process_connections()
0
- if client = FFI::waiting_clients.shift
0
- process_client(app, client)
0
- end
0
- end
0
+ while @running
0
+ FFI::server_process_connections()
0
+ while client = FFI::waiting_clients.shift
0
+ #process_client(app, client)
0
+ Thread.new(client) { |c| c.process(app) }
0
       end
0
- workers.add(thread)
0
     end
0
- workers.list.each { |thread| thread.join }
0
     
0
     puts "Ebb unlistening"
0
     FFI::server_unlisten()
0
   end
0
   
0
- def self.process_client(app, client)
0
- #puts "Request: #{client.env.inspect}\n"
0
- begin
0
- status, headers, body = app.call(client.env)
0
- rescue
0
- raise if $DEBUG
0
- status = 500
0
- headers = {'Content-Type' => 'text/plain'}
0
- body = "Internal Server Error\n"
0
- end
0
-
0
- client.write_status(status)
0
-
0
- if body.respond_to? :length and status != 304
0
- headers['Connection'] = 'close'
0
- headers['Content-Length'] = body.length
0
- end
0
-
0
- headers.each { |k, v| client.write_header(k,v) }
0
-
0
- client.write "\r\n"
0
-
0
- # Not many apps use streaming yet so i'll hold off on that feature
0
- # until the rest of ebb is more developed.
0
- if body.kind_of?(String)
0
- client.write body
0
- client.body_written = true
0
- client.begin_transmission
0
- else
0
- client.begin_transmission
0
- body.each { |p| client.write(p) }
0
- client.body_written = true
0
- end
0
- end
0
-
0
   def FFI.waiting_clients
0
     @waiting_clients
0
   end
0
   
0
   class Client
0
     BASE_ENV = {
0
+ 'SERVER_NAME' => '0.0.0.0',
0
       'SCRIPT_NAME' => '',
0
       'SERVER_SOFTWARE' => "Ebb #{Ebb::VERSION}",
0
       'SERVER_PROTOCOL' => 'HTTP/1.1',
0
       'rack.version' => [0, 1],
0
       'rack.errors' => STDERR,
0
       'rack.url_scheme' => 'http',
0
- 'rack.multithread' => false,
0
+ 'rack.multithread' => true,
0
       'rack.multiprocess' => false,
0
       'rack.run_once' => false
0
     }
0
     
0
- def env
0
- @env ||= begin
0
- env = FFI::client_env(self).update(BASE_ENV)
0
- env['rack.input'] = RequestBody.new(self)
0
- env
0
+ def process(app)
0
+ #puts "Request: #{client.inspect}\n"
0
+ begin
0
+ status, headers, body = app.call(env)
0
+ rescue
0
+ raise if $DEBUG
0
+ status = 500
0
+ headers = {'Content-Type' => 'text/plain'}
0
+ body = "Internal Server Error\n"
0
+ end
0
+
0
+ write_status(status)
0
+
0
+ if body.respond_to? :length and status != 304
0
+ headers['Connection'] = 'close'
0
+ headers['Content-Length'] = body.length
0
+ end
0
+
0
+ headers.each { |k, v| write_header(k,v) }
0
+
0
+ write("\r\n")
0
+
0
+ # Not many apps use streaming yet so i'll hold off on that feature
0
+ # until the rest of ebb is more developed.
0
+ if body.kind_of?(String)
0
+ write(body)
0
+ FFI::client_set_body_written(self, true)
0
+ FFI::client_begin_transmission(self)
0
+ else
0
+ FFI::client_begin_transmission(self)
0
+ body.each { |p| write(p) }
0
+ FFI::client_set_body_written(self, true)
0
       end
0
     end
0
     
0
- def begin_transmission
0
- FFI::client_begin_transmission(self)
0
- end
0
+ private
0
     
0
- def body_written=(v)
0
- FFI::client_set_body_written(self, v)
0
+ def env
0
+ env = FFI::client_env(self).update(BASE_ENV)
0
+ env['rack.input'] = RequestBody.new(self)
0
+ env
0
     end
0
     
0
     def write(data)
...
118
119
120
121
 
122
123
124
...
118
119
120
 
121
122
123
124
0
@@ -118,7 +118,7 @@ module Ebb
0
         parser.on("-l", "--log-file FILE", "File to redirect output") { |f| options[:log_file]=f }
0
         parser.on("-P", "--pid-file FILE", "File to store PID") { |f| options[:pid_file]=f }
0
         parser.on("-t", "--timeout SECONDS", "(default: #{options[:timeout]})") { |s| options[:timeout]=s }
0
- parser.on("-w", "--workers WORKERS", "Number of worker threads (default: #{options[:workers]})") { |w| options[:workers]=w }
0
+ #parser.on("-w", "--workers WORKERS", "Number of worker threads (default: #{options[:workers]})") { |w| options[:workers]=w }
0
         parser.separator ""
0
         parser.on_tail("-h", "--help", "Show this message") do
0
           puts parser
...
31
32
33
34
 
35
36
37
...
46
47
48
49
 
50
51
52
...
61
62
63
64
 
65
66
67
...
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
124
125
126
127
128
129
...
133
134
135
136
137
138
139
140
141
142
...
291
292
293
294
 
295
296
297
 
298
299
300
301
302
303
304
 
305
306
307
...
313
314
315
316
 
317
318
319
320
321
322
323
 
324
325
326
327
328
 
329
330
331
332
333
334
 
335
336
337
...
31
32
33
 
34
35
36
37
...
46
47
48
 
49
50
51
52
...
61
62
63
 
64
65
66
67
...
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
124
125
126
 
127
128
129
...
133
134
135
 
 
 
 
136
137
138
...
287
288
289
 
290
291
292
 
293
294
295
296
297
298
299
 
300
301
302
303
...
309
310
311
 
312
313
 
314
315
316
317
 
318
319
320
321
322
 
323
324
325
326
327
328
 
329
330
331
332
0
@@ -31,7 +31,7 @@
0
 
0
 static int server_socket_unix(const char *path, int access_mask);
0
 
0
-static void env_add(ebb_client *client, const char *field, int flen, const char *value, int vlen)
0
+void env_add(ebb_client *client, const char *field, int flen, const char *value, int vlen)
0
 {
0
   if(client->env_size >= EBB_MAX_ENV) {
0
     client->parser.overflow_error = TRUE;
0
@@ -46,7 +46,7 @@ static void env_add(ebb_client *client, const char *field, int flen, const char
0
 }
0
 
0
 
0
-static void env_add_const(ebb_client *client, int type, const char *value, int vlen)
0
+void env_add_const(ebb_client *client, int type, const char *value, int vlen)
0
 {
0
   if(client->env_size >= EBB_MAX_ENV) {
0
     client->parser.overflow_error = TRUE;
0
@@ -61,7 +61,7 @@ static void env_add_const(ebb_client *client, int type, const char *value, int v
0
 }
0
 
0
 
0
-static void http_field_cb(void *data, const char *field, size_t flen, const char *value, size_t vlen)
0
+void http_field_cb(void *data, const char *field, size_t flen, const char *value, size_t vlen)
0
 {
0
   ebb_client *client = (ebb_client*)(data);
0
   assert(field != NULL);
0
@@ -70,60 +70,60 @@ static void http_field_cb(void *data, const char *field, size_t flen, const char
0
 }
0
 
0
 
0
-static void request_method_cb(void *data, const char *at, size_t length)
0
+void request_method_cb(void *data, const char *at, size_t length)
0
 {
0
   ebb_client *client = (ebb_client*)(data);
0
   env_add_const(client, EBB_REQUEST_METHOD, at, length);
0
 }
0
 
0
 
0
-static void request_uri_cb(void *data, const char *at, size_t length)
0
+void request_uri_cb(void *data, const char *at, size_t length)
0
 {
0
   ebb_client *client = (ebb_client*)(data);
0
   env_add_const(client, EBB_REQUEST_URI, at, length);
0
 }
0
 
0
 
0
-static void fragment_cb(void *data, const char *at, size_t length)
0
+void fragment_cb(void *data, const char *at, size_t length)
0
 {
0
   ebb_client *client = (ebb_client*)(data);
0
   env_add_const(client, EBB_FRAGMENT, at, length);
0
 }
0
 
0
 
0
-static void request_path_cb(void *data, const char *at, size_t length)
0
+void request_path_cb(void *data, const char *at, size_t length)
0
 {
0
   ebb_client *client = (ebb_client*)(data);
0
   env_add_const(client, EBB_REQUEST_PATH, at, length);
0
 }
0
 
0
 
0
-static void query_string_cb(void *data, const char *at, size_t length)
0
+void query_string_cb(void *data, const char *at, size_t length)
0
 {
0
   ebb_client *client = (ebb_client*)(data);
0
   env_add_const(client, EBB_QUERY_STRING, at, length);
0
 }
0
 
0
 
0
-static void http_version_cb(void *data, const char *at, size_t length)
0
+void http_version_cb(void *data, const char *at, size_t length)
0
 {
0
   ebb_client *client = (ebb_client*)(data);
0
   env_add_const(client, EBB_HTTP_VERSION, at, length);
0
 }
0
 
0
 
0
-static void content_length_cb(void *data, const char *at, size_t length)
0
+void content_length_cb(void *data, const char *at, size_t length)
0
 {
0
   ebb_client *client = (ebb_client*)(data);
0
   env_add_const(client, EBB_CONTENT_LENGTH, at, length);
0
   /* atoi_length - why isn't this in the statndard library? i hate c */
0
+ assert(client->content_length == 0);
0
   int i, mult;
0
   for(mult=1, i=length-1; i>=0; i--, mult*=10)
0
     client->content_length += (at[i] - '0') * mult;
0
 }
0
 
0
 
0
-const char* localhost_str = "0.0.0.0";
0
 static void dispatch(ebb_client *client)
0
 {
0
   ebb_server *server = client->server;
0
@@ -133,10 +133,6 @@ static void dispatch(ebb_client *client)
0
   
0
   /* Set the env variables */
0
   if(server->port) {
0
- env_add_const(client, EBB_SERVER_NAME
0
- , localhost_str
0
- , 7
0
- );
0
     env_add_const(client, EBB_SERVER_PORT
0
                         , server->port
0
                         , strlen(server->port)
0
@@ -291,17 +287,17 @@ static client_init(ebb_server *server, ebb_client *client)
0
   for(i=0; i< EBB_BUFFERSIZE; i++)
0
     client->request_buffer[i] = 'A';
0
 #endif
0
-
0
+
0
   client->open = TRUE;
0
   client->server = server;
0
-
0
+
0
   /* DO SOCKET STUFF */
0
   socklen_t len;
0
   client->fd = accept(server->fd, (struct sockaddr*)&(server->sockaddr), &len);
0
   assert(client->fd >= 0);
0
   int flags = fcntl(client->fd, F_GETFL, 0);
0
   assert(0 <= fcntl(client->fd, F_SETFL, flags | O_NONBLOCK));
0
-
0
+
0
   /* INITIALIZE http_parser */
0
   http_parser_init(&(client->parser));
0
   client->parser.data = client;
0
@@ -313,25 +309,24 @@ static client_init(ebb_server *server, ebb_client *client)
0
   client->parser.query_string = query_string_cb;
0
   client->parser.http_version = http_version_cb;
0
   client->parser.content_length = content_length_cb;
0
-
0
+
0
   /* OTHER */
0
-
0
   client->env_size = 0;
0
   client->read = client->nread_from_body = 0;
0
   client->response_buffer->len = 0; /* see note in ebb_client_close */
0
   client->content_length = 0;
0
-
0
+
0
   client->status_written = FALSE;
0
   client->headers_written = FALSE;
0
   client->body_written = FALSE;
0
   client->began_transmission = FALSE;
0
-
0
+
0
   /* SETUP READ AND TIMEOUT WATCHERS */
0
   client->read_watcher.data = client;
0
   ev_init(&client->read_watcher, on_readable);
0
   ev_io_set(&client->read_watcher, client->fd, EV_READ | EV_ERROR);
0
   ev_io_start(server->loop, &client->read_watcher);
0
-
0
+
0
   client->timeout_watcher.data = client;
0
   ev_timer_init(&client->timeout_watcher, on_timeout, EBB_TIMEOUT, EBB_TIMEOUT);
0
   ev_timer_start(server->loop, &client->timeout_watcher);
...
4
5
6
7
 
 
8
9
10
11
12
13
14
15
16
17
18
19
20
...
43
44
45
46
47
48
49
...
4
5
6
 
7
8
9
10
11
 
 
 
 
12
13
 
14
15
16
...
39
40
41
 
42
43
44
0
@@ -4,17 +4,13 @@
0
  */
0
 #ifndef ebb_h
0
 #define ebb_h
0
-
0
+#define EV_STANDALONE 1
0
+#include <ev.h>
0
 #include <sys/socket.h>
0
 #include <netinet/in.h>
0
 #include <glib.h>
0
-
0
-#define EV_STANDALONE 1
0
-#include <ev.h>
0
-
0
 #include "parser.h"
0
 
0
-
0
 typedef struct ebb_server ebb_server;
0
 typedef struct ebb_client ebb_client;
0
 
0
@@ -43,7 +39,6 @@ struct ebb_env_item {
0
        , EBB_REQUEST_PATH
0
        , EBB_QUERY_STRING
0
        , EBB_HTTP_VERSION
0
- , EBB_SERVER_NAME
0
        , EBB_SERVER_PORT
0
        , EBB_CONTENT_LENGTH
0
        } type;
...
17
18
19
20
21
22
23
...
103
104
105
106
107
108
109
...
219
220
221
222
223
224
225
...
17
18
19
 
20
21
22
...
102
103
104
 
105
106
107
...
217
218
219
 
220
221
222
0
@@ -17,7 +17,6 @@ static VALUE global_request_path;
0
 static VALUE global_query_string;
0
 static VALUE global_http_version;
0
 static VALUE global_request_body;
0
-static VALUE global_server_name;
0
 static VALUE global_server_port;
0
 static VALUE global_path_info;
0
 static VALUE global_content_length;
0
@@ -103,7 +102,6 @@ VALUE env_field(struct ebb_env_item *item)
0
     case EBB_REQUEST_PATH: return global_request_path;
0
     case EBB_QUERY_STRING: return global_query_string;
0
     case EBB_HTTP_VERSION: return global_http_version;
0
- case EBB_SERVER_NAME: return global_server_name;
0
     case EBB_SERVER_PORT: return global_server_port;
0
     case EBB_CONTENT_LENGTH: return global_content_length;
0
   }
0
@@ -219,7 +217,6 @@ void Init_ebb_ext()
0
   DEF_GLOBAL(query_string, "QUERY_STRING");
0
   DEF_GLOBAL(http_version, "HTTP_VERSION");
0
   DEF_GLOBAL(request_body, "REQUEST_BODY");
0
- DEF_GLOBAL(server_name, "SERVER_NAME");
0
   DEF_GLOBAL(server_port, "SERVER_PORT");
0
   DEF_GLOBAL(path_info, "PATH_INFO");
0
   DEF_GLOBAL(content_length, "CONTENT_LENGTH");

Comments

    No one has commented yet.