rainbows 2.0.1 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +1 -0
- data/.gitignore +1 -0
- data/.manifest +46 -18
- data/.wrongdoc.yml +8 -0
- data/ChangeLog +849 -374
- data/Documentation/comparison.haml +26 -21
- data/FAQ +6 -0
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +23 -65
- data/LATEST +27 -0
- data/NEWS +53 -26
- data/README +7 -7
- data/Rakefile +1 -98
- data/Summary +0 -7
- data/TODO +2 -2
- data/lib/rainbows/app_pool.rb +2 -1
- data/lib/rainbows/base.rb +1 -0
- data/lib/rainbows/configurator.rb +9 -0
- data/lib/rainbows/const.rb +1 -1
- data/lib/rainbows/coolio/client.rb +191 -0
- data/lib/rainbows/coolio/core.rb +25 -0
- data/lib/rainbows/{rev → coolio}/deferred_chunk_response.rb +3 -2
- data/lib/rainbows/{rev → coolio}/deferred_response.rb +3 -3
- data/lib/rainbows/coolio/heartbeat.rb +20 -0
- data/lib/rainbows/{rev → coolio}/master.rb +2 -3
- data/lib/rainbows/{rev → coolio}/sendfile.rb +1 -1
- data/lib/rainbows/coolio/server.rb +11 -0
- data/lib/rainbows/coolio/thread_client.rb +36 -0
- data/lib/rainbows/coolio.rb +45 -0
- data/lib/rainbows/coolio_fiber_spawn.rb +26 -0
- data/lib/rainbows/coolio_support.rb +9 -0
- data/lib/rainbows/coolio_thread_pool/client.rb +8 -0
- data/lib/rainbows/coolio_thread_pool/watcher.rb +14 -0
- data/lib/rainbows/coolio_thread_pool.rb +57 -0
- data/lib/rainbows/coolio_thread_spawn/client.rb +8 -0
- data/lib/rainbows/coolio_thread_spawn.rb +27 -0
- data/lib/rainbows/dev_fd_response.rb +6 -2
- data/lib/rainbows/ev_core/cap_input.rb +3 -2
- data/lib/rainbows/ev_core.rb +13 -3
- data/lib/rainbows/event_machine/client.rb +124 -0
- data/lib/rainbows/event_machine/response_pipe.rb +1 -2
- data/lib/rainbows/event_machine/server.rb +15 -0
- data/lib/rainbows/event_machine.rb +13 -137
- data/lib/rainbows/fiber/base.rb +6 -7
- data/lib/rainbows/fiber/body.rb +4 -2
- data/lib/rainbows/fiber/coolio/heartbeat.rb +15 -0
- data/lib/rainbows/fiber/{rev → coolio}/methods.rb +4 -5
- data/lib/rainbows/fiber/{rev → coolio}/server.rb +1 -1
- data/lib/rainbows/fiber/{rev → coolio}/sleeper.rb +2 -2
- data/lib/rainbows/fiber/coolio.rb +12 -0
- data/lib/rainbows/fiber/io/methods.rb +6 -0
- data/lib/rainbows/fiber/io.rb +8 -10
- data/lib/rainbows/fiber/queue.rb +24 -30
- data/lib/rainbows/fiber.rb +7 -4
- data/lib/rainbows/fiber_pool.rb +1 -1
- data/lib/rainbows/http_server.rb +9 -2
- data/lib/rainbows/max_body.rb +3 -1
- data/lib/rainbows/never_block/core.rb +15 -0
- data/lib/rainbows/never_block/event_machine.rb +8 -3
- data/lib/rainbows/never_block.rb +37 -70
- data/lib/rainbows/process_client.rb +3 -6
- data/lib/rainbows/rack_input.rb +17 -0
- data/lib/rainbows/response/body.rb +18 -19
- data/lib/rainbows/response.rb +1 -1
- data/lib/rainbows/rev.rb +21 -43
- data/lib/rainbows/rev_fiber_spawn.rb +4 -19
- data/lib/rainbows/rev_thread_pool.rb +21 -75
- data/lib/rainbows/rev_thread_spawn.rb +18 -36
- data/lib/rainbows/revactor/body.rb +4 -1
- data/lib/rainbows/revactor/tee_socket.rb +44 -0
- data/lib/rainbows/revactor.rb +13 -48
- data/lib/rainbows/socket_proxy.rb +24 -0
- data/lib/rainbows/sync_close.rb +37 -0
- data/lib/rainbows/thread_pool.rb +66 -70
- data/lib/rainbows/thread_spawn.rb +40 -50
- data/lib/rainbows/thread_timeout.rb +33 -27
- data/lib/rainbows/timed_read.rb +5 -1
- data/lib/rainbows/worker_yield.rb +16 -0
- data/lib/rainbows/writer_thread_pool/client.rb +19 -0
- data/lib/rainbows/writer_thread_pool.rb +60 -91
- data/lib/rainbows/writer_thread_spawn/client.rb +69 -0
- data/lib/rainbows/writer_thread_spawn.rb +37 -117
- data/lib/rainbows.rb +12 -4
- data/rainbows.gemspec +15 -19
- data/t/GNUmakefile +4 -4
- data/t/close-has-env.ru +65 -0
- data/t/simple-http_Coolio.ru +9 -0
- data/t/simple-http_CoolioFiberSpawn.ru +10 -0
- data/t/simple-http_CoolioThreadPool.ru +9 -0
- data/t/simple-http_CoolioThreadSpawn.ru +9 -0
- data/t/t0004-heartbeat-timeout.sh +2 -2
- data/t/t0007-worker-follows-master-to-death.sh +1 -1
- data/t/t0015-working_directory.sh +7 -1
- data/t/t0017-keepalive-timeout-zero.sh +1 -1
- data/t/t0019-keepalive-cpu-usage.sh +62 -0
- data/t/t0040-keepalive_requests-setting.sh +51 -0
- data/t/t0050-response-body-close-has-env.sh +109 -0
- data/t/t0102-rack-input-short.sh +6 -6
- data/t/t0106-rack-input-keepalive.sh +48 -2
- data/t/t0113-rewindable-input-false.sh +28 -0
- data/t/t0113.ru +12 -0
- data/t/t0114-rewindable-input-true.sh +28 -0
- data/t/t0114.ru +12 -0
- data/t/t9100-thread-timeout.sh +24 -2
- data/t/t9101-thread-timeout-threshold.sh +6 -13
- data/t/test-lib.sh +2 -1
- data/t/test_isolate.rb +9 -4
- data/t/times.ru +6 -0
- metadata +109 -42
- data/GIT-VERSION-FILE +0 -1
- data/lib/rainbows/fiber/rev/heartbeat.rb +0 -8
- data/lib/rainbows/fiber/rev/kato.rb +0 -22
- data/lib/rainbows/fiber/rev.rb +0 -13
- data/lib/rainbows/rev/client.rb +0 -194
- data/lib/rainbows/rev/core.rb +0 -41
- data/lib/rainbows/rev/heartbeat.rb +0 -23
- data/lib/rainbows/rev/thread.rb +0 -46
- data/man/man1/rainbows.1 +0 -193
data/lib/rainbows/fiber/io.rb
CHANGED
@@ -18,7 +18,7 @@ class Rainbows::Fiber::IO
|
|
18
18
|
end
|
19
19
|
# :startdoc:
|
20
20
|
|
21
|
-
#
|
21
|
+
# no longer used internally within Rainbows!, only for compatibility
|
22
22
|
def write_nonblock(buf)
|
23
23
|
@to_io.write_nonblock(buf)
|
24
24
|
end
|
@@ -59,19 +59,17 @@ class Rainbows::Fiber::IO
|
|
59
59
|
else
|
60
60
|
begin
|
61
61
|
(rv = @to_io.write_nonblock(buf)) == buf.bytesize and return
|
62
|
-
buf = byte_slice(buf, rv
|
62
|
+
buf = byte_slice(buf, rv)
|
63
63
|
rescue Errno::EAGAIN
|
64
64
|
kgio_wait_writable
|
65
65
|
end while true
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
-
def byte_slice(buf,
|
70
|
-
|
71
|
-
buf.dup.force_encoding(Encoding::BINARY)
|
72
|
-
|
73
|
-
buf[range]
|
74
|
-
end
|
69
|
+
def byte_slice(buf, start) # :nodoc:
|
70
|
+
buf.encoding == Encoding::BINARY or
|
71
|
+
buf = buf.dup.force_encoding(Encoding::BINARY)
|
72
|
+
buf.slice(start, buf.size)
|
75
73
|
end
|
76
74
|
|
77
75
|
# used for reading headers (respecting keepalive_timeout)
|
@@ -82,7 +80,7 @@ class Rainbows::Fiber::IO
|
|
82
80
|
case rv = @to_io.kgio_tryread(16384, buf)
|
83
81
|
when :wait_readable
|
84
82
|
return if expire && expire < Time.now
|
85
|
-
expire ||=
|
83
|
+
expire ||= read_expire
|
86
84
|
kgio_wait_readable
|
87
85
|
else
|
88
86
|
return rv
|
@@ -93,7 +91,7 @@ class Rainbows::Fiber::IO
|
|
93
91
|
return @to_io.read_nonblock(16384, buf)
|
94
92
|
rescue Errno::EAGAIN
|
95
93
|
return if expire && expire < Time.now
|
96
|
-
expire ||=
|
94
|
+
expire ||= read_expire
|
97
95
|
kgio_wait_readable
|
98
96
|
end while true
|
99
97
|
end
|
data/lib/rainbows/fiber/queue.rb
CHANGED
@@ -1,36 +1,30 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
2
|
# :enddoc:
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
end
|
16
|
-
super queue, waiters
|
17
|
-
end
|
18
|
-
|
19
|
-
def shift
|
20
|
-
# ah the joys of not having to deal with race conditions
|
21
|
-
if queue.empty?
|
22
|
-
waiters << ::Fiber.current
|
23
|
-
::Fiber.yield
|
24
|
-
end
|
25
|
-
queue.shift
|
26
|
-
end
|
27
|
-
|
28
|
-
def <<(obj)
|
29
|
-
queue << obj
|
30
|
-
blocked = waiters.shift and blocked.resume
|
31
|
-
queue # not quite 100% compatible but no-one's looking :>
|
32
|
-
end
|
3
|
+
#
|
4
|
+
# a self-sufficient Queue implementation for Fiber-based concurrency
|
5
|
+
# models. This requires no external scheduler, so it may be used with
|
6
|
+
# Revactor as well as FiberSpawn and FiberPool.
|
7
|
+
class Rainbows::Fiber::Queue < Struct.new(:queue, :waiters)
|
8
|
+
def initialize(queue = [], waiters = [])
|
9
|
+
# move elements of the Queue into an Array
|
10
|
+
if queue.class.name == "Queue"
|
11
|
+
queue = queue.length.times.map { queue.pop }
|
12
|
+
end
|
13
|
+
super queue, waiters
|
14
|
+
end
|
33
15
|
|
16
|
+
def shift
|
17
|
+
# ah the joys of not having to deal with race conditions
|
18
|
+
if queue.empty?
|
19
|
+
waiters << Fiber.current
|
20
|
+
Fiber.yield
|
34
21
|
end
|
22
|
+
queue.shift
|
23
|
+
end
|
24
|
+
|
25
|
+
def <<(obj)
|
26
|
+
queue << obj
|
27
|
+
blocked = waiters.shift and blocked.resume
|
28
|
+
queue # not quite 100% compatible but no-one's looking :>
|
35
29
|
end
|
36
30
|
end
|
data/lib/rainbows/fiber.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
|
-
# :
|
2
|
+
# :stopdoc:
|
3
3
|
begin
|
4
4
|
require 'fiber'
|
5
5
|
rescue LoadError
|
6
6
|
defined?(NeverBlock) or raise
|
7
7
|
end
|
8
|
+
# :startdoc:
|
8
9
|
|
9
|
-
# core
|
10
|
+
# core namespace for all things that use Fibers in \Rainbows!
|
10
11
|
module Rainbows::Fiber
|
11
12
|
|
13
|
+
# :stopdoc:
|
12
14
|
# blocked readers (key: fileno, value: Rainbows::Fiber::IO object)
|
13
15
|
RD = []
|
14
16
|
|
@@ -17,6 +19,7 @@ module Rainbows::Fiber
|
|
17
19
|
|
18
20
|
# sleeping fibers go here (key: Fiber object, value: wakeup time)
|
19
21
|
ZZ = {}
|
22
|
+
# :startdoc:
|
20
23
|
|
21
24
|
# puts the current Fiber into uninterruptible sleep for at least
|
22
25
|
# +seconds+. Unlike Kernel#sleep, this it is not possible to sleep
|
@@ -24,8 +27,8 @@ module Rainbows::Fiber
|
|
24
27
|
# right?). Calling this directly is deprecated, use
|
25
28
|
# Rainbows.sleep(seconds) instead.
|
26
29
|
def self.sleep(seconds)
|
27
|
-
ZZ[
|
28
|
-
|
30
|
+
ZZ[Fiber.current] = Time.now + seconds
|
31
|
+
Fiber.yield
|
29
32
|
end
|
30
33
|
|
31
34
|
autoload :Base, 'rainbows/fiber/base'
|
data/lib/rainbows/fiber_pool.rb
CHANGED
@@ -19,7 +19,7 @@ module Rainbows::FiberPool
|
|
19
19
|
worker_connections.times {
|
20
20
|
Fiber.new {
|
21
21
|
process(Fiber.yield) while pool << Fiber.current
|
22
|
-
}.resume # resume to hit
|
22
|
+
}.resume # resume to hit Fiber.yield so it waits on a client
|
23
23
|
}
|
24
24
|
Rainbows::Fiber::Base.setup(self.class, app)
|
25
25
|
|
data/lib/rainbows/http_server.rb
CHANGED
@@ -74,7 +74,8 @@ class Rainbows::HttpServer < Unicorn::HttpServer
|
|
74
74
|
new_defaults = {
|
75
75
|
'rainbows.model' => (@use = model.to_sym),
|
76
76
|
'rack.multithread' => !!(model.to_s =~ /Thread/),
|
77
|
-
'rainbows.autochunk' => [:Rev
|
77
|
+
'rainbows.autochunk' => [:Coolio,:Rev,
|
78
|
+
:EventMachine,:NeverBlock].include?(@use),
|
78
79
|
}
|
79
80
|
Rainbows::Const::RACK_DEFAULTS.update(new_defaults)
|
80
81
|
end
|
@@ -89,10 +90,16 @@ class Rainbows::HttpServer < Unicorn::HttpServer
|
|
89
90
|
|
90
91
|
def keepalive_timeout(nr)
|
91
92
|
(Integer === nr && nr >= 0) or
|
92
|
-
raise ArgumentError, "
|
93
|
+
raise ArgumentError, "keepalive_timeout must be a non-negative Integer"
|
93
94
|
G.kato = nr
|
94
95
|
end
|
95
96
|
|
97
|
+
def keepalive_requests(nr)
|
98
|
+
Integer === nr or
|
99
|
+
raise ArgumentError, "keepalive_requests must be a non-negative Integer"
|
100
|
+
Unicorn::HttpRequest.keepalive_requests = nr
|
101
|
+
end
|
102
|
+
|
96
103
|
def client_max_body_size(nr)
|
97
104
|
err = "client_max_body_size must be nil or a non-negative Integer"
|
98
105
|
case nr
|
data/lib/rainbows/max_body.rb
CHANGED
@@ -53,7 +53,9 @@ class Rainbows::MaxBody
|
|
53
53
|
def self.setup # :nodoc:
|
54
54
|
Rainbows.max_bytes or return
|
55
55
|
case Rainbows::G.server.use
|
56
|
-
when :Rev, :
|
56
|
+
when :Rev, :Coolio, :EventMachine, :NeverBlock,
|
57
|
+
:RevThreadSpawn, :RevThreadPool,
|
58
|
+
:CoolioThreadSpawn, :CoolioThreadPool
|
57
59
|
return
|
58
60
|
end
|
59
61
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
# :enddoc:
|
3
|
+
module Rainbows::NeverBlock::Core
|
4
|
+
def init_worker_process(worker)
|
5
|
+
super
|
6
|
+
o = Rainbows::O
|
7
|
+
pool = NB::Pool::FiberPool.new(o[:pool_size])
|
8
|
+
base = o[:backend].to_s.gsub!(/([a-z])([A-Z])/, '\1_\2').downcase!
|
9
|
+
require "rainbows/never_block/#{base}"
|
10
|
+
client_class = Rainbows::NeverBlock::Client
|
11
|
+
client_class.superclass.const_set(:APP, Rainbows::G.server.app)
|
12
|
+
client_class.const_set(:POOL, pool)
|
13
|
+
logger.info "NeverBlock/#{o[:backend]} pool_size=#{o[:pool_size]}"
|
14
|
+
end
|
15
|
+
end
|
@@ -1,8 +1,13 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
2
|
# :enddoc:
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
class Rainbows::NeverBlock::Client < Rainbows::EventMachine::Client
|
4
|
+
def app_call
|
5
|
+
POOL.spawn do
|
6
|
+
begin
|
7
|
+
super
|
8
|
+
rescue => e
|
9
|
+
handle_error(e)
|
10
|
+
end
|
6
11
|
end
|
7
12
|
end
|
8
13
|
end
|
data/lib/rainbows/never_block.rb
CHANGED
@@ -1,75 +1,42 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
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
|
-
end
|
35
|
-
|
36
|
-
def self.extended(klass)
|
37
|
-
klass.extend(Rainbows.const_get(O[:backend])) # EventMachine
|
38
|
-
klass.extend(Core)
|
39
|
-
end
|
40
|
-
|
41
|
-
module Core # :nodoc: all
|
42
|
-
def self.setup
|
43
|
-
self.const_set(:POOL, ::NB::Pool::FiberPool.new(O[:pool_size]))
|
44
|
-
base = O[:backend].to_s.gsub!(/([a-z])([A-Z])/, '\1_\2').downcase!
|
45
|
-
require "rainbows/never_block/#{base}"
|
46
|
-
Rainbows::NeverBlock.const_get(:Client).class_eval do
|
47
|
-
self.superclass.const_set(:APP, G.server.app)
|
48
|
-
include Rainbows::NeverBlock::Core
|
49
|
-
alias _app_call app_call
|
50
|
-
undef_method :app_call
|
51
|
-
alias app_call nb_app_call
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def nb_app_call
|
56
|
-
POOL.spawn do
|
57
|
-
begin
|
58
|
-
_app_call
|
59
|
-
rescue => e
|
60
|
-
handle_error(e)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def init_worker_process(worker)
|
66
|
-
super
|
67
|
-
Core.setup
|
68
|
-
logger.info "NeverBlock/#{O[:backend]} pool_size=#{O[:pool_size]}"
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
# :startdoc:
|
3
|
+
# {NeverBlock}[www.espace.com.eg/neverblock/] library that combines
|
4
|
+
# the EventMachine library with Ruby Fibers. This includes use of
|
5
|
+
# Thread-based Fibers under Ruby 1.8. It currently does NOT support
|
6
|
+
# a streaming "rack.input" but is compatible with everything else
|
7
|
+
# EventMachine supports.
|
8
|
+
#
|
9
|
+
# In your Rainbows! config block, you may specify a Fiber pool size
|
10
|
+
# to limit your application concurrency (without using Rainbows::AppPool)
|
11
|
+
#
|
12
|
+
# Rainbows! do
|
13
|
+
# use :NeverBlock, :pool_size => 50
|
14
|
+
# worker_connections 100
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
module Rainbows::NeverBlock
|
18
|
+
|
19
|
+
# :stopdoc:
|
20
|
+
DEFAULTS = {
|
21
|
+
:pool_size => 20, # same default size used by NB
|
22
|
+
:backend => :EventMachine, # NeverBlock doesn't support Rev yet
|
23
|
+
}
|
24
|
+
|
25
|
+
# same pool size NB core itself uses
|
26
|
+
def self.setup # :nodoc:
|
27
|
+
o = Rainbows::O
|
28
|
+
DEFAULTS.each { |k,v| o[k] ||= v }
|
29
|
+
Integer === o[:pool_size] && o[:pool_size] > 0 or
|
30
|
+
raise ArgumentError, "pool_size must a be an Integer > 0"
|
31
|
+
mod = Rainbows.const_get(o[:backend])
|
32
|
+
require "never_block" # require EM first since we need a higher version
|
33
|
+
end
|
73
34
|
|
35
|
+
def self.extended(klass)
|
36
|
+
klass.extend(Rainbows.const_get(Rainbows::O[:backend])) # EventMachine
|
37
|
+
klass.extend(Rainbows::NeverBlock::Core)
|
74
38
|
end
|
39
|
+
# :startdoc:
|
75
40
|
end
|
41
|
+
# :enddoc:
|
42
|
+
require 'rainbows/never_block/core'
|
@@ -1,12 +1,11 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
2
|
# :enddoc:
|
3
|
+
require 'rainbows/rack_input'
|
3
4
|
module Rainbows::ProcessClient
|
4
5
|
G = Rainbows::G
|
5
6
|
include Rainbows::Response
|
6
7
|
HttpParser = Unicorn::HttpParser
|
7
|
-
|
8
|
-
RACK_INPUT = Unicorn::HttpRequest::RACK_INPUT
|
9
|
-
TeeInput = Unicorn::TeeInput
|
8
|
+
include Rainbows::RackInput
|
10
9
|
include Rainbows::Const
|
11
10
|
|
12
11
|
# once a client is accepted, it is processed in its entirety here
|
@@ -25,9 +24,7 @@ module Rainbows::ProcessClient
|
|
25
24
|
buf << buf2
|
26
25
|
end
|
27
26
|
|
28
|
-
env
|
29
|
-
env[RACK_INPUT] = 0 == hp.content_length ?
|
30
|
-
NULL_IO : TeeInput.new(client, hp)
|
27
|
+
set_input(env, hp, client)
|
31
28
|
env[REMOTE_ADDR] = remote_addr
|
32
29
|
status, headers, body = APP.call(env.update(RACK_DEFAULTS))
|
33
30
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
# :enddoc:
|
3
|
+
# only used by synchronous interfaces
|
4
|
+
module Rainbows::RackInput
|
5
|
+
NULL_IO = Unicorn::HttpRequest::NULL_IO
|
6
|
+
RACK_INPUT = Unicorn::HttpRequest::RACK_INPUT
|
7
|
+
CLIENT_IO = Rainbows::Const::CLIENT_IO
|
8
|
+
|
9
|
+
def self.setup
|
10
|
+
const_set(:IC, Unicorn::HttpRequest.input_class)
|
11
|
+
end
|
12
|
+
|
13
|
+
def set_input(env, hp, client)
|
14
|
+
env[RACK_INPUT] = 0 == hp.content_length ? NULL_IO : IC.new(client, hp)
|
15
|
+
env[CLIENT_IO] = client
|
16
|
+
end
|
17
|
+
end
|
@@ -32,8 +32,14 @@ module Rainbows::Response::Body # :nodoc:
|
|
32
32
|
|
33
33
|
FD_MAP = Rainbows::FD_MAP
|
34
34
|
|
35
|
+
class F < File; end
|
36
|
+
|
37
|
+
def close_if_private(io)
|
38
|
+
io.close if F === io
|
39
|
+
end
|
40
|
+
|
35
41
|
def io_for_fd(fd)
|
36
|
-
FD_MAP.delete(fd) ||
|
42
|
+
FD_MAP.delete(fd) || F.for_fd(fd)
|
37
43
|
end
|
38
44
|
|
39
45
|
# to_io is not part of the Rack spec, but make an exception here
|
@@ -47,13 +53,16 @@ module Rainbows::Response::Body # :nodoc:
|
|
47
53
|
# try to take advantage of Rainbows::DevFdResponse, calling File.open
|
48
54
|
# is a last resort
|
49
55
|
path = body.to_path
|
50
|
-
path =~ %r{\A/dev/fd/(\d+)\z} ? io_for_fd($1.to_i) :
|
56
|
+
path =~ %r{\A/dev/fd/(\d+)\z} ? io_for_fd($1.to_i) : F.open(path)
|
51
57
|
end
|
52
58
|
end
|
53
59
|
|
54
60
|
if IO.method_defined?(:sendfile_nonblock)
|
55
61
|
def write_body_file(sock, body, range)
|
56
|
-
|
62
|
+
io = body_to_io(body)
|
63
|
+
range ? sock.sendfile(io, range[0], range[1]) : sock.sendfile(io, 0)
|
64
|
+
ensure
|
65
|
+
close_if_private(io)
|
57
66
|
end
|
58
67
|
end
|
59
68
|
|
@@ -70,8 +79,6 @@ module Rainbows::Response::Body # :nodoc:
|
|
70
79
|
# pread() semantics
|
71
80
|
def write_body_stream(sock, body, range)
|
72
81
|
IO.copy_stream(body, sock)
|
73
|
-
ensure
|
74
|
-
body.respond_to?(:close) and body.close
|
75
82
|
end
|
76
83
|
else
|
77
84
|
# fall back to body#each, which is a Rack standard
|
@@ -79,27 +86,19 @@ module Rainbows::Response::Body # :nodoc:
|
|
79
86
|
end
|
80
87
|
|
81
88
|
if method_defined?(:write_body_file)
|
82
|
-
|
83
89
|
# middlewares/apps may return with a body that responds to +to_path+
|
84
90
|
def write_body_path(sock, body, range)
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
write_body_file(sock, inp, range)
|
89
|
-
ensure
|
90
|
-
inp.close if inp != body
|
91
|
-
end
|
92
|
-
else
|
93
|
-
write_body_stream(sock, inp, range)
|
94
|
-
end
|
91
|
+
stat = File.stat(body.to_path)
|
92
|
+
stat.file? ? write_body_file(sock, body, range) :
|
93
|
+
write_body_stream(sock, body, range)
|
95
94
|
ensure
|
96
|
-
body.respond_to?(:close)
|
95
|
+
body.respond_to?(:close) and body.close
|
97
96
|
end
|
98
97
|
elsif method_defined?(:write_body_stream)
|
99
98
|
def write_body_path(sock, body, range)
|
100
|
-
write_body_stream(sock,
|
99
|
+
write_body_stream(sock, body, range)
|
101
100
|
ensure
|
102
|
-
body.respond_to?(:close)
|
101
|
+
body.respond_to?(:close) and body.close
|
103
102
|
end
|
104
103
|
end
|
105
104
|
|
data/lib/rainbows/response.rb
CHANGED
@@ -38,7 +38,7 @@ module Rainbows::Response
|
|
38
38
|
range_class = body_class = klass
|
39
39
|
case Rainbows::Const::RACK_DEFAULTS['rainbows.model']
|
40
40
|
when :WriterThreadSpawn
|
41
|
-
body_class = Rainbows::WriterThreadSpawn::
|
41
|
+
body_class = Rainbows::WriterThreadSpawn::Client
|
42
42
|
range_class = Rainbows::HttpServer
|
43
43
|
when :EventMachine, :NeverBlock
|
44
44
|
range_class = nil # :<
|
data/lib/rainbows/rev.rb
CHANGED
@@ -1,44 +1,22 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
# temporary file before the application is entered.
|
24
|
-
|
25
|
-
module Rev
|
26
|
-
|
27
|
-
# :stopdoc:
|
28
|
-
# keep-alive timeout scoreboard
|
29
|
-
KATO = {}
|
30
|
-
|
31
|
-
# all connected clients
|
32
|
-
CONN = {}
|
33
|
-
|
34
|
-
if {}.respond_to?(:compare_by_identity)
|
35
|
-
CONN.compare_by_identity
|
36
|
-
KATO.compare_by_identity
|
37
|
-
end
|
38
|
-
|
39
|
-
autoload :DeferredResponse,'rainbows/rev/deferred_response'
|
40
|
-
autoload :DeferredChunkResponse,'rainbows/rev/deferred_chunk_response'
|
41
|
-
include Core
|
42
|
-
# :startdoc:
|
43
|
-
end
|
44
|
-
end
|
2
|
+
Rainbows.const_set(:Rev, Rainbows::Coolio)
|
3
|
+
# Coolio is the new version of this, use that instead.
|
4
|
+
#
|
5
|
+
# Implements a basic single-threaded event model with
|
6
|
+
# {Rev}[http://rev.rubyforge.org/]. It is capable of handling
|
7
|
+
# thousands of simultaneous client connections, but with only a
|
8
|
+
# single-threaded app dispatch. It is suited for slow clients and
|
9
|
+
# fast applications (applications that do not have slow network
|
10
|
+
# dependencies) or applications that use DevFdResponse for deferrable
|
11
|
+
# response bodies. It does not require your Rack application to be
|
12
|
+
# thread-safe, reentrancy is only required for the DevFdResponse body
|
13
|
+
# generator.
|
14
|
+
#
|
15
|
+
# Compatibility: Whatever \Rev itself supports, currently Ruby
|
16
|
+
# 1.8/1.9.
|
17
|
+
#
|
18
|
+
# This model does not implement as streaming "rack.input" which
|
19
|
+
# allows the Rack application to process data as it arrives. This
|
20
|
+
# means "rack.input" will be fully buffered in memory or to a
|
21
|
+
# temporary file before the application is entered.
|
22
|
+
module Rainbows::Rev; end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
|
-
|
2
|
+
Rainbows.const_set(:RevFiberSpawn, Rainbows::CoolioFiberSpawn)
|
3
3
|
|
4
|
+
# CoolioFiberSpawn is the new version of this, use that instead.
|
5
|
+
#
|
4
6
|
# A combination of the Rev and FiberSpawn models. This allows Ruby
|
5
7
|
# 1.9 Fiber-based concurrency for application processing while
|
6
8
|
# exposing a synchronous execution model and using scalable network
|
@@ -8,21 +10,4 @@ require 'rainbows/fiber/rev'
|
|
8
10
|
# being Sunshowers-compatible. Applications are strongly advised to
|
9
11
|
# wrap all slow IO objects (sockets, pipes) using the
|
10
12
|
# Rainbows::Fiber::IO or a Rev-compatible class whenever possible.
|
11
|
-
module Rainbows::RevFiberSpawn
|
12
|
-
|
13
|
-
include Rainbows::Base
|
14
|
-
include Rainbows::Fiber::Rev
|
15
|
-
|
16
|
-
def worker_loop(worker) # :nodoc:
|
17
|
-
Rainbows::Response.setup(Server)
|
18
|
-
init_worker_process(worker)
|
19
|
-
Server.const_set(:MAX, @worker_connections)
|
20
|
-
Rainbows::Fiber::Base.setup(Server, nil)
|
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::Rev::Methods.const_set(:KATO, kato)
|
25
|
-
LISTENERS.map! { |s| Server.new(s).attach(Rev::Loop.default) }
|
26
|
-
Rev::Loop.default.run
|
27
|
-
end
|
28
|
-
end
|
13
|
+
module Rainbows::RevFiberSpawn; end
|