Skip to content

Commit 8eb717a

Browse files
Optimize the sizes of buffers requested from mem pool (#563)
1 parent a9218e5 commit 8eb717a

13 files changed

Lines changed: 253 additions & 78 deletions

.github/workflows/ci.yml

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737
- manylinux2014-x86
3838
- al2-x64
3939
steps:
40-
- uses: aws-actions/configure-aws-credentials@v4
40+
- uses: aws-actions/configure-aws-credentials@v6
4141
with:
4242
role-to-assume: ${{ env.CRT_CI_ROLE }}
4343
aws-region: ${{ env.AWS_DEFAULT_REGION }}
@@ -88,7 +88,7 @@ jobs:
8888
# our base Linux image to Ubuntu 22.
8989
extra-build-flag: --cmake-extra=-DCMAKE_EXE_LINKER_FLAGS="-lresolv"
9090
steps:
91-
- uses: aws-actions/configure-aws-credentials@v4
91+
- uses: aws-actions/configure-aws-credentials@v6
9292
with:
9393
role-to-assume: ${{ env.CRT_CI_ROLE }}
9494
aws-region: ${{ env.AWS_DEFAULT_REGION }}
@@ -104,7 +104,7 @@ jobs:
104104
matrix:
105105
sanitizers: [",thread", ",address,undefined"]
106106
steps:
107-
- uses: aws-actions/configure-aws-credentials@v4
107+
- uses: aws-actions/configure-aws-credentials@v6
108108
with:
109109
role-to-assume: ${{ env.CRT_CI_ROLE }}
110110
aws-region: ${{ env.AWS_DEFAULT_REGION }}
@@ -117,7 +117,7 @@ jobs:
117117
linux-shared-libs:
118118
runs-on: ubuntu-24.04 # latest
119119
steps:
120-
- uses: aws-actions/configure-aws-credentials@v4
120+
- uses: aws-actions/configure-aws-credentials@v6
121121
with:
122122
role-to-assume: ${{ env.CRT_CI_ROLE }}
123123
aws-region: ${{ env.AWS_DEFAULT_REGION }}
@@ -130,7 +130,7 @@ jobs:
130130
byo-crypto:
131131
runs-on: ubuntu-24.04 # latest
132132
steps:
133-
- uses: aws-actions/configure-aws-credentials@v4
133+
- uses: aws-actions/configure-aws-credentials@v6
134134
with:
135135
role-to-assume: ${{ env.CRT_CI_ROLE }}
136136
aws-region: ${{ env.AWS_DEFAULT_REGION }}
@@ -143,7 +143,7 @@ jobs:
143143
windows:
144144
runs-on: windows-2025 # latest
145145
steps:
146-
- uses: aws-actions/configure-aws-credentials@v4
146+
- uses: aws-actions/configure-aws-credentials@v6
147147
with:
148148
role-to-assume: ${{ env.CRT_CI_ROLE }}
149149
aws-region: ${{ env.AWS_DEFAULT_REGION }}
@@ -159,7 +159,7 @@ jobs:
159159
matrix:
160160
arch: [x86, x64]
161161
steps:
162-
- uses: aws-actions/configure-aws-credentials@v4
162+
- uses: aws-actions/configure-aws-credentials@v6
163163
with:
164164
role-to-assume: ${{ env.CRT_CI_ROLE }}
165165
aws-region: ${{ env.AWS_DEFAULT_REGION }}
@@ -171,7 +171,7 @@ jobs:
171171
windows-shared-libs:
172172
runs-on: windows-2025 # latest
173173
steps:
174-
- uses: aws-actions/configure-aws-credentials@v4
174+
- uses: aws-actions/configure-aws-credentials@v6
175175
with:
176176
role-to-assume: ${{ env.CRT_CI_ROLE }}
177177
aws-region: ${{ env.AWS_DEFAULT_REGION }}
@@ -183,7 +183,7 @@ jobs:
183183
windows-app-verifier:
184184
runs-on: windows-2025 # latest
185185
steps:
186-
- uses: aws-actions/configure-aws-credentials@v4
186+
- uses: aws-actions/configure-aws-credentials@v6
187187
with:
188188
role-to-assume: ${{ env.CRT_CI_ROLE }}
189189
aws-region: ${{ env.AWS_DEFAULT_REGION }}
@@ -198,7 +198,7 @@ jobs:
198198
macos:
199199
runs-on: macos-14 # latest
200200
steps:
201-
- uses: aws-actions/configure-aws-credentials@v4
201+
- uses: aws-actions/configure-aws-credentials@v6
202202
with:
203203
role-to-assume: ${{ env.CRT_CI_ROLE }}
204204
aws-region: ${{ env.AWS_DEFAULT_REGION }}
@@ -215,7 +215,7 @@ jobs:
215215
macos-x64:
216216
runs-on: macos-14-large # latest
217217
steps:
218-
- uses: aws-actions/configure-aws-credentials@v4
218+
- uses: aws-actions/configure-aws-credentials@v6
219219
with:
220220
role-to-assume: ${{ env.CRT_CI_ROLE }}
221221
aws-region: ${{ env.AWS_DEFAULT_REGION }}
@@ -234,7 +234,7 @@ jobs:
234234
downstream:
235235
runs-on: ubuntu-24.04 # latest
236236
steps:
237-
- uses: aws-actions/configure-aws-credentials@v4
237+
- uses: aws-actions/configure-aws-credentials@v6
238238
with:
239239
role-to-assume: ${{ env.CRT_CI_ROLE }}
240240
aws-region: ${{ env.AWS_DEFAULT_REGION }}
@@ -247,7 +247,7 @@ jobs:
247247
linux-debug:
248248
runs-on: ubuntu-24.04 # latest
249249
steps:
250-
- uses: aws-actions/configure-aws-credentials@v4
250+
- uses: aws-actions/configure-aws-credentials@v6
251251
with:
252252
role-to-assume: ${{ env.CRT_CI_ROLE }}
253253
aws-region: ${{ env.AWS_DEFAULT_REGION }}

.github/workflows/codecov.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
codecov-linux:
2121
runs-on: ubuntu-24.04
2222
steps:
23-
- uses: aws-actions/configure-aws-credentials@v4
23+
- uses: aws-actions/configure-aws-credentials@v6
2424
with:
2525
role-to-assume: ${{ env.CRT_CI_ROLE }}
2626
aws-region: ${{ env.AWS_DEFAULT_REGION }}

include/aws/s3/private/s3_default_buffer_pool.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ struct aws_s3_default_buffer_pool_usage_stats {
4444
/* Max size of buffer to be allocated from primary. */
4545
size_t primary_cutoff;
4646

47+
/* Min size of buffer to be allocated from primary. */
48+
size_t primary_min_cutoff;
49+
4750
/* Overall memory allocated for blocks. */
4851
size_t primary_allocated;
4952
/* Number of blocks allocated in primary. */
@@ -91,6 +94,9 @@ struct aws_s3_default_buffer_pool {
9194
/* size at which allocations should go to secondary */
9295
size_t primary_size_cutoff;
9396

97+
/* size below which allocations should go to secondary */
98+
size_t primary_size_min_cutoff;
99+
94100
/* NOTE: See aws_s3_buffer_pool_usage_stats for descriptions of most fields */
95101

96102
size_t mem_limit;
@@ -185,6 +191,18 @@ AWS_S3_API struct aws_byte_buf aws_s3_default_buffer_pool_acquire_buffer(
185191
AWS_S3_API struct aws_s3_default_buffer_pool_usage_stats aws_s3_default_buffer_pool_get_usage(
186192
struct aws_s3_buffer_pool *buffer_pool);
187193

194+
enum aws_s3_default_buffer_pool_reserved_from {
195+
AWS_S3_BUFFER_POOL_RESERVED_FROM_SECONDARY = 0,
196+
AWS_S3_BUFFER_POOL_RESERVED_FROM_PRIMARY,
197+
AWS_S3_BUFFER_POOL_RESERVED_FROM_SPECIAL,
198+
};
199+
200+
/*
201+
* Helper to determine which area of default buffer pool ticket was reserved from.
202+
*/
203+
AWS_S3_API enum aws_s3_default_buffer_pool_reserved_from aws_s3_default_buffer_pool_get_ticket_reserved_from(
204+
struct aws_s3_default_buffer_ticket *ticket);
205+
188206
/*
189207
* Trims all unused mem from the pool.
190208
* Warning: fairly slow operation, do not use in critical path.

include/aws/s3/private/s3_request.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,10 +240,12 @@ struct aws_s3_request {
240240
*/
241241
struct aws_s3_buffer_ticket *ticket;
242242

243-
/* Beginning range of this part. */
243+
/* Beginning range of this part. */
244244
uint64_t part_range_start;
245245

246-
/* Last byte of this part.*/
246+
/* Last byte of this part.
247+
* Note: this is available on both put and get, but in put case it can be optimistic,
248+
* ex for unknown content length we dont know what the end will be until we finish reading data. */
247249
uint64_t part_range_end;
248250

249251
/* Part number that this request refers to. If this is not a part, this can be 0. (S3 Part Numbers start at 1.)
@@ -364,6 +366,11 @@ struct aws_s3_request *aws_s3_request_new(
364366
uint32_t part_number,
365367
uint32_t flags);
366368

369+
/* Gets the size of the part payload.
370+
* Range is inclusive (i.e. 0-0 range has 1 byte size). In case of misconfigured range returns 0. */
371+
AWS_S3_API
372+
uint64_t aws_s3_request_get_payload_size(struct aws_s3_request *request);
373+
367374
/* Set up the request to be sent. Called each time before the request is sent. Will initially call
368375
* aws_s3_request_clean_up_send_data to clear out anything previously existing in send_data. */
369376
AWS_S3_API

source/s3_auto_ranged_get.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,10 @@ static bool s_s3_auto_ranged_get_update(
265265
1 /*part_number*/,
266266
AWS_S3_REQUEST_FLAG_RECORD_RESPONSE_HEADERS |
267267
AWS_S3_REQUEST_FLAG_ALLOCATE_BUFFER_FROM_POOL);
268+
/* Note: our current default logic is to do part 1, discover size and then abort if payload its
269+
* too huge We optimistically reserve part size for it */
270+
request->part_range_start = 0;
271+
request->part_range_end = meta_request->part_size - 1;
268272
++auto_ranged_get->synced_data.num_parts_requested;
269273

270274
break;

source/s3_auto_ranged_put.c

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,36 @@ static struct aws_s3_meta_request_vtable s_s3_auto_ranged_put_vtable = {
323323
.pause = s_s3_auto_ranged_put_pause,
324324
};
325325

326+
/**
327+
* Helper to initialize the request ranges and content-length
328+
* based on the request->part_number and meta_request->part_size
329+
*/
330+
static int s_compute_request_body_size(const struct aws_s3_meta_request *meta_request, struct aws_s3_request *request) {
331+
AWS_ERROR_PRECONDITION(meta_request);
332+
AWS_ERROR_PRECONDITION(request);
333+
334+
const struct aws_s3_auto_ranged_put *auto_ranged_put = meta_request->impl;
335+
336+
size_t request_body_size = meta_request->part_size;
337+
/* Last part--adjust size to match remaining content length. */
338+
if (auto_ranged_put->has_content_length &&
339+
request->part_number == auto_ranged_put->total_num_parts_from_content_length) {
340+
size_t content_remainder = (size_t)(auto_ranged_put->content_length % (uint64_t)meta_request->part_size);
341+
342+
if (content_remainder > 0) {
343+
request_body_size = content_remainder;
344+
}
345+
}
346+
if (aws_mul_u64_checked(request->part_number - 1, meta_request->part_size, &request->part_range_start)) {
347+
return AWS_OP_ERR;
348+
}
349+
if (aws_add_u64_checked(request->part_range_start, request_body_size - 1, &request->part_range_end)) {
350+
return AWS_OP_ERR;
351+
}
352+
request->content_length = request_body_size;
353+
return AWS_OP_SUCCESS;
354+
}
355+
326356
/* Allocate a new auto-ranged put meta request */
327357
struct aws_s3_meta_request *aws_s3_meta_request_auto_ranged_put_new(
328358
struct aws_allocator *allocator,
@@ -605,6 +635,8 @@ static bool s_s3_auto_ranged_put_update(
605635

606636
request->part_number = auto_ranged_put->threaded_update_data.next_part_number;
607637

638+
s_compute_request_body_size(meta_request, request);
639+
608640
/* If request was previously uploaded, we prepare it to ensure checksums still match,
609641
* but ultimately it gets marked no-op and we don't send it */
610642
request->was_previously_uploaded = request_previously_uploaded;
@@ -761,36 +793,6 @@ static bool s_s3_auto_ranged_put_update(
761793
return work_remaining;
762794
}
763795

764-
/**
765-
* Helper to initialize the request ranges and content-length
766-
* based on the request->part_number and meta_request->part_size
767-
*/
768-
static int s_compute_request_body_size(const struct aws_s3_meta_request *meta_request, struct aws_s3_request *request) {
769-
AWS_ERROR_PRECONDITION(meta_request);
770-
AWS_ERROR_PRECONDITION(request);
771-
772-
const struct aws_s3_auto_ranged_put *auto_ranged_put = meta_request->impl;
773-
774-
size_t request_body_size = meta_request->part_size;
775-
/* Last part--adjust size to match remaining content length. */
776-
if (auto_ranged_put->has_content_length &&
777-
request->part_number == auto_ranged_put->total_num_parts_from_content_length) {
778-
size_t content_remainder = (size_t)(auto_ranged_put->content_length % (uint64_t)meta_request->part_size);
779-
780-
if (content_remainder > 0) {
781-
request_body_size = content_remainder;
782-
}
783-
}
784-
if (aws_mul_u64_checked(request->part_number - 1, meta_request->part_size, &request->part_range_start)) {
785-
return AWS_OP_ERR;
786-
}
787-
if (aws_add_u64_checked(request->part_range_start, request_body_size - 1, &request->part_range_end)) {
788-
return AWS_OP_ERR;
789-
}
790-
request->content_length = request_body_size;
791-
return AWS_OP_SUCCESS;
792-
}
793-
794796
static int s_verify_part_matches_checksum(
795797
struct aws_allocator *allocator,
796798
struct aws_byte_cursor body_cur,

source/s3_client.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "aws/s3/private/s3_default_meta_request.h"
1212
#include "aws/s3/private/s3_meta_request_impl.h"
1313
#include "aws/s3/private/s3_parallel_input_stream.h"
14+
#include "aws/s3/private/s3_request.h"
1415
#include "aws/s3/private/s3_request_messages.h"
1516
#include "aws/s3/private/s3_util.h"
1617
#include "aws/s3/private/s3express_credentials_provider_impl.h"
@@ -2059,7 +2060,10 @@ void s_acquire_mem_and_prepare_request(
20592060
aws_s3_meta_request_prepare_request_callback_fn *callback,
20602061
void *user_data) {
20612062

2062-
if (request->ticket == NULL && request->should_allocate_buffer_from_pool) {
2063+
size_t request_size = (size_t)aws_s3_request_get_payload_size(request);
2064+
AWS_ASSERT(request_size != 0); /* Note: 0 request size is invalid in all cases. */
2065+
2066+
if (request->ticket == NULL && request->should_allocate_buffer_from_pool && request_size > 0) {
20632067

20642068
if (request->send_data.metrics) {
20652069
struct aws_s3_request_metrics *metric = request->send_data.metrics;
@@ -2069,10 +2073,11 @@ void s_acquire_mem_and_prepare_request(
20692073

20702074
struct aws_allocator *allocator = request->allocator;
20712075
struct aws_s3_meta_request *meta_request = request->meta_request;
2076+
20722077
struct aws_s3_buffer_pool_reserve_meta meta = {
20732078
.client = client,
20742079
.meta_request = meta_request,
2075-
.size = request->buffer_size,
2080+
.size = request_size,
20762081
};
20772082

20782083
struct aws_s3_reserve_memory_payload *payload =

0 commit comments

Comments
 (0)