mogilefs-client 3.0.0.rc1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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