rainbows 0.9.0 → 0.90.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Documentation/comparison.haml +21 -2
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +2 -2
- data/README +2 -1
- data/Rakefile +2 -2
- data/TODO +5 -1
- data/bin/rainbows +1 -1
- data/lib/rainbows.rb +34 -15
- data/lib/rainbows/app_pool.rb +1 -1
- data/lib/rainbows/base.rb +8 -15
- data/lib/rainbows/const.rb +5 -5
- data/lib/rainbows/dev_fd_response.rb +1 -1
- data/lib/rainbows/error.rb +10 -1
- data/lib/rainbows/ev_core.rb +0 -4
- data/lib/rainbows/event_machine.rb +1 -1
- data/lib/rainbows/fiber/base.rb +3 -2
- data/lib/rainbows/fiber/io.rb +15 -9
- data/lib/rainbows/fiber/rev.rb +160 -0
- data/lib/rainbows/rev/core.rb +1 -1
- data/lib/rainbows/rev_fiber_spawn.rb +29 -0
- data/lib/rainbows/revactor.rb +1 -12
- data/lib/rainbows/thread_pool.rb +8 -0
- data/t/GNUmakefile +1 -0
- data/t/simple-http_RevFiberSpawn.ru +10 -0
- data/t/simple-http_Revactor.ru +0 -1
- data/t/simple-http_ThreadPool.ru +0 -1
- data/t/simple-http_ThreadSpawn.ru +0 -1
- data/t/sleep.ru +1 -8
- data/t/t9000.ru +1 -8
- data/t/worker-follows-master-to-death.ru +1 -6
- metadata +7 -2
@@ -92,6 +92,13 @@
|
|
92
92
|
%td.r19 Yes
|
93
93
|
%td.rbx No
|
94
94
|
%td.slow Yes
|
95
|
+
%tr.comp_row
|
96
|
+
%td.mod RevFiberSpawn
|
97
|
+
%td.tee Yes
|
98
|
+
%td.r18 No
|
99
|
+
%td.r19 Yes
|
100
|
+
%td.rbx No
|
101
|
+
%td.slow Yes
|
95
102
|
%ul
|
96
103
|
%li
|
97
104
|
RevThread* + 1.8 performance is bad with Rev <= 0.3.1.
|
@@ -191,6 +198,12 @@
|
|
191
198
|
%a(href="http://rev.rubyforge.org/") Rev
|
192
199
|
%td.thr Yes
|
193
200
|
%td.reent No
|
201
|
+
%tr.comp_row
|
202
|
+
%td.mod RevFiberSpawn
|
203
|
+
%td.slowio
|
204
|
+
%a(href="Rainbows/Fiber/IO.html") Rainbows::Fiber::IO
|
205
|
+
%td.thr No
|
206
|
+
%td.reent Yes
|
194
207
|
|
195
208
|
%ul
|
196
209
|
%li
|
@@ -276,14 +289,14 @@
|
|
276
289
|
%td.devfd Yes
|
277
290
|
%td.app_pool Yes
|
278
291
|
%td.lock No!
|
279
|
-
%td.async Rainbows::Fiber
|
292
|
+
%td.async Rainbows::Fiber::IO, Rainbows.sleep
|
280
293
|
%td.ws Sunshowers
|
281
294
|
%tr.comp_row
|
282
295
|
%td.mod FiberPool
|
283
296
|
%td.devfd Yes
|
284
297
|
%td.app_pool Yes
|
285
298
|
%td.lock No!
|
286
|
-
%td.async Rainbows::Fiber
|
299
|
+
%td.async Rainbows::Fiber::IO, Rainbows.sleep
|
287
300
|
%td.ws Sunshowers
|
288
301
|
%tr.comp_row
|
289
302
|
%td.mod ActorSpawn
|
@@ -306,6 +319,12 @@
|
|
306
319
|
%td.lock Dumb
|
307
320
|
%td.async standard Ruby
|
308
321
|
%td.ws no
|
322
|
+
%tr.comp_row
|
323
|
+
%td.mod RevFiberSpawn
|
324
|
+
%td.devfd Yes
|
325
|
+
%td.app_pool Yes
|
326
|
+
%td.lock No!
|
327
|
+
%td.async Rainbows::Fiber::IO, Rainbows.sleep
|
309
328
|
|
310
329
|
%ul
|
311
330
|
%li
|
data/GIT-VERSION-GEN
CHANGED
data/GNUmakefile
CHANGED
@@ -58,7 +58,7 @@ NEWS: GIT-VERSION-FILE
|
|
58
58
|
$(RAKE) -s news_rdoc > $@+
|
59
59
|
mv $@+ $@
|
60
60
|
|
61
|
-
SINCE = 0.
|
61
|
+
SINCE = 0.9.0
|
62
62
|
ChangeLog: LOG_VERSION = \
|
63
63
|
$(shell git rev-parse -q "$(GIT_VERSION)" >/dev/null 2>&1 && \
|
64
64
|
echo $(GIT_VERSION) || git describe)
|
@@ -155,7 +155,7 @@ package: $(pkgtgz) $(pkggem)
|
|
155
155
|
release: verify package $(release_notes) $(release_changes)
|
156
156
|
# make tgz release on RubyForge
|
157
157
|
rubyforge add_release -f -n $(release_notes) -a $(release_changes) \
|
158
|
-
$(rfproject) $(rfpackage) $(VERSION) $(
|
158
|
+
$(rfproject) $(rfpackage) $(VERSION) $(pkgtgz)
|
159
159
|
# push gem to Gemcutter
|
160
160
|
gem push $(pkggem)
|
161
161
|
# in case of gem downloads from RubyForge releases page
|
data/README
CHANGED
@@ -13,6 +13,7 @@ suck; differently.
|
|
13
13
|
|
14
14
|
For network concurrency, models we currently support are:
|
15
15
|
|
16
|
+
* {RevFiberSpawn}[link:Rainbows/RevFiberSpawn.html]
|
16
17
|
* {Revactor}[link:Rainbows/Revactor.html]
|
17
18
|
* {ThreadPool}[link:Rainbows/ThreadPool.html]
|
18
19
|
* {Rev}[link:Rainbows/Rev.html]
|
@@ -155,7 +156,7 @@ and we'll try our best to fix it.
|
|
155
156
|
|
156
157
|
== Contact
|
157
158
|
|
158
|
-
All feedback (bug reports, user/development
|
159
|
+
All feedback (bug reports, user/development discussion, patches, pull
|
159
160
|
requests) go to the mailing list/newsgroup. Patches must be sent inline
|
160
161
|
(git format-patch -M + git send-email). No subscription is necessary
|
161
162
|
to post on the mailing list. No top posting. Address replies +To:+
|
data/Rakefile
CHANGED
@@ -164,8 +164,8 @@ task :fm_update do
|
|
164
164
|
require 'net/netrc'
|
165
165
|
require 'json'
|
166
166
|
version = ENV['VERSION'] or abort "VERSION= needed"
|
167
|
-
uri = URI.parse('http://freshmeat.net/projects/
|
168
|
-
rc = Net::Netrc.locate('
|
167
|
+
uri = URI.parse('http://freshmeat.net/projects/rainbows/releases.json')
|
168
|
+
rc = Net::Netrc.locate('rainbows-fm') or abort "~/.netrc not found"
|
169
169
|
api_token = rc.password
|
170
170
|
changelog = tags.find { |t| t[:tag] == "v#{version}" }[:body]
|
171
171
|
tmp = Tempfile.new('fm-changelog')
|
data/TODO
CHANGED
@@ -14,7 +14,11 @@ care about.
|
|
14
14
|
* conditional app.deferred?(env) support
|
15
15
|
Merb uses it, some other servers support it
|
16
16
|
|
17
|
-
*
|
17
|
+
* EventMachine+Fibers+streaming input
|
18
|
+
|
19
|
+
* RevFiberPool
|
20
|
+
|
21
|
+
* ThreadPoolRevFiber{Spawn,Pool}: just because
|
18
22
|
|
19
23
|
* Rev + callcc - current Rev model with callcc (should work with MBARI)
|
20
24
|
|
data/bin/rainbows
CHANGED
data/lib/rainbows.rb
CHANGED
@@ -34,11 +34,44 @@ module Rainbows
|
|
34
34
|
|
35
35
|
class << self
|
36
36
|
|
37
|
+
# Sleeps the current application dispatch. This will pick the
|
38
|
+
# optimal method to sleep depending on the concurrency model chosen
|
39
|
+
# (which may still suck and block the entire process). Using this
|
40
|
+
# with the basic :Rev or :EventMachine models is not recommended.
|
41
|
+
# This should be used within your Rack application.
|
42
|
+
def sleep(nr)
|
43
|
+
case G.server.use
|
44
|
+
when :FiberPool, :FiberSpawn
|
45
|
+
Rainbows::Fiber.sleep(nr)
|
46
|
+
when :RevFiberSpawn
|
47
|
+
Rainbows::Fiber::Rev::Sleeper.new(nr)
|
48
|
+
when :Revactor
|
49
|
+
Actor.sleep(nr)
|
50
|
+
else
|
51
|
+
Kernel.sleep(nr)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
37
55
|
# runs the Rainbows! HttpServer with +app+ and +options+ and does
|
38
56
|
# not return until the server has exited.
|
39
57
|
def run(app, options = {})
|
40
58
|
HttpServer.new(app, options).start.join
|
41
59
|
end
|
60
|
+
|
61
|
+
# returns nil if accept fails
|
62
|
+
if defined?(Fcntl::FD_CLOEXEC)
|
63
|
+
def accept(sock)
|
64
|
+
rv = sock.accept_nonblock
|
65
|
+
rv.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
66
|
+
rv
|
67
|
+
rescue Errno::EAGAIN, Errno::ECONNABORTED
|
68
|
+
end
|
69
|
+
else
|
70
|
+
def accept(sock)
|
71
|
+
sock.accept_nonblock
|
72
|
+
rescue Errno::EAGAIN, Errno::ECONNABORTED
|
73
|
+
end
|
74
|
+
end
|
42
75
|
end
|
43
76
|
|
44
77
|
# configures \Rainbows! with a given concurrency model to +use+ and
|
@@ -87,27 +120,13 @@ module Rainbows
|
|
87
120
|
:FiberPool => 50,
|
88
121
|
:ActorSpawn => 50,
|
89
122
|
:NeverBlock => 50,
|
123
|
+
:RevFiberSpawn => 50,
|
90
124
|
}.each do |model, _|
|
91
125
|
u = model.to_s.gsub(/([a-z0-9])([A-Z0-9])/) { "#{$1}_#{$2.downcase!}" }
|
92
126
|
autoload model, "rainbows/#{u.downcase!}"
|
93
127
|
end
|
94
128
|
autoload :Fiber, 'rainbows/fiber' # core class
|
95
129
|
|
96
|
-
# returns nil if accept fails
|
97
|
-
if defined?(Fcntl::FD_CLOEXEC)
|
98
|
-
def self.accept(sock)
|
99
|
-
rv = sock.accept_nonblock
|
100
|
-
rv.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
101
|
-
rv
|
102
|
-
rescue Errno::EAGAIN, Errno::ECONNABORTED
|
103
|
-
end
|
104
|
-
else
|
105
|
-
def self.accept(sock)
|
106
|
-
sock.accept_nonblock
|
107
|
-
rescue Errno::EAGAIN, Errno::ECONNABORTED
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
130
|
end
|
112
131
|
|
113
132
|
# inject the Rainbows! method into Unicorn::Configurator
|
data/lib/rainbows/app_pool.rb
CHANGED
@@ -91,7 +91,7 @@ module Rainbows
|
|
91
91
|
# concurrency models
|
92
92
|
self.re ||= begin
|
93
93
|
case env["rainbows.model"]
|
94
|
-
when :FiberSpawn, :FiberPool, :Revactor, :NeverBlock
|
94
|
+
when :FiberSpawn, :FiberPool, :Revactor, :NeverBlock, :RevFiberSpawn
|
95
95
|
self.pool = Rainbows::Fiber::Queue.new(pool)
|
96
96
|
end
|
97
97
|
true
|
data/lib/rainbows/base.rb
CHANGED
@@ -10,15 +10,16 @@ module Rainbows
|
|
10
10
|
include Rainbows::Const
|
11
11
|
G = Rainbows::G
|
12
12
|
|
13
|
-
def handle_error(client, e)
|
14
|
-
msg = Error.response(e) and client.write_nonblock(msg)
|
15
|
-
rescue
|
16
|
-
end
|
17
|
-
|
18
13
|
def init_worker_process(worker)
|
19
14
|
super(worker)
|
20
15
|
G.tmp = worker.tmp
|
21
16
|
|
17
|
+
# avoid spurious wakeups and blocking-accept() with 1.8 green threads
|
18
|
+
if RUBY_VERSION.to_f < 1.9
|
19
|
+
require "io/nonblock"
|
20
|
+
HttpServer::LISTENERS.each { |l| l.nonblock = true }
|
21
|
+
end
|
22
|
+
|
22
23
|
# we're don't use the self-pipe mechanism in the Rainbows! worker
|
23
24
|
# since we don't defer reopening logs
|
24
25
|
HttpServer::SELF_PIPE.each { |x| x.close }.clear
|
@@ -65,17 +66,9 @@ module Rainbows
|
|
65
66
|
# if the socket is already closed or broken. We'll always ensure
|
66
67
|
# the socket is closed at the end of this function
|
67
68
|
rescue => e
|
68
|
-
|
69
|
+
Error.write(client, e)
|
69
70
|
ensure
|
70
|
-
client.close
|
71
|
-
end
|
72
|
-
|
73
|
-
def join_threads(threads)
|
74
|
-
G.quit!
|
75
|
-
threads.delete_if do |thr|
|
76
|
-
G.tick
|
77
|
-
thr.alive? ? thr.join(0.01) : true
|
78
|
-
end until threads.empty?
|
71
|
+
client.close unless client.closed?
|
79
72
|
end
|
80
73
|
|
81
74
|
def self.included(klass)
|
data/lib/rainbows/const.rb
CHANGED
@@ -3,21 +3,21 @@
|
|
3
3
|
module Rainbows
|
4
4
|
|
5
5
|
module Const
|
6
|
-
RAINBOWS_VERSION = '0.
|
6
|
+
RAINBOWS_VERSION = '0.90.0'
|
7
7
|
|
8
8
|
include Unicorn::Const
|
9
9
|
|
10
|
-
RACK_DEFAULTS =
|
10
|
+
RACK_DEFAULTS = Unicorn::HttpRequest::DEFAULTS.update({
|
11
11
|
"SERVER_SOFTWARE" => "Rainbows! #{RAINBOWS_VERSION}",
|
12
12
|
|
13
13
|
# using the Rev model, we'll automatically chunk pipe and socket objects
|
14
|
-
# if they're the response body
|
15
|
-
|
14
|
+
# if they're the response body. Unset by default.
|
15
|
+
# "rainbows.autochunk" => false,
|
16
16
|
})
|
17
17
|
|
18
18
|
CONN_CLOSE = "Connection: close\r\n"
|
19
19
|
CONN_ALIVE = "Connection: keep-alive\r\n"
|
20
|
-
LOCALHOST =
|
20
|
+
LOCALHOST = Unicorn::HttpRequest::LOCALHOST
|
21
21
|
|
22
22
|
# client IO object that supports reading and writing directly
|
23
23
|
# without filtering it through the HTTP chunk parser.
|
@@ -39,7 +39,7 @@ module Rainbows
|
|
39
39
|
|
40
40
|
# we need to make sure our pipe output is Fiber-compatible
|
41
41
|
case env["rainbows.model"]
|
42
|
-
when :FiberSpawn, :FiberPool
|
42
|
+
when :FiberSpawn, :FiberPool, :RevFiberSpawn
|
43
43
|
return [ status, headers.to_hash, Fiber::IO.new(io,::Fiber.current) ]
|
44
44
|
end
|
45
45
|
else # unlikely, char/block device file, directory, ...
|
data/lib/rainbows/error.rb
CHANGED
@@ -4,6 +4,15 @@ module Rainbows
|
|
4
4
|
class Error
|
5
5
|
class << self
|
6
6
|
|
7
|
+
# if we get any error, try to write something back to the client
|
8
|
+
# assuming we haven't closed the socket, but don't get hung up
|
9
|
+
# if the socket is already closed or broken. We'll always ensure
|
10
|
+
# the socket is closed at the end of this function
|
11
|
+
def write(io, e)
|
12
|
+
msg = Error.response(e) and io.write_nonblock(msg)
|
13
|
+
rescue
|
14
|
+
end
|
15
|
+
|
7
16
|
def app(e)
|
8
17
|
G.server.logger.error "app error: #{e.inspect}"
|
9
18
|
G.server.logger.error e.backtrace.join("\n")
|
@@ -19,7 +28,7 @@ module Rainbows
|
|
19
28
|
|
20
29
|
def response(e)
|
21
30
|
case e
|
22
|
-
when EOFError,
|
31
|
+
when EOFError,Errno::ECONNRESET,Errno::EPIPE,Errno::EINVAL,Errno::EBADF
|
23
32
|
# swallow error if client shuts down one end or disconnects
|
24
33
|
when Unicorn::HttpParserError
|
25
34
|
Const::ERROR_400_RESPONSE # try to tell the client they're bad
|
data/lib/rainbows/ev_core.rb
CHANGED
@@ -11,10 +11,6 @@ module Rainbows
|
|
11
11
|
# Apps may return this Rack response: AsyncResponse = [ -1, {}, [] ]
|
12
12
|
ASYNC_CALLBACK = "async.callback".freeze
|
13
13
|
|
14
|
-
def self.setup(klass)
|
15
|
-
klass.const_set(:APP, G.server.app)
|
16
|
-
end
|
17
|
-
|
18
14
|
def post_init
|
19
15
|
@remote_addr = ::TCPSocket === @_io ? @_io.peeraddr.last : LOCALHOST
|
20
16
|
@env = {}
|
@@ -190,7 +190,7 @@ module Rainbows
|
|
190
190
|
client_class = Rainbows.const_get(@use).const_get(:Client)
|
191
191
|
Server.const_set(:MAX, worker_connections + LISTENERS.size)
|
192
192
|
Server.const_set(:CL, client_class)
|
193
|
-
|
193
|
+
client_class.const_set(:APP, G.server.app)
|
194
194
|
EM.run {
|
195
195
|
conns = EM.instance_variable_get(:@conns) or
|
196
196
|
raise RuntimeError, "EM @conns instance variable not accessible!"
|
data/lib/rainbows/fiber/base.rb
CHANGED
@@ -16,7 +16,8 @@ module Rainbows
|
|
16
16
|
# puts the current Fiber into uninterruptible sleep for at least
|
17
17
|
# +seconds+. Unlike Kernel#sleep, this it is not possible to sleep
|
18
18
|
# indefinitely to be woken up (nobody wants that in a web server,
|
19
|
-
# right?).
|
19
|
+
# right?). Calling this directly is deprecated, use
|
20
|
+
# Rainbows.sleep(seconds) instead.
|
20
21
|
def self.sleep(seconds)
|
21
22
|
ZZ[::Fiber.current] = Time.now + seconds
|
22
23
|
::Fiber.yield
|
@@ -99,7 +100,7 @@ module Rainbows
|
|
99
100
|
HttpResponse.write(client, response, out)
|
100
101
|
end while alive and hp.reset.nil? and env.clear
|
101
102
|
rescue => e
|
102
|
-
|
103
|
+
Error.write(io, e)
|
103
104
|
ensure
|
104
105
|
G.cur -= 1
|
105
106
|
RD.delete(client)
|
data/lib/rainbows/fiber/io.rb
CHANGED
@@ -22,14 +22,24 @@ module Rainbows
|
|
22
22
|
to_io.close
|
23
23
|
end
|
24
24
|
|
25
|
+
def wait_readable
|
26
|
+
RD[self] = false
|
27
|
+
::Fiber.yield
|
28
|
+
RD.delete(self)
|
29
|
+
end
|
30
|
+
|
31
|
+
def wait_writable
|
32
|
+
WR[self] = false
|
33
|
+
::Fiber.yield
|
34
|
+
WR.delete(self)
|
35
|
+
end
|
36
|
+
|
25
37
|
def write(buf)
|
26
38
|
begin
|
27
39
|
(w = to_io.write_nonblock(buf)) == buf.size and return
|
28
40
|
buf = buf[w..-1]
|
29
41
|
rescue Errno::EAGAIN
|
30
|
-
|
31
|
-
::Fiber.yield
|
32
|
-
WR.delete(self)
|
42
|
+
wait_writable
|
33
43
|
retry
|
34
44
|
end while true
|
35
45
|
end
|
@@ -41,10 +51,8 @@ module Rainbows
|
|
41
51
|
to_io.read_nonblock(16384)
|
42
52
|
rescue Errno::EAGAIN
|
43
53
|
return if expire && expire < Time.now
|
44
|
-
RD[self] = false
|
45
54
|
expire ||= Time.now + G.kato
|
46
|
-
|
47
|
-
RD.delete(self)
|
55
|
+
wait_readable
|
48
56
|
retry
|
49
57
|
end
|
50
58
|
end
|
@@ -53,9 +61,7 @@ module Rainbows
|
|
53
61
|
begin
|
54
62
|
to_io.read_nonblock(length, buf)
|
55
63
|
rescue Errno::EAGAIN
|
56
|
-
|
57
|
-
::Fiber.yield
|
58
|
-
RD.delete(self)
|
64
|
+
wait_readable
|
59
65
|
retry
|
60
66
|
end
|
61
67
|
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
require 'rev'
|
3
|
+
require 'rainbows/fiber'
|
4
|
+
require 'rainbows/fiber/io'
|
5
|
+
|
6
|
+
module Rainbows::Fiber
|
7
|
+
module Rev
|
8
|
+
G = Rainbows::G
|
9
|
+
|
10
|
+
# keep-alive timeout class
|
11
|
+
class Kato < ::Rev::TimerWatcher
|
12
|
+
def initialize
|
13
|
+
@watch = []
|
14
|
+
super(1, true)
|
15
|
+
end
|
16
|
+
|
17
|
+
def <<(fiber)
|
18
|
+
@watch << fiber
|
19
|
+
enable unless enabled?
|
20
|
+
end
|
21
|
+
|
22
|
+
def on_timer
|
23
|
+
@watch.uniq!
|
24
|
+
while f = @watch.shift
|
25
|
+
f.resume if f.alive?
|
26
|
+
end
|
27
|
+
disable
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class Heartbeat < ::Rev::TimerWatcher
|
32
|
+
def on_timer
|
33
|
+
exit if (! G.tick && G.cur <= 0)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class Sleeper < ::Rev::TimerWatcher
|
38
|
+
|
39
|
+
def initialize(seconds)
|
40
|
+
@f = ::Fiber.current
|
41
|
+
super(seconds, false)
|
42
|
+
attach(::Rev::Loop.default)
|
43
|
+
::Fiber.yield
|
44
|
+
end
|
45
|
+
|
46
|
+
def on_timer
|
47
|
+
@f.resume
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class Server < ::Rev::IOWatcher
|
52
|
+
include Unicorn
|
53
|
+
include Rainbows
|
54
|
+
include Rainbows::Const
|
55
|
+
FIO = Rainbows::Fiber::IO
|
56
|
+
|
57
|
+
def to_io
|
58
|
+
@io
|
59
|
+
end
|
60
|
+
|
61
|
+
def initialize(io)
|
62
|
+
@io = io
|
63
|
+
super(self, :r)
|
64
|
+
end
|
65
|
+
|
66
|
+
def close
|
67
|
+
detach if attached?
|
68
|
+
@io.close
|
69
|
+
end
|
70
|
+
|
71
|
+
def on_readable
|
72
|
+
return if G.cur >= MAX
|
73
|
+
c = Rainbows.accept(@io) and ::Fiber.new { process(c) }.resume
|
74
|
+
end
|
75
|
+
|
76
|
+
def process(io)
|
77
|
+
G.cur += 1
|
78
|
+
client = FIO.new(io, ::Fiber.current)
|
79
|
+
buf = client.read_timeout or return
|
80
|
+
hp = HttpParser.new
|
81
|
+
env = {}
|
82
|
+
alive = true
|
83
|
+
remote_addr = TCPSocket === io ? io.peeraddr.last : LOCALHOST
|
84
|
+
|
85
|
+
begin # loop
|
86
|
+
buf << (client.read_timeout or return) until hp.headers(env, buf)
|
87
|
+
|
88
|
+
env[CLIENT_IO] = client
|
89
|
+
env[RACK_INPUT] = 0 == hp.content_length ?
|
90
|
+
HttpRequest::NULL_IO : TeeInput.new(client, env, hp, buf)
|
91
|
+
env[REMOTE_ADDR] = remote_addr
|
92
|
+
response = APP.call(env.update(RACK_DEFAULTS))
|
93
|
+
|
94
|
+
if 100 == response.first.to_i
|
95
|
+
client.write(EXPECT_100_RESPONSE)
|
96
|
+
env.delete(HTTP_EXPECT)
|
97
|
+
response = APP.call(env)
|
98
|
+
end
|
99
|
+
|
100
|
+
alive = hp.keepalive? && G.alive
|
101
|
+
out = [ alive ? CONN_ALIVE : CONN_CLOSE ] if hp.headers?
|
102
|
+
HttpResponse.write(client, response, out)
|
103
|
+
end while alive and hp.reset.nil? and env.clear
|
104
|
+
rescue => e
|
105
|
+
Error.write(io, e)
|
106
|
+
ensure
|
107
|
+
G.cur -= 1
|
108
|
+
client.close
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
class IO # see rainbows/fiber/io for original definition
|
114
|
+
|
115
|
+
class Watcher < ::Rev::IOWatcher
|
116
|
+
def initialize(fio, flag)
|
117
|
+
@fiber = fio.f
|
118
|
+
super(fio, flag)
|
119
|
+
attach(::Rev::Loop.default)
|
120
|
+
end
|
121
|
+
|
122
|
+
def on_readable
|
123
|
+
@fiber.resume
|
124
|
+
end
|
125
|
+
|
126
|
+
alias on_writable on_readable
|
127
|
+
end
|
128
|
+
|
129
|
+
undef_method :wait_readable
|
130
|
+
undef_method :wait_writable
|
131
|
+
undef_method :close
|
132
|
+
|
133
|
+
def initialize(*args)
|
134
|
+
super
|
135
|
+
@r = @w = false
|
136
|
+
end
|
137
|
+
|
138
|
+
def close
|
139
|
+
@w.detach if @w
|
140
|
+
@r.detach if @r
|
141
|
+
@r = @w = false
|
142
|
+
to_io.close unless to_io.closed?
|
143
|
+
end
|
144
|
+
|
145
|
+
def wait_writable
|
146
|
+
@w ||= Watcher.new(self, :w)
|
147
|
+
@w.enable unless @w.enabled?
|
148
|
+
::Fiber.yield
|
149
|
+
@w.disable
|
150
|
+
end
|
151
|
+
|
152
|
+
def wait_readable
|
153
|
+
@r ||= Watcher.new(self, :r)
|
154
|
+
@r.enable unless @r.enabled?
|
155
|
+
KATO << f
|
156
|
+
::Fiber.yield
|
157
|
+
@r.disable
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
data/lib/rainbows/rev/core.rb
CHANGED
@@ -27,7 +27,7 @@ module Rainbows
|
|
27
27
|
rloop = Server.const_set(:LOOP, ::Rev::Loop.default)
|
28
28
|
Server.const_set(:MAX, @worker_connections)
|
29
29
|
Server.const_set(:CL, mod.const_get(:Client))
|
30
|
-
EvCore.
|
30
|
+
EvCore.const_set(:APP, G.server.app)
|
31
31
|
Heartbeat.new(1, true).attach(rloop)
|
32
32
|
LISTENERS.map! { |s| Server.new(s).attach(rloop) }
|
33
33
|
rloop.run
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
require 'rainbows/fiber/rev'
|
3
|
+
|
4
|
+
module Rainbows
|
5
|
+
|
6
|
+
# A combination of the Rev and FiberSpawn models. This allows Ruby
|
7
|
+
# 1.9 Fiber-based concurrency for application processing while
|
8
|
+
# exposing a synchronous execution model and using scalable network
|
9
|
+
# concurrency provided by Rev. A "rack.input" is exposed as well
|
10
|
+
# being Sunshowers-compatible. Applications are strongly advised to
|
11
|
+
# wrap all slow IO objects (sockets, pipes) using the
|
12
|
+
# Rainbows::Fiber::IO or a Rev-compatible class whenever possible.
|
13
|
+
module RevFiberSpawn
|
14
|
+
|
15
|
+
include Base
|
16
|
+
include Fiber::Rev
|
17
|
+
|
18
|
+
def worker_loop(worker)
|
19
|
+
init_worker_process(worker)
|
20
|
+
Server.const_set(:MAX, @worker_connections)
|
21
|
+
Server.const_set(:APP, G.server.app)
|
22
|
+
Heartbeat.new(1, true).attach(::Rev::Loop.default)
|
23
|
+
kato = Kato.new.attach(::Rev::Loop.default)
|
24
|
+
Rainbows::Fiber::IO.const_set(:KATO, kato)
|
25
|
+
LISTENERS.map! { |s| Server.new(s).attach(::Rev::Loop.default) }
|
26
|
+
::Rev::Loop.default.run
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/rainbows/revactor.rb
CHANGED
@@ -68,7 +68,7 @@ module Rainbows
|
|
68
68
|
end while alive and hp.reset.nil? and env.clear
|
69
69
|
rescue ::Revactor::TCP::ReadError
|
70
70
|
rescue => e
|
71
|
-
|
71
|
+
Error.write(client.instance_eval { @_io }, e)
|
72
72
|
ensure
|
73
73
|
client.close
|
74
74
|
end
|
@@ -121,17 +121,6 @@ module Rainbows
|
|
121
121
|
rescue Errno::EMFILE => e
|
122
122
|
end
|
123
123
|
|
124
|
-
# if we get any error, try to write something back to the client
|
125
|
-
# assuming we haven't closed the socket, but don't get hung up
|
126
|
-
# if the socket is already closed or broken. We'll always ensure
|
127
|
-
# the socket is closed at the end of this function
|
128
|
-
def handle_error(client, e)
|
129
|
-
# this is Revactor implementation dependent
|
130
|
-
msg = Error.response(e) and
|
131
|
-
client.instance_eval { @_io.write_nonblock(msg) }
|
132
|
-
rescue
|
133
|
-
end
|
134
|
-
|
135
124
|
def revactorize_listeners
|
136
125
|
LISTENERS.map do |s|
|
137
126
|
case s
|
data/lib/rainbows/thread_pool.rb
CHANGED
data/t/GNUmakefile
CHANGED
data/t/simple-http_Revactor.ru
CHANGED
data/t/simple-http_ThreadPool.ru
CHANGED
data/t/sleep.ru
CHANGED
@@ -7,14 +7,7 @@ run lambda { |env|
|
|
7
7
|
nr = 1
|
8
8
|
env["PATH_INFO"] =~ %r{/([\d\.]+)\z} and nr = $1.to_f
|
9
9
|
|
10
|
-
(
|
11
|
-
when :FiberPool, :FiberSpawn
|
12
|
-
Rainbows::Fiber
|
13
|
-
when :Revactor
|
14
|
-
Actor
|
15
|
-
else
|
16
|
-
Kernel
|
17
|
-
end).sleep(nr)
|
10
|
+
Rainbows.sleep(nr)
|
18
11
|
|
19
12
|
[ 200, {'Content-Type' => 'text/plain'}, [ "Hello\n" ] ]
|
20
13
|
}
|
data/t/t9000.ru
CHANGED
@@ -3,14 +3,7 @@ use Rack::ContentType
|
|
3
3
|
use Rainbows::AppPool, :size => ENV['APP_POOL_SIZE'].to_i
|
4
4
|
class Sleeper
|
5
5
|
def call(env)
|
6
|
-
(
|
7
|
-
when :FiberPool, :FiberSpawn
|
8
|
-
Rainbows::Fiber
|
9
|
-
when :Revactor
|
10
|
-
Actor
|
11
|
-
else
|
12
|
-
Kernel
|
13
|
-
end).sleep(1)
|
6
|
+
Rainbows.sleep(1)
|
14
7
|
[ 200, {}, [ "#{object_id}\n" ] ]
|
15
8
|
end
|
16
9
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rainbows
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.90.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rainbows! hackers
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-12-
|
12
|
+
date: 2009-12-22 00:00:00 +00:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -51,6 +51,7 @@ extra_rdoc_files:
|
|
51
51
|
- lib/rainbows/fiber/base.rb
|
52
52
|
- lib/rainbows/fiber/io.rb
|
53
53
|
- lib/rainbows/fiber/queue.rb
|
54
|
+
- lib/rainbows/fiber/rev.rb
|
54
55
|
- lib/rainbows/fiber_pool.rb
|
55
56
|
- lib/rainbows/fiber_spawn.rb
|
56
57
|
- lib/rainbows/http_response.rb
|
@@ -64,6 +65,7 @@ extra_rdoc_files:
|
|
64
65
|
- lib/rainbows/rev/heartbeat.rb
|
65
66
|
- lib/rainbows/rev/master.rb
|
66
67
|
- lib/rainbows/rev/thread.rb
|
68
|
+
- lib/rainbows/rev_fiber_spawn.rb
|
67
69
|
- lib/rainbows/rev_thread_pool.rb
|
68
70
|
- lib/rainbows/rev_thread_spawn.rb
|
69
71
|
- lib/rainbows/revactor.rb
|
@@ -118,6 +120,7 @@ files:
|
|
118
120
|
- lib/rainbows/fiber/base.rb
|
119
121
|
- lib/rainbows/fiber/io.rb
|
120
122
|
- lib/rainbows/fiber/queue.rb
|
123
|
+
- lib/rainbows/fiber/rev.rb
|
121
124
|
- lib/rainbows/fiber_pool.rb
|
122
125
|
- lib/rainbows/fiber_spawn.rb
|
123
126
|
- lib/rainbows/http_response.rb
|
@@ -131,6 +134,7 @@ files:
|
|
131
134
|
- lib/rainbows/rev/heartbeat.rb
|
132
135
|
- lib/rainbows/rev/master.rb
|
133
136
|
- lib/rainbows/rev/thread.rb
|
137
|
+
- lib/rainbows/rev_fiber_spawn.rb
|
134
138
|
- lib/rainbows/rev_thread_pool.rb
|
135
139
|
- lib/rainbows/rev_thread_spawn.rb
|
136
140
|
- lib/rainbows/revactor.rb
|
@@ -167,6 +171,7 @@ files:
|
|
167
171
|
- t/simple-http_FiberSpawn.ru
|
168
172
|
- t/simple-http_NeverBlock.ru
|
169
173
|
- t/simple-http_Rev.ru
|
174
|
+
- t/simple-http_RevFiberSpawn.ru
|
170
175
|
- t/simple-http_RevThreadPool.ru
|
171
176
|
- t/simple-http_RevThreadSpawn.ru
|
172
177
|
- t/simple-http_Revactor.ru
|