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.
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