Skip to content

Commit

Permalink
avoid allocating copies of known operation name strings
Browse files Browse the repository at this point in the history
  • Loading branch information
graebm committed Jun 19, 2024
1 parent 550678b commit 4d52adb
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 58 deletions.
11 changes: 11 additions & 0 deletions include/aws/s3/private/s3_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,17 @@ extern const uint32_t g_s3_max_num_upload_parts;
AWS_S3_API
enum aws_s3_request_type aws_s3_request_type_from_operation_name(struct aws_byte_cursor name);

/**
* Return operation name for aws_s3_request_type as static-lifetime aws_string*
* or NULL if the type doesn't map to an actual operation.
* For example:
* AWS_S3_REQUEST_TYPE_HEAD_OBJECT -> static aws_string "HeadObject"
* AWS_S3_REQUEST_TYPE_UNKNOWN -> NULL
* AWS_S3_REQUEST_TYPE_MAX -> NULL
*/
AWS_S3_API
struct aws_string *aws_s3_request_type_to_operation_name_static_string(enum aws_s3_request_type type);

/**
* Cache and initial the signing config based on the client.
*
Expand Down
120 changes: 74 additions & 46 deletions source/s3.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,44 +77,90 @@ static struct aws_log_subject_info_list s_s3_log_subject_list = {
.count = AWS_ARRAY_SIZE(s_s3_log_subject_infos),
};

struct aws_s3_request_type_operation_name_pair {
struct aws_s3_request_type_info {
enum aws_s3_request_type type;
struct aws_byte_cursor name;
struct aws_string *name_string;
struct aws_byte_cursor name_cursor;
};

#define DEFINE_REQUEST_TYPE_OPERATION_NAME_PAIR(TYPE, NAME) \
[TYPE] = {.type = TYPE, .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(NAME)}

static struct aws_s3_request_type_operation_name_pair s_s3_request_type_operation_name_array[] = {
DEFINE_REQUEST_TYPE_OPERATION_NAME_PAIR(AWS_S3_REQUEST_TYPE_HEAD_OBJECT, "HeadObject"),
DEFINE_REQUEST_TYPE_OPERATION_NAME_PAIR(AWS_S3_REQUEST_TYPE_GET_OBJECT, "GetObject"),
DEFINE_REQUEST_TYPE_OPERATION_NAME_PAIR(AWS_S3_REQUEST_TYPE_LIST_PARTS, "ListParts"),
DEFINE_REQUEST_TYPE_OPERATION_NAME_PAIR(AWS_S3_REQUEST_TYPE_CREATE_MULTIPART_UPLOAD, "CreateMultipartUpload"),
DEFINE_REQUEST_TYPE_OPERATION_NAME_PAIR(AWS_S3_REQUEST_TYPE_UPLOAD_PART, "UploadPart"),
DEFINE_REQUEST_TYPE_OPERATION_NAME_PAIR(AWS_S3_REQUEST_TYPE_ABORT_MULTIPART_UPLOAD, "AbortMultipartUpload"),
DEFINE_REQUEST_TYPE_OPERATION_NAME_PAIR(AWS_S3_REQUEST_TYPE_COMPLETE_MULTIPART_UPLOAD, "CompleteMultipartUpload"),
DEFINE_REQUEST_TYPE_OPERATION_NAME_PAIR(AWS_S3_REQUEST_TYPE_UPLOAD_PART_COPY, "UploadPartCopy"),
DEFINE_REQUEST_TYPE_OPERATION_NAME_PAIR(AWS_S3_REQUEST_TYPE_COPY_OBJECT, "CopyObject"),
DEFINE_REQUEST_TYPE_OPERATION_NAME_PAIR(AWS_S3_REQUEST_TYPE_PUT_OBJECT, "PutObject"),
DEFINE_REQUEST_TYPE_OPERATION_NAME_PAIR(AWS_S3_REQUEST_TYPE_CREATE_SESSION, "CreateSession"),
};
static struct aws_s3_request_type_info s_s3_request_type_info_array[AWS_S3_REQUEST_TYPE_MAX];

/* Hash-table for case-insensitive lookup, from operation-name -> request-type.
* key is operation-name (stored as `struct aws_byte_cursor*`, pointing into array above).
* value is request-type (stored as `enum aws_s3_request_type *`, pointing into array above). */
static struct aws_hash_table s_s3_operation_name_to_request_type_table;

