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
web site and benchmark fixes
Ryan Dahl (author)
2 months ago
commit  0e2dc886e26a1afc11882f3f6e999943d7af2478
tree    16962c1b0285b95935377ff46e3c15d9df38f2ff
parent  7897e7c5897e264fc0f80ee423ed393e606180cb
...
1
 
2
3
 
4
5
6
7
 
 
8
9
10
...
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
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
 
1
2
 
3
4
 
 
 
5
6
7
8
9
...
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
0
@@ -1,10 +1,9 @@
0
-Ebb Web Server
0
+# A Web Server Called *Ebb*
0
 
0
-= Design
0
+## Design
0
 
0
-The design is similar to the Evented Mongrel web server; except instead of
0
-using EventMachine (a ruby binding to libevent), the Ebb web server is written
0
-in C and uses the libev event loop library (http://software.schmorp.de/pkg/libev.html).
0
+The design is similar to the [Evented Mongrel][1] web server; except instead
0
+of using EventMachine (a ruby binding to libevent), the Ebb web server is written in C and uses the [libev][2] event loop library.
0
 
0
 Connections are processed as follows:
0
 
0
@@ -27,31 +26,47 @@ make it useful to Non-Ruby frameworks. For example, a Python WSGI interface is
0
 forthcoming.
0
 
0
 Ebb aims to be the smallest and fastest web server possible specifically for
0
-doing the processing for web frameworks like Rails.
0
+doing the processing for web frameworks like Rails, Merb, and Django.
0
 
0
-= TODO
0
-* Option to listen on unix sockets instead of tcp
0
+## Why?
0
+
0
+Why? Because by building the server in C one is able to side-step the limitations on speed of many scripting languages. Inefficiencies are okay for quick and beautiful code, but for production web servers that might handle thousands of requests a second, an attempt should be made to be as efficient as possible.
0
+
0
+![Response Size](http://s3.amazonaws.com/four.livejournal/20080227/response_size.png)
0
+
0
+![Concurrency](http://s3.amazonaws.com/four.livejournal/20080227/concurrency.png)
0
+
0
+![Uploads](http://s3.amazonaws.com/four.livejournal/20080227/post_size.png)
0
+
0
+## Download
0
+
0
+
0
+## TODO
0
+* Option to listen on unix sockets instead of TCP
0
 * Python binding
0
 
0
-= License
0
+## License
0
 
0
 Copyright (c) 2007 Ryan Dahl
0
 
0
-Permission is hereby granted, free of charge, to any person obtaining
0
-a copy of this software and associated documentation files (the
0
-"Software"), to deal in the Software without restriction, including
0
-without limitation the rights to use, copy, modify, merge, publish,
0
-distribute, sublicense, and/or sell copies of the Software, and to
0
-permit persons to whom the Software is furnished to do so, subject to
0
-the following conditions:
0
-
0
-The above copyright notice and this permission notice shall be
0
-included in all copies or substantial portions of the Software.
0
-
0
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
0
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
0
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
0
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0
+> Permission is hereby granted, free of charge, to any person obtaining
0
+> a copy of this software and associated documentation files (the
0
+> "Software"), to deal in the Software without restriction, including
0
+> without limitation the rights to use, copy, modify, merge, publish,
0
+> distribute, sublicense, and/or sell copies of the Software, and to
0
+> permit persons to whom the Software is furnished to do so, subject to
0
+> the following conditions:
0
+>
0
+> The above copyright notice and this permission notice shall be
0
+> included in all copies or substantial portions of the Software.
0
+>
0
+> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0
+> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0
+> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0
+> NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
0
+> LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
0
+> OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
0
+> WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0
+
0
+ [1]: http://swiftiply.swiftcore.org/mongrel.html
0
+ [2]: http://software.schmorp.de/pkg/libev.html
...
24
25
26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
28
29
...
55
56
57
58
 
59
...
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
...
78
79
80
 
81
82
0
@@ -24,6 +24,29 @@ task(:test => :compile) do
0
   sh "ruby #{dir("benchmark/test.rb")}"
0
 end
0
 
0
+
0
+task(:generate_site => 'site/index.html')
0
+file('site/index.html' => %w{README site/style.css}) do
0
+ require 'BlueCloth'
0
+
0
+ doc = BlueCloth.new(File.read(dir('README')))
0
+ template = <<-HEREDOC
0
+ <html>
0
+ <head>
0
+ <title>Ebb</title>
0
+ <link type="text/css" rel="stylesheet" href="style.css" media="screen"/>
0
+ </head>
0
+ <body>
0
+ <div id="content">CONTENT</div>
0
+ </body>
0
+ </html>
0
+HEREDOC
0
+
0
+ File.open(dir('site/index.html'), "w+") do |f|
0
+ f.write template.sub('CONTENT', doc.to_html)
0
+ end
0
+end
0
+
0
 spec = Gem::Specification.new do |s|
0
   s.platform = Gem::Platform::RUBY
0
   s.summary = "A Web Server"
0
@@ -55,5 +78,5 @@ Rake::GemPackageTask.new(spec) do |pkg|
0
   pkg.need_zip = true
0
 end
0
 
0
-CLEAN.add ["**/*.{o,bundle,so,obj,pdb,lib,def,exp}", "benchmark/*.dump"]
0
+CLEAN.add ["**/*.{o,bundle,so,obj,pdb,lib,def,exp}", "benchmark/*.dump", 'site/index.html']
0
 CLOBBER.add ['src/Makefile', 'src/parser.c', 'src/mkmf.log','doc', 'coverage']
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
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
0
@@ -0,0 +1,45 @@
0
+# supply the benchmark dump file as an argumetn to this program
0
+require 'rubygems'
0
+require 'google_chart'
0
+require 'server_test'
0
+
0
+class Array
0
+ def avg
0
+ sum.to_f / length
0
+ end
0
+ def sum
0
+ inject(0) { |i, s| s += i }
0
+ end
0
+end
0
+
0
+
0
+
0
+colors = %w{F74343 444130 7DA478 E4AC3D}
0
+max_x = 0
0
+max_y = 0
0
+results = ServerTestResults.open(ARGV[0])
0
+all_m = []
0
+response_chart = GoogleChart::LineChart.new('400x300', Time.now.strftime('%Y.%m.%d'), true)
0
+results.servers.each do |server|
0
+ data = results.data(server).sort
0
+ response_chart.data(server, data, colors.shift)
0
+ x = data.map { |d| d[0] }.max
0
+ y = data.map { |d| d[1] }.max
0
+ max_x = x if x > max_x
0
+ max_y = y if y > max_y
0
+end
0
+
0
+label = case results.benchmark
0
+when "response_size"
0
+ "kilobytes served"
0
+when "wait_fib", "concurrency"
0
+ "concurrency"
0
+when "post_size"
0
+ "kilobytes uploaded"
0
+end
0
+
0
+response_chart.axis(:y, :range => [0,max_y])
0
+response_chart.axis(:y, :labels => ['req/s'], :positions => [50])
0
+response_chart.axis(:x, :range => [0,max_x])
0
+response_chart.axis(:x, :labels => [label], :positions => [50])
0
+puts response_chart.to_url
...
1
2
3
4
5
6
7
8
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
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0
@@ -1,34 +0,0 @@
0
-# supply the benchmark dump file as an argumetn to this program
0
-require 'rubygems'
0
-require 'google_response_chart'
0
-require 'server_test'
0
-
0
-class Array
0
- def avg
0
- sum.to_f / length
0
- end
0
- def sum
0
- inject(0) { |i, s| s += i }
0
- end
0
-end
0
-
0
-colors = %w{F74343 444130 7DA478 E4AC3D}
0
-max_x = 0
0
-max_y = 0
0
-results = ServerTestResults.open(ARGV[0])
0
-all_m = []
0
-response_chart = GoogleChart::LineChart.new('400x300', Time.now.strftime('%Y.%m.%d'), true)
0
-results.servers.each do |server|
0
- data = results.data(server, :size).sort
0
- response_chart.data(server, data, colors.shift)
0
- # data.delete_if { |d| d[0] > 100.kilobytes }
0
- x = data.map { |d| d[0] }.max
0
- y = data.map { |d| d[1] }.max
0
- max_x = x if x > max_x
0
- max_y = y if y > max_y
0
-end
0
-response_chart.axis(:y, :range => [0,max_y])
0
-response_chart.axis(:y, :labels => ['req/s'], :positions => [50])
0
-response_chart.axis(:x, :range => [0,max_x])
0
-response_chart.axis(:x, :labels => ['bytes served'], :positions => [50])
0
-puts response_chart.to_url
...
21
22
23
24
 
25
26
27
...
63
64
65
66
67
 
...
21
22
23
 
24
25
26
27
...
63
64
65
 
66
67
0
@@ -21,7 +21,7 @@ trials = {
0
   'wait_fib' => [1,20,40,60,80,100].map { |c|
0
     [c, "ab -t 3 -q -c #{c} http://0.0.0.0:PORT/periodical_activity/fibonacci/20}"]
0
   },
0
- 'post_size' => [0.1,1,5,7,10,15,18,20,23,25,30,40,45,50].map { |l|
0
+ 'post_size' => [0.1,1,5,7,10,15,18,20,23,25,30,35,37,40,45,50].map { |l|
0
     size = (l * 1024).to_i
0
     fn = "/tmp/ebb_post_trial_#{size}"
0
     File.open(fn, 'w+') { |f| f.write("C"*size) } unless FileTest.exists?(fn)
0
@@ -63,4 +63,4 @@ ensure
0
   puts "\n\nkilling servers"
0
   servers.each { |server| server.kill }
0
   results.write(dumpfile)
0
-end
0
\ No newline at end of file
0
+end
...
73
74
75
76
77
78
79
...
99
100
101
102
103
104
105
106
...
112
113
114
115
 
116
117
 
118
119
120
121
 
122
123
124
...
73
74
75
 
76
77
78
...
98
99
100
 
 
101
102
103
...
109
110
111
 
112
113
 
114
115
116
 
 
117
118
119
120
0
@@ -73,7 +73,6 @@ class ServerTest
0
   def initialize(name, port, &start_block)
0
     @name = name
0
     @port = port
0
- @start_block = start_block
0
   end
0
   
0
   def <=>(a)
0
@@ -99,8 +98,6 @@ class ServerTest
0
       @pid = fork { start_mongrel }
0
     when 'thin'
0
       @pid = fork { start_thin }
0
- else
0
- @pid = fork { @start_block.call }
0
     end
0
   end
0
   
0
@@ -112,13 +109,12 @@ class ServerTest
0
     require 'mongrel'
0
     require 'swiftcore/evented_mongrel'
0
     ENV['EVENT'] = "1"
0
- Rack::Handler::Mongrel.run(app, :Port => @port)
0
+ Rack::Handler::Mongrel.run(app, :Host => '0.0.0.0', :Port => @port)
0
   end
0
-
0
+
0
   def start_ebb
0
     require File.dirname(__FILE__) + '/../ruby_lib/ebb'
0
- server = Ebb::Server.new(app, :port => @port)
0
- server.start
0
+ server = Ebb::Server.run(app, :port => @port)
0
   end
0
   
0
   def start_mongrel
...
95
96
97
98
 
99
100
101
...
136
137
138
139
140
 
...
95
96
97
 
98
99
100
101
...
136
137
138
 
139
140
0
@@ -95,7 +95,7 @@ class EbbTest < Test::Unit::TestCase
0
   end
0
   
0
   def test_large_post
0
- response = post("/test_post_length", 'C'*1024*15)
0
+ response = post("/test_post_length", 'C'*1024*50)
0
     assert_equal 200, response.code.to_i, response.body
0
   end
0
   
0
@@ -136,4 +136,4 @@ end
0
 #
0
 # assert !File.exists?(filename)
0
 # end
0
-# end
0
\ No newline at end of file
0
+# end
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
0
@@ -0,0 +1,30 @@
0
+/* #E4AC3D pride of the leo (orange)
0
+ * #CBCFB6 sandy field (light gray)
0
+ * #7DA478 neverending garden (green)
0
+ * #444130 lost independance (brown)
0
+ * #F74343 Groovy Baby (red)
0
+ */
0
+body {
0
+ background: #FFF;
0
+ color: #444130;
0
+ font-family: Arial;
0
+ line-height: 15pt;
0
+ font-size: 11pt;
0
+ margin: 0;
0
+}
0
+
0
+h1, h2, h3, h4 { color: #CBCFB6; }
0
+
0
+a { color: #E4AC3D; }
0
+blockquote { font-size: 80%; }
0
+
0
+#content {
0
+ margin: 1em auto ;
0
+ max-width: 30em;
0
+}
0
+
0
+#content p {
0
+}
0
+#about {
0
+ list-style:none;
0
+}

Comments

    No one has commented yet.