Skip to content

Commit

Permalink
Support H5Fget_filesize
Browse files Browse the repository at this point in the history
This does not trigger a rescan on server side, so it may
return a slightly out-of-date value
  • Loading branch information
mattjala committed Jan 30, 2024
1 parent c8e0237 commit 2e2b72a
Show file tree
Hide file tree
Showing 7 changed files with 227 additions and 8 deletions.
62 changes: 59 additions & 3 deletions src/rest_vol.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ const char *attributes_keys[] = {"attributes", (const char *)0};
/* JSON keys to retrieve allocated size */
const char *allocated_size_keys[] = {"allocated_size", (const char *)0};

/* JSON keys to retrieve information from a scan of a domain */
const char *scan_info_keys[] = {"scan_info", (const char *)0};
const char *allocated_bytes_keys[] = {"allocated_bytes", (const char *)0};

/* Default size for the buffer to allocate during base64-encoding if the caller
* of RV_base64_encode supplies a 0-sized buffer.
*/
Expand Down Expand Up @@ -252,7 +256,7 @@ static const H5VL_class_t H5VL_rest_g = {
RV_file_open,
RV_file_get,
RV_file_specific,
NULL,
RV_file_optional,
RV_file_close,
},

Expand Down Expand Up @@ -3393,9 +3397,9 @@ RV_parse_server_version(char *HTTP_response, void *callback_data_in, void *callb
return ret_value;
}

/* Helper function to parse an object's allocated size from server response */
/* Helper function to parse a non-domain object's allocated size from server response */
herr_t
RV_parse_allocated_size_callback(char *HTTP_response, void *callback_data_in, void *callback_data_out)
RV_parse_allocated_size_cb(char *HTTP_response, void *callback_data_in, void *callback_data_out)
{
yajl_val parse_tree = NULL, key_obj = NULL;
herr_t ret_value = SUCCEED;
Expand Down Expand Up @@ -3899,3 +3903,55 @@ RV_JSON_escape_string(const char *in, char *out, size_t *out_size)

return ret_value;
}

/*-------------------------------------------------------------------------
* Function: RV_parse_domain_allocated_size_cb
*
* Purpose: Given an HSDS response containing scan information about a
* domain, retrieves the allocated_byte values and modifies
* callback_data_out to point to it. HSDS returns scan info
* on a domain request with the 'verbose' parameter
*
* Return: Non-negative on success/Negative on failure
*
* Programmer: Matthew Larson
* January, 2024
*/
herr_t
RV_parse_domain_allocated_size_cb(char *HTTP_response, void *callback_data_in, void *callback_data_out)
{
yajl_val parse_tree = NULL, key_obj;
char *parsed_object_string;
size_t *filesize = (size_t *)callback_data_out;
herr_t ret_value = SUCCEED;

#ifdef RV_CONNECTOR_DEBUG
printf("-> Retrieving filesize from server's HTTP response\n\n");
#endif

if (!HTTP_response)
FUNC_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "HTTP response buffer was NULL");
if (!filesize)
FUNC_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "output pointer was NULL");

if (NULL == (parse_tree = yajl_tree_parse(HTTP_response, NULL, 0)))
FUNC_GOTO_ERROR(H5E_CALLBACK, H5E_PARSEERROR, FAIL, "parsing JSON failed");

if (NULL == (key_obj = yajl_tree_get(parse_tree, scan_info_keys, yajl_t_object)))
FUNC_GOTO_ERROR(H5E_CALLBACK, H5E_PARSEERROR, FAIL, "couldn't get scan info");

if (NULL == (key_obj = yajl_tree_get(key_obj, allocated_bytes_keys, yajl_t_number))) {
FUNC_GOTO_ERROR(H5E_CALLBACK, H5E_PARSEERROR, FAIL, "couldn't parse allocated bytes");
}

if (YAJL_GET_INTEGER(key_obj) < 0)
FUNC_GOTO_ERROR(H5E_CALLBACK, H5E_PARSEERROR, FAIL, "parsed filesize is negative");

*filesize = (size_t)YAJL_GET_INTEGER(key_obj);

done:
if (parse_tree)
yajl_tree_free(parse_tree);

