rainbows 2.0.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. data/.document +1 -0
  2. data/.gitignore +1 -0
  3. data/.manifest +46 -18
  4. data/.wrongdoc.yml +8 -0
  5. data/ChangeLog +849 -374
  6. data/Documentation/comparison.haml +26 -21
  7. data/FAQ +6 -0
  8. data/GIT-VERSION-GEN +1 -1
  9. data/GNUmakefile +23 -65
  10. data/LATEST +27 -0
  11. data/NEWS +53 -26
  12. data/README +7 -7
  13. data/Rakefile +1 -98
  14. data/Summary +0 -7
  15. data/TODO +2 -2
  16. data/lib/rainbows/app_pool.rb +2 -1
  17. data/lib/rainbows/base.rb +1 -0
  18. data/lib/rainbows/configurator.rb +9 -0
  19. data/lib/rainbows/const.rb +1 -1
  20. data/lib/rainbows/coolio/client.rb +191 -0
  21. data/lib/rainbows/coolio/core.rb +25 -0
  22. data/lib/rainbows/{rev → coolio}/deferred_chunk_response.rb +3 -2
  23. data/lib/rainbows/{rev → coolio}/deferred_response.rb +3 -3
  24. data/lib/rainbows/coolio/heartbeat.rb +20 -0
  25. data/lib/rainbows/{rev → coolio}/master.rb +2 -3
  26. data/lib/rainbows/{rev → coolio}/sendfile.rb +1 -1
  27. data/lib/rainbows/coolio/server.rb +11 -0
  28. data/lib/rainbows/coolio/thread_client.rb +36 -0
  29. data/lib/rainbows/coolio.rb +45 -0
  30. data/lib/rainbows/coolio_fiber_spawn.rb +26 -0
  31. data/lib/rainbows/coolio_support.rb +9 -0
  32. data/lib/rainbows/coolio_thread_pool/client.rb +8 -0
  33. data/lib/rainbows/coolio_thread_pool/watcher.rb +14 -0
  34. data/lib/rainbows/coolio_thread_pool.rb +57 -0
  35. data/lib/rainbows/coolio_thread_spawn/client.rb +8 -0
  36. data/lib/rainbows/coolio_thread_spawn.rb +27 -0
  37. data/lib/rainbows/dev_fd_response.rb +6 -2
  38. data/lib/rainbows/ev_core/cap_input.rb +3 -2
  39. data/lib/rainbows/ev_core.rb +13 -3
  40. data/lib/rainbows/event_machine/client.rb +124 -0
  41. data/lib/rainbows/event_machine/response_pipe.rb +1 -2
  42. data/lib/rainbows/event_machine/server.rb +15 -0
  43. data/lib/rainbows/event_machine.rb +13 -137
  44. data/lib/rainbows/fiber/base.rb +6 -7
  45. data/lib/rainbows/fiber/body.rb +4 -2
  46. data/lib/rainbows/fiber/coolio/heartbeat.rb +15 -0
  47. data/lib/rainbows/fiber/{rev → coolio}/methods.rb +4 -5
  48. data/lib/rainbows/fiber/{rev → coolio}/server.rb +1 -1
  49. data/lib/rainbows/fiber/{rev → coolio}/sleeper.rb +2 -2
  50. data/lib/rainbows/fiber/coolio.rb +12 -0
  51. data/lib/rainbows/fiber/io/methods.rb +6 -0
  52. data/lib/rainbows/fiber/io.rb +8 -10
  53. data/lib/rainbows/fiber/queue.rb +24 -30
  54. data/lib/rainbows/fiber.rb +7 -4
  55. data/lib/rainbows/fiber_pool.rb +1 -1
  56. data/lib/rainbows/http_server.rb +9 -2
  57. data/lib/rainbows/max_body.rb +3 -1
  58. data/lib/rainbows/never_block/core.rb +15 -0
  59. data/lib/rainbows/never_block/event_machine.rb +8 -3
  60. data/lib/rainbows/never_block.rb +37 -70
  61. data/lib/rainbows/process_client.rb +3 -6
  62. data/lib/rainbows/rack_input.rb +17 -0
  63. data/lib/rainbows/response/body.rb +18 -19
  64. data/lib/rainbows/response.rb +1 -1
  65. data/lib/rainbows/rev.rb +21 -43
  66. data/lib/rainbows/rev_fiber_spawn.rb +4 -19
  67. data/lib/rainbows/rev_thread_pool.rb +21 -75
  68. data/lib/rainbows/rev_thread_spawn.rb +18 -36
  69. data/lib/rainbows/revactor/body.rb +4 -1
  70. data/lib/rainbows/revactor/tee_socket.rb +44 -0
  71. data/lib/rainbows/revactor.rb +13 -48
  72. data/lib/rainbows/socket_proxy.rb +24 -0
  73. data/lib/rainbows/sync_close.rb +37 -0
  74. data/lib/rainbows/thread_pool.rb +66 -70
  75. data/lib/rainbows/thread_spawn.rb +40 -50
  76. data/lib/rainbows/thread_timeout.rb +33 -27
  77. data/lib/rainbows/timed_read.rb +5 -1
  78. data/lib/rainbows/worker_yield.rb +16 -0
  79. data/lib/rainbows/writer_thread_pool/client.rb +19 -0
  80. data/lib/rainbows/writer_thread_pool.rb +60 -91
  81. data/lib/rainbows/writer_thread_spawn/client.rb +69 -0
  82. data/lib/rainbows/writer_thread_spawn.rb +37 -117
  83. data/lib/rainbows.rb +12 -4
  84. data/rainbows.gemspec +15 -19
  85. data/t/GNUmakefile +4 -4
  86. data/t/close-has-env.ru +65 -0
  87. data/t/simple-http_Coolio.ru +9 -0
  88. data/t/simple-http_CoolioFiberSpawn.ru +10 -0
  89. data/t/simple-http_CoolioThreadPool.ru +9 -0
  90. data/t/simple-http_CoolioThreadSpawn.ru +9 -0
  91. data/t/t0004-heartbeat-timeout.sh +2 -2
  92. data/t/t0007-worker-follows-master-to-death.sh +1 -1
  93. data/t/t0015-working_directory.sh +7 -1
  94. data/t/t0017-keepalive-timeout-zero.sh +1 -1
  95. data/t/t0019-keepalive-cpu-usage.sh +62 -0
  96. data/t/t0040-keepalive_requests-setting.sh +51 -0
  97. data/t/t0050-response-body-close-has-env.sh +109 -0
  98. data/t/t0102-rack-input-short.sh +6 -6
  99. data/t/t0106-rack-input-keepalive.sh +48 -2
  100. data/t/t0113-rewindable-input-false.sh +28 -0
  101. data/t/t0113.ru +12 -0
  102. data/t/t0114-rewindable-input-true.sh +28 -0
  103. data/t/t0114.ru +12 -0
  104. data/t/t9100-thread-timeout.sh +24 -2
  105. data/t/t9101-thread-timeout-threshold.sh +6 -13
  106. data/t/test-lib.sh +2 -1
  107. data/t/test_isolate.rb +9 -4
  108. data/t/times.ru +6 -0
  109. metadata +109 -42
  110. data/GIT-VERSION-FILE +0 -1
  111. data/lib/rainbows/fiber/rev/heartbeat.rb +0 -8
  112. data/lib/rainbows/fiber/rev/kato.rb +0 -22
  113. data/lib/rainbows/fiber/rev.rb +0 -13
  114. data/lib/rainbows/rev/client.rb +0 -194
  115. data/lib/rainbows/rev/core.rb +0 -41
  116. data/lib/rainbows/rev/heartbeat.rb +0 -23
  117. data/lib/rainbows/rev/thread.rb +0 -46
  118. data/man/man1/rainbows.1 +0 -193