const char *aws_s3_request_type_operation_name(enum aws_s3_request_type type) {
static void s_s3_request_type_register(enum aws_s3_request_type type, const struct aws_string *name) {

AWS_PRECONDITION(type >= 0 && type < AWS_ARRAY_SIZE(s_s3_request_type_info_array));
AWS_PRECONDITION(AWS_IS_ZEROED(s_s3_request_type_info_array[type]));

struct aws_s3_request_type_info *info = &s_s3_request_type_info_array[type];
info->type = type;
info->name_string = (struct aws_string *)name;
info->name_cursor = aws_byte_cursor_from_string(name);

int err = aws_hash_table_put(&s_s3_operation_name_to_request_type_table, &info->name_cursor, &info->type, NULL);
AWS_FATAL_ASSERT(!err);
}

AWS_STATIC_STRING_FROM_LITERAL(s_HeadObject_str, "HeadObject");
AWS_STATIC_STRING_FROM_LITERAL(s_GetObject_str, "GetObject");
AWS_STATIC_STRING_FROM_LITERAL(s_ListParts_str, "ListParts");
AWS_STATIC_STRING_FROM_LITERAL(s_CreateMultipartUpload_str, "CreateMultipartUpload");
AWS_STATIC_STRING_FROM_LITERAL(s_UploadPart_str, "UploadPart");
AWS_STATIC_STRING_FROM_LITERAL(s_AbortMultipartUpload_str, "AbortMultipartUpload");
AWS_STATIC_STRING_FROM_LITERAL(s_CompleteMultipartUpload_str, "CompleteMultipartUpload");
AWS_STATIC_STRING_FROM_LITERAL(s_UploadPartCopy_str, "UploadPartCopy");
AWS_STATIC_STRING_FROM_LITERAL(s_CopyObject_str, "CopyObject");
AWS_STATIC_STRING_FROM_LITERAL(s_PutObject_str, "PutObject");
AWS_STATIC_STRING_FROM_LITERAL(s_CreateSession_str, "CreateSession");

static void s_s3_request_type_info_init(struct aws_allocator *allocator) {
int err = aws_hash_table_init(
&s_s3_operation_name_to_request_type_table,
allocator,
AWS_ARRAY_SIZE(s_s3_request_type_info_array) /*initial_size*/,
aws_hash_byte_cursor_ptr_ignore_case,
(aws_hash_callback_eq_fn *)aws_byte_cursor_eq_ignore_case,
NULL /*destroy_key*/,
NULL /*destroy_value*/);
AWS_FATAL_ASSERT(!err);

s_s3_request_type_register(AWS_S3_REQUEST_TYPE_HEAD_OBJECT, s_HeadObject_str);
s_s3_request_type_register(AWS_S3_REQUEST_TYPE_GET_OBJECT, s_GetObject_str);
s_s3_request_type_register(AWS_S3_REQUEST_TYPE_LIST_PARTS, s_ListParts_str);
s_s3_request_type_register(AWS_S3_REQUEST_TYPE_CREATE_MULTIPART_UPLOAD, s_CreateMultipartUpload_str);
s_s3_request_type_register(AWS_S3_REQUEST_TYPE_UPLOAD_PART, s_UploadPart_str);
s_s3_request_type_register(AWS_S3_REQUEST_TYPE_ABORT_MULTIPART_UPLOAD, s_AbortMultipartUpload_str);
s_s3_request_type_register(AWS_S3_REQUEST_TYPE_COMPLETE_MULTIPART_UPLOAD, s_CompleteMultipartUpload_str);
s_s3_request_type_register(AWS_S3_REQUEST_TYPE_UPLOAD_PART_COPY, s_UploadPartCopy_str);
s_s3_request_type_register(AWS_S3_REQUEST_TYPE_COPY_OBJECT, s_CopyObject_str);
s_s3_request_type_register(AWS_S3_REQUEST_TYPE_PUT_OBJECT, s_PutObject_str);
s_s3_request_type_register(AWS_S3_REQUEST_TYPE_CREATE_SESSION, s_CreateSession_str);
}

static void s_s3_request_type_info_clean_up(void) {
aws_hash_table_clean_up(&s_s3_operation_name_to_request_type_table);
}

struct aws_string *aws_s3_request_type_to_operation_name_static_string(enum aws_s3_request_type type) {

if (type >= 0 && type < AWS_ARRAY_SIZE(s_s3_request_type_info_array)) {
struct aws_s3_request_type_info *info = &s_s3_request_type_info_array[type];
return info->name_string;
}

if (type >= 0 && type < AWS_ARRAY_SIZE(s_s3_request_type_operation_name_array)) {
const struct aws_s3_request_type_operation_name_pair *pair = &s_s3_request_type_operation_name_array[type];
/* The array may have gaps in it */
if (pair->name.len > 0) {
return (const char *)pair->name.ptr;
}
return NULL;
}

const char *aws_s3_request_type_operation_name(enum aws_s3_request_type type) {
struct aws_string *name_string = aws_s3_request_type_to_operation_name_static_string(type);
if (name_string != NULL) {
return aws_string_c_str(name_string);
}

return "";
return NULL;
}

enum aws_s3_request_type aws_s3_request_type_from_operation_name(struct aws_byte_cursor name) {
Expand Down Expand Up @@ -149,25 +195,7 @@ void aws_s3_library_init(struct aws_allocator *allocator) {
aws_register_log_subject_info_list(&s_s3_log_subject_list);
s_loader = aws_s3_platform_info_loader_new(allocator);
AWS_FATAL_ASSERT(s_loader);

/* Initialize s_s3_operation_name_to_request_type_table */
int err = aws_hash_table_init(
&s_s3_operation_name_to_request_type_table,
allocator,
AWS_ARRAY_SIZE(s_s3_request_type_operation_name_array) /*initial_size*/,
aws_hash_byte_cursor_ptr_ignore_case,
(aws_hash_callback_eq_fn *)aws_byte_cursor_eq_ignore_case,
NULL /*destroy_key*/,
NULL /*destroy_value*/);
AWS_FATAL_ASSERT(!err);
for (size_t i = 0; i < AWS_ARRAY_SIZE(s_s3_request_type_operation_name_array); ++i) {
struct aws_s3_request_type_operation_name_pair *pair = &s_s3_request_type_operation_name_array[i];
/* The array may have gaps in it */
if (pair->name.len != 0) {
err = aws_hash_table_put(&s_s3_operation_name_to_request_type_table, &pair->name, &pair->type, NULL);
AWS_FATAL_ASSERT(!err);
}
}
s_s3_request_type_info_init(allocator);

s_library_initialized = true;
}
Expand All @@ -192,7 +220,7 @@ void aws_s3_library_clean_up(void) {
s_library_initialized = false;
aws_thread_join_all_managed();

aws_hash_table_clean_up(&s_s3_operation_name_to_request_type_table);
s_s3_request_type_info_clean_up();
s_loader = aws_s3_platform_info_loader_release(s_loader);
aws_unregister_log_subject_info_list(&s_s3_log_subject_list);
aws_unregister_error_info(&s_error_list);
Expand Down
20 changes: 12 additions & 8 deletions source/s3_default_meta_request.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,16 +107,20 @@ struct aws_s3_meta_request *aws_s3_meta_request_default_new(

meta_request_default->content_length = (size_t)content_length;

if (request_type == AWS_S3_REQUEST_TYPE_UNKNOWN) {
/* use name to get type */
meta_request_default->operation_name = aws_string_new_from_cursor(allocator, &options->operation_name);
/* If request_type is unknown, look it up from operation name */
if (request_type != AWS_S3_REQUEST_TYPE_UNKNOWN) {
meta_request_default->request_type = request_type;
} else {
meta_request_default->request_type = aws_s3_request_type_from_operation_name(options->operation_name);
}

/* If we have a static string for this operation name, use that.
* Otherwise, copy the operation_name passed in by user. */
struct aws_string *static_operation_name = aws_s3_request_type_to_operation_name_static_string(request_type);
if (static_operation_name != NULL) {
meta_request_default->operation_name = static_operation_name;
} else {
/* use type to get name */
meta_request_default->request_type = request_type;
meta_request_default->operation_name =
aws_string_new_from_c_str(allocator, aws_s3_request_type_operation_name(request_type));
AWS_ASSERT(meta_request_default->operation_name->len != 0);
meta_request_default->operation_name = aws_string_new_from_cursor(allocator, &options->operation_name);
}

AWS_LOGF_DEBUG(
Expand Down
5 changes: 1 addition & 4 deletions source/s3_request.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,7 @@ struct aws_s3_request *aws_s3_request_new(
request->request_tag = request_tag;
request->request_type = request_type;

const char *operation_name = aws_s3_request_type_operation_name(request_type);
if (operation_name[0] != '\0') {
request->operation_name = aws_string_new_from_c_str(request->allocator, operation_name);
}
request->operation_name = aws_s3_request_type_to_operation_name_static_string(request_type);

request->part_number = part_number;
request->record_response_headers = (flags & AWS_S3_REQUEST_FLAG_RECORD_RESPONSE_HEADERS) != 0;
Expand Down

0 comments on commit 4d52adb

Please sign in to comment.