return ret_value;
} /* end RV_parse_domain_allocated_size_cb */
9 changes: 7 additions & 2 deletions src/rest_vol.h
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,9 @@ typedef struct RV_type_info {
#define H5I_MAX_NUM_TYPES TYPE_MASK
extern RV_type_info *RV_type_info_array_g[];

/* Enum values in RV_file_optional_args_t that specify certain operations */
#define RV_FILE_GET_SIZE 8

/**************************
* *
* Typedefs *
Expand Down Expand Up @@ -737,8 +740,10 @@ size_t H5_rest_curl_write_data_callback_no_global(char *buffer, size_t size, siz
/* Helper to turn an object type into a string for a server request */
herr_t RV_set_object_type_header(H5I_type_t parent_obj_type, const char **parent_obj_type_header);

/* Helper function to parse an object's allocated size from server response */
herr_t RV_parse_allocated_size_callback(char *HTTP_response, void *callback_data_in, void *callback_data_out);
/* Helper functions to parse an object's allocated size from server response */
herr_t RV_parse_allocated_size_cb(char *HTTP_response, void *callback_data_in, void *callback_data_out);
herr_t RV_parse_domain_allocated_size_cb(char *HTTP_response, void *callback_data_in,
void *callback_data_out);

void RV_free_visited_link_hash_table_key(rv_hash_table_key_t value);

Expand Down
4 changes: 2 additions & 2 deletions src/rest_vol_dataset.c
Original file line number Diff line number Diff line change
Expand Up @@ -1429,8 +1429,8 @@ RV_dataset_get(void *obj, H5VL_dataset_get_args_t *args, hid_t dxpl_id, void **r

CURL_PERFORM(curl, H5E_DATASET, H5E_CANTGET, FAIL);

if (RV_parse_allocated_size_callback(response_buffer.buffer, NULL,
args->args.get_storage_size.storage_size) < 0)
if (RV_parse_allocated_size_cb(response_buffer.buffer, NULL,
args->args.get_storage_size.storage_size) < 0)
FUNC_GOTO_ERROR(H5E_DATASET, H5E_PARSEERROR, FAIL,
"can't get allocated size from server response");

Expand Down
24 changes: 24 additions & 0 deletions src/rest_vol_debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,30 @@ file_specific_type_to_string(H5VL_file_specific_t specific_type)
} /* end switch */
} /* end file_specific_type_to_string() */

/*-------------------------------------------------------------------------
* Function: file_optional_type_to_string
*
* Purpose: Helper function to convert each member of the
* H5VL_file_optional_t enum into its string representation
*
* Return: String representation of given object or '(unknown)' if
* the function can't determine the type of object it has
* been given (can't fail).
*
* Programmer: Matthew Larson
* January, 2024
*/
const char *
file_optional_type_to_string(H5VL_optional_args_t optional_type)
{
switch (optional_type.op_type) {
case RV_FILE_GET_SIZE:
return "RV_FILE_GET_FILESIZE";
default:
return "(unknown)";
} /* end switch */
} /* end file_specific_type_to_string() */

/*-------------------------------------------------------------------------
* Function: group_get_type_to_string
*
Expand Down
1 change: 1 addition & 0 deletions src/rest_vol_debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const char *dataset_specific_type_to_string(H5VL_dataset_specific_t specific_typ
const char *file_flags_to_string(unsigned flags);
const char *file_get_type_to_string(H5VL_file_get_t get_type);
const char *file_specific_type_to_string(H5VL_file_specific_t specific_type);
const char *file_optional_type_to_string(H5VL_optional_args_t optional_type);
const char *group_get_type_to_string(H5VL_group_get_t get_type);
const char *link_create_type_to_string(H5VL_link_create_t link_create_type);
const char *link_get_type_to_string(H5VL_link_get_t get_type);
Expand Down
134 changes: 133 additions & 1 deletion src/rest_vol_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ struct get_obj_ids_udata_t {
char *local_filename;
} typedef get_obj_ids_udata_t;

/* Parameters for file 'optional' operations.
A subset of H5VL_native_file_optional_args_t */
typedef union RV_file_optional_args_t {
/* H5VL_NATIVE_FILE_GET_SIZE */
struct {
hsize_t *size; /* Size of file (OUT) */
} get_size;

} RV_file_optional_args_t;

/*-------------------------------------------------------------------------
* Function: RV_file_create
*
Expand Down Expand Up @@ -874,6 +884,128 @@ RV_file_specific(void *obj, H5VL_file_specific_args_t *args, hid_t dxpl_id, void
return ret_value;
} /* end RV_file_specific() */

