Skip to content

Commit 7eed309

Browse files
error pending futures out on cancel
1 parent b8155a3 commit 7eed309

File tree

5 files changed

+58
-5
lines changed

5 files changed

+58
-5
lines changed

include/aws/s3/private/s3_meta_request_impl.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,9 @@ struct aws_s3_meta_request {
227227
/* To track aws_s3_requests with cancellable HTTP streams */
228228
struct aws_linked_list cancellable_http_streams_list;
229229

230+
/* To track aws_future_s3_buffers that might need to be cleaned up on cancel */
231+
struct aws_linked_list pending_buffer_futures;
232+
230233
/* Data for async-writes. */
231234
struct aws_s3_async_write_data {
232235
/* Whether a part request can be sent (we have 1 part's worth of data, or EOF) */
@@ -403,6 +406,9 @@ bool aws_s3_meta_request_are_events_out_for_delivery_synced(struct aws_s3_meta_r
403406
/* Cancel the requests with cancellable HTTP stream for the meta request */
404407
void aws_s3_meta_request_cancel_cancellable_requests_synced(struct aws_s3_meta_request *meta_request, int error_code);
405408

409+
/* Cancel the pending buffer futures for the meta request */
410+
void aws_s3_meta_request_cancel_pending_buffer_futures_synced(struct aws_s3_meta_request *meta_request, int error_code);
411+
406412
/* Asynchronously read from the meta request's input stream. Should always be done outside of any mutex,
407413
* as reading from the stream could cause user code to call back into aws-c-s3.
408414
* This will fill the buffer to capacity, unless end of stream is reached.

include/aws/s3/private/s3_request.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,16 @@ struct aws_s3_request {
114114
/* Linked list node used for tracking the request is active from HTTP level. */
115115
struct aws_linked_list_node cancellable_http_streams_list_node;
116116

117+
/* Linked list node used for tracking buffer acquire futures. */
118+
struct aws_linked_list_node pending_buffer_future_list_node;
119+
117120
/* The meta request lock must be held to access the data */
118121
struct {
119122
/* The underlying http stream, only valid when the request is active from HTTP level */
120123
struct aws_http_stream *cancellable_http_stream;
124+
125+
/* Buffer future. */
126+
struct aws_future_s3_buffer_ticket *buffer_future;
121127
} synced_data;
122128

123129
/* TODO Ref count on the request is no longer needed--only one part of code should ever be holding onto a request,

source/s3_auto_ranged_put.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1743,6 +1743,7 @@ static int s_s3_auto_ranged_put_pause(
17431743
aws_s3_meta_request_set_fail_synced(meta_request, NULL, AWS_ERROR_S3_PAUSED);
17441744

17451745
aws_s3_meta_request_cancel_cancellable_requests_synced(meta_request, AWS_ERROR_S3_PAUSED);
1746+
aws_s3_meta_request_cancel_pending_buffer_futures_synced(meta_request, AWS_ERROR_S3_PAUSED);
17461747

17471748
/* unlock */
17481749
aws_s3_meta_request_unlock_synced_data(meta_request);

source/s3_client.c

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1860,16 +1860,26 @@ static void s_on_pool_buffer_reserved(void *user_data) {
18601860

18611861
request->ticket = aws_future_s3_buffer_ticket_get_result_by_move(future_ticket);
18621862

1863+
/* BEGIN CRITICAL SECTION */
1864+
{
1865+
aws_s3_meta_request_lock_synced_data(meta_request);
1866+
AWS_FATAL_ASSERT(request->synced_data.buffer_future);
1867+
aws_linked_list_remove(&request->pending_buffer_future_list_node);
1868+
request->synced_data.buffer_future = aws_future_s3_buffer_ticket_release(request->synced_data.buffer_future);
1869+
aws_s3_meta_request_unlock_synced_data(meta_request);
1870+
}
1871+
/* END CRITICAL SECTION */
1872+
18631873
aws_future_s3_buffer_ticket_release(payload->buffer_future);
18641874
aws_mem_release(payload->allocator, payload);
18651875

1866-
aws_s3_meta_request_prepare_request(request->meta_request,
1867-
request, payload->callback, payload->user_data);
1876+
aws_s3_meta_request_prepare_request(request->meta_request, request, payload->callback, payload->user_data);
18681877
return;
18691878
}
18701879

1871-
void s_acquire_mem_and_prepare_request(struct aws_s3_client *client,
1872-
struct aws_s3_request *request,
1880+
void s_acquire_mem_and_prepare_request(
1881+
struct aws_s3_client *client,
1882+
struct aws_s3_request *request,
18731883
aws_s3_meta_request_prepare_request_callback_fn *callback,
18741884
void *user_data) {
18751885

@@ -1879,14 +1889,25 @@ void s_acquire_mem_and_prepare_request(struct aws_s3_client *client,
18791889
struct aws_s3_buffer_pool_reserve_meta meta = {
18801890
.client = client, .meta_request = meta_request, .size = meta_request->part_size};
18811891

1882-
struct aws_s3_reserve_memory_payload *payload = aws_mem_calloc(allocator, 1, sizeof(struct aws_s3_reserve_memory_payload));
1892+
struct aws_s3_reserve_memory_payload *payload =
1893+
aws_mem_calloc(allocator, 1, sizeof(struct aws_s3_reserve_memory_payload));
18831894

18841895
payload->allocator = allocator;
18851896
payload->request = request;
18861897
payload->callback = callback;
18871898
payload->user_data = user_data;
18881899
payload->buffer_future = aws_s3_buffer_pool_reserve(request->meta_request->client->buffer_pool, meta);
18891900

1901+
/* BEGIN CRITICAL SECTION */
1902+
{
1903+
aws_s3_meta_request_lock_synced_data(meta_request);
1904+
aws_linked_list_push_back(
1905+
&meta_request->synced_data.pending_buffer_futures, &request->pending_buffer_future_list_node);
1906+
request->synced_data.buffer_future = aws_future_s3_buffer_ticket_acquire(payload->buffer_future);
1907+
aws_s3_meta_request_unlock_synced_data(meta_request);
1908+
}
1909+
/* END CRITICAL SECTION */
1910+
18901911
aws_future_s3_buffer_ticket_register_callback(payload->buffer_future, s_on_pool_buffer_reserved, payload);
18911912
return;
18921913
}

source/s3_meta_request.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ int aws_s3_meta_request_init_base(
180180
/* Set up reference count. */
181181
aws_ref_count_init(&meta_request->ref_count, meta_request, s_s3_meta_request_destroy);
182182
aws_linked_list_init(&meta_request->synced_data.cancellable_http_streams_list);
183+
aws_linked_list_init(&meta_request->synced_data.pending_buffer_futures);
183184

184185
if (part_size == SIZE_MAX) {
185186
aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
@@ -377,6 +378,7 @@ void aws_s3_meta_request_cancel(struct aws_s3_meta_request *meta_request) {
377378
aws_s3_meta_request_lock_synced_data(meta_request);
378379
aws_s3_meta_request_set_fail_synced(meta_request, NULL, AWS_ERROR_S3_CANCELED);
379380
aws_s3_meta_request_cancel_cancellable_requests_synced(meta_request, AWS_ERROR_S3_CANCELED);
381+
aws_s3_meta_request_cancel_pending_buffer_futures_synced(meta_request, AWS_ERROR_S3_CANCELED);
380382
aws_s3_meta_request_unlock_synced_data(meta_request);
381383
/* END CRITICAL SECTION */
382384

@@ -537,6 +539,7 @@ static void s_s3_meta_request_destroy(void *user_data) {
537539
aws_array_list_clean_up(&meta_request->io_threaded_data.event_delivery_array);
538540

539541
AWS_ASSERT(aws_linked_list_empty(&meta_request->synced_data.cancellable_http_streams_list));
542+
AWS_ASSERT(aws_linked_list_empty(&meta_request->synced_data.pending_buffer_futures));
540543

541544
aws_s3_meta_request_result_clean_up(meta_request, &meta_request->synced_data.finish_result);
542545

@@ -1825,6 +1828,22 @@ void aws_s3_meta_request_cancel_cancellable_requests_synced(struct aws_s3_meta_r
18251828
}
18261829
}
18271830

1831+
void aws_s3_meta_request_cancel_pending_buffer_futures_synced(
1832+
struct aws_s3_meta_request *meta_request,
1833+
int error_code) {
1834+
ASSERT_SYNCED_DATA_LOCK_HELD(meta_request);
1835+
while (!aws_linked_list_empty(&meta_request->synced_data.pending_buffer_futures)) {
1836+
1837+
struct aws_linked_list_node *request_node =
1838+
aws_linked_list_pop_front(&meta_request->synced_data.pending_buffer_futures);
1839+
1840+
struct aws_s3_request *request =
1841+
AWS_CONTAINER_OF(request_node, struct aws_s3_request, pending_buffer_future_list_node);
1842+
1843+
aws_future_s3_buffer_ticket_set_error(request->synced_data.buffer_future, error_code);
1844+
}
1845+
}
1846+
18281847
static struct aws_s3_request_metrics *s_s3_request_finish_up_and_release_metrics(
18291848
struct aws_s3_request_metrics *metrics,
18301849
struct aws_s3_meta_request *meta_request) {

0 commit comments

Comments
 (0)