Skip to content

Commit 4b1634b

Browse files
authored
Fix max_pending_connection_acquisitions to respect connection pool size (#485)
1 parent 4e74ab1 commit 4b1634b

File tree

5 files changed

+62
-10
lines changed

5 files changed

+62
-10
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ on:
66
- 'main'
77

88
env:
9-
BUILDER_VERSION: v0.9.62
9+
BUILDER_VERSION: v0.9.64
1010
BUILDER_SOURCE: releases
1111
BUILDER_HOST: https://d19elf31gohf1l.cloudfront.net
1212
PACKAGE_NAME: aws-c-http

include/aws/http/connection_manager.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,9 @@ struct aws_http_connection_manager_options {
134134

135135
/*
136136
* If set to a non-zero value, aws_http_connection_manager_acquire_connection() calls will fail with
137-
* AWS_ERROR_HTTP_CONNECTION_MANAGER_MAX_PENDING_ACQUISITIONS_EXCEEDED if there are already pending acquisitions
138-
* equal to `max_pending_connection_acquisitions`.
137+
* AWS_ERROR_HTTP_CONNECTION_MANAGER_MAX_PENDING_ACQUISITIONS_EXCEEDED if the number of pending acquisitions
138+
* reaches `max_pending_connection_acquisitions` after the connection pool has reached its capacity (i.e., all
139+
* `num_connections` have been vended).
139140
*/
140141
uint64_t max_pending_connection_acquisitions;
141142

source/connection_manager.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1311,7 +1311,8 @@ void aws_http_connection_manager_acquire_connection(
13111311
AWS_FATAL_ASSERT(manager->state == AWS_HCMST_READY);
13121312

13131313
if (manager->max_pending_connection_acquisitions == 0 ||
1314-
manager->pending_acquisition_count < manager->max_pending_connection_acquisitions) {
1314+
manager->pending_acquisition_count + manager->internal_ref[AWS_HCMCT_VENDED_CONNECTION] <
1315+
manager->max_pending_connection_acquisitions + manager->max_connections) {
13151316
aws_linked_list_push_back(&manager->pending_acquisitions, &request->node);
13161317
++manager->pending_acquisition_count;
13171318
} else {

tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,7 @@ add_net_test_case(test_connection_manager_acquire_release)
546546
add_net_test_case(test_connection_manager_close_and_release)
547547
add_net_test_case(test_connection_manager_acquire_release_mix)
548548
add_net_test_case(test_connection_manager_max_pending_acquisitions)
549+
add_net_test_case(test_connection_manager_max_pending_acquisitions_with_vended_connections)
549550

550551
# Integration test that requires proxy envrionment in us-east-1 region.
551552
# TODO: test the server name validation properly

tests/test_connection_manager.c

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -749,32 +749,81 @@ static int s_test_connection_manager_max_pending_acquisitions(struct aws_allocat
749749
(void)ctx;
750750

751751
size_t num_connections = 2;
752-
size_t num_pending_connections = 3;
752+
size_t max_pending_connection_acquisitions = 2;
753+
size_t num_connections_pending_error = 4;
753754
struct cm_tester_options options = {
754755
.allocator = allocator,
755756
.max_connections = num_connections,
756-
.max_pending_connection_acquisitions = num_connections,
757+
.max_pending_connection_acquisitions = max_pending_connection_acquisitions,
757758
};
758759

759760
ASSERT_SUCCESS(s_cm_tester_init(&options));
760761

761-
s_acquire_connections(num_connections + num_pending_connections);
762+
s_acquire_connections(num_connections + max_pending_connection_acquisitions + num_connections_pending_error);
762763

763-
ASSERT_SUCCESS(s_wait_on_connection_reply_count(num_connections + num_pending_connections));
764-
ASSERT_UINT_EQUALS(num_pending_connections, s_tester.connection_errors);
765-
for (size_t i = 0; i < num_pending_connections; i++) {
764+
ASSERT_SUCCESS(s_wait_on_connection_reply_count(num_connections + num_connections_pending_error));
765+
ASSERT_UINT_EQUALS(num_connections_pending_error, s_tester.connection_errors);
766+
for (size_t i = 0; i < num_connections_pending_error; i++) {
766767
uint32_t error_code;
767768
aws_array_list_get_at(&s_tester.connection_errors_list, &error_code, i);
768769
ASSERT_UINT_EQUALS(AWS_ERROR_HTTP_CONNECTION_MANAGER_MAX_PENDING_ACQUISITIONS_EXCEEDED, error_code);
769770
}
771+
770772
ASSERT_SUCCESS(s_release_connections(num_connections, false));
773+
ASSERT_SUCCESS(s_wait_on_connection_reply_count(
774+
num_connections + max_pending_connection_acquisitions + num_connections_pending_error));
775+
ASSERT_SUCCESS(s_release_connections(max_pending_connection_acquisitions, false));
771776

772777
ASSERT_SUCCESS(s_cm_tester_clean_up());
773778

774779
return AWS_OP_SUCCESS;
775780
}
776781
AWS_TEST_CASE(test_connection_manager_max_pending_acquisitions, s_test_connection_manager_max_pending_acquisitions);
777782

783+
static int s_test_connection_manager_max_pending_acquisitions_with_vended_connections(
784+
struct aws_allocator *allocator,
785+
void *ctx) {
786+
(void)ctx;
787+
788+
size_t num_connections = 2;
789+
size_t max_pending_connection_acquisitions = 2;
790+
size_t num_connections_pending_error = 4;
791+
struct cm_tester_options options = {
792+
.allocator = allocator,
793+
.max_connections = num_connections,
794+
.max_pending_connection_acquisitions = max_pending_connection_acquisitions,
795+
};
796+
797+
ASSERT_SUCCESS(s_cm_tester_init(&options));
798+
799+
// fill the connection pool
800+
s_acquire_connections(num_connections);
801+
ASSERT_SUCCESS(s_wait_on_connection_reply_count(num_connections));
802+
803+
// try to acquire over max_pending_connection_acquisitions
804+
s_acquire_connections(max_pending_connection_acquisitions + num_connections_pending_error);
805+
ASSERT_SUCCESS(s_wait_on_connection_reply_count(num_connections + num_connections_pending_error));
806+
807+
ASSERT_UINT_EQUALS(num_connections_pending_error, s_tester.connection_errors);
808+
for (size_t i = 0; i < num_connections_pending_error; i++) {
809+
uint32_t error_code;
810+
aws_array_list_get_at(&s_tester.connection_errors_list, &error_code, i);
811+
ASSERT_UINT_EQUALS(AWS_ERROR_HTTP_CONNECTION_MANAGER_MAX_PENDING_ACQUISITIONS_EXCEEDED, error_code);
812+
}
813+
814+
ASSERT_SUCCESS(s_release_connections(num_connections, false));
815+
ASSERT_SUCCESS(s_wait_on_connection_reply_count(
816+
num_connections + max_pending_connection_acquisitions + num_connections_pending_error));
817+
ASSERT_SUCCESS(s_release_connections(max_pending_connection_acquisitions, false));
818+
819+
ASSERT_SUCCESS(s_cm_tester_clean_up());
820+
821+
return AWS_OP_SUCCESS;
822+
}
823+
AWS_TEST_CASE(
824+
test_connection_manager_max_pending_acquisitions_with_vended_connections,
825+
s_test_connection_manager_max_pending_acquisitions_with_vended_connections);
826+
778827
static int s_aws_http_connection_manager_create_connection_sync_mock(
779828
const struct aws_http_client_connection_options *options) {
780829
struct cm_tester *tester = &s_tester;

0 commit comments

Comments
 (0)