cmogstored.git  about / heads / tags
alternative mogstored implementation for MogileFS
blob b9a79a865651fc92bdf31e67160a3f1bd1a7a714 3885 bytes (raw)
$ git show gl-env: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-2016 all contributors <cmogstored-public@bogomips.org>
# 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)
      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