cmogstored.git  about / heads / tags
alternative mogstored implementation for MogileFS
blob 6731ba51668aa4cb1a0614be570d9a686d1bc125 3892 bytes (raw)
$ git show HEAD: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
 
#!/usr/bin/env ruby
# -*- encoding: binary -*-
# Copyright (C) 2012-2020 all contributors <cmogstored-public@yhbt.net>
# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
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)
      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) # move knob to PWRITE_WRAP_SLOW
    wait_for(5, 'move to slow knob', 0.01) do
      File.readlines(@err.path).grep(/knob set: slow/)[0]
    end
    Process.kill(:TTIN, @pid) # turn on the switch for where the knob is
    wait_for(5, 'enable slow knob', 0.01) do
      File.readlines(@err.path).grep(/flag set: slow/)[0]
    end

    client_2 = get_client

    thr = Thread.new do
      begin
        size = 100 * 1024 * 1024
        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