Rainbows! Rack HTTP server user/dev discussion
 help / Atom feed
From: Eric Wong <e@80x24.org>
To: rainbows-public@bogomips.org
Subject: [PATCH 3/3] bump to unicorn 5.0.1, use monotonic clock
Date: Wed, 18 Nov 2015 03:58:05 +0000
Message-ID: <20151118035805.29572-4-e@80x24.org> (raw)
In-Reply-To: <20151118035805.29572-1-e@80x24.org>

The timeout (mis)feature in unicorn uses the monotonic clock
if available.  We must follow suit to avoid having our timeout
functionality completely broken.
---
 lib/rainbows.rb                            | 19 ++++++++++++++++---
 lib/rainbows/coolio/client.rb              |  2 +-
 lib/rainbows/coolio/heartbeat.rb           |  2 +-
 lib/rainbows/epoll/client.rb               |  4 ++--
 lib/rainbows/fiber.rb                      |  2 +-
 lib/rainbows/fiber/base.rb                 |  4 ++--
 lib/rainbows/fiber/coolio/heartbeat.rb     |  2 +-
 lib/rainbows/fiber/io.rb                   |  2 +-
 lib/rainbows/join_threads.rb               |  4 ++--
 lib/rainbows/process_client.rb             |  4 ++--
 lib/rainbows/thread_timeout.rb             |  8 ++++----
 lib/rainbows/xepoll_thread_pool/client.rb  |  4 ++--
 lib/rainbows/xepoll_thread_spawn/client.rb |  4 ++--
 rainbows.gemspec                           |  2 +-
 t/test_isolate.rb                          |  2 +-
 15 files changed, 39 insertions(+), 26 deletions(-)

diff --git a/lib/rainbows.rb b/lib/rainbows.rb
index 0af5620..f23b387 100644
--- a/lib/rainbows.rb
+++ b/lib/rainbows.rb
@@ -75,8 +75,8 @@ module Rainbows
   end
 
   def self.tick
-    @worker.tick = Time.now.to_i
-    exit!(2) if @expire && Time.now >= @expire
+    @worker.tick = now.to_i
+    exit!(2) if @expire && now >= @expire
     @alive && @server.master_pid == Process.ppid or quit!
   end
 
@@ -88,7 +88,7 @@ module Rainbows
     unless @expire
       @alive = false
       Rainbows::HttpParser.quit
-      @expire = Time.now + (@server.timeout * 2.0)
+      @expire = now + (@server.timeout * 2.0)
       tmp = @readers.dup
       @readers.clear
       tmp.each { |s| s.close rescue nil }.clear
@@ -100,6 +100,19 @@ module Rainbows
     false
   end
 
+  # try to use the monotonic clock in Ruby >= 2.1, it is immune to clock
+  # offset adjustments and generates less garbage (Float vs Time object)
+  begin
+    Process.clock_gettime(Process::CLOCK_MONOTONIC)
+    def self.now
+      Process.clock_gettime(Process::CLOCK_MONOTONIC)
+    end
+  rescue NameError, NoMethodError
+    def self.now # Ruby <= 2.0
+      Rainbows.now
+    end
+  end
+
   autoload :Base, "rainbows/base"
   autoload :WriterThreadPool, "rainbows/writer_thread_pool"
   autoload :WriterThreadSpawn, "rainbows/writer_thread_spawn"
diff --git a/lib/rainbows/coolio/client.rb b/lib/rainbows/coolio/client.rb
index ad827f6..cd22c22 100644
--- a/lib/rainbows/coolio/client.rb
+++ b/lib/rainbows/coolio/client.rb
@@ -154,7 +154,7 @@ class Rainbows::Coolio::Client < Coolio::IO
         # buf == :wait_readable
         unless enabled?
           enable
-          KATO[self] = Time.now
+          KATO[self] = Rainbows.now
         end
       else
         on_read(''.freeze)
diff --git a/lib/rainbows/coolio/heartbeat.rb b/lib/rainbows/coolio/heartbeat.rb
index 3ae9e16..fcfbb0f 100644
--- a/lib/rainbows/coolio/heartbeat.rb
+++ b/lib/rainbows/coolio/heartbeat.rb
@@ -13,7 +13,7 @@ class Rainbows::Coolio::Heartbeat < Coolio::TimerWatcher
 
   def on_timer
     if (ot = KEEPALIVE_TIMEOUT) >= 0
-      ot = Time.now - ot
+      ot = Rainbows.now - ot
       KATO.delete_if { |client, time| time < ot and client.timeout? }
     end
     exit if (! Rainbows.tick && CONN.size <= 0)
diff --git a/lib/rainbows/epoll/client.rb b/lib/rainbows/epoll/client.rb
index 6dcbb81..fe04258 100644
--- a/lib/rainbows/epoll/client.rb
+++ b/lib/rainbows/epoll/client.rb
@@ -14,10 +14,10 @@ module Rainbows::Epoll::Client
   Rainbows.at_quit { KATO.each_key { |k| k.timeout! }.clear }
   Rainbows.config!(self, :keepalive_timeout)
   EP = Rainbows::EP
-  @@last_expire = Time.now
+  @@last_expire = Rainbows.now
 
   def self.expire
-    return if ((now = Time.now) - @@last_expire) < 1.0
+    return if ((now = Rainbows.now) - @@last_expire) < 1.0
     if (ot = KEEPALIVE_TIMEOUT) >= 0
       ot = now - ot
       KATO.delete_if { |client, time| time < ot and client.timeout! }
diff --git a/lib/rainbows/fiber.rb b/lib/rainbows/fiber.rb
index a0f3f99..a37512f 100644
--- a/lib/rainbows/fiber.rb
+++ b/lib/rainbows/fiber.rb
@@ -29,7 +29,7 @@ module Rainbows::Fiber
   # right?).  Calling this directly is deprecated, use
   # Rainbows.sleep(seconds) instead.
   def self.sleep(seconds)
-    ZZ[Fiber.current] = Time.now + seconds
+    ZZ[Fiber.current] = Rainbows.now + seconds
     Fiber.yield
   end
 
diff --git a/lib/rainbows/fiber/base.rb b/lib/rainbows/fiber/base.rb
index e8f5b16..7c4fb59 100644
--- a/lib/rainbows/fiber/base.rb
+++ b/lib/rainbows/fiber/base.rb
@@ -40,7 +40,7 @@ module Rainbows::Fiber::Base
   # woken and returns an interval to IO.select on
   def schedule_sleepers
     max = nil
-    now = Time.now
+    now = Rainbows.now
     fibs = []
     ZZ.delete_if { |fib, time|
       if now >= time
@@ -54,7 +54,7 @@ module Rainbows::Fiber::Base
 
     max_sleep = 1.0 # wake up semi-frequently to prevent SIGKILL from master
     if max
-      max -= Time.now
+      max -= Rainbows.now
       return 0 if max < 0.0
       return max_sleep if max > max_sleep
       max
diff --git a/lib/rainbows/fiber/coolio/heartbeat.rb b/lib/rainbows/fiber/coolio/heartbeat.rb
index 6b1e4f9..7014dbe 100644
--- a/lib/rainbows/fiber/coolio/heartbeat.rb
+++ b/lib/rainbows/fiber/coolio/heartbeat.rb
@@ -5,7 +5,7 @@ class Rainbows::Fiber::Coolio::Heartbeat < Coolio::TimerWatcher
   ZZ = Rainbows::Fiber::ZZ
   def on_timer
     exit if (! Rainbows.tick && Rainbows.cur <= 0)
-    now = Time.now
+    now = Rainbows.now
     fibs = []
     ZZ.delete_if { |fib, time| now >= time ? fibs << fib : ! fib.alive? }
     fibs.each { |fib| fib.resume if fib.alive? }
diff --git a/lib/rainbows/fiber/io.rb b/lib/rainbows/fiber/io.rb
index b121854..111132f 100644
--- a/lib/rainbows/fiber/io.rb
+++ b/lib/rainbows/fiber/io.rb
@@ -63,7 +63,7 @@ class Rainbows::Fiber::IO
     expire = nil
     case rv = Kgio.tryread(@to_io, 16384, buf)
     when :wait_readable
-      return if expire && expire < Time.now
+      return if expire && expire < Rainbows.now
       expire ||= read_expire
       kgio_wait_readable
     else
diff --git a/lib/rainbows/join_threads.rb b/lib/rainbows/join_threads.rb
index 7ab2004..2ae6aa4 100644
--- a/lib/rainbows/join_threads.rb
+++ b/lib/rainbows/join_threads.rb
@@ -5,12 +5,12 @@ module Rainbows::JoinThreads
 
   # blocking acceptor threads must be forced to run
   def self.acceptors(threads)
-    expire = Time.now + Rainbows.server.timeout
+    expire = Rainbows.now + Rainbows.server.timeout
     threads.delete_if do |thr|
       Rainbows.tick
       begin
         # blocking accept() may not wake up properly
-        thr.raise(Errno::EINTR) if Time.now > expire && thr.stop?
+        thr.raise(Errno::EINTR) if Rainbows.now > expire && thr.stop?
 
         thr.run
         thr.join(0.01)
diff --git a/lib/rainbows/process_client.rb b/lib/rainbows/process_client.rb
index a39d6cd..4bf9878 100644
--- a/lib/rainbows/process_client.rb
+++ b/lib/rainbows/process_client.rb
@@ -9,7 +9,7 @@ module Rainbows::ProcessClient
   Rainbows.config!(self, :client_header_buffer_size, :keepalive_timeout)
 
   def read_expire
-    Time.now + KEEPALIVE_TIMEOUT
+    Rainbows.now + KEEPALIVE_TIMEOUT
   end
 
   # used for reading headers (respecting keepalive_timeout)
@@ -18,7 +18,7 @@ module Rainbows::ProcessClient
     begin
       case rv = kgio_tryread(CLIENT_HEADER_BUFFER_SIZE, buf)
       when :wait_readable
-        return if expire && expire < Time.now
+        return if expire && expire < Rainbows.now
         expire ||= read_expire
         kgio_wait_readable(KEEPALIVE_TIMEOUT)
       else
diff --git a/lib/rainbows/thread_timeout.rb b/lib/rainbows/thread_timeout.rb
index 8348272..8739d29 100644
--- a/lib/rainbows/thread_timeout.rb
+++ b/lib/rainbows/thread_timeout.rb
@@ -63,7 +63,7 @@ class Rainbows::ThreadTimeout
 
   # The MRI 1.8 won't be usable in January 2038, we'll raise this
   # when we eventually drop support for 1.8 (before 2038, hopefully)
-  NEVER = Time.at(0x7fffffff)
+  NEVER = 0x7fffffff
 
   def initialize(app, opts)
     # @timeout must be Numeric since we add this to Time
@@ -114,7 +114,7 @@ class Rainbows::ThreadTimeout
     # is hopeless and we might as well just die anyways.
     # initialize guarantees @timeout will be Numeric
     start_watchdog(env) unless @watchdog
-    @active[Thread.current] = Time.now + @timeout
+    @active[Thread.current] = Rainbows.now + @timeout
 
     begin
       # It is important to unlock inside this begin block
@@ -162,7 +162,7 @@ class Rainbows::ThreadTimeout
         # that are about to release themselves from the eye of the
         # watchdog thread.
         @lock.synchronize do
-          now = Time.now
+          now = Rainbows.now
           @active.delete_if do |thread, expire_at|
             # We also use this loop to get the maximum possible time to
             # sleep for if we're not killing the thread.
@@ -184,7 +184,7 @@ class Rainbows::ThreadTimeout
           sleep(@timeout)
         else
           # sleep until the next known thread is about to expire.
-          sec = next_expiry - Time.now
+          sec = next_expiry - Rainbows.now
           sec > 0.0 ? sleep(sec) : Thread.pass # give other threads a chance
         end
       rescue => e
diff --git a/lib/rainbows/xepoll_thread_pool/client.rb b/lib/rainbows/xepoll_thread_pool/client.rb
index 001e69d..760bbde 100644
--- a/lib/rainbows/xepoll_thread_pool/client.rb
+++ b/lib/rainbows/xepoll_thread_pool/client.rb
@@ -46,7 +46,7 @@ module Rainbows::XEpollThreadPool::Client
     LOCK.synchronize { clients = KATO.keys; KATO.clear }
     clients.each { |io| io.closed? or io.close }
   end
-  @@last_expire = Time.now
+  @@last_expire = Rainbows.now
 
   def kato_set
     LOCK.synchronize { KATO[self] = @@last_expire }
@@ -70,7 +70,7 @@ module Rainbows::XEpollThreadPool::Client
   end
 
   def self.expire
-    return if ((now = Time.now) - @@last_expire) < 1.0
+    return if ((now = Rainbows.now) - @@last_expire) < 1.0
     if (ot = KEEPALIVE_TIMEOUT) >= 0
       ot = now - ot
       defer = []
diff --git a/lib/rainbows/xepoll_thread_spawn/client.rb b/lib/rainbows/xepoll_thread_spawn/client.rb
index a3277cf..67c5976 100644
--- a/lib/rainbows/xepoll_thread_spawn/client.rb
+++ b/lib/rainbows/xepoll_thread_spawn/client.rb
@@ -35,7 +35,7 @@ module Rainbows::XEpollThreadSpawn::Client
     LOCK.synchronize { clients = KATO.keys; KATO.clear }
     clients.each { |io| io.closed? or io.shutdown }
   end
-  @@last_expire = Time.now
+  @@last_expire = Rainbows.now
 
   def kato_set
     LOCK.synchronize { KATO[self] = @@last_expire }
@@ -59,7 +59,7 @@ module Rainbows::XEpollThreadSpawn::Client
   end
 
   def self.expire
-    return if ((now = Time.now) - @@last_expire) < 1.0
+    return if ((now = Rainbows.now) - @@last_expire) < 1.0
     if (ot = KEEPALIVE_TIMEOUT) >= 0
       ot = now - ot
       defer = []
diff --git a/rainbows.gemspec b/rainbows.gemspec
index afc8b5a..6ddf630 100644
--- a/rainbows.gemspec
+++ b/rainbows.gemspec
@@ -27,7 +27,7 @@ Gem::Specification.new do |s|
   # we need unicorn for the HTTP parser and process management
   # we need unicorn 4.8.0+ since we depend on undocumented/unsupported
   # unicorn internals.
-  s.add_dependency(%q<unicorn>, ["~> 4.8"])
+  s.add_dependency(%q<unicorn>, ["~> 5.0"])
 
   s.add_development_dependency(%q<isolate>, "~> 3.1")
   s.add_development_dependency(%q<olddoc>, "~> 1.0")
diff --git a/t/test_isolate.rb b/t/test_isolate.rb
index 98918f6..58bc4dc 100644
--- a/t/test_isolate.rb
+++ b/t/test_isolate.rb
@@ -20,7 +20,7 @@ Isolate.now!(opts) do
   gem 'rack', '1.6.4'
   gem 'kcar', '0.5.0'
   gem 'raindrops', '0.13.0'
-  gem 'unicorn', '4.9.0'
+  gem 'unicorn', '5.0.1'
 
   if engine == "ruby"
     gem 'sendfile', '1.2.2'
-- 
EW


      parent reply index

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-18  3:58 [PATCH 0/3] final round of changes for unicorn 5 compatibility Eric Wong
2015-11-18  3:58 ` [PATCH 1/3] http_server: add master_pid attribute Eric Wong
2015-11-18  3:58 ` [PATCH 2/3] stream_response_epoll: remove hijack_prepare call Eric Wong
2015-11-18  3:58 ` Eric Wong [this message]

Reply instructions:

You may reply publically to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://bogomips.org/rainbows/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20151118035805.29572-4-e@80x24.org \
    --to=e@80x24.org \
    --cc=rainbows-public@bogomips.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Rainbows! Rack HTTP server user/dev discussion

Archives are clonable:
	git clone --mirror https://bogomips.org/rainbows-public
	git clone --mirror http://ou63pmih66umazou.onion/rainbows-public

Newsgroups are available over NNTP:
	nntp://news.public-inbox.org/inbox.comp.lang.ruby.rainbows
	nntp://ou63pmih66umazou.onion/inbox.comp.lang.ruby.rainbows

 note: .onion URLs require Tor: https://www.torproject.org/
       or Tor2web: https://www.tor2web.org/

AGPL code for this site: git clone https://public-inbox.org/ public-inbox