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 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: