about summary refs log tree commit homepage
path: root/test/pwrite_wrap.rb
diff options
context:
space:
mode:
Diffstat (limited to 'test/pwrite_wrap.rb')
-rw-r--r--test/pwrite_wrap.rb136
1 files changed, 136 insertions, 0 deletions
diff --git a/test/pwrite_wrap.rb b/test/pwrite_wrap.rb
new file mode 100644
index 0000000..34d342a
--- /dev/null
+++ b/test/pwrite_wrap.rb
@@ -0,0 +1,136 @@
+#!/usr/bin/env ruby
+# -*- encoding: binary -*-
+# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net>
+# License: GPLv3 or later (see COPYING for details)
+require 'test/test_helper'
+require 'timeout'
+
+TEST_PROG = 'test/pwrite-wrap'
+class TestPwriteWrap < Test::Unit::TestCase
+  def setup
+    @tmpdir = Dir.mktmpdir('cmogstored-pwrite-wrap-test')
+    @to_close = []
+    @host = TEST_HOST
+
+    srv = TCPServer.new(@host, 0)
+    @port = srv.addr[1]
+    srv.close
+
+    srv = TCPServer.new(@host, 0)
+    @mgmt_port = srv.addr[1]
+    srv.close
+
+    Dir.mkdir("#@tmpdir/dev666")
+    Dir.mkdir("#@tmpdir/dev333")
+    File.open("#@tmpdir/dev666/get.fid", "w") { |fp|
+      fp.seek(1000)
+      fp.write("\0")
+    }
+
+    @err = Tempfile.new("stderr")
+    cmd = [ TEST_PROG, "--docroot=#@tmpdir", "--httplisten=#@host:#@port",
+            "--mgmtlisten=#@host:#@mgmt_port", "--maxconns=500" ]
+
+    @slow_time = 5000
+    if vg = ENV["VALGRIND"]
+      cmd = vg.split(/\s+/).concat(cmd)
+      # valgrind slows everything down, so increase the sleep time
+      @slow_time *= 2
+    end
+    ENV["PWRITE_WRAP_SLOW_MSEC"] ||= (@slow_time * 2).to_s
+    @pid = fork {
+      $stderr.reopen(@err.path, "a")
+      @err.close
+      exec(*cmd)
+    }
+    @client = get_client
+    @mgmt_client = get_client(300, @mgmt_port)
+    @mgmt_client.write "server aio_threads = 1\r\n"
+    @mgmt_client.gets
+    warning = "fewer aio_threads(1) than devices(2)"
+    wait_for(30, warning) do
+      buf = File.read(@err.path)
+      if buf =~ /aio_threads/
+        puts "BUF: #{buf}"
+      end
+      buf.include?(warning)
+    end
+  end
+
+  def wait_for(sec, reason, res = 0.1)
+    stop = Time.now + sec
+    begin
+      return if yield
+      sleep res
+    end while Time.now < stop
+    assert false, reason
+  end
+
+  def test_pwrite_slow_chunked
+    __test_pwrite_slow(true)
+  end
+
+  def test_pwrite_slow_identity
+    __test_pwrite_slow(false)
+  end
+
+  def __test_pwrite_slow(chunked)
+    Process.kill(:VTALRM, @pid)
+    t_yield
+    Process.kill(:TTIN, @pid)
+    wait_for(5, "enable slow knob") do
+      File.readlines(@err.path).grep(/knob set: slow/)[0] &&
+                       File.readlines(@err.path).grep(/flag set: slow/)[0]
+    end
+
+    client_2 = get_client
+
+    thr = Thread.new do
+      begin
+        size = 1024 * 1024 * 1024 * 10
+        if chunked
+          @client.write("PUT /dev666/foo.fid HTTP/1.1\r\n" \
+                        "Host: example.com\r\n" \
+                        "Transfer-Encoding: chunked\r\n\r\n" \
+                        "#{'%x' % size}\r\n")
+        else
+          @client.write("PUT /dev666/foo.fid HTTP/1.0\r\n" \
+                        "Content-Length: #{size}\r\n\r\n")
+        end
+        IO.copy_stream("/dev/zero", @client, size)
+      rescue => err
+      end
+      err
+    end
+
+    wait_for(5, "temporary file to exist", 0.05) do
+      Dir["#@tmpdir/dev666/foo.*tmp"][0]
+    end
+    t_yield
+
+    # this should cause mog_ioq_contended to return true in http_put.c
+    a = Time.now
+    Timeout.timeout(@slow_time * 4) {
+      client_2.write("GET /dev666/get.fid HTTP/1.0\r\n\r\n")
+      assert_match(%r{HTTP/1\.1 200 OK}, client_2.gets)
+    }
+    diff = Time.now - a
+    assert_operator diff, :<, (@slow_time * 2), "diff=#{diff}"
+    @client.shutdown
+    thr.join
+    Process.kill(:TTOU, @pid)
+    wait_for(5, "clear slow flag") do
+      File.readlines(@err.path).grep(/flag set: slow/)[0]
+    end
+  end
+
+  def teardown
+    Process.kill(:QUIT, @pid) rescue nil
+    _, status = Process.waitpid2(@pid)
+    @to_close.each { |io| io.close unless io.closed? }
+    FileUtils.rm_rf(@tmpdir)
+    @err.rewind
+    $stderr.write(@err.read) if $DEBUG
+    assert status.success?, status.inspect
+  end
+end if File.exist?(TEST_PROG)