/*-------------------------------------------------------------------------
* Function: RV_file_optional
*
* Purpose: Performs a connector-specific operation on an HDF5 file, such
* as calling the H5Fget_filesize routine
*
* Return: Non-negative on success/Negative on failure
*
* Programmer: Matthew Larson
* January, 2024
*/
herr_t
RV_file_optional(void *obj, H5VL_optional_args_t *args, hid_t dxpl_id, void **req)
{
RV_object_t *file = (RV_object_t *)obj;
herr_t ret_value = SUCCEED;
size_t host_header_len = 0;
char *host_header = NULL;
char request_url[URL_MAX_LENGTH];
int url_len = 0;
long http_response = 0;

#ifdef RV_CONNECTOR_DEBUG
printf("-> Received file-optional call with following parameters:\n");
printf(" - File-optional call type: %s\n",
file_optional_type_to_string(*((H5VL_optional_args_t *)args)));
if (file) {
printf(" - File's URI: %s\n", file->URI);
printf(" - File's pathname: %s\n", file->domain->u.file.filepath_name);
} /* end if */
printf("\n");
#endif

switch (args->op_type) {
/* H5VL_FILE_GET_FILESIZE */
case (RV_FILE_GET_SIZE): {
RV_file_optional_args_t *opt_args = (RV_file_optional_args_t *)args->args;
size_t *size_out = opt_args->get_size.size;
/* Setup cURL to make GET request */

/* Assemble URL */
if ((url_len = snprintf(request_url, URL_MAX_LENGTH, "%s?verbose=1",
file->domain->u.file.server_info.base_URL)) < 0)
FUNC_GOTO_ERROR(H5E_FILE, H5E_SYSERRSTR, FAIL, "snprintf error");

if (url_len >= URL_MAX_LENGTH)
FUNC_GOTO_ERROR(H5E_FILE, H5E_SYSERRSTR, FAIL,
"H5Fget_filesize request URL size exceeded maximum URL size");

/* Setup the host header */
host_header_len = strlen(file->domain->u.file.filepath_name) + strlen(host_string) + 1;
if (NULL == (host_header = (char *)RV_malloc(host_header_len)))
FUNC_GOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL,
"can't allocate space for request Host header");

strcpy(host_header, host_string);

curl_headers =
curl_slist_append(curl_headers, strncat(host_header, file->domain->u.file.filepath_name,
host_header_len - strlen(host_string) - 1));

/* Disable use of Expect: 100 Continue HTTP response */
curl_headers = curl_slist_append(curl_headers, "Expect:");

if (CURLE_OK !=
curl_easy_setopt(curl, CURLOPT_USERNAME, file->domain->u.file.server_info.username))
FUNC_GOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "can't set cURL username: %s", curl_err_buf);
if (CURLE_OK !=
curl_easy_setopt(curl, CURLOPT_PASSWORD, file->domain->u.file.server_info.password))
FUNC_GOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "can't set cURL password: %s", curl_err_buf);
if (CURLE_OK != curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curl_headers))
FUNC_GOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "can't set cURL HTTP headers: %s", curl_err_buf);
if (CURLE_OK != curl_easy_setopt(curl, CURLOPT_HTTPGET, 1))
FUNC_GOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "can't set up cURL to make HTTP GET request: %s",
curl_err_buf);
if (CURLE_OK != curl_easy_setopt(curl, CURLOPT_URL, request_url))
FUNC_GOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "can't set cURL request URL: %s", curl_err_buf);

#ifdef RV_CONNECTOR_DEBUG
printf("-> Checking allocated bytes for domain using URL: %s\n\n", request_url);

printf(" /**********************************\\\n");
printf("-> | Making GET request to the server |\n");
printf(" \\**********************************/\n\n");
#endif

CURL_PERFORM_NO_ERR(curl, FAIL);

if (CURLE_OK != curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_response))
FUNC_GOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get HTTP response code");

if (!(HTTP_SUCCESS(http_response)))
FUNC_GOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL,
"request to server failed with HTTP response %ld", http_response);

/* Retrieve number of bytes allocated for file from response */
if (RV_parse_response(response_buffer.buffer, NULL, (void *)size_out,
RV_parse_domain_allocated_size_cb) < 0)
FUNC_GOTO_ERROR(H5E_FILE, H5E_PARSEERROR, FAIL,
"can't parse allocated bytes from server response");
}

break;

default:
FUNC_GOTO_ERROR(H5E_FILE, H5E_UNSUPPORTED, FAIL, "unsupported optional file operation");
break;
}

done:

if (host_header)
RV_free(host_header);

if (curl_headers) {
curl_slist_free_all(curl_headers);
curl_headers = NULL;
}

return (ret_value);
} /* end RV_file_optional */

/*-------------------------------------------------------------------------
* Function: RV_file_close
*
Expand Down Expand Up @@ -1079,4 +1211,4 @@ RV_iterate_count_obj_cb(hid_t obj_id, void *udata)
RV_free(containing_filename);

return ret_value;
}
}
1 change: 1 addition & 0 deletions src/rest_vol_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ void *RV_file_create(const char *name, unsigned flags, hid_t fcpl_id, hid_t fap
void *RV_file_open(const char *name, unsigned flags, hid_t fapl_id, hid_t dxpl_id, void **req);
herr_t RV_file_get(void *obj, H5VL_file_get_args_t *args, hid_t dxpl_id, void **req);
herr_t RV_file_specific(void *obj, H5VL_file_specific_args_t *args, hid_t dxpl_id, void **req);
herr_t RV_file_optional(void *obj, H5VL_optional_args_t *args, hid_t dxpl_id, void **req);
herr_t RV_file_close(void *file, hid_t dxpl_id, void **req);

#ifdef __cplusplus
Expand Down

0 comments on commit 2e2b72a

Please sign in to comment.