@@ -18,7 +18,7 @@ class Rainbows::Fiber::IO
18
18
  end
19
19
  # :startdoc:
20
20
 
21
- # needed to write errors with
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..-1)
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, range) # :nodoc:
70
- if buf.encoding != Encoding::BINARY
71
- buf.dup.force_encoding(Encoding::BINARY)[range]
72
- else
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 ||= Time.now + G.kato
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 ||= Time.now + G.kato
94
+ expire ||= read_expire
97
95
  kgio_wait_readable
98
96
  end while true
99
97
  end
@@ -1,36 +1,30 @@
1
1
  # -*- encoding: binary -*-
2
2
  # :enddoc:
3
- module Rainbows
4
- module Fiber
5
-
6
- # a self-sufficient Queue implementation for Fiber-based concurrency
7
- # models. This requires no external scheduler, so it may be used with
8
- # Revactor as well as FiberSpawn and FiberPool.
9
- class Queue < Struct.new(:queue, :waiters)
10
-
11
- def initialize(queue = [], waiters = [])
12
- # move elements of the Queue into an Array
13
- if queue.class.name == "Queue"
14
- queue = queue.length.times.map { queue.pop }
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
@@ -1,14 +1,16 @@
1
1
  # -*- encoding: binary -*-
2
- # :enddoc:
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 module for all things that use Fibers in Rainbows!
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[::Fiber.current] = Time.now + seconds
28
- ::Fiber.yield
30
+ ZZ[Fiber.current] = Time.now + seconds
31
+ Fiber.yield
29
32
  end
