rainbows 2.0.1 → 2.1.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/.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
|