mogilefs-client 3.0.0.rc1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/GIT-VERSION-GEN CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  CONSTANT = "MogileFS::VERSION"
3
3
  RVF = "lib/mogilefs/version.rb"
4
- DEF_VER = "v3.0.0-rc1"
4
+ DEF_VER = "v3.0.0"
5
5
  vn = DEF_VER
6
6
 
7
7
  # First see if there is a version file (included in release tarballs),
@@ -1,5 +1,4 @@
1
1
  # -*- encoding: binary -*-
2
- require 'tempfile'
3
2
  require 'digest/md5'
4
3
  require 'rack'
5
4
 
@@ -22,11 +21,28 @@ class MogstoredRack
22
21
 
23
22
  def initialize(root, opts = {})
24
23
  @root = File.expand_path(root)
24
+ @io_size = opts[:io_size] || 0x100000
25
25
  @rack_file = (opts[:app] || Rack::File.new(@root))
26
26
  @fsync = !! opts[:fsync]
27
27
  @creat_perms = opts[:creat_perms] || (~File.umask & 0666)
28
28
  @mkdir_perms = opts[:mkdir_perms] || (~File.umask & 0777)
29
29
  @reread_verify = !! opts[:reread_verify]
30
+ @open_flags = opts[:open_flags] || 0
31
+ @open_flags |= IO::RDWR | IO::CREAT | IO::EXCL
32
+ end
33
+
34
+ def tmpfile(basename, dir)
35
+ t = Time.now.utc.strftime("%Y%m%d%H%M%S")
36
+ seq = 0
37
+ begin
38
+ fp = File.open("#{dir}/#{basename}.#{t}.#{seq}.tmp", @open_flags, 0600)
39
+ rescue Errno::EEXIST
40
+ retry if (seq += 1) < 10
41
+ raise
42
+ end
43
+ fp.binmode
44
+ fp.sync = true
45
+ fp
30
46
  end
31
47
 
32
48
  def call(env)
@@ -75,32 +91,29 @@ class MogstoredRack
75
91
  dir = File.dirname(path)
76
92
  File.directory?(dir) or return r(403)
77
93
 
78
- Tempfile.open([File.basename(path), ".tmp"], dir) do |tmp|
79
- tmp = tmp.to_io # delegated method calls are slower
80
- tmp.sync = true
81
- tmp.binmode
82
- buf = ""
83
- received = put_loop(env["rack.input"], tmp, buf)
84
- err = content_md5_fail?(env, received) and return err
85
- if @reread_verify && err = reread_md5_fail?(env, tmp, received, buf)
86
- return err
87
- end
88
- tmp.chmod(@creat_perms)
89
- begin
90
- File.link(tmp.path, path)
91
- rescue Errno::EEXIST
92
- err = rename_overwrite_fail?(tmp.path, path) and return err
93
- end
94
- fsync(dir, tmp) if @fsync
95
- resp = r(201)
96
- resp[1]["X-Received-Content-MD5"] = received
97
- return resp
94
+ tmp = tmpfile(File.basename(path), dir)
95
+ buf = ""
96
+ received = put_loop(env["rack.input"], tmp, buf)
97
+ err = content_md5_fail?(env, received) and return err
98
+ if @reread_verify && err = reread_md5_fail?(env, tmp, received, buf)
99
+ return err
98
100
  end
101
+ tmp.chmod(@creat_perms)
102
+ File.rename(tmp.path, path)
103
+ fsync(dir, tmp) if @fsync
104
+ resp = r(201)
105
+ resp[1]["X-Received-Content-MD5"] = received
106
+ resp
107
+ rescue
108
+ File.unlink(tmp.path) if tmp && File.exist?(tmp.path)
109
+ raise
110
+ ensure
111
+ tmp.close if tmp
99
112
  end
100
113
 
101
114
  def put_loop(src, dst, buf)
102
115
  md5 = ContentMD5.new
103
- while src.read(0x4000, buf)
116
+ while src.read(@io_size, buf)
104
117
  md5.update(buf)
105
118
  dst.write(buf)
106
119
  end
@@ -167,20 +180,6 @@ class MogstoredRack
167
180
  "received: #{received}", env)
168
181
  end
169
182
 
170
- def rename_overwrite_fail?(src, dst)
171
- 10.times do
172
- begin
173
- tmp_dst = "#{dst}.#{rand}"
174
- File.link(src, tmp_dst)
175
- rescue Errno::EEXIST
176
- next
177
- end
178
- File.rename(tmp_dst, dst)
179
- return false # success!
180
- end
181
- r(409)
182
- end
183
-
184
183
  # fsync each and every directory component above us on the same device
185
184
  def fsync(dir, tmp)
186
185
  tmp.fsync
@@ -295,7 +295,10 @@ class MogileFS::Backend
295
295
  # Turns the +line+ response from the server into a Hash of options, an
296
296
  # error, or raises, as appropriate.
297
297
  def parse_response(line, request = nil)
298
- if line =~ /^ERR\s+(\w+)\s*([^\r\n]*)/
298
+ case line
299
+ when /\AOK\s+\d*\s*(\S*)\r?\n\z/
300
+ url_decode($1)
301
+ when /\AERR\s+(\w+)\s*([^\r\n]*)/
299
302
  @lasterr = $1
300
303
  @lasterrstr = $2 ? url_unescape($2) : nil
301
304
  if request
@@ -304,12 +307,10 @@ class MogileFS::Backend
304
307
  return error(@lasterr).new(@lasterrstr)
305
308
  end
306
309
  raise error(@lasterr).new(@lasterrstr)
310
+ else
311
+ raise MogileFS::InvalidResponseError,
312
+ "Invalid response from server: #{line.inspect}"
307
313
  end
308
-
309
- return url_decode($1) if line =~ /^OK\s+\d*\s*(\S*)\r\n\z/
310
-
311
- raise MogileFS::InvalidResponseError,
312
- "Invalid response from server: #{line.inspect}"
313
314
  end
314
315
 
315
316
  # this command is special since the cache is per-tracker, so we connect
@@ -3,7 +3,7 @@
3
3
  # internal compatibility class for older Rubies
4
4
  module MogileFS::CopyStream # :nodoc:
5
5
  @r_args = IO::RDONLY | IO::NOCTTY
6
- @w_args = [ IO::WRONLY|IO::CREAT|IO::NOCTTY|IO::TRUNC, 0600 ]
6
+ @w_args = [ IO::WRONLY|IO::CREAT|IO::NOCTTY|IO::TRUNC, 0666 ]
7
7
  def self.copy_stream(src, dst)
8
8
  src_io = src.respond_to?(:to_str) ? File.open(src, @r_args) : src
9
9
  dst_io = dst.respond_to?(:to_str) ? File.open(dst, *@w_args) : dst
@@ -20,12 +20,27 @@ class MogileFS::HTTPFile < StringIO
20
20
  end
21
21
  class NonRetryableError < MogileFS::Error; end
22
22
 
23
+ class HTTPSock < MogileFS::Socket
24
+ attr_accessor :start
25
+
26
+ # Increase timeout as we become more invested in uploading with
27
+ # this socket. The server could be experiencing I/O delays
28
+ # from large uploads because the sysadmin forgot to tune the
29
+ # VM sysctls for handling large files.
30
+ def write(buf)
31
+ timed_write(buf, Time.now - @start + 5.0)
32
+ end
33
+ end
34
+
23
35
  # :stopdoc:
24
36
  MD5_TRAILER_NODES = {} # :nodoc: # EXPERIMENTAL
25
37
  class << self
26
38
  attr_accessor :response_timeout_cb
27
39
  end
28
40
 
41
+ # temporary directories (nginx) may not be configured on the
42
+ # same device, necessitating a time-consuming full file copy
43
+ # instead of a quick rename(2)/link(2) operation
29
44
  @response_timeout_cb = lambda do |elapsed_time, bytes_uploaded|
30
45
  mbytes_uploaded = bytes_uploaded / (1024.0 * 1024.0)
31
46
  # assumes worst case is 10M/s on the remote storage disk
@@ -107,7 +122,8 @@ class MogileFS::HTTPFile < StringIO
107
122
  # returns file size if the socket finished writing
108
123
  def upload(devid, uri) # :nodoc:
109
124
  start = Time.now
110
- sock = MogileFS::Socket.tcp(uri.host, uri.port)
125
+ sock = HTTPSock.tcp(uri.host, uri.port)
126
+ sock.start = start
111
127
  file_size = length
112
128
 
113
129
  if @streaming_io
@@ -50,6 +50,4 @@ class MogileFS::Socket < Kgio::Socket
50
50
  return expect
51
51
  end while true
52
52
  end
53
-
54
- alias write timed_write
55
53
  end
@@ -65,6 +65,4 @@ class MogileFS::Socket < Socket
65
65
  request_truncated!(written, expect)
66
66
  end while true
67
67
  end
68
-
69
- alias write timed_write
70
68
  end
@@ -249,7 +249,7 @@ class TestMogileFS__MogileFS < TestMogileFS
249
249
  end
250
250
 
251
251
  def test_store_content_http
252
- received = Tempfile.new('recieved')
252
+ received = Tempfile.new('received')
253
253
  expected = "PUT /path HTTP/1.0\r\nContent-Length: 4\r\n\r\ndata"
254
254
 
255
255
  t = TempServer.new(Proc.new do |serv, accept|
@@ -282,7 +282,7 @@ class TestMogileFS__MogileFS < TestMogileFS
282
282
 
283
283
 
284
284
  def test_store_content_with_writer_callback
285
- received = Tempfile.new('recieved')
285
+ received = Tempfile.new('received')
286
286
  expected = "PUT /path HTTP/1.0\r\nContent-Length: 40\r\n\r\n"
287
287
  10.times do
288
288
  expected += "data"
@@ -19,8 +19,6 @@ class TestMogileFSIntegration < TestMogIntegration
19
19
  tmp.close!
20
20
  assert_equal 4, @client.get_file_data("CRUD", tmp_path)
21
21
  assert_equal "DATA", File.read(tmp_path)
22
- st = File.stat(tmp_path)
23
- assert_equal 0100600, st.mode
24
22
  File.unlink(tmp_path)
25
23
 
26
24
  sio = StringIO.new("")
metadata CHANGED
@@ -1,15 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mogilefs-client
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15424119
5
- prerelease: 6
4
+ hash: 7
5
+ prerelease:
6
6
  segments:
7
7
  - 3
8
8
  - 0
9
9
  - 0
10
- - rc
11
- - 1
12
- version: 3.0.0.rc1
10
+ version: 3.0.0
13
11
  platform: ruby
14
12
  authors:
15
13
  - Eric Wong
@@ -17,7 +15,7 @@ autorequire:
17
15
  bindir: bin
18
16
  cert_chain: []
19
17
 
20
- date: 2011-11-21 00:00:00 Z
18
+ date: 2011-11-28 00:00:00 Z
21
19
  dependencies:
22
20
  - !ruby/object:Gem::Dependency
23
21
  name: hoe
@@ -130,14 +128,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
130
128
  required_rubygems_version: !ruby/object:Gem::Requirement
131
129
  none: false
132
130
  requirements:
133
- - - ">"
131
+ - - ">="
134
132
  - !ruby/object:Gem::Version
135
- hash: 25
133
+ hash: 3
136
134
  segments:
137
- - 1
138
- - 3
139
- - 1
140
- version: 1.3.1
135
+ - 0
136
+ version: "0"
141
137
  requirements: []
142
138
 
143
139
  rubyforge_project: seattlerb