30
33
 
31
34
  autoload :Base, 'rainbows/fiber/base'
@@ -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 ::Fiber.yield so it waits on a client
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
 
@@ -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,:EventMachine,:NeverBlock].include?(@use),
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, "keepalive must be a non-negative Integer"
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
@@ -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, :EventMachine, :NeverBlock, :RevThreadSpawn, :RevThreadPool
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
- module Rainbows
4
- module NeverBlock
5
- class Client < Rainbows::EventMachine::Client
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
@@ -1,75 +1,42 @@
1
1
  # -*- encoding: binary -*-
2
2
 
3
- module Rainbows
4
-
5
- # {NeverBlock}[www.espace.com.eg/neverblock/] library that combines
6
- # the EventMachine library with Ruby Fibers. This includes use of
7
- # Thread-based Fibers under Ruby 1.8. It currently does NOT support
8
- # a streaming "rack.input" but is compatible with everything else
9
- # EventMachine supports.
10
- #
11
- # In your Rainbows! config block, you may specify a Fiber pool size
12
- # to limit your application concurrency (without using Rainbows::AppPool)
13
- #
14
- # Rainbows! do
15
- # use :NeverBlock, :pool_size => 50
16
- # worker_connections 100
17
- # end
18
- #
19
- module NeverBlock
20
-
21
- # :stopdoc:
22
- DEFAULTS = {
23
- :pool_size => 20, # same default size used by NB
24
- :backend => :EventMachine, # NeverBlock doesn't support Rev yet
25
- }
26
-
27
- # same pool size NB core itself uses
28
- def self.setup # :nodoc:
29
- DEFAULTS.each { |k,v| O[k] ||= v }
30
- Integer === O[:pool_size] && O[:pool_size] > 0 or
31
- raise ArgumentError, "pool_size must a be an Integer > 0"
32
- mod = Rainbows.const_get(O[:backend])
33
- require "never_block" # require EM first since we need a higher version
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
- NULL_IO = Unicorn::HttpRequest::NULL_IO
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[CLIENT_IO] = client
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) || IO.new(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) : File.open(path)
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
- range ? sock.sendfile(body, range[0], range[1]) : sock.sendfile(body, 0)
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
- inp = body_to_io(body)
86
- if inp.stat.file?
87
- begin
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) && inp != body and body.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, inp = body_to_io(body), range)
99
+ write_body_stream(sock, body, range)
101
100
  ensure
102
- body.respond_to?(:close) && inp != body and body.close
101
+ body.respond_to?(:close) and body.close
103
102
  end
104
103
  end
105
104
 
@@ -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::MySocket
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
- require 'rainbows/rev/core'
3
- require 'rainbows/rev/client'
4
-
5
- module Rainbows
6
-
7
- # Implements a basic single-threaded event model with
8
- # {Rev}[http://rev.rubyforge.org/]. It is capable of handling
9
- # thousands of simultaneous client connections, but with only a
10
- # single-threaded app dispatch. It is suited for slow clients and
11
- # fast applications (applications that do not have slow network
12
- # dependencies) or applications that use DevFdResponse for deferrable
13
- # response bodies. It does not require your Rack application to be
14
- # thread-safe, reentrancy is only required for the DevFdResponse body
15
- # generator.
16
- #
17
- # Compatibility: Whatever \Rev itself supports, currently Ruby
18
- # 1.8/1.9.
19
- #
20
- # This model does not implement as streaming "rack.input" which
21
- # allows the Rack application to process data as it arrives. This
22
- # means "rack.input" will be fully buffered in memory or to a
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
- require 'rainbows/fiber/rev'
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