Skip to content

Commit 5d7d268

Browse files
authored
collect part range for auto-range-put as well (#588)
1 parent 54d5c38 commit 5d7d268

File tree

3 files changed

+61
-32
lines changed

3 files changed

+61
-32
lines changed

include/aws/s3/private/s3_request.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,11 +241,9 @@ struct aws_s3_request {
241241
struct aws_s3_buffer_ticket *ticket;
242242

243243
/* Beginning range of this part. */
244-
/* TODO currently only used by auto_range_get, could be hooked up to auto_range_put as well. */
245244
uint64_t part_range_start;
246245

247246
/* Last byte of this part.*/
248-
/* TODO currently only used by auto_range_get, could be hooked up to auto_range_put as well. */
249247
uint64_t part_range_end;
250248

251249
/* Part number that this request refers to. If this is not a part, this can be 0. (S3 Part Numbers start at 1.)

source/s3_auto_ranged_put.c

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -759,31 +759,33 @@ static bool s_s3_auto_ranged_put_update(
759759
}
760760

761761
/**
762-
* Helper to compute request body size.
763-
* Basically returns either part size or if content is not equally divisible into parts, the size of the remaining last
764-
* part.
762+
* Helper to initialize the request ranges and content-length
763+
* based on the request->part_number and meta_request->part_size
765764
*/
766-
static size_t s_compute_request_body_size(
767-
const struct aws_s3_meta_request *meta_request,
768-
uint32_t part_number,
769-
uint64_t *offset_out) {
770-
AWS_PRECONDITION(meta_request);
765+
static int s_compute_request_body_size(const struct aws_s3_meta_request *meta_request, struct aws_s3_request *request) {
766+
AWS_ERROR_PRECONDITION(meta_request);
767+
AWS_ERROR_PRECONDITION(request);
771768

772769
const struct aws_s3_auto_ranged_put *auto_ranged_put = meta_request->impl;
773770

774771
size_t request_body_size = meta_request->part_size;
775772
/* Last part--adjust size to match remaining content length. */
776-
if (auto_ranged_put->has_content_length && part_number == auto_ranged_put->total_num_parts_from_content_length) {
773+
if (auto_ranged_put->has_content_length &&
774+
request->part_number == auto_ranged_put->total_num_parts_from_content_length) {
777775
size_t content_remainder = (size_t)(auto_ranged_put->content_length % (uint64_t)meta_request->part_size);
778776

779777
if (content_remainder > 0) {
780778
request_body_size = content_remainder;
781779
}
782780
}
783-
/* The part_number starts at 1 */
784-
*offset_out = (part_number - 1) * meta_request->part_size;
785-
786-
return request_body_size;
781+
if (aws_mul_u64_checked(request->part_number - 1, meta_request->part_size, &request->part_range_start)) {
782+
return AWS_OP_ERR;
783+
}
784+
if (aws_add_u64_checked(request->part_range_start, request_body_size - 1, &request->part_range_end)) {
785+
return AWS_OP_ERR;
786+
}
787+
request->content_length = request_body_size;
788+
return AWS_OP_SUCCESS;
787789
}
788790

789791
static int s_verify_part_matches_checksum(
@@ -1085,23 +1087,24 @@ struct aws_future_http_message *s_s3_prepare_upload_part(struct aws_s3_request *
10851087
part_prep->allocator = allocator;
10861088
part_prep->request = request;
10871089
part_prep->on_complete = aws_future_http_message_acquire(message_future);
1090+
if (s_compute_request_body_size(meta_request, request)) {
1091+
s_s3_prepare_upload_part_finish(part_prep, aws_last_error_or_unknown());
1092+
return message_future;
1093+
}
10881094

10891095
if (request->fio_streaming) {
10901096
/* Create the request body stream for the HTTP to read directly from the file. If retry happens, just recreate
10911097
* it. */
10921098
aws_input_stream_release(request->request_body_stream);
1093-
uint64_t offset = 0;
1094-
size_t request_body_size = s_compute_request_body_size(meta_request, request->part_number, &offset);
10951099
AWS_ASSERT(meta_request->request_body_parallel_stream != NULL);
1100+
int error_code = AWS_ERROR_SUCCESS;
10961101
request->request_body_stream = aws_part_streaming_input_stream_new(
10971102
allocator,
10981103
meta_request->request_body_parallel_stream,
10991104
request->ticket,
1100-
offset,
1101-
request_body_size,
1105+
request->part_range_start,
1106+
(size_t)request->content_length,
11021107
meta_request->fio_opts.direct_io);
1103-
request->content_length = request_body_size;
1104-
int error_code = AWS_ERROR_SUCCESS;
11051108

11061109
if (request->num_times_prepared == 0) {
11071110
if (s_s3_new_upload_part_info_after_body(request, meta_request, false)) {
@@ -1117,15 +1120,14 @@ struct aws_future_http_message *s_s3_prepare_upload_part(struct aws_s3_request *
11171120
* from an upload that had been paused) */
11181121

11191122
/* Read the body */
1120-
uint64_t offset = 0;
1121-
size_t request_body_size = s_compute_request_body_size(meta_request, request->part_number, &offset);
11221123
if (request->request_body.capacity == 0) {
11231124
AWS_FATAL_ASSERT(request->ticket);
11241125
request->request_body = aws_s3_buffer_ticket_claim(request->ticket);
1125-
request->request_body.capacity = request_body_size;
1126+
request->request_body.capacity = (size_t)request->content_length;
11261127
}
11271128

1128-
part_prep->asyncstep_read_part = aws_s3_meta_request_read_body(meta_request, offset, &request->request_body);
1129+
part_prep->asyncstep_read_part =
1130+
aws_s3_meta_request_read_body(meta_request, request->part_range_start, &request->request_body);
11291131
aws_future_bool_register_callback(
11301132
part_prep->asyncstep_read_part, s_s3_prepare_upload_part_on_read_done, part_prep);
11311133
} else {
@@ -1159,21 +1161,21 @@ static void s_s3_prepare_upload_part_on_read_done(void *user_data) {
11591161
request->request_body.capacity);
11601162
goto on_done;
11611163
}
1162-
/* Reading succeeded. */
1163-
request->content_length = request->request_body.len;
11641164
bool is_body_stream_at_end = aws_future_bool_get_result(part_prep->asyncstep_read_part);
1165-
1166-
uint64_t offset = 0;
1167-
size_t request_body_size = s_compute_request_body_size(meta_request, request->part_number, &offset);
11681165
/* If Content-Length is defined, check that we read the expected amount */
1169-
if (has_content_length && (request->request_body.len < request_body_size)) {
1166+
if (has_content_length && (request->request_body.len < request->content_length)) {
11701167
error_code = AWS_ERROR_S3_INCORRECT_CONTENT_LENGTH;
11711168
AWS_LOGF_ERROR(
11721169
AWS_LS_S3_META_REQUEST,
11731170
"id=%p: Request body is smaller than 'Content-Length' header said it would be",
11741171
(void *)meta_request);
11751172
goto on_done;
11761173
}
1174+
if (!has_content_length && (request->request_body.len < request->content_length)) {
1175+
/* The stream is not ready to provide enough data as expected. Update the tracking numbers. */
1176+
request->content_length = request->request_body.len;
1177+
request->part_range_end = request->part_range_start + request->content_length - 1;
1178+
}
11771179
request->is_noop = request->part_number >
11781180
1 && /* allow first part to have 0 length to support empty unknown content length objects. */
11791181
request->request_body.len == 0;

tests/s3_data_plane_tests.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4987,6 +4987,33 @@ static int s_test_s3_round_trip_mpu_with_filepath_streaming_full_object_checksum
49874987
AWS_TEST_FOC_CALLBACK);
49884988
}
49894989

4990+
static int s_check_metrics_upload_part_helper(
4991+
struct aws_s3_meta_request_test_results *test_results,
4992+
size_t expected_part_size,
4993+
size_t index) {
4994+
struct aws_s3_request_metrics *metrics = NULL;
4995+
/* The upload part can be completed out of order. Just make sure the range matches the part number */
4996+
ASSERT_SUCCESS(aws_array_list_get_at(&test_results->synced_data.succeed_metrics, (void **)&metrics, index));
4997+
enum aws_s3_request_type out_request_type = AWS_S3_REQUEST_TYPE_UNKNOWN;
4998+
aws_s3_request_metrics_get_request_type(metrics, &out_request_type);
4999+
uint32_t part_number = 0;
5000+
aws_s3_request_metrics_get_part_number(metrics, &part_number);
5001+
ASSERT_TRUE(part_number >= 1); /* The part number starts at 1 */
5002+
/* calculate the expected range start and end based on the part number and part size. */
5003+
size_t expected_range_start = (part_number - 1) * expected_part_size;
5004+
size_t expected_range_end = part_number * expected_part_size - 1;
5005+
5006+
uint64_t range_start = 0;
5007+
uint64_t range_end = 0;
5008+
aws_s3_request_metrics_get_part_range_start(metrics, &range_start);
5009+
aws_s3_request_metrics_get_part_range_end(metrics, &range_end);
5010+
ASSERT_UINT_EQUALS(AWS_S3_REQUEST_TYPE_UPLOAD_PART, out_request_type);
5011+
ASSERT_UINT_EQUALS(expected_range_start, range_start);
5012+
ASSERT_UINT_EQUALS(expected_range_end, range_end);
5013+
5014+
return AWS_OP_SUCCESS;
5015+
}
5016+
49905017
static int s_check_metrics_helper(
49915018
struct aws_s3_meta_request_test_results *test_results,
49925019
size_t index,
@@ -4996,7 +5023,6 @@ static int s_check_metrics_helper(
49965023
size_t expected_range_end) {
49975024
struct aws_s3_request_metrics *metrics = NULL;
49985025

4999-
/* First metrics should be the CreateMPU */
50005026
ASSERT_SUCCESS(aws_array_list_get_at(&test_results->synced_data.succeed_metrics, (void **)&metrics, index));
50015027
enum aws_s3_request_type out_request_type = AWS_S3_REQUEST_TYPE_UNKNOWN;
50025028
aws_s3_request_metrics_get_request_type(metrics, &out_request_type);
@@ -5066,6 +5092,9 @@ static int s_test_s3_round_trip_dynamic_range_size_download_multipart(struct aws
50665092
};
50675093

50685094
ASSERT_SUCCESS(aws_s3_tester_send_meta_request_with_options(&tester, &put_options, &test_results));
5095+
ASSERT_SUCCESS(s_check_metrics_helper(&test_results, 0, AWS_S3_REQUEST_TYPE_CREATE_MULTIPART_UPLOAD, 0, 0, 0));
5096+
ASSERT_SUCCESS(s_check_metrics_upload_part_helper(&test_results, stored_part_size, 1));
5097+
ASSERT_SUCCESS(s_check_metrics_upload_part_helper(&test_results, stored_part_size, 2));
50695098
aws_s3_meta_request_test_results_clean_up(&test_results);
50705099

50715100
/*** GET FILE WITH CHECKSUM -- Head object first ***/

0 commit comments

Comments
 (0)