aws-sdk-s3 1.132.0 → 1.133.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/VERSION +1 -1
- data/lib/aws-sdk-s3/client.rb +1 -1
- data/lib/aws-sdk-s3/customizations/object.rb +45 -2
- data/lib/aws-sdk-s3/file_downloader.rb +120 -24
- data/lib/aws-sdk-s3.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04f11cfde483787571492064565bb589b16323f4bb7f33f5a7507b993f6cead3
|
4
|
+
data.tar.gz: 1dd900a34a20b97fb82c41407ca12c40d33397fb14e29678e0f7e3b0a1e5b77c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 745b68d37b0845463f3c2a1cfdb29e8833bd0d723e31a1071c1f3936f095e4c735c909573c8df49f077b3f56dfa13f9e45552c68d7e5a5c0718b67d3f08418e2
|
7
|
+
data.tar.gz: f995dde0e5628863ab664b36a4db27a23e8d68827aab268fecacfa217a104f1bb3cfd67e84bf6729e52544d9015fd3c64765a53fe0758647e5904c1f104235e1
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,18 @@
|
|
1
1
|
Unreleased Changes
|
2
2
|
------------------
|
3
3
|
|
4
|
+
1.133.0 (2023-08-22)
|
5
|
+
------------------
|
6
|
+
|
7
|
+
* Feature - Code Generated Changes, see `./build_tools` or `aws-sdk-core`'s CHANGELOG.md for details.
|
8
|
+
|
9
|
+
* Feature - Add support for `progress_callback` in `Object#download_file` and improve multi-threaded performance #(2901).
|
10
|
+
|
11
|
+
1.132.1 (2023-08-09)
|
12
|
+
------------------
|
13
|
+
|
14
|
+
* Issue - Add support for disabling checksum validation in `Object#download_file` (#2893).
|
15
|
+
|
4
16
|
1.132.0 (2023-07-24)
|
5
17
|
------------------
|
6
18
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.133.0
|
data/lib/aws-sdk-s3/client.rb
CHANGED
@@ -15653,7 +15653,7 @@ module Aws::S3
|
|
15653
15653
|
params: params,
|
15654
15654
|
config: config)
|
15655
15655
|
context[:gem_name] = 'aws-sdk-s3'
|
15656
|
-
context[:gem_version] = '1.
|
15656
|
+
context[:gem_version] = '1.133.0'
|
15657
15657
|
Seahorse::Client::Request.new(handlers, context)
|
15658
15658
|
end
|
15659
15659
|
|
@@ -353,6 +353,10 @@ module Aws
|
|
353
353
|
# obj.upload_stream do |write_stream|
|
354
354
|
# IO.copy_stream(STDIN, write_stream)
|
355
355
|
# end
|
356
|
+
# @param [Hash] options
|
357
|
+
# Additional options for {Client#create_multipart_upload},
|
358
|
+
# {Client#complete_multipart_upload},
|
359
|
+
# and {Client#upload_part} can be provided.
|
356
360
|
#
|
357
361
|
# @option options [Integer] :thread_count (10) The number of parallel
|
358
362
|
# multipart uploads
|
@@ -375,6 +379,9 @@ module Aws
|
|
375
379
|
# @return [Boolean] Returns `true` when the object is uploaded
|
376
380
|
# without any errors.
|
377
381
|
#
|
382
|
+
# @see Client#create_multipart_upload
|
383
|
+
# @see Client#complete_multipart_upload
|
384
|
+
# @see Client#upload_part
|
378
385
|
def upload_stream(options = {}, &block)
|
379
386
|
uploading_options = options.dup
|
380
387
|
uploader = MultipartStreamUploader.new(
|
@@ -427,6 +434,13 @@ module Aws
|
|
427
434
|
# using an open Tempfile, rewind it before uploading or else the object
|
428
435
|
# will be empty.
|
429
436
|
#
|
437
|
+
# @param [Hash] options
|
438
|
+
# Additional options for {Client#put_object}
|
439
|
+
# when file sizes below the multipart threshold. For files larger than
|
440
|
+
# the multipart threshold, options for {Client#create_multipart_upload},
|
441
|
+
# {Client#complete_multipart_upload},
|
442
|
+
# and {Client#upload_part} can be provided.
|
443
|
+
#
|
430
444
|
# @option options [Integer] :multipart_threshold (104857600) Files larger
|
431
445
|
# than or equal to `:multipart_threshold` are uploaded using the S3
|
432
446
|
# multipart APIs.
|
@@ -448,6 +462,11 @@ module Aws
|
|
448
462
|
#
|
449
463
|
# @return [Boolean] Returns `true` when the object is uploaded
|
450
464
|
# without any errors.
|
465
|
+
#
|
466
|
+
# @see Client#put_object
|
467
|
+
# @see Client#create_multipart_upload
|
468
|
+
# @see Client#complete_multipart_upload
|
469
|
+
# @see Client#upload_part
|
451
470
|
def upload_file(source, options = {})
|
452
471
|
uploading_options = options.dup
|
453
472
|
uploader = FileUploader.new(
|
@@ -475,8 +494,21 @@ module Aws
|
|
475
494
|
# # and the parts are downloaded in parallel
|
476
495
|
# obj.download_file('/path/to/very_large_file')
|
477
496
|
#
|
497
|
+
# You can provide a callback to monitor progress of the download:
|
498
|
+
#
|
499
|
+
# # bytes and part_sizes are each an array with 1 entry per part
|
500
|
+
# # part_sizes may not be known until the first bytes are retrieved
|
501
|
+
# progress = Proc.new do |bytes, part_sizes, file_size|
|
502
|
+
# puts bytes.map.with_index { |b, i| "Part #{i+1}: #{b} / #{part_sizes[i]}"}.join(' ') + "Total: #{100.0 * bytes.sum / file_size}%" }
|
503
|
+
# end
|
504
|
+
# obj.download_file('/path/to/file', progress_callback: progress)
|
505
|
+
#
|
478
506
|
# @param [String] destination Where to download the file to.
|
479
507
|
#
|
508
|
+
# @param [Hash] options
|
509
|
+
# Additional options for {Client#get_object} and #{Client#head_object}
|
510
|
+
# may be provided.
|
511
|
+
#
|
480
512
|
# @option options [String] mode `auto`, `single_request`, `get_range`
|
481
513
|
# `single_request` mode forces only 1 GET request is made in download,
|
482
514
|
# `get_range` mode allows `chunk_size` parameter to configured in
|
@@ -496,16 +528,27 @@ module Aws
|
|
496
528
|
# the object has a stored checksum, it will be used to validate the
|
497
529
|
# download and will raise an `Aws::Errors::ChecksumError` if
|
498
530
|
# checksum validation fails. You may provide a `on_checksum_validated`
|
499
|
-
# callback if you need to verify that validation
|
500
|
-
# algorithm was used.
|
531
|
+
# callback if you need to verify that validation occurred and which
|
532
|
+
# algorithm was used. To disable checksum validation, set
|
533
|
+
# `checksum_mode` to "DISABLED".
|
501
534
|
#
|
502
535
|
# @option options [Callable] on_checksum_validated Called each time a
|
503
536
|
# request's checksum is validated with the checksum algorithm and the
|
504
537
|
# response. For multipart downloads, this will be called for each
|
505
538
|
# part that is downloaded and validated.
|
506
539
|
#
|
540
|
+
# @option options [Proc] :progress_callback
|
541
|
+
# A Proc that will be called when each chunk of the download is received.
|
542
|
+
# It will be invoked with [bytes_read], [part_sizes], file_size.
|
543
|
+
# When the object is downloaded as parts (rather than by ranges), the
|
544
|
+
# part_sizes will not be known ahead of time and will be nil in the
|
545
|
+
# callback until the first bytes in the part are received.
|
546
|
+
#
|
507
547
|
# @return [Boolean] Returns `true` when the file is downloaded without
|
508
548
|
# any errors.
|
549
|
+
#
|
550
|
+
# @see Client#get_object
|
551
|
+
# @see Client#head_object
|
509
552
|
def download_file(destination, options = {})
|
510
553
|
downloader = FileDownloader.new(client: client)
|
511
554
|
Aws::Plugins::UserAgent.feature('resource') do
|
@@ -31,9 +31,17 @@ module Aws
|
|
31
31
|
key: options[:key],
|
32
32
|
}
|
33
33
|
@params[:version_id] = options[:version_id] if options[:version_id]
|
34
|
-
|
34
|
+
|
35
|
+
# checksum_mode only supports the value "ENABLED"
|
36
|
+
# falsey values (false/nil) or "DISABLED" should be considered
|
37
|
+
# disabled and the api parameter should be unset.
|
38
|
+
if (checksum_mode = options.fetch(:checksum_mode, 'ENABLED'))
|
39
|
+
@params[:checksum_mode] = checksum_mode unless checksum_mode.upcase == 'DISABLED'
|
40
|
+
end
|
35
41
|
@on_checksum_validated = options[:on_checksum_validated]
|
36
42
|
|
43
|
+
@progress_callback = options[:progress_callback]
|
44
|
+
|
37
45
|
validate!
|
38
46
|
|
39
47
|
Aws::Plugins::UserAgent.feature('s3-transfer') do
|
@@ -43,7 +51,7 @@ module Aws
|
|
43
51
|
when 'get_range'
|
44
52
|
if @chunk_size
|
45
53
|
resp = @client.head_object(@params)
|
46
|
-
multithreaded_get_by_ranges(
|
54
|
+
multithreaded_get_by_ranges(resp.content_length)
|
47
55
|
else
|
48
56
|
msg = 'In :get_range mode, :chunk_size must be provided'
|
49
57
|
raise ArgumentError, msg
|
@@ -76,7 +84,7 @@ module Aws
|
|
76
84
|
if resp.content_length <= MIN_CHUNK_SIZE
|
77
85
|
single_request
|
78
86
|
else
|
79
|
-
multithreaded_get_by_ranges(
|
87
|
+
multithreaded_get_by_ranges(resp.content_length)
|
80
88
|
end
|
81
89
|
else
|
82
90
|
# partNumber is an option
|
@@ -93,9 +101,9 @@ module Aws
|
|
93
101
|
chunk_size = compute_chunk(file_size)
|
94
102
|
part_size = (file_size.to_f / count.to_f).ceil
|
95
103
|
if chunk_size < part_size
|
96
|
-
multithreaded_get_by_ranges(
|
104
|
+
multithreaded_get_by_ranges(file_size)
|
97
105
|
else
|
98
|
-
multithreaded_get_by_parts(count)
|
106
|
+
multithreaded_get_by_parts(count, file_size)
|
99
107
|
end
|
100
108
|
end
|
101
109
|
|
@@ -127,30 +135,65 @@ module Aws
|
|
127
135
|
chunks.each_slice(@thread_count).to_a
|
128
136
|
end
|
129
137
|
|
130
|
-
def multithreaded_get_by_ranges(
|
131
|
-
|
138
|
+
def multithreaded_get_by_ranges(file_size)
|
139
|
+
offset = 0
|
140
|
+
default_chunk_size = compute_chunk(file_size)
|
141
|
+
chunks = []
|
142
|
+
part_number = 1 # parts start at 1
|
143
|
+
while offset < file_size
|
144
|
+
progress = offset + default_chunk_size
|
145
|
+
progress = file_size if progress > file_size
|
146
|
+
range = "bytes=#{offset}-#{progress - 1}"
|
147
|
+
chunks << Part.new(
|
148
|
+
part_number: part_number,
|
149
|
+
size: (progress-offset),
|
150
|
+
params: @params.merge(range: range)
|
151
|
+
)
|
152
|
+
part_number += 1
|
153
|
+
offset = progress
|
154
|
+
end
|
155
|
+
download_in_threads(PartList.new(chunks), file_size)
|
132
156
|
end
|
133
157
|
|
134
|
-
def multithreaded_get_by_parts(
|
135
|
-
|
158
|
+
def multithreaded_get_by_parts(n_parts, total_size)
|
159
|
+
parts = (1..n_parts).map do |part|
|
160
|
+
Part.new(part_number: part, params: @params.merge(part_number: part))
|
161
|
+
end
|
162
|
+
download_in_threads(PartList.new(parts), total_size)
|
136
163
|
end
|
137
164
|
|
138
|
-
def
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
165
|
+
def download_in_threads(pending, total_size)
|
166
|
+
threads = []
|
167
|
+
if @progress_callback
|
168
|
+
progress = MultipartProgress.new(pending, total_size, @progress_callback)
|
169
|
+
end
|
170
|
+
@thread_count.times do
|
171
|
+
thread = Thread.new do
|
172
|
+
begin
|
173
|
+
while part = pending.shift
|
174
|
+
if progress
|
175
|
+
part.params[:on_chunk_received] =
|
176
|
+
proc do |_chunk, bytes, total|
|
177
|
+
progress.call(part.part_number, bytes, total)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
resp = @client.get_object(part.params)
|
181
|
+
write(resp)
|
182
|
+
if @on_checksum_validated && resp.checksum_validated
|
183
|
+
@on_checksum_validated.call(resp.checksum_validated, resp)
|
184
|
+
end
|
149
185
|
end
|
186
|
+
nil
|
187
|
+
rescue => error
|
188
|
+
# keep other threads from downloading other parts
|
189
|
+
pending.clear!
|
190
|
+
raise error
|
150
191
|
end
|
151
192
|
end
|
152
|
-
|
193
|
+
thread.abort_on_exception = true
|
194
|
+
threads << thread
|
153
195
|
end
|
196
|
+
threads.map(&:value).compact
|
154
197
|
end
|
155
198
|
|
156
199
|
def write(resp)
|
@@ -160,9 +203,9 @@ module Aws
|
|
160
203
|
end
|
161
204
|
|
162
205
|
def single_request
|
163
|
-
|
164
|
-
|
165
|
-
)
|
206
|
+
params = @params.merge(response_target: @path)
|
207
|
+
params[:on_chunk_received] = single_part_progress if @progress_callback
|
208
|
+
resp = @client.get_object(params)
|
166
209
|
|
167
210
|
return resp unless @on_checksum_validated
|
168
211
|
|
@@ -172,6 +215,59 @@ module Aws
|
|
172
215
|
|
173
216
|
resp
|
174
217
|
end
|
218
|
+
|
219
|
+
def single_part_progress
|
220
|
+
proc do |_chunk, bytes_read, total_size|
|
221
|
+
@progress_callback.call([bytes_read], [total_size], total_size)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
class Part < Struct.new(:part_number, :size, :params)
|
226
|
+
include Aws::Structure
|
227
|
+
end
|
228
|
+
|
229
|
+
# @api private
|
230
|
+
class PartList
|
231
|
+
include Enumerable
|
232
|
+
def initialize(parts = [])
|
233
|
+
@parts = parts
|
234
|
+
@mutex = Mutex.new
|
235
|
+
end
|
236
|
+
|
237
|
+
def shift
|
238
|
+
@mutex.synchronize { @parts.shift }
|
239
|
+
end
|
240
|
+
|
241
|
+
def size
|
242
|
+
@mutex.synchronize { @parts.size }
|
243
|
+
end
|
244
|
+
|
245
|
+
def clear!
|
246
|
+
@mutex.synchronize { @parts.clear }
|
247
|
+
end
|
248
|
+
|
249
|
+
def each(&block)
|
250
|
+
@mutex.synchronize { @parts.each(&block) }
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
# @api private
|
255
|
+
class MultipartProgress
|
256
|
+
def initialize(parts, total_size, progress_callback)
|
257
|
+
@bytes_received = Array.new(parts.size, 0)
|
258
|
+
@part_sizes = parts.map(&:size)
|
259
|
+
@total_size = total_size
|
260
|
+
@progress_callback = progress_callback
|
261
|
+
end
|
262
|
+
|
263
|
+
def call(part_number, bytes_received, total)
|
264
|
+
# part numbers start at 1
|
265
|
+
@bytes_received[part_number - 1] = bytes_received
|
266
|
+
# part size may not be known until we get the first response
|
267
|
+
@part_sizes[part_number - 1] ||= total
|
268
|
+
@progress_callback.call(@bytes_received, @part_sizes, @total_size)
|
269
|
+
end
|
270
|
+
end
|
175
271
|
end
|
176
272
|
end
|
177
273
|
end
|
data/lib/aws-sdk-s3.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aws-sdk-s3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.133.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Amazon Web Services
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-08-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-kms
|
@@ -47,7 +47,7 @@ dependencies:
|
|
47
47
|
version: '3'
|
48
48
|
- - ">="
|
49
49
|
- !ruby/object:Gem::Version
|
50
|
-
version: 3.
|
50
|
+
version: 3.181.0
|
51
51
|
type: :runtime
|
52
52
|
prerelease: false
|
53
53
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -57,7 +57,7 @@ dependencies:
|
|
57
57
|
version: '3'
|
58
58
|
- - ">="
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version: 3.
|
60
|
+
version: 3.181.0
|
61
61
|
description: Official AWS Ruby gem for Amazon Simple Storage Service (Amazon S3).
|
62
62
|
This gem is part of the AWS SDK for Ruby.
|
63
63
|
email:
|