cmogstored.git  about / heads / tags
alternative mogstored implementation for MogileFS
blob d3cde3e5d92df8cb2a0a7c51d055ac05e69da506 3835 bytes (raw)
$ git show valgrind-fixes:test/pwrite_wrap.rb	# shows this blob on the CLI

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
 
#!/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

# this test is horribly slow under valgrind, and we probably don't need
# valgrind, here...
end if File.exist?(TEST_PROG) && ! ENV["VALGRIND"]

git clone https://yhbt.net/cmogstored.git