Skip to content

Commit

Permalink
S3Express (#381)
Browse files Browse the repository at this point in the history
Co-authored-by: Dmitriy Musatkin <musatkd@amazon.com>
Co-authored-by: Dmitriy Musatkin <63878209+DmitriyMusatkin@users.noreply.github.com>
Co-authored-by: Michael Graeb <graebm@amazon.com>
Co-authored-by: Waqar Ahmed Khan <waahm7@gmail.com>
  • Loading branch information
5 people committed Nov 28, 2023
1 parent cc6ba34 commit dc90010
Show file tree
Hide file tree
Showing 23 changed files with 6,162 additions and 2,772 deletions.
8 changes: 8 additions & 0 deletions include/aws/s3/private/s3_client_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,11 @@ struct aws_s3_client {
/* Cached signing config. Can be NULL if no signing config was specified. */
struct aws_cached_signing_config_aws *cached_signing_config;

/* The auth provider for S3 Express. */
aws_s3express_provider_factory_fn *s3express_provider_factory;
void *factory_user_data;
struct aws_s3express_credentials_provider *s3express_provider;

/* Throughput target in Gbps that we are trying to reach. */
const double throughput_target_gbps;

Expand Down Expand Up @@ -365,6 +370,9 @@ struct aws_s3_client {
* shutdown callback has not yet been called.*/
uint32_t body_streaming_elg_allocated : 1;

/* Whether or not a S3 Express provider is active with the client.*/
uint32_t s3express_provider_active : 1;

/* True if client has been flagged to finish destroying itself. Used to catch double-destroy bugs.*/
uint32_t finish_destroy : 1;

Expand Down
1 change: 1 addition & 0 deletions include/aws/s3/private/s3_meta_request_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ struct aws_s3_meta_request {
aws_s3_meta_request_finish_fn *finish_user_callback_after_checksum;

enum aws_s3_meta_request_type type;
struct aws_string *s3express_session_host;

struct {
struct aws_mutex lock;
Expand Down
10 changes: 10 additions & 0 deletions include/aws/s3/private/s3_request.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ struct aws_s3_request_metrics {
/* The time duration for the request from start receiving to finish receiving (receive_end_timestamp_ns -
* receive_start_timestamp_ns). When receive_end_timestamp_ns is 0, means data not available. */
int64_t receiving_duration_ns;

/* The time stamp when the request started to be signed. -1 means data not
* available. Timestamp are from `aws_high_res_clock_get_ticks` */
int64_t sign_start_timestamp_ns;
/* The time stamp when the response finished to be signed. -1 means data not
* available. Timestamp are from `aws_high_res_clock_get_ticks` */
int64_t sign_end_timestamp_ns;
/* The time duration for the request from start signing to finish signing (sign_end_timestamp_ns -
* sign_start_timestamp_ns). When sign_end_timestamp_ns is 0, means data not available. */
int64_t signing_duration_ns;
} time_metrics;

struct {
Expand Down
13 changes: 12 additions & 1 deletion include/aws/s3/private/s3_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ struct aws_allocator;
struct aws_http_stream;
struct aws_http_headers;
struct aws_http_message;
struct aws_s3_client;

enum aws_s3_response_status {
AWS_S3_RESPONSE_STATUS_SUCCESS = 200,
Expand Down Expand Up @@ -143,6 +144,9 @@ extern const size_t g_s3_min_upload_part_size;
AWS_S3_API
extern const struct aws_byte_cursor g_s3_service_name;

AWS_S3_API
extern const struct aws_byte_cursor g_s3express_service_name;

AWS_S3_API
extern const struct aws_byte_cursor g_range_header_name;

Expand All @@ -168,8 +172,15 @@ extern const struct aws_byte_cursor g_delete_method;
AWS_S3_API
extern const uint32_t g_s3_max_num_upload_parts;

/**
* Cache and initial the signing config based on the client.
*
* @param client
* @param signing_config
* @return struct aws_cached_signing_config_aws*
*/
struct aws_cached_signing_config_aws *aws_cached_signing_config_new(
struct aws_allocator *allocator,
struct aws_s3_client *client,
const struct aws_signing_config_aws *signing_config);

void aws_cached_signing_config_destroy(struct aws_cached_signing_config_aws *cached_signing_config);
Expand Down
118 changes: 118 additions & 0 deletions include/aws/s3/private/s3express_credentials_provider_impl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#ifndef AWS_S3EXPRESS_CREDENTIALS_PROVIDER_IMPL_H
#define AWS_S3EXPRESS_CREDENTIALS_PROVIDER_IMPL_H

#include <aws/common/hash_table.h>
#include <aws/common/mutex.h>
#include <aws/common/ref_count.h>
#include <aws/s3/s3_client.h>
#include <aws/s3/s3express_credentials_provider.h>

struct aws_cache;

/**
* Everything in the session should ONLY be accessed with lock HELD
*/
struct aws_s3express_session {
struct aws_allocator *allocator;
/* The hash key for the table storing creator and session. */
struct aws_string *hash_key;

/* The s3express credentials cached for the session */
struct aws_credentials *s3express_credentials;

/* Pointer to the creator if the session is in process creating */
struct aws_s3express_session_creator *creator;

/* The region and host of the session */
struct aws_string *region;
struct aws_string *host;
bool inactive;

/* Only used for mock tests */
struct aws_s3express_credentials_provider_impl *impl;
};

struct aws_s3express_credentials_provider_impl {
struct aws_s3_client *client;

/* Internal Refcount to make sure the provider out lives all the context. */
struct aws_ref_count internal_ref;

struct aws_task *bg_refresh_task;
struct aws_event_loop *bg_event_loop;

const struct aws_credentials *default_original_credentials;
struct aws_credentials_provider *default_original_credentials_provider;

struct {
/* Protected by the impl lock */
struct aws_mutex lock;
/**
* Store the session creators in process.
* `struct aws_string *` as Key. `struct aws_s3express_session_creator *` as Value
*/
struct aws_hash_table session_creator_table;
/**
* An LRU cache to store all the sessions.
* `struct aws_string *` as Key. `struct aws_s3express_session *` as Value
**/
struct aws_cache *cache;
bool destroying;
} synced_data;

struct {
/* Overrides for testing purpose. */

struct aws_uri *endpoint_override;
uint64_t bg_refresh_secs_override;

bool (*s3express_session_is_valid_override)(struct aws_s3express_session *session, uint64_t now_seconds);
bool (*s3express_session_about_to_expire_override)(struct aws_s3express_session *session, uint64_t now_seconds);

/* The callback to be invoked before the real meta request finished callback for provider */
aws_s3_meta_request_finish_fn *meta_request_finished_overhead;
} mock_test;
};

/**
* Configuration options for the default S3 Express credentials provider
*/
struct aws_s3express_credentials_provider_default_options {
/**
* The S3 client to fetch credentials.
* Note, the client is not owned by the provider, user should keep the s3 client outlive the provider. */
struct aws_s3_client *client;

/* Optional callback for shutdown complete of the provider */
aws_simple_completion_callback *shutdown_complete_callback;
void *shutdown_user_data;

struct {
uint64_t bg_refresh_secs_override;
} mock_test;
};

AWS_EXTERN_C_BEGIN
/**
* Create the default S3 Express credentials provider.
*
* @param allocator
* @return
*/
AWS_S3_API
struct aws_s3express_credentials_provider *aws_s3express_credentials_provider_new_default(
struct aws_allocator *allocator,
const struct aws_s3express_credentials_provider_default_options *options);

/**
* Encode the hash key to be [host_value][hash_of_credentials]
* hash_of_credentials is the sha256 of [access_key][secret_access_key]
*/
AWS_S3_API
struct aws_string *aws_encode_s3express_hash_key_new(
struct aws_allocator *allocator,
const struct aws_credentials *original_credentials,
struct aws_byte_cursor host_value);

AWS_EXTERN_C_END
#endif /* AWS_S3EXPRESS_CREDENTIALS_PROVIDER_IMPL_H */
84 changes: 80 additions & 4 deletions include/aws/s3/s3_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

#include <aws/auth/signing_config.h>
#include <aws/common/ref_count.h>
#include <aws/io/retry_strategy.h>
#include <aws/s3/s3.h>

Expand All @@ -19,6 +20,7 @@ struct aws_http_message;
struct aws_http_headers;
struct aws_tls_connection_options;
struct aws_input_stream;
struct aws_hash_table;

struct aws_s3_client;
struct aws_s3_request;
Expand All @@ -29,6 +31,8 @@ struct aws_uri;
struct aws_string;

struct aws_s3_request_metrics;
struct aws_s3express_credentials_provider;
struct aws_credentials_properties_s3express;

/**
* A Meta Request represents a group of generated requests that are being done on behalf of the
Expand Down Expand Up @@ -301,6 +305,34 @@ typedef int(aws_s3_meta_request_upload_review_fn)(
const struct aws_s3_upload_review *review,
void *user_data);

/**
* The factory function for S3 client to create a S3 Express credentials provider.
* The S3 client will be the only owner of the S3 Express credentials provider.
*
* During S3 client destruction, S3 client will start the destruction of the provider, and wait the
* on_provider_shutdown_callback to be invoked before the S3 client finish destruction.
*
* Note to implement the factory properly:
* - Make sure `on_provider_shutdown_callback` will be invoked after the provider finish shutdown, otherwise,
* leak will happen.
* - The provider must not acquire a reference to the client; otherwise, a circular reference will cause a deadlock.
* - The `client` provided CANNOT be used within the factory function call or the destructor.
*
* @param allocator memory allocator to create the provider.
* @param client The S3 client uses and owns the provider.
* @param on_provider_shutdown_callback The callback to be invoked when the provider finishes shutdown.
* @param shutdown_user_data The user data to invoke shutdown callback with
* @param user_data The user data with the factory
*
* @return The aws_s3express_credentials_provider.
*/
typedef struct aws_s3express_credentials_provider *(aws_s3express_provider_factory_fn)(
struct aws_allocator *allocator,
struct aws_s3_client *client,
aws_simple_completion_callback on_provider_shutdown_callback,
void *shutdown_user_data,
void *factory_user_data);

/* Keepalive properties are TCP only.
* If interval or timeout are zero, then default values are used.
*/
Expand All @@ -321,7 +353,7 @@ struct aws_s3_client_config {
* throughput_target_gbps. (Recommended) */
uint32_t max_active_connections_override;

/* Region that the S3 bucket lives in. */
/* Region that the client default to. */
struct aws_byte_cursor region;

/* Client bootstrap used for common staples such as event loop group, host resolver, etc.. s*/
Expand All @@ -340,7 +372,21 @@ struct aws_s3_client_config {
* is ENABLED, this is required. Otherwise, this is optional. */
struct aws_tls_connection_options *tls_connection_options;

/* Signing options to be used for each request. Specify NULL to not sign requests. */
/**
* Required.
* Configure the signing for the requests made from the client.
* - Credentials or credentials provider is required. Other configs are all optional, and will be default to what
* needs to sign the request for S3, only overrides when Non-zero/Not-empty is set.
* - To skip signing, you can config it with anonymous credentials.
* - S3 Client will derive the right config for signing process based on this.
*
* Notes:
* - For AWS_SIGNING_ALGORITHM_V4_S3EXPRESS, S3 client will use the credentials in the config to derive the
* S3 Express credentials that are used in the signing process.
* - For other auth algorithm, client may make modifications to signing config before passing it on to signer.
*
* TODO: deprecate this structure from auth, introduce a new S3 specific one.
*/
struct aws_signing_config_aws *signing_config;

/* Size of parts the files will be downloaded or uploaded in. */
Expand Down Expand Up @@ -436,6 +482,22 @@ struct aws_s3_client_config {
* Ignored unless `enable_read_backpressure` is true.
*/
size_t initial_read_window;

/**
* To enable S3 Express support or not.
*/
bool enable_s3express;

/**
* Optional.
* Only used when `enable_s3express` is set.
*
* If set, client will invoke the factory to get the provider to use, when needed.
*
* If not set, client will create a default S3 Express provider under the hood.
*/
aws_s3express_provider_factory_fn *s3express_provider_override_factory;
void *factory_user_data;
};

struct aws_s3_checksum_config {
Expand Down Expand Up @@ -506,8 +568,22 @@ struct aws_s3_meta_request_options {
*/
struct aws_byte_cursor operation_name;

/* Signing options to be used for each request created for this meta request. If NULL, options in the client will
* be used. If not NULL, these options will override the client options. */
/**
* Configure the signing for each request created for this meta request. If NULL, options in the client will be
* used.
* - The credentials will be obtained based on the precedence of:
* 1. `credentials` from `signing_config` in `aws_s3_meta_request_options`
* 2. `credentials_provider` from `signing_config` in `aws_s3_meta_request_options`
* 3. `credentials` from `signing_config` cached in the client
* 4. `credentials_provider` cached in the client
* - To skip signing, you can config it with anonymous credentials.
* - S3 Client will derive the right config for signing process based on this.
*
* Notes:
* - For AWS_SIGNING_ALGORITHM_V4_S3EXPRESS, S3 client will use the credentials in the config to derive the
* S3 Express credentials that are used in the signing process.
* - For other auth algorithm, client may make modifications to signing config before passing it on to signer.
**/
const struct aws_signing_config_aws *signing_config;

/* Initial HTTP message that defines what operation we are doing.
Expand Down
Loading

0 comments on commit dc90010

Please sign in to comment.