diff options
author | robot-contrib <robot-contrib@yandex-team.com> | 2023-03-07 09:11:05 +0300 |
---|---|---|
committer | robot-contrib <robot-contrib@yandex-team.com> | 2023-03-07 09:11:05 +0300 |
commit | 980f2a05eb72bde52c212d5c67f8860e45ef1b10 (patch) | |
tree | aea8ee1e3d4e5c51e3de18069d4bc56a2021c31b /contrib | |
parent | db461a7619dcd5bc525a809660d32a5331638e85 (diff) | |
download | ydb-980f2a05eb72bde52c212d5c67f8860e45ef1b10.tar.gz |
Update contrib/restricted/aws/aws-c-io to 0.13.17
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/restricted/aws/aws-c-io/include/aws/io/host_resolver.h | 49 | ||||
-rw-r--r-- | contrib/restricted/aws/aws-c-io/source/host_resolver.c | 268 |
2 files changed, 263 insertions, 54 deletions
diff --git a/contrib/restricted/aws/aws-c-io/include/aws/io/host_resolver.h b/contrib/restricted/aws/aws-c-io/include/aws/io/host_resolver.h index aed7430727..7733edfb87 100644 --- a/contrib/restricted/aws/aws-c-io/include/aws/io/host_resolver.h +++ b/contrib/restricted/aws/aws-c-io/include/aws/io/host_resolver.h @@ -76,10 +76,20 @@ struct aws_host_listener; struct aws_host_listener_options; +struct aws_host_resolver_purge_host_options { + /* the host to purge the cache for */ + const struct aws_string *host; + /* Callback to invoke when the purge is complete */ + aws_simple_completion_callback *on_host_purge_complete_callback; + /* user_data will be passed as it is in the callback. */ + void *user_data; +}; + /** should you absolutely disdain the default implementation, feel free to implement your own. */ struct aws_host_resolver_vtable { /** clean up everything you allocated, but not resolver itself. */ void (*destroy)(struct aws_host_resolver *resolver); + /** resolve the host by host_name, the user owns host_name, so it needs to be copied if you persist it, * invoke res with the result. This function should never block. */ int (*resolve_host)( @@ -88,12 +98,28 @@ struct aws_host_resolver_vtable { aws_on_host_resolved_result_fn *res, const struct aws_host_resolution_config *config, void *user_data); + /** gives your implementation a hint that an address has some failed connections occuring. Do whatever you want (or * nothing) about it. */ - int (*record_connection_failure)(struct aws_host_resolver *resolver, struct aws_host_address *address); - /** wipe out anything you have cached. */ + int (*record_connection_failure)(struct aws_host_resolver *resolver, const struct aws_host_address *address); + + /** + * @Deprecated Use purge_cache_with_callback instead + * wipe out anything you have cached. */ int (*purge_cache)(struct aws_host_resolver *resolver); + + /** wipe out anything you have cached. */ + int (*purge_cache_with_callback)( + struct aws_host_resolver *resolver, + aws_simple_completion_callback *on_purge_cache_complete_callback, + void *user_data); + + /** wipe out anything cached for a specific host */ + int (*purge_host_cache)( + struct aws_host_resolver *resolver, + const struct aws_host_resolver_purge_host_options *options); + /** get number of addresses for a given host. */ size_t (*get_host_address_count)( struct aws_host_resolver *resolver, @@ -212,14 +238,31 @@ AWS_IO_API int aws_host_resolver_resolve_host( */ AWS_IO_API int aws_host_resolver_record_connection_failure( struct aws_host_resolver *resolver, - struct aws_host_address *address); + const struct aws_host_address *address); /** + * @Deprecated Use purge_cache_with_callback instead * calls purge_cache on the vtable. */ AWS_IO_API int aws_host_resolver_purge_cache(struct aws_host_resolver *resolver); /** + * Calls aws_host_resolver_purge_cache_with_callback on the vtable which will wipe out everything host resolver has + * cached. + */ +AWS_IO_API int aws_host_resolver_purge_cache_with_callback( + struct aws_host_resolver *resolver, + aws_simple_completion_callback *on_purge_cache_complete_callback, + void *user_data); + +/** + * Removes the cache for a host asynchronously. + */ +AWS_IO_API int aws_host_resolver_purge_host_cache( + struct aws_host_resolver *resolver, + const struct aws_host_resolver_purge_host_options *options); + +/** * get number of addresses for a given host. */ AWS_IO_API size_t aws_host_resolver_get_host_address_count( diff --git a/contrib/restricted/aws/aws-c-io/source/host_resolver.c b/contrib/restricted/aws/aws-c-io/source/host_resolver.c index 050f00a187..4854ab16b7 100644 --- a/contrib/restricted/aws/aws-c-io/source/host_resolver.c +++ b/contrib/restricted/aws/aws-c-io/source/host_resolver.c @@ -2,6 +2,7 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ +#include <aws/io/event_loop.h> #include <aws/io/host_resolver.h> #include <aws/common/atomics.h> @@ -11,6 +12,7 @@ #include <aws/common/lru_cache.h> #include <aws/common/mutex.h> #include <aws/common/string.h> +#include <aws/common/task_scheduler.h> #include <aws/common/thread.h> #include <aws/io/logging.h> @@ -22,18 +24,7 @@ const uint64_t NS_PER_SEC = 1000000000; int aws_host_address_copy(const struct aws_host_address *from, struct aws_host_address *to) { to->allocator = from->allocator; to->address = aws_string_new_from_string(to->allocator, from->address); - - if (!to->address) { - return AWS_OP_ERR; - } - to->host = aws_string_new_from_string(to->allocator, from->host); - - if (!to->host) { - aws_string_destroy((void *)to->address); - return AWS_OP_ERR; - } - to->record_type = from->record_type; to->use_count = from->use_count; to->connection_failure_count = from->connection_failure_count; @@ -80,7 +71,37 @@ int aws_host_resolver_purge_cache(struct aws_host_resolver *resolver) { return resolver->vtable->purge_cache(resolver); } -int aws_host_resolver_record_connection_failure(struct aws_host_resolver *resolver, struct aws_host_address *address) { +int aws_host_resolver_purge_cache_with_callback( + struct aws_host_resolver *resolver, + aws_simple_completion_callback *on_purge_cache_complete_callback, + void *user_data) { + AWS_PRECONDITION(resolver); + AWS_PRECONDITION(resolver->vtable); + + if (!resolver->vtable->purge_cache_with_callback) { + AWS_LOGF_ERROR(AWS_LS_IO_DNS, "purge_cache_with_callback function is not supported"); + return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); + } + + return resolver->vtable->purge_cache_with_callback(resolver, on_purge_cache_complete_callback, user_data); +} + +int aws_host_resolver_purge_host_cache( + struct aws_host_resolver *resolver, + const struct aws_host_resolver_purge_host_options *options) { + AWS_PRECONDITION(resolver); + AWS_PRECONDITION(resolver->vtable); + + if (!resolver->vtable->purge_host_cache) { + AWS_LOGF_ERROR(AWS_LS_IO_DNS, "purge_host_cache function is not supported"); + return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); + } + return resolver->vtable->purge_host_cache(resolver, options); +} + +int aws_host_resolver_record_connection_failure( + struct aws_host_resolver *resolver, + const struct aws_host_address *address) { AWS_ASSERT(resolver->vtable && resolver->vtable->record_connection_failure); return resolver->vtable->record_connection_failure(resolver, address); } @@ -153,6 +174,8 @@ struct default_host_resolver { * Function to use to query current time. Overridable in construction options. */ aws_io_clock_fn *system_clock_fn; + + struct aws_event_loop_group *event_loop_group; }; /* Default host resolver implementation for listener. */ @@ -228,6 +251,8 @@ struct host_entry { enum default_resolver_state state; struct aws_array_list new_addresses; struct aws_array_list expired_addresses; + aws_simple_completion_callback *on_host_purge_complete; + void *on_host_purge_complete_user_data; }; /* @@ -286,10 +311,42 @@ static void s_remove_host_listener_from_entry( static void s_host_listener_destroy(struct host_listener *listener); +struct host_purge_callback_options { + struct aws_allocator *allocator; + struct aws_ref_count ref_count; + aws_simple_completion_callback *on_purge_cache_complete_callback; + void *user_data; +}; + +static void s_host_purge_callback_options_destroy(void *user_data) { + struct host_purge_callback_options *options = user_data; + options->on_purge_cache_complete_callback(options->user_data); + aws_mem_release(options->allocator, options); +} + +static struct host_purge_callback_options *s_host_purge_callback_options_new( + struct aws_allocator *allocator, + aws_simple_completion_callback *on_purge_cache_complete_callback, + void *user_data) { + struct host_purge_callback_options *purge_callback_options = + aws_mem_calloc(allocator, 1, sizeof(struct host_purge_callback_options)); + purge_callback_options->allocator = allocator; + aws_ref_count_init( + &purge_callback_options->ref_count, purge_callback_options, s_host_purge_callback_options_destroy); + purge_callback_options->on_purge_cache_complete_callback = on_purge_cache_complete_callback; + purge_callback_options->user_data = user_data; + return purge_callback_options; +} + +static void s_purge_cache_callback(void *user_data) { + struct host_purge_callback_options *purge_callback_options = user_data; + aws_ref_count_release(&purge_callback_options->ref_count); +} + /* * resolver lock must be held before calling this function */ -static void s_clear_default_resolver_entry_table(struct default_host_resolver *resolver) { +static void s_clear_default_resolver_entry_table_synced(struct default_host_resolver *resolver) { struct aws_hash_table *table = &resolver->host_entry_table; for (struct aws_hash_iter iter = aws_hash_iter_begin(table); !aws_hash_iter_done(&iter); aws_hash_iter_next(&iter)) { @@ -300,18 +357,75 @@ static void s_clear_default_resolver_entry_table(struct default_host_resolver *r aws_hash_table_clear(table); } -static int resolver_purge_cache(struct aws_host_resolver *resolver) { +static int s_resolver_purge_cache(struct aws_host_resolver *resolver) { struct default_host_resolver *default_host_resolver = resolver->impl; aws_mutex_lock(&default_host_resolver->resolver_lock); - s_clear_default_resolver_entry_table(default_host_resolver); + s_clear_default_resolver_entry_table_synced(default_host_resolver); aws_mutex_unlock(&default_host_resolver->resolver_lock); return AWS_OP_SUCCESS; } +static void s_purge_host_cache_callback_task(struct aws_task *task, void *arg, enum aws_task_status status) { + (void)status; + struct host_purge_callback_options *options = arg; + aws_mem_release(options->allocator, task); + aws_ref_count_release(&options->ref_count); +} + +static void s_sechdule_purge_cache_callback_async( + struct default_host_resolver *default_host_resolver, + struct host_purge_callback_options *purge_callback_options) { + + struct aws_task *task = aws_mem_calloc(default_host_resolver->allocator, 1, sizeof(struct aws_task)); + aws_task_init(task, s_purge_host_cache_callback_task, purge_callback_options, "async_purge_host_callback_task"); + + struct aws_event_loop *loop = aws_event_loop_group_get_next_loop(default_host_resolver->event_loop_group); + AWS_FATAL_ASSERT(loop != NULL); + aws_event_loop_schedule_task_now(loop, task); +} + +static int s_resolver_purge_cache_with_callback( + struct aws_host_resolver *resolver, + aws_simple_completion_callback *on_purge_cache_complete_callback, + void *user_data) { + + if (!on_purge_cache_complete_callback) { + return s_resolver_purge_cache(resolver); + } + + struct default_host_resolver *default_host_resolver = resolver->impl; + aws_mutex_lock(&default_host_resolver->resolver_lock); + struct aws_hash_table *table = &default_host_resolver->host_entry_table; + + struct host_purge_callback_options *purge_callback_options = s_host_purge_callback_options_new( + default_host_resolver->allocator, on_purge_cache_complete_callback, user_data); + + /* purge all cache */ + for (struct aws_hash_iter iter = aws_hash_iter_begin(table); !aws_hash_iter_done(&iter); + aws_hash_iter_next(&iter)) { + struct host_entry *entry = iter.element.value; + /* acquire a refernce to wait for the callback to trigger */ + aws_ref_count_acquire(&purge_callback_options->ref_count); + aws_mutex_lock(&entry->entry_lock); + entry->on_host_purge_complete = s_purge_cache_callback; + entry->on_host_purge_complete_user_data = purge_callback_options; + entry->state = DRS_SHUTTING_DOWN; + aws_mutex_unlock(&entry->entry_lock); + } + + aws_hash_table_clear(table); + aws_mutex_unlock(&default_host_resolver->resolver_lock); + + /* release the original reference async */ + s_sechdule_purge_cache_callback_async(default_host_resolver, purge_callback_options); + return AWS_OP_SUCCESS; +} + static void s_cleanup_default_resolver(struct aws_host_resolver *resolver) { struct default_host_resolver *default_host_resolver = resolver->impl; + aws_event_loop_group_release(default_host_resolver->event_loop_group); aws_hash_table_clean_up(&default_host_resolver->host_entry_table); aws_hash_table_clean_up(&default_host_resolver->listener_entry_table); @@ -337,7 +451,7 @@ static void resolver_destroy(struct aws_host_resolver *resolver) { AWS_FATAL_ASSERT(default_host_resolver->state == DRS_ACTIVE); - s_clear_default_resolver_entry_table(default_host_resolver); + s_clear_default_resolver_entry_table_synced(default_host_resolver); default_host_resolver->state = DRS_SHUTTING_DOWN; if (default_host_resolver->pending_host_entry_shutdown_completion_callbacks == 0) { cleanup_resolver = true; @@ -547,7 +661,58 @@ static inline void process_records( } } -static int resolver_record_connection_failure(struct aws_host_resolver *resolver, struct aws_host_address *address) { +static int s_resolver_purge_host_cache( + struct aws_host_resolver *resolver, + const struct aws_host_resolver_purge_host_options *options) { + + AWS_PRECONDITION(resolver); + if (options == NULL) { + AWS_LOGF_ERROR(AWS_LS_IO_DNS, "Cannot purge host cache; options structure is NULL."); + return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); + } + + struct default_host_resolver *default_host_resolver = resolver->impl; + AWS_LOGF_INFO(AWS_LS_IO_DNS, "id=%p: purging record for %s", (void *)resolver, options->host->bytes); + + aws_mutex_lock(&default_host_resolver->resolver_lock); + + struct aws_hash_element *element = NULL; + aws_hash_table_find(&default_host_resolver->host_entry_table, options->host, &element); + + /* Success if entry doesn't exist in cache. */ + if (element == NULL) { + aws_mutex_unlock(&default_host_resolver->resolver_lock); + if (options->on_host_purge_complete_callback != NULL) { + /* Schedule completion callback asynchronouly */ + struct host_purge_callback_options *purge_callback_options = s_host_purge_callback_options_new( + default_host_resolver->allocator, options->on_host_purge_complete_callback, options->user_data); + + s_sechdule_purge_cache_callback_async(default_host_resolver, purge_callback_options); + } + return AWS_OP_SUCCESS; + } + + struct host_entry *host_entry = element->value; + AWS_FATAL_ASSERT(host_entry); + + /* Setup the on_host_purge_complete callback. */ + aws_mutex_lock(&host_entry->entry_lock); + AWS_FATAL_ASSERT(!host_entry->on_host_purge_complete); + AWS_FATAL_ASSERT(!host_entry->on_host_purge_complete_user_data); + host_entry->on_host_purge_complete = options->on_host_purge_complete_callback; + host_entry->on_host_purge_complete_user_data = options->user_data; + aws_mutex_unlock(&host_entry->entry_lock); + + s_shutdown_host_entry(host_entry); + aws_hash_table_remove_element(&default_host_resolver->host_entry_table, element); + + aws_mutex_unlock(&default_host_resolver->resolver_lock); + return AWS_OP_SUCCESS; +} + +static int resolver_record_connection_failure( + struct aws_host_resolver *resolver, + const struct aws_host_address *address) { struct default_host_resolver *default_host_resolver = resolver->impl; AWS_LOGF_INFO( @@ -1211,6 +1376,10 @@ done: aws_array_list_clean_up(&new_address_list); aws_array_list_clean_up(&expired_address_list); + /* trigger the purge complete callback */ + if (host_entry->on_host_purge_complete != NULL) { + host_entry->on_host_purge_complete(host_entry->on_host_purge_complete_user_data); + } /* please don't fail */ aws_thread_current_at_exit(s_on_host_entry_shutdown_completion, host_entry); } @@ -1346,10 +1515,7 @@ static inline int create_and_init_host_entry( new_host_entry->resolution_config = *config; aws_condition_variable_init(&new_host_entry->entry_signal); - if (aws_thread_init(&new_host_entry->resolver_thread, resolver->allocator)) { - goto setup_host_entry_error; - } - + aws_thread_init(&new_host_entry->resolver_thread, resolver->allocator); thread_init = true; struct default_host_resolver *default_host_resolver = resolver->impl; if (AWS_UNLIKELY( @@ -1360,8 +1526,10 @@ static inline int create_and_init_host_entry( struct aws_thread_options thread_options = *aws_default_thread_options(); thread_options.join_strategy = AWS_TJS_MANAGED; thread_options.name = aws_byte_cursor_from_c_str("AwsHostResolver"); /* 15 characters is max for Linux */ - - aws_thread_launch(&new_host_entry->resolver_thread, aws_host_resolver_thread, new_host_entry, &thread_options); + if (aws_thread_launch( + &new_host_entry->resolver_thread, aws_host_resolver_thread, new_host_entry, &thread_options)) { + goto setup_host_entry_error; + } ++default_host_resolver->pending_host_entry_shutdown_completion_callbacks; return AWS_OP_SUCCESS; @@ -1371,6 +1539,10 @@ setup_host_entry_error: if (thread_init) { aws_thread_clean_up(&new_host_entry->resolver_thread); } + // If we registered a callback, clear it. So that we don’t trigger callback and return an error. + if (!aws_linked_list_empty(&new_host_entry->pending_resolution_callbacks)) { + aws_linked_list_remove(&pending_callback->node); + } s_clean_up_host_entry(new_host_entry); @@ -1446,37 +1618,31 @@ static int default_resolve_host( /* these will all need to be copied so that we don't hold the lock during the callback. */ if (aaaa_record) { struct aws_host_address aaaa_record_cpy; - if (!aws_host_address_copy(aaaa_record, &aaaa_record_cpy)) { - aws_array_list_push_back(&callback_address_list, &aaaa_record_cpy); - AWS_LOGF_TRACE( - AWS_LS_IO_DNS, - "id=%p: vending address %s for host %s to caller", - (void *)resolver, - aaaa_record->address->bytes, - host_entry->host_name->bytes); - } + aws_host_address_copy(aaaa_record, &aaaa_record_cpy); + aws_array_list_push_back(&callback_address_list, &aaaa_record_cpy); + AWS_LOGF_TRACE( + AWS_LS_IO_DNS, + "id=%p: vending address %s for host %s to caller", + (void *)resolver, + aaaa_record->address->bytes, + host_entry->host_name->bytes); } if (a_record) { struct aws_host_address a_record_cpy; - if (!aws_host_address_copy(a_record, &a_record_cpy)) { - aws_array_list_push_back(&callback_address_list, &a_record_cpy); - AWS_LOGF_TRACE( - AWS_LS_IO_DNS, - "id=%p: vending address %s for host %s to caller", - (void *)resolver, - a_record->address->bytes, - host_entry->host_name->bytes); - } + aws_host_address_copy(a_record, &a_record_cpy); + aws_array_list_push_back(&callback_address_list, &a_record_cpy); + AWS_LOGF_TRACE( + AWS_LS_IO_DNS, + "id=%p: vending address %s for host %s to caller", + (void *)resolver, + a_record->address->bytes, + host_entry->host_name->bytes); } aws_mutex_unlock(&host_entry->entry_lock); /* we don't want to do the callback WHILE we hold the lock someone may reentrantly call us. */ - if (aws_array_list_length(&callback_address_list)) { - res(resolver, host_name, AWS_OP_SUCCESS, &callback_address_list, user_data); - } else { - res(resolver, host_name, aws_last_error(), NULL, user_data); - result = AWS_OP_ERR; - } + // TODO: Fire the callback asynchronously + res(resolver, host_name, AWS_OP_SUCCESS, &callback_address_list, user_data); for (size_t i = 0; i < aws_array_list_length(&callback_address_list); ++i) { struct aws_host_address *address_ptr = NULL; @@ -1538,13 +1704,15 @@ static size_t default_get_host_address_count( } static struct aws_host_resolver_vtable s_vtable = { - .purge_cache = resolver_purge_cache, + .purge_cache = s_resolver_purge_cache, + .purge_cache_with_callback = s_resolver_purge_cache_with_callback, .resolve_host = default_resolve_host, .record_connection_failure = resolver_record_connection_failure, .get_host_address_count = default_get_host_address_count, .add_host_listener = default_add_host_listener, .remove_host_listener = default_remove_host_listener, .destroy = resolver_destroy, + .purge_host_cache = s_resolver_purge_host_cache, }; static void s_aws_host_resolver_destroy(struct aws_host_resolver *resolver) { @@ -1557,9 +1725,6 @@ struct aws_host_resolver *aws_host_resolver_new_default( const struct aws_host_resolver_default_options *options) { AWS_FATAL_ASSERT(options != NULL); - /* NOTE: we don't use el_group yet, but we will in the future. Also, we - don't want host resolvers getting cleaned up after el_groups; this will force that - in bindings, and encourage it in C land. */ AWS_ASSERT(options->el_group); struct aws_host_resolver *resolver = NULL; @@ -1587,6 +1752,7 @@ struct aws_host_resolver *aws_host_resolver_new_default( resolver->allocator = allocator; resolver->impl = default_host_resolver; + default_host_resolver->event_loop_group = aws_event_loop_group_acquire(options->el_group); default_host_resolver->allocator = allocator; default_host_resolver->pending_host_entry_shutdown_completion_callbacks = 0; default_host_resolver->state = DRS_ACTIVE; |