@@ -787,7 +787,7 @@ static void s_s3_auto_ranged_get_request_finished(
787787 error_code = AWS_ERROR_S3_MISSING_ETAG ;
788788 goto update_synced_data ;
789789 }
790- /* Extract number of parts from ETag and calculate estimated part size */
790+ /* Extract number of parts stored in S3 from ETag and calculate estimated part size */
791791 uint32_t num_parts = 0 ;
792792 if (aws_s3_extract_parts_from_etag (etag_header_value , & num_parts ) == AWS_OP_SUCCESS && num_parts > 0 ) {
793793 auto_ranged_get -> estimated_object_stored_part_size = object_size / num_parts ;
@@ -801,6 +801,7 @@ static void s_s3_auto_ranged_get_request_finished(
801801 num_parts ,
802802 auto_ranged_get -> estimated_object_stored_part_size );
803803 } else {
804+ num_parts = 1 ;
804805 /* Failed to parse ETags */
805806 AWS_LOGF_WARN (
806807 AWS_LS_S3_META_REQUEST ,
@@ -809,24 +810,49 @@ static void s_s3_auto_ranged_get_request_finished(
809810 auto_ranged_get -> estimated_object_stored_part_size = g_default_part_size_fallback ;
810811 goto update_synced_data ;
811812 }
813+ auto_ranged_get -> num_stored_parts = num_parts ;
812814 }
813815
814816 /* If we were able to discover the object-range/content length successfully, then any error code that was passed
815817 * into this function is being handled and does not indicate an overall failure.*/
816818 error_code = AWS_ERROR_SUCCESS ;
817819 found_object_size = true;
820+ uint32_t max_connections = aws_s3_client_get_max_active_connections (meta_request -> client , meta_request );
818821
819822 if (auto_ranged_get -> force_dynamic_part_size ||
820823 (!auto_ranged_get -> part_size_set && !meta_request -> client -> part_size_set )) {
821824 /* No part size has been set from user. Now we use the optimal part size based on the throughput and memory
822825 * limit */
823826 uint64_t out_request_optimal_range_size = 0 ;
827+
824828 if (aws_s3_calculate_request_optimal_range_size (
825829 meta_request -> client -> optimal_range_size ,
826830 auto_ranged_get -> estimated_object_stored_part_size ,
831+ meta_request -> is_express ,
827832 & out_request_optimal_range_size ) == AWS_OP_SUCCESS ) {
833+ /* Apply a buffer pool alignment to the calculated result. */
834+ out_request_optimal_range_size = aws_s3_buffer_pool_derive_aligned_buffer_size (
835+ meta_request -> client -> buffer_pool , out_request_optimal_range_size );
836+ AWS_LOGF_INFO (
837+ AWS_LS_S3_META_REQUEST ,
838+ "id=%p: Override the part size to be optimal. part_size=%" PRIu64 "." ,
839+ (void * )meta_request ,
840+ out_request_optimal_range_size );
828841 /* Override the part size to be optimal */
829842 * ((size_t * )& meta_request -> part_size ) = (size_t )out_request_optimal_range_size ;
843+ uint64_t parts_threshold = aws_mul_u64_saturating (max_connections , 2 );
844+ if (auto_ranged_get -> num_stored_parts > parts_threshold ) {
845+ /* If the number of parts is greater than the threshold, so that we will be reusing the buffers
846+ * enough from the buffer pool. Let's add a special block for the buffer pool to optimize the
847+ * case.*/
848+ AWS_LOGF_INFO (
849+ AWS_LS_S3_META_REQUEST ,
850+ "id=%p: Apply buffer pool optimization for the size=%zu." ,
851+ (void * )meta_request ,
852+ meta_request -> part_size );
853+ aws_s3_buffer_pool_add_special_size (meta_request -> client -> buffer_pool , meta_request -> part_size );
854+ meta_request -> buffer_pool_optimized = true;
855+ }
830856 if (request -> request_tag == AWS_S3_AUTO_RANGE_GET_REQUEST_TYPE_HEAD_OBJECT ) {
831857 /* Update the first part size as well, if we haven't made the request yet. */
832858 first_part_size = meta_request -> part_size ;
@@ -847,6 +873,31 @@ static void s_s3_auto_ranged_get_request_finished(
847873 }
848874 }
849875
876+ if (meta_request -> is_express &&
877+ meta_request -> part_size < g_s3express_connection_limitation_part_size_threshold &&
878+ object_size > g_s3express_connection_limitation_object_size_threshold ) {
879+ /**
880+ * TODO: THIS IS A TEMP WORKAROUND, not the long term solution.
881+ * 1. If the Part Size we set is larger than the possible size to hit the limitation, we are safe to
882+ * make as many connections as we want.
883+ * 2. If the object size is less than the threshold, we keep our previous behavior, as it's less likely
884+ * to hit the server side limitation.
885+ *
886+ * Otherwise, we need to make sure the number of concurrent connections is lower than the limitation.
887+ */
888+ uint32_t max_active_connections_override = aws_min_u32 (g_s3express_connection_limitation , max_connections );
889+ if (max_active_connections_override < max_connections ) {
890+ /* Override the max active connections to be the limitation. */
891+ * ((uint32_t * )& meta_request -> max_active_connections_override ) =
892+ (uint32_t )max_active_connections_override ;
893+ AWS_LOGF_WARN (
894+ AWS_LS_S3_META_REQUEST ,
895+ "id=%p: Override the max active connections for the meta request to be the limitation: %d" ,
896+ (void * )meta_request ,
897+ max_active_connections_override );
898+ }
899+ }
900+
850901 if (!empty_file_error && meta_request -> headers_callback != NULL ) {
851902 /* Modify the header received to fake the header for the whole meta request. */
852903 if (request -> request_tag == AWS_S3_AUTO_RANGE_GET_REQUEST_TYPE_GET_OBJECT_WITH_RANGE ||
@@ -936,8 +987,8 @@ static void s_s3_auto_ranged_get_request_finished(
936987 if (empty_file_error ) {
937988 /*
938989 * Try to download the object again using GET_OBJECT_WITH_PART_NUMBER_1. If the file is still
939- * empty, successful response headers will be provided to users. If not, the newer version of the
940- * file will be downloaded.
990+ * empty, successful response headers will be provided to users. If not, the newer version of
991+ * the file will be downloaded.
941992 */
942993 auto_ranged_get -> synced_data .num_parts_requested = 0 ;
943994 auto_ranged_get -> synced_data .object_range_known = 0 ;
@@ -999,7 +1050,8 @@ static void s_s3_auto_ranged_get_request_finished(
9991050 }
10001051 aws_s3_meta_request_set_fail_synced (meta_request , request , error_code );
10011052 if (error_code == AWS_ERROR_S3_RESPONSE_CHECKSUM_MISMATCH ) {
1002- /* It's a mismatch of checksum, tell user that we validated the checksum and the algorithm we validated
1053+ /* It's a mismatch of checksum, tell user that we validated the checksum and the algorithm we
1054+ * validated
10031055 */
10041056 meta_request -> synced_data .finish_result .did_validate = true;
10051057 meta_request -> synced_data .finish_result .validation_algorithm = request -> validation_algorithm ;
0 commit comments