about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e+fbsd@80x24.org>2014-07-16 19:32:08 +0000
committerEric Wong <e+fbsd@80x24.org>2014-07-16 19:35:19 +0000
commit54d8f7898470fa2bb08d308876eecf3e32b33dff (patch)
tree066362f517f35972b02b7e1a6a21a0c20166a61c
parent1fd6784e59e9b6d733b1712573d4689affed0140 (diff)
downloadyahns-54d8f7898470fa2bb08d308876eecf3e32b33dff.tar.gz
This bug is noticeable on a amd64 FreeBSD 9.2 VM, and possible under
Linux, too.  This happens as a zero-copy sendfile implementation means
pages queued for transmission by the sendfile system call should not be
modified at any point after the sendfile syscall is made.

To prevent modification, we replace the temporary file with a new one.
This has a similar effect as truncate and can still prevent a dirty
flush in cases when a client consumes the response fast enough.

This reverts the misguided ade89b5142bedbcf07f38aa062bfdbfcb8bc48d3
commit ("wbuf: hack to avoid response corruption on FreeBSD")

Note: this bug was finally fixed because I finally noticed this flaw
in a different (non-Ruby, non-HTTP) server of mine.
-rw-r--r--lib/yahns/wbuf.rb21
1 files changed, 5 insertions, 16 deletions
diff --git a/lib/yahns/wbuf.rb b/lib/yahns/wbuf.rb
index 21bccce..991557e 100644
--- a/lib/yahns/wbuf.rb
+++ b/lib/yahns/wbuf.rb
@@ -30,16 +30,9 @@ require_relative 'wbuf_common'
 class Yahns::Wbuf # :nodoc:
   include Yahns::WbufCommon
 
-  # TODO: Figure out why this hack is needed to pass output buffering tests.
-  # It could be a bug in our code, Ruby, the sendfile gem, or FreeBSD itself.
-  # Tested on FreeBSD fbsd 9.2-RELEASE FreeBSD 9.2-RELEASE #0 r255898
-  # We are able to use bypass mode on Linux to reduce buffering in some
-  # cases.  Without bypass mode, we must always finish writing the entire
-  # response completely before sending more data to the client.
-  bypass_ok = RUBY_PLATFORM =~ /linux/
-
   def initialize(body, persist, tmpdir)
     @tmpio = Yahns::TmpIO.new(tmpdir)
+    @tmpdir = tmpdir
     @sf_offset = @sf_count = 0
     @wbuf_persist = persist # whether or not we keep the connection alive
     @body = body
@@ -71,16 +64,12 @@ class Yahns::Wbuf # :nodoc:
 
     # we're all caught up, try to prevent dirty data from getting flushed
     # to disk if we can help it.
-    @tmpio.truncate(@sf_offset = 0)
-    @tmpio.rewind
+    @tmpio.close
+    @sf_offset = 0
+    @tmpio = Yahns::TmpIO.new(@tmpdir)
     @bypass = true
     nil
-  end if bypass_ok
-
-  def wbuf_write(client, buf)
-    @sf_count += @tmpio.write(buf)
-    :wait_writable
-  end unless bypass_ok
+  end
 
   # called by last wbuf_flush
   def wbuf_close(client)