rainbows 0.94.0 → 0.95.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +1 -0
- data/.manifest +18 -0
- data/ChangeLog +394 -226
- data/GIT-VERSION-FILE +1 -1
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +6 -4
- data/NEWS +18 -0
- data/README +13 -5
- data/Static_Files +71 -0
- data/TODO +12 -0
- data/Test_Suite +1 -1
- data/bin/rainbows +1 -4
- data/lib/rainbows/actor_spawn.rb +1 -1
- data/lib/rainbows/app_pool.rb +1 -1
- data/lib/rainbows/base.rb +79 -89
- data/lib/rainbows/byte_slice.rb +17 -0
- data/lib/rainbows/configurator.rb +46 -0
- data/lib/rainbows/const.rb +2 -2
- data/lib/rainbows/dev_fd_response.rb +52 -44
- data/lib/rainbows/error.rb +1 -0
- data/lib/rainbows/ev_core.rb +3 -2
- data/lib/rainbows/event_machine.rb +26 -24
- data/lib/rainbows/fiber/base.rb +30 -40
- data/lib/rainbows/fiber/body.rb +34 -0
- data/lib/rainbows/fiber/io.rb +28 -8
- data/lib/rainbows/fiber/queue.rb +1 -0
- data/lib/rainbows/fiber/rev.rb +4 -2
- data/lib/rainbows/fiber.rb +1 -0
- data/lib/rainbows/fiber_pool.rb +2 -2
- data/lib/rainbows/fiber_spawn.rb +2 -2
- data/lib/rainbows/http_response.rb +20 -31
- data/lib/rainbows/http_server.rb +3 -4
- data/lib/rainbows/max_body.rb +1 -0
- data/lib/rainbows/never_block/event_machine.rb +2 -0
- data/lib/rainbows/never_block.rb +5 -4
- data/lib/rainbows/queue_pool.rb +1 -0
- data/lib/rainbows/response/body.rb +119 -0
- data/lib/rainbows/response.rb +43 -0
- data/lib/rainbows/rev/client.rb +79 -9
- data/lib/rainbows/rev/core.rb +4 -0
- data/lib/rainbows/rev/deferred_response.rb +1 -44
- data/lib/rainbows/rev/heartbeat.rb +1 -0
- data/lib/rainbows/rev/master.rb +1 -0
- data/lib/rainbows/rev/sendfile.rb +26 -0
- data/lib/rainbows/rev/thread.rb +2 -1
- data/lib/rainbows/rev.rb +2 -0
- data/lib/rainbows/rev_fiber_spawn.rb +3 -1
- data/lib/rainbows/rev_thread_pool.rb +7 -5
- data/lib/rainbows/rev_thread_spawn.rb +2 -2
- data/lib/rainbows/revactor.rb +146 -146
- data/lib/rainbows/sendfile.rb +10 -21
- data/lib/rainbows/server_token.rb +39 -0
- data/lib/rainbows/stream_file.rb +14 -0
- data/lib/rainbows/tee_input.rb +1 -0
- data/lib/rainbows/thread_pool.rb +12 -7
- data/lib/rainbows/thread_spawn.rb +2 -3
- data/lib/rainbows/writer_thread_pool.rb +13 -7
- data/lib/rainbows/writer_thread_spawn.rb +12 -9
- data/lib/rainbows.rb +16 -45
- data/rainbows.gemspec +8 -8
- data/t/.gitignore +1 -1
- data/t/GNUmakefile +26 -16
- data/t/README +1 -1
- data/t/async-response-no-autochunk.ru +0 -1
- data/t/async-response.ru +0 -1
- data/t/cramp/rainsocket.ru +26 -0
- data/t/fork-sleep.ru +0 -1
- data/t/my-tap-lib.sh +3 -2
- data/t/simple-http_ActorSpawn.ru +9 -0
- data/t/t0009-broken-app.sh +1 -1
- data/t/t0009.ru +0 -1
- data/t/t0011-close-on-exec-set.sh +1 -1
- data/t/t0015-working_directory.sh +56 -0
- data/t/t0016-onenine-encoding-is-tricky.sh +28 -0
- data/t/t0016.rb +15 -0
- data/t/t0020-large-sendfile-response.sh +141 -0
- data/t/t0300-async_sinatra.sh +0 -6
- data/t/t0501-cramp-rainsocket.sh +38 -0
- data/t/t9001-sendfile-to-path.sh +5 -4
- data/t/t9002-server-token.sh +37 -0
- data/t/t9002.ru +4 -0
- data/t/test-lib.sh +1 -1
- data/t/test_isolate.rb +14 -11
- metadata +87 -18
@@ -0,0 +1,119 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
# :enddoc:
|
3
|
+
# non-portable body response stuff goes here
|
4
|
+
#
|
5
|
+
# The sendfile 1.0.0 RubyGem includes IO#sendfile and
|
6
|
+
# IO#sendfile_nonblock. Previous versions of "sendfile" didn't have
|
7
|
+
# IO#sendfile_nonblock, and IO#sendfile in previous versions could
|
8
|
+
# block other threads under 1.8 with large files
|
9
|
+
#
|
10
|
+
# IO#sendfile currently (June 2010) beats 1.9 IO.copy_stream with
|
11
|
+
# non-Linux support and large files on 32-bit. We still fall back to
|
12
|
+
# IO.copy_stream (if available) if we're dealing with DevFdResponse
|
13
|
+
# objects, though.
|
14
|
+
#
|
15
|
+
# Linux-only splice(2) support via the "io_splice" gem will eventually
|
16
|
+
# be added for streaming sockets/pipes, too.
|
17
|
+
#
|
18
|
+
# * write_body_file - regular files (sendfile or pread+write)
|
19
|
+
# * write_body_stream - socket/pipes (read+write, splice later)
|
20
|
+
# * write_body_each - generic fallback
|
21
|
+
#
|
22
|
+
# callgraph is as follows:
|
23
|
+
#
|
24
|
+
# write_body
|
25
|
+
# `- write_body_each
|
26
|
+
# `- write_body_path
|
27
|
+
# `- write_body_file
|
28
|
+
# `- write_body_stream
|
29
|
+
#
|
30
|
+
module Rainbows::Response::Body # :nodoc:
|
31
|
+
ALIASES = {}
|
32
|
+
|
33
|
+
# to_io is not part of the Rack spec, but make an exception here
|
34
|
+
# since we can conserve path lookups and file descriptors.
|
35
|
+
# \Rainbows! will never get here without checking for the existence
|
36
|
+
# of body.to_path first.
|
37
|
+
def body_to_io(body)
|
38
|
+
if body.respond_to?(:to_io)
|
39
|
+
body.to_io
|
40
|
+
else
|
41
|
+
# try to take advantage of Rainbows::DevFdResponse, calling File.open
|
42
|
+
# is a last resort
|
43
|
+
path = body.to_path
|
44
|
+
path =~ %r{\A/dev/fd/(\d+)\z} ? IO.new($1.to_i) : File.open(path, 'rb')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
if IO.method_defined?(:sendfile_nonblock)
|
49
|
+
def write_body_file(sock, body)
|
50
|
+
sock.sendfile(body, 0)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
if IO.respond_to?(:copy_stream)
|
55
|
+
unless method_defined?(:write_body_file)
|
56
|
+
# try to use sendfile() via IO.copy_stream, otherwise pread()+write()
|
57
|
+
def write_body_file(sock, body)
|
58
|
+
IO.copy_stream(body, sock, nil, 0)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# only used when body is a pipe or socket that can't handle
|
63
|
+
# pread() semantics
|
64
|
+
def write_body_stream(sock, body)
|
65
|
+
IO.copy_stream(body, sock)
|
66
|
+
ensure
|
67
|
+
body.respond_to?(:close) and body.close
|
68
|
+
end
|
69
|
+
else
|
70
|
+
# fall back to body#each, which is a Rack standard
|
71
|
+
ALIASES[:write_body_stream] = :write_body_each
|
72
|
+
end
|
73
|
+
|
74
|
+
if method_defined?(:write_body_file)
|
75
|
+
|
76
|
+
# middlewares/apps may return with a body that responds to +to_path+
|
77
|
+
def write_body_path(sock, body)
|
78
|
+
inp = body_to_io(body)
|
79
|
+
if inp.stat.file?
|
80
|
+
begin
|
81
|
+
write_body_file(sock, inp)
|
82
|
+
ensure
|
83
|
+
inp.close if inp != body
|
84
|
+
end
|
85
|
+
else
|
86
|
+
write_body_stream(sock, inp)
|
87
|
+
end
|
88
|
+
ensure
|
89
|
+
body.respond_to?(:close) && inp != body and body.close
|
90
|
+
end
|
91
|
+
else
|
92
|
+
def write_body_path(sock, body)
|
93
|
+
write_body_stream(sock, body_to_io(body))
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
if method_defined?(:write_body_path)
|
98
|
+
def write_body(client, body)
|
99
|
+
body.respond_to?(:to_path) ?
|
100
|
+
write_body_path(client, body) :
|
101
|
+
write_body_each(client, body)
|
102
|
+
end
|
103
|
+
else
|
104
|
+
ALIASES[:write_body] = :write_body_each
|
105
|
+
end
|
106
|
+
|
107
|
+
# generic body writer, used for most dynamically generated responses
|
108
|
+
def write_body_each(socket, body)
|
109
|
+
body.each { |chunk| socket.write(chunk) }
|
110
|
+
ensure
|
111
|
+
body.respond_to?(:close) and body.close
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.included(klass)
|
115
|
+
ALIASES.each do |new_method, orig_method|
|
116
|
+
klass.__send__(:alias_method, new_method, orig_method)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
# :enddoc:
|
3
|
+
require 'time' # for Time#httpdate
|
4
|
+
|
5
|
+
module Rainbows::Response
|
6
|
+
|
7
|
+
CODES = Unicorn::HttpResponse::CODES
|
8
|
+
|
9
|
+
def response_header(response, out)
|
10
|
+
status, headers = response
|
11
|
+
status = CODES[status.to_i] || status
|
12
|
+
|
13
|
+
headers.each do |key, value|
|
14
|
+
next if %r{\A(?:X-Rainbows-|Connection\z|Date\z|Status\z)}i =~ key
|
15
|
+
if value =~ /\n/
|
16
|
+
# avoiding blank, key-only cookies with /\n+/
|
17
|
+
out.concat(value.split(/\n+/).map! { |v| "#{key}: #{v}\r\n" })
|
18
|
+
else
|
19
|
+
out << "#{key}: #{value}\r\n"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
"HTTP/1.1 #{status}\r\n" \
|
24
|
+
"Date: #{Time.now.httpdate}\r\n" \
|
25
|
+
"Status: #{status}\r\n" \
|
26
|
+
"#{out.join('')}\r\n"
|
27
|
+
end
|
28
|
+
|
29
|
+
def write_header(socket, response, out)
|
30
|
+
out and socket.write(response_header(response, out))
|
31
|
+
end
|
32
|
+
|
33
|
+
def write_response(socket, response, out)
|
34
|
+
write_header(socket, response, out)
|
35
|
+
write_body(socket, response[2])
|
36
|
+
end
|
37
|
+
|
38
|
+
# called after forking
|
39
|
+
def self.setup(klass)
|
40
|
+
require('rainbows/response/body') and
|
41
|
+
klass.__send__(:include, Rainbows::Response::Body)
|
42
|
+
end
|
43
|
+
end
|
data/lib/rainbows/rev/client.rb
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
|
+
# :enddoc:
|
2
3
|
require 'rainbows/ev_core'
|
3
4
|
module Rainbows
|
4
5
|
module Rev
|
5
6
|
|
6
7
|
class Client < ::Rev::IO
|
8
|
+
include Rainbows::ByteSlice
|
7
9
|
include Rainbows::EvCore
|
10
|
+
include Rainbows::Response
|
8
11
|
G = Rainbows::G
|
12
|
+
HH = Rack::Utils::HeaderHash
|
9
13
|
|
10
14
|
def initialize(io)
|
11
15
|
CONN[self] = false
|
@@ -14,6 +18,33 @@ module Rainbows
|
|
14
18
|
@deferred_bodies = [] # for (fast) regular files only
|
15
19
|
end
|
16
20
|
|
21
|
+
def quit
|
22
|
+
super
|
23
|
+
close if @deferred_bodies.empty? && @_write_buffer.empty?
|
24
|
+
end
|
25
|
+
|
26
|
+
# override the ::Rev::IO#write method try to write directly to the
|
27
|
+
# kernel socket buffers to avoid an extra userspace copy if
|
28
|
+
# possible.
|
29
|
+
def write(buf)
|
30
|
+
if @_write_buffer.empty?
|
31
|
+
begin
|
32
|
+
w = @_io.write_nonblock(buf)
|
33
|
+
if w == Rack::Utils.bytesize(buf)
|
34
|
+
return on_write_complete
|
35
|
+
end
|
36
|
+
# we never care for the return value, but yes, we may return
|
37
|
+
# a "fake" short write from super(buf) if anybody cares.
|
38
|
+
buf = byte_slice(buf, w..-1)
|
39
|
+
rescue Errno::EAGAIN
|
40
|
+
break # fall through to super(buf)
|
41
|
+
rescue
|
42
|
+
return close
|
43
|
+
end while true
|
44
|
+
end
|
45
|
+
super(buf)
|
46
|
+
end
|
47
|
+
|
17
48
|
# queued, optional response bodies, it should only be unpollable "fast"
|
18
49
|
# devices where read(2) is uninterruptable. Unfortunately, NFS and ilk
|
19
50
|
# are also part of this. We'll also stick DeferredResponse bodies in
|
@@ -27,6 +58,42 @@ module Rainbows
|
|
27
58
|
@_write_buffer.empty? && @deferred_bodies.empty? and close.nil?
|
28
59
|
end
|
29
60
|
|
61
|
+
def rev_write_response(response, out)
|
62
|
+
status, headers, body = response
|
63
|
+
|
64
|
+
body.respond_to?(:to_path) or
|
65
|
+
return write_response(self, response, out)
|
66
|
+
|
67
|
+
headers = HH.new(headers)
|
68
|
+
io = body_to_io(body)
|
69
|
+
st = io.stat
|
70
|
+
|
71
|
+
if st.socket? || st.pipe?
|
72
|
+
do_chunk = !!(headers['Transfer-Encoding'] =~ %r{\Achunked\z}i)
|
73
|
+
do_chunk = false if headers.delete('X-Rainbows-Autochunk') == 'no'
|
74
|
+
# too tricky to support keepalive/pipelining when a response can
|
75
|
+
# take an indeterminate amount of time here.
|
76
|
+
if out.nil?
|
77
|
+
do_chunk = false
|
78
|
+
else
|
79
|
+
out[0] = CONN_CLOSE
|
80
|
+
end
|
81
|
+
|
82
|
+
# we only want to attach to the Rev::Loop belonging to the
|
83
|
+
# main thread in Ruby 1.9
|
84
|
+
io = DeferredResponse.new(io, self, do_chunk, body).
|
85
|
+
attach(Server::LOOP)
|
86
|
+
elsif st.file?
|
87
|
+
headers.delete('Transfer-Encoding')
|
88
|
+
headers['Content-Length'] ||= st.size.to_s
|
89
|
+
io = to_sendfile(io)
|
90
|
+
else # char/block device, directory, whatever... nobody cares
|
91
|
+
return write_response(self, response, out)
|
92
|
+
end
|
93
|
+
defer_body(io, out)
|
94
|
+
write_header(self, response, out)
|
95
|
+
end
|
96
|
+
|
30
97
|
def app_call
|
31
98
|
begin
|
32
99
|
KATO.delete(self)
|
@@ -36,7 +103,7 @@ module Rainbows
|
|
36
103
|
alive = @hp.keepalive? && G.alive
|
37
104
|
out = [ alive ? CONN_ALIVE : CONN_CLOSE ] if @hp.headers?
|
38
105
|
|
39
|
-
|
106
|
+
rev_write_response(response, out)
|
40
107
|
if alive
|
41
108
|
@env.clear
|
42
109
|
@hp.reset
|
@@ -52,16 +119,16 @@ module Rainbows
|
|
52
119
|
end
|
53
120
|
|
54
121
|
def on_write_complete
|
55
|
-
if body = @deferred_bodies
|
122
|
+
if body = @deferred_bodies[0]
|
123
|
+
# no socket or pipes, body must be a regular file to continue here
|
56
124
|
return if DeferredResponse === body
|
125
|
+
|
57
126
|
begin
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
close if :close == @state && @deferred_bodies.empty?
|
64
|
-
end
|
127
|
+
rev_sendfile(body)
|
128
|
+
rescue EOFError # expected at file EOF
|
129
|
+
@deferred_bodies.shift
|
130
|
+
body.close
|
131
|
+
close if :close == @state && @deferred_bodies.empty?
|
65
132
|
rescue => e
|
66
133
|
handle_error(e)
|
67
134
|
end
|
@@ -71,6 +138,9 @@ module Rainbows
|
|
71
138
|
end
|
72
139
|
|
73
140
|
def on_close
|
141
|
+
while f = @deferred_bodies.shift
|
142
|
+
DeferredResponse === f or f.close
|
143
|
+
end
|
74
144
|
CONN.delete(self)
|
75
145
|
end
|
76
146
|
|
data/lib/rainbows/rev/core.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
|
+
# :enddoc:
|
2
3
|
require 'rev'
|
3
4
|
Rev::VERSION >= '0.3.0' or abort 'rev >= 0.3.0 is required'
|
4
5
|
require 'rainbows/rev/heartbeat'
|
@@ -22,6 +23,9 @@ module Rainbows
|
|
22
23
|
# for connections and doesn't die until the parent dies (or is
|
23
24
|
# given a INT, QUIT, or TERM signal)
|
24
25
|
def worker_loop(worker)
|
26
|
+
Rainbows::Response.setup(Rainbows::Rev::Client)
|
27
|
+
require 'rainbows/rev/sendfile'
|
28
|
+
Rainbows::Rev::Client.__send__(:include, Rainbows::Rev::Sendfile)
|
25
29
|
init_worker_process(worker)
|
26
30
|
mod = self.class.const_get(@use)
|
27
31
|
rloop = Server.const_set(:LOOP, ::Rev::Loop.default)
|
@@ -1,55 +1,12 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
|
+
# :enddoc:
|
2
3
|
module Rainbows
|
3
4
|
module Rev
|
4
5
|
|
5
6
|
# this is class is specific to Rev for writing large static files
|
6
7
|
# or proxying IO-derived objects
|
7
8
|
class DeferredResponse < ::Rev::IO
|
8
|
-
include Unicorn
|
9
9
|
include Rainbows::Const
|
10
|
-
G = Rainbows::G
|
11
|
-
HH = Rack::Utils::HeaderHash
|
12
|
-
|
13
|
-
def self.write(client, response, out)
|
14
|
-
status, headers, body = response
|
15
|
-
|
16
|
-
body.respond_to?(:to_path) or
|
17
|
-
return HttpResponse.write(client, response, out)
|
18
|
-
|
19
|
-
headers = HH.new(headers)
|
20
|
-
|
21
|
-
# to_io is not part of the Rack spec, but make an exception
|
22
|
-
# here since we can't get here without checking to_path first
|
23
|
-
io = body.to_io if body.respond_to?(:to_io)
|
24
|
-
io ||= ::IO.new($1.to_i) if body.to_path =~ %r{\A/dev/fd/(\d+)\z}
|
25
|
-
io ||= File.open(body.to_path, 'rb')
|
26
|
-
st = io.stat
|
27
|
-
|
28
|
-
if st.socket? || st.pipe?
|
29
|
-
do_chunk = !!(headers['Transfer-Encoding'] =~ %r{\Achunked\z}i)
|
30
|
-
do_chunk = false if headers.delete('X-Rainbows-Autochunk') == 'no'
|
31
|
-
# too tricky to support keepalive/pipelining when a response can
|
32
|
-
# take an indeterminate amount of time here.
|
33
|
-
if out.nil?
|
34
|
-
do_chunk = false
|
35
|
-
else
|
36
|
-
out[0] = CONN_CLOSE
|
37
|
-
end
|
38
|
-
|
39
|
-
# we only want to attach to the Rev::Loop belonging to the
|
40
|
-
# main thread in Ruby 1.9
|
41
|
-
io = new(io, client, do_chunk, body).attach(Server::LOOP)
|
42
|
-
elsif st.file?
|
43
|
-
headers.delete('Transfer-Encoding')
|
44
|
-
headers['Content-Length'] ||= st.size.to_s
|
45
|
-
else # char/block device, directory, whatever... nobody cares
|
46
|
-
return HttpResponse.write(client, response, out)
|
47
|
-
end
|
48
|
-
client.defer_body(io, out)
|
49
|
-
out.nil? or
|
50
|
-
client.write(HttpResponse.header_string(status, headers.to_hash, out))
|
51
|
-
end
|
52
|
-
|
53
10
|
def initialize(io, client, do_chunk, body)
|
54
11
|
super(io)
|
55
12
|
@client, @do_chunk, @body = client, do_chunk, body
|
data/lib/rainbows/rev/master.rb
CHANGED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
# :enddoc:
|
3
|
+
module Rainbows::Rev::Sendfile
|
4
|
+
if IO.method_defined?(:sendfile_nonblock)
|
5
|
+
F = Rainbows::StreamFile
|
6
|
+
|
7
|
+
def to_sendfile(io)
|
8
|
+
F[0, io]
|
9
|
+
end
|
10
|
+
|
11
|
+
def rev_sendfile(body)
|
12
|
+
body.offset += @_io.sendfile_nonblock(body, body.offset, 0x10000)
|
13
|
+
enable_write_watcher
|
14
|
+
rescue Errno::EAGAIN
|
15
|
+
enable_write_watcher
|
16
|
+
end
|
17
|
+
else
|
18
|
+
def to_sendfile(io)
|
19
|
+
io
|
20
|
+
end
|
21
|
+
|
22
|
+
def rev_sendfile(body)
|
23
|
+
write(body.sysread(0x4000))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/rainbows/rev/thread.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
|
+
# :enddoc:
|
2
3
|
require 'thread'
|
3
4
|
require 'rainbows/rev/master'
|
4
5
|
|
@@ -22,7 +23,7 @@ module Rainbows
|
|
22
23
|
enable
|
23
24
|
alive = @hp.keepalive? && G.alive
|
24
25
|
out = [ alive ? CONN_ALIVE : CONN_CLOSE ] if @hp.headers?
|
25
|
-
|
26
|
+
rev_write_response(response, out)
|
26
27
|
return quit unless alive && G.alive
|
27
28
|
|
28
29
|
@env.clear
|
data/lib/rainbows/rev.rb
CHANGED
@@ -15,9 +15,11 @@ module Rainbows
|
|
15
15
|
include Base
|
16
16
|
include Fiber::Rev
|
17
17
|
|
18
|
-
def worker_loop(worker)
|
18
|
+
def worker_loop(worker) # :nodoc:
|
19
|
+
Rainbows::Response.setup(Rainbows::Fiber::Rev::Server)
|
19
20
|
init_worker_process(worker)
|
20
21
|
Server.const_set(:MAX, @worker_connections)
|
22
|
+
Rainbows::Fiber::Base.setup(Rainbows::Fiber::Rev::Server, nil)
|
21
23
|
Server.const_set(:APP, G.server.app)
|
22
24
|
Heartbeat.new(1, true).attach(::Rev::Loop.default)
|
23
25
|
kato = Kato.new.attach(::Rev::Loop.default)
|
@@ -20,17 +20,19 @@ module Rainbows
|
|
20
20
|
|
21
21
|
module RevThreadPool
|
22
22
|
|
23
|
+
# :stopdoc:
|
23
24
|
DEFAULTS = {
|
24
25
|
:pool_size => 20, # same default size as ThreadPool (w/o Rev)
|
25
26
|
}
|
27
|
+
#:startdoc:
|
26
28
|
|
27
|
-
def self.setup
|
29
|
+
def self.setup # :nodoc:
|
28
30
|
DEFAULTS.each { |k,v| O[k] ||= v }
|
29
31
|
Integer === O[:pool_size] && O[:pool_size] > 0 or
|
30
32
|
raise ArgumentError, "pool_size must a be an Integer > 0"
|
31
33
|
end
|
32
34
|
|
33
|
-
class PoolWatcher < ::Rev::TimerWatcher
|
35
|
+
class PoolWatcher < ::Rev::TimerWatcher # :nodoc: all
|
34
36
|
def initialize(threads)
|
35
37
|
@threads = threads
|
36
38
|
super(G.server.timeout, true)
|
@@ -41,7 +43,7 @@ module Rainbows
|
|
41
43
|
end
|
42
44
|
end
|
43
45
|
|
44
|
-
class Client < Rainbows::Rev::ThreadClient
|
46
|
+
class Client < Rainbows::Rev::ThreadClient # :nodoc:
|
45
47
|
def app_dispatch
|
46
48
|
QUEUE << self
|
47
49
|
end
|
@@ -49,7 +51,7 @@ module Rainbows
|
|
49
51
|
|
50
52
|
include Rainbows::Rev::Core
|
51
53
|
|
52
|
-
def init_worker_threads(master, queue)
|
54
|
+
def init_worker_threads(master, queue) # :nodoc:
|
53
55
|
O[:pool_size].times.map do
|
54
56
|
Thread.new do
|
55
57
|
begin
|
@@ -62,7 +64,7 @@ module Rainbows
|
|
62
64
|
end
|
63
65
|
end
|
64
66
|
|
65
|
-
def init_worker_process(worker)
|
67
|
+
def init_worker_process(worker) # :nodoc:
|
66
68
|
super
|
67
69
|
master = Rev::Master.new(Queue.new).attach(::Rev::Loop.default)
|
68
70
|
queue = Client.const_set(:QUEUE, Queue.new)
|
@@ -20,7 +20,7 @@ module Rainbows
|
|
20
20
|
|
21
21
|
module RevThreadSpawn
|
22
22
|
|
23
|
-
class Client < Rainbows::Rev::ThreadClient
|
23
|
+
class Client < Rainbows::Rev::ThreadClient # :nodoc: all
|
24
24
|
def app_dispatch
|
25
25
|
Thread.new(self) { |client| MASTER << [ client, app_response ] }
|
26
26
|
end
|
@@ -28,7 +28,7 @@ module Rainbows
|
|
28
28
|
|
29
29
|
include Rainbows::Rev::Core
|
30
30
|
|
31
|
-
def init_worker_process(worker)
|
31
|
+
def init_worker_process(worker) # :nodoc:
|
32
32
|
super
|
33
33
|
master = Rev::Master.new(Queue.new).attach(::Rev::Loop.default)
|
34
34
|
Client.const_set(:MASTER, master)
|