aws-sdk-s3 1.132.0 → 1.133.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: adbed389cd50d435107ac0380117b7e1a316f18dc19cc9a140b223320980fb27
4
- data.tar.gz: feea3f5c604991ae327c7e3a7c1811ea0de5ab4474154e3bc69162d8262def72
3
+ metadata.gz: 04f11cfde483787571492064565bb589b16323f4bb7f33f5a7507b993f6cead3
4
+ data.tar.gz: 1dd900a34a20b97fb82c41407ca12c40d33397fb14e29678e0f7e3b0a1e5b77c
5
5
  SHA512:
6
- metadata.gz: 3f9adfd588e576e5dd17a9abac897b5d3e113b3fefd03de458fc0c8556c9a43336f84af4a3faf4f8516995cfff58cb9085af209f1f2ef8991204e11f7b7e9164
7
- data.tar.gz: 5eb78921bec0f584949cec19adc7d6f38c65daabab5f9ed01c7298d7bfb14501512a1ea99abc6449591867bf548bab50ec0fd3fe54c21dd5ddfddafa370aaae6
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.132.0
1
+ 1.133.0
@@ -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.132.0'
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 occured and which
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
- @params[:checksum_mode] = options[:checksum_mode] || 'ENABLED'
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(construct_chunks(resp.content_length))
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(construct_chunks(resp.content_length))
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(construct_chunks(file_size))
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(chunks)
131
- thread_batches(chunks, 'range')
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(parts)
135
- thread_batches(parts, 'part_number')
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 thread_batches(chunks, param)
139
- batches(chunks, param).each do |batch|
140
- threads = []
141
- batch.each do |chunk|
142
- threads << Thread.new do
143
- resp = @client.get_object(
144
- @params.merge(param.to_sym => chunk)
145
- )
146
- write(resp)
147
- if @on_checksum_validated && resp.checksum_validated
148
- @on_checksum_validated.call(resp.checksum_validated, resp)
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
- threads.each(&:join)
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
- resp = @client.get_object(
164
- @params.merge(response_target: @path)
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
@@ -73,6 +73,6 @@ require_relative 'aws-sdk-s3/event_streams'
73
73
  # @!group service
74
74
  module Aws::S3
75
75
 
76
- GEM_VERSION = '1.132.0'
76
+ GEM_VERSION = '1.133.0'
77
77
 
78
78
  end
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.132.0
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-07-24 00:00:00.000000000 Z
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.179.0
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.179.0
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: