diff options
author | Quincey Koziol <koziol@hdfgroup.org> | 2019-03-10 03:41:38 (GMT) |
---|---|---|
committer | Quincey Koziol <koziol@hdfgroup.org> | 2019-03-10 03:41:38 (GMT) |
commit | deeb302747fe186d18bbf3e47d750ce6e47aef62 (patch) | |
tree | eb74d361608c829e7a531165378a5af873ff7ad2 /src | |
parent | 679b49d43d744f0cc34054944e827326f17a6f3d (diff) | |
download | hdf5-deeb302747fe186d18bbf3e47d750ce6e47aef62.zip hdf5-deeb302747fe186d18bbf3e47d750ce6e47aef62.tar.gz hdf5-deeb302747fe186d18bbf3e47d750ce6e47aef62.tar.bz2 |
Specify the default VOL connector to use with an environment variable.
This implicitly adds support for changing the VOL connector for command-line
tools or any application linked with the library.
Also, add 'make check-vol' support for all directories, clearing up necessary
issues in testing scripts, etc.
Diffstat (limited to 'src')
-rw-r--r-- | src/H5.c | 6 | ||||
-rw-r--r-- | src/H5Dcontig.c | 20 | ||||
-rw-r--r-- | src/H5Fint.c | 13 | ||||
-rw-r--r-- | src/H5Pfapl.c | 37 | ||||
-rw-r--r-- | src/H5Pint.c | 110 | ||||
-rw-r--r-- | src/H5Ppkg.h | 4 | ||||
-rw-r--r-- | src/H5Pprivate.h | 3 | ||||
-rw-r--r-- | src/H5VL.c | 200 | ||||
-rw-r--r-- | src/H5VLcallback.c | 45 | ||||
-rw-r--r-- | src/H5VLint.c | 629 | ||||
-rw-r--r-- | src/H5VLpassthru.c | 36 | ||||
-rw-r--r-- | src/H5VLpkg.h | 15 | ||||
-rw-r--r-- | src/H5VLprivate.h | 8 |
13 files changed, 840 insertions, 286 deletions
@@ -214,7 +214,7 @@ H5_init_library(void) */ if(H5E_init() < 0) HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize error interface") - if(H5VL_init() < 0) + if(H5VL_init_phase1() < 0) HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize vol interface") if(H5P_init() < 0) HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize property list interface") @@ -229,6 +229,10 @@ H5_init_library(void) if(H5FS_init() < 0) HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize FS interface") + /* Finish initializing interfaces that depend on the interfaces above */ + if(H5VL_init_phase2() < 0) + HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize vol interface") + /* Debugging? */ H5_debug_mask("-all"); H5_debug_mask(HDgetenv("HDF5_DEBUG")); diff --git a/src/H5Dcontig.c b/src/H5Dcontig.c index ad12ba0..8bd5e31 100644 --- a/src/H5Dcontig.c +++ b/src/H5Dcontig.c @@ -755,11 +755,6 @@ H5D__contig_readvv_sieve_cb(hsize_t dst_off, hsize_t src_off, size_t len, /* Reset sieve buffer dirty flag */ dset_contig->sieve_dirty = FALSE; - - /* Stash local copies of these value */ - sieve_start = dset_contig->sieve_loc; - sieve_size = dset_contig->sieve_size; - sieve_end = sieve_start+sieve_size; } /* end else */ } /* end if */ else { @@ -825,11 +820,6 @@ H5D__contig_readvv_sieve_cb(hsize_t dst_off, hsize_t src_off, size_t len, min = MIN3(rel_eoa - dset_contig->sieve_loc, max_data, dset_contig->sieve_buf_size); H5_CHECKED_ASSIGN(dset_contig->sieve_size, size_t, min, hsize_t); - /* Update local copies of sieve information */ - sieve_start = dset_contig->sieve_loc; - sieve_size = dset_contig->sieve_size; - sieve_end = sieve_start + sieve_size; - /* Read the new sieve buffer */ if(H5F_block_read(file, H5FD_MEM_DRAW, dset_contig->sieve_loc, dset_contig->sieve_size, dset_contig->sieve_buf) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed") @@ -1110,11 +1100,6 @@ H5D__contig_writevv_sieve_cb(hsize_t dst_off, hsize_t src_off, size_t len, /* Adjust sieve size */ dset_contig->sieve_size += len; - - /* Update local copies of sieve information */ - sieve_start = dset_contig->sieve_loc; - sieve_size = dset_contig->sieve_size; - sieve_end = sieve_start + sieve_size; } /* end if */ /* Can't add the new data onto the existing sieve buffer */ else { @@ -1146,11 +1131,6 @@ H5D__contig_writevv_sieve_cb(hsize_t dst_off, hsize_t src_off, size_t len, min = MIN3(rel_eoa - dset_contig->sieve_loc, max_data, dset_contig->sieve_buf_size); H5_CHECKED_ASSIGN(dset_contig->sieve_size, size_t, min, hsize_t); - /* Update local copies of sieve information */ - sieve_start = dset_contig->sieve_loc; - sieve_size = dset_contig->sieve_size; - sieve_end = sieve_start + sieve_size; - /* Check if there is any point in reading the data from the file */ if(dset_contig->sieve_size > len) { /* Read the new sieve buffer */ diff --git a/src/H5Fint.c b/src/H5Fint.c index 8a7019d..339c61b 100644 --- a/src/H5Fint.c +++ b/src/H5Fint.c @@ -1362,19 +1362,10 @@ H5F__dest(H5F_t *f, hbool_t flush) HDONE_ERROR(H5E_FILE, H5E_CANTDEC, FAIL, "can't close property list") /* Clean up the cached VOL connector ID & info */ - if(f->shared->vol_info) { - H5VL_class_t *connector; /* Pointer to connector */ - - /* Retrieve the connector for the ID */ - if(NULL == (connector = (H5VL_class_t *)H5I_object(f->shared->vol_id))) - /* Push error, but keep going*/ - HDONE_ERROR(H5E_FILE, H5E_BADTYPE, FAIL, "not a VOL connector ID") - - /* Free the connector info */ - if(H5VL_free_connector_info(connector, f->shared->vol_info) < 0) + if(f->shared->vol_info) + if(H5VL_free_connector_info(f->shared->vol_id, f->shared->vol_info) < 0) /* Push error, but keep going*/ HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "unable to release VOL connector info object") - } /* end if */ if(f->shared->vol_id > 0) if(H5I_dec_ref(f->shared->vol_id) < 0) /* Push error, but keep going*/ diff --git a/src/H5Pfapl.c b/src/H5Pfapl.c index bfb52ff..4b9bbdc 100644 --- a/src/H5Pfapl.c +++ b/src/H5Pfapl.c @@ -4907,6 +4907,43 @@ done: /*------------------------------------------------------------------------- + * Function: H5P_reset_vol_class + * + * Purpose: Change the VOL connector for a file access property class. + * + * Note: The VOL property will be copied into the property list and + * the reference count on the previous VOL will _NOT_ be decremented. + * The reference count on the new VOL will _NOT_ be incremented. + * + * Return: SUCCEED/FAIL + * + * Programmer: Quincey Koziol + * March 8, 2019 + * + *------------------------------------------------------------------------- + */ +herr_t +H5P_reset_vol_class(const H5P_genclass_t *pclass, const H5VL_connector_prop_t *vol_prop) +{ + H5VL_connector_prop_t old_vol_prop; /* Previous VOL connector property */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Get the connector ID & info property */ + if(H5P__class_get(pclass, H5F_ACS_VOL_CONN_NAME, &old_vol_prop) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get VOL connector ID & info") + + /* Set the new connector ID & info property */ + if(H5P__class_set(pclass, H5F_ACS_VOL_CONN_NAME, vol_prop) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set VOL connector ID & info") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5P_set_vol_class() */ + + +/*------------------------------------------------------------------------- * Function: H5Pset_vol * * Purpose: Set the file VOL connector (VOL_ID) for a file access diff --git a/src/H5Pint.c b/src/H5Pint.c index e2ae792..79b6cf5 100644 --- a/src/H5Pint.c +++ b/src/H5Pint.c @@ -3061,6 +3061,116 @@ done: /*-------------------------------------------------------------------------- NAME + H5P__class_get + PURPOSE + Internal routine to get a property's value from a property class. + USAGE + herr_t H5P__class_get(pclass, name, value) + const H5P_genclass_t *pclass; IN: Property class to find property in + const char *name; IN: Name of property to get + void *value; IN: Pointer to the value for the property + RETURNS + Returns non-negative on success, negative on failure. + DESCRIPTION + Gets the current value for a property in a property class. The property + name must exist or this routine will fail. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + The 'get' callback routine registered for this property will _NOT_ be + called, this routine is designed for internal library use only! + + This routine may not be called for zero-sized properties and will + return an error in that case. + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5P__class_get(const H5P_genclass_t *pclass, const char *name, void *value) +{ + H5P_genprop_t *prop; /* Temporary property pointer */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Sanity check */ + HDassert(pclass); + HDassert(name); + HDassert(value); + + /* Find property in list */ + if(NULL == (prop = (H5P_genprop_t *)H5SL_search(pclass->props, name))) + HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "property doesn't exist") + + /* Check for property size >0 */ + if(0 == prop->size) + HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "property has zero size") + + /* Copy the property value */ + HDmemcpy(value, prop->value, prop->size); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5P__class_get() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P__class_set + PURPOSE + Internal routine to set a property's value in a property class. + USAGE + herr_t H5P__class_set(pclass, name, value) + const H5P_genclass_t *pclass; IN: Property class to find property in + const char *name; IN: Name of property to set + const void *value; IN: Pointer to the value for the property + RETURNS + Returns non-negative on success, negative on failure. + DESCRIPTION + Sets a new value for a property in a property class. The property name + must exist or this routine will fail. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + The 'set' callback routine registered for this property will _NOT_ be + called, this routine is designed for internal library use only! + + This routine may not be called for zero-sized properties and will + return an error in that case. + + The previous value is overwritten, not released in any way. + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5P__class_set(const H5P_genclass_t *pclass, const char *name, const void *value) +{ + H5P_genprop_t *prop; /* Temporary property pointer */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Sanity check */ + HDassert(pclass); + HDassert(name); + HDassert(value); + + /* Find property in list */ + if(NULL == (prop = (H5P_genprop_t *)H5SL_search(pclass->props, name))) + HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "property doesn't exist") + + /* Check for property size >0 */ + if(0 == prop->size) + HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "property has zero size") + + /* Copy the property value */ + HDmemcpy(prop->value, value, prop->size); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5P__class_set() */ + + +/*-------------------------------------------------------------------------- + NAME H5P_exist_plist PURPOSE Internal routine to query the existance of a property in a property list. diff --git a/src/H5Ppkg.h b/src/H5Ppkg.h index 13f3b13..c8e5e98 100644 --- a/src/H5Ppkg.h +++ b/src/H5Ppkg.h @@ -151,6 +151,10 @@ H5_DLL herr_t H5P__register(H5P_genclass_t **pclass, const char *name, size_t si H5P_prp_close_func_t prp_close); H5_DLL herr_t H5P__add_prop(H5SL_t *props, H5P_genprop_t *prop); H5_DLL herr_t H5P__access_class(H5P_genclass_t *pclass, H5P_class_mod_t mod); +H5_DLL herr_t H5P__class_get(const H5P_genclass_t *pclass, const char *name, + void *value); +H5_DLL herr_t H5P__class_set(const H5P_genclass_t *pclass, const char *name, + const void *value); H5_DLL htri_t H5P__exist_pclass(H5P_genclass_t *pclass, const char *name); H5_DLL herr_t H5P__get_size_plist(const H5P_genplist_t *plist, const char *name, size_t *size); diff --git a/src/H5Pprivate.h b/src/H5Pprivate.h index 866f088..49f7a12 100644 --- a/src/H5Pprivate.h +++ b/src/H5Pprivate.h @@ -148,6 +148,7 @@ H5_DLLVAR const struct H5P_libclass_t H5P_CLS_OCPY[1]; /* Object copy */ /* Forward declaration of structs used below */ struct H5O_fill_t; struct H5T_t; +struct H5VL_connector_prop_t; /* Package initialization routine */ H5_DLL herr_t H5P_init(void); @@ -178,6 +179,8 @@ H5_DLL const void *H5P_peek_driver_info(H5P_genplist_t *plist); H5_DLL herr_t H5P_set_driver(H5P_genplist_t *plist, hid_t new_driver_id, const void *new_driver_info); H5_DLL herr_t H5P_set_vol(H5P_genplist_t *plist, hid_t vol_id, const void *vol_info); +H5_DLL herr_t H5P_reset_vol_class(const H5P_genclass_t *pclass, + const struct H5VL_connector_prop_t *vol_prop); H5_DLL herr_t H5P_set_vlen_mem_manager(H5P_genplist_t *plist, H5MM_allocate_t alloc_func, void *alloc_info, H5MM_free_t free_func, void *free_info); @@ -29,11 +29,8 @@ /***********/ #include "H5private.h" /* Generic Functions */ -#include "H5Aprivate.h" /* Attributes */ #include "H5Eprivate.h" /* Error handling */ #include "H5Iprivate.h" /* IDs */ -#include "H5MMprivate.h" /* Memory management */ -#include "H5PLprivate.h" /* Plugins */ #include "H5VLpkg.h" /* Virtual Object Layer */ @@ -46,29 +43,10 @@ /* Local Typedefs */ /******************/ -/* Information needed for iterating over the registered VOL connector hid_t IDs. - * The name or value of the new VOL connector that is being registered is - * stored in the name (or value) field and the found_id field is initialized to - * H5I_INVALID_HID (-1). If we find a VOL connector with the same name / value, - * we set the found_id field to the existing ID for return to the function. - */ -typedef struct { - /* IN */ - H5VL_get_connector_kind_t kind; /* Which kind of connector search to make */ - union { - const char *name; /* The name of the VOL connector to check */ - H5VL_class_value_t value; /* The value of the VOL connector to check */ - } u; - - /* OUT */ - hid_t found_id; /* The connector ID, if we found a match */ -} H5VL_get_connector_ud_t; - /********************/ /* Local Prototypes */ /********************/ -static int H5VL__get_connector_cb(void *obj, hid_t id, void *_op_data); /*********************/ @@ -88,45 +66,6 @@ static int H5VL__get_connector_cb(void *obj, hid_t id, void *_op_data); /*------------------------------------------------------------------------- - * Function: H5VL__get_connector_cb - * - * Purpose: Callback routine to search through registered VOLs - * - * Return: Success: H5_ITER_STOP if the class and op_data name - * members match. H5_ITER_CONT otherwise. - * - * Failure: Can't fail - * - *------------------------------------------------------------------------- - */ -static int -H5VL__get_connector_cb(void *obj, hid_t id, void *_op_data) -{ - H5VL_get_connector_ud_t *op_data = (H5VL_get_connector_ud_t *)_op_data; /* User data for callback */ - H5VL_class_t *cls = (H5VL_class_t *)obj; - int ret_value = H5_ITER_CONT; /* Callback return value */ - - FUNC_ENTER_STATIC_NOERR - - if(H5VL_GET_CONNECTOR_BY_NAME == op_data->kind) { - if(0 == HDstrcmp(cls->name, op_data->u.name)) { - op_data->found_id = id; - ret_value = H5_ITER_STOP; - } /* end if */ - } /* end if */ - else { - HDassert(H5VL_GET_CONNECTOR_BY_VALUE == op_data->kind); - if(cls->value == op_data->u.value) { - op_data->found_id = id; - ret_value = H5_ITER_STOP; - } /* end if */ - } /* end else */ - - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5VL__get_connector_cb() */ - - -/*------------------------------------------------------------------------- * Function: H5VLregister_connector * * Purpose: Registers a new VOL connector as a member of the virtual object @@ -143,8 +82,7 @@ H5VL__get_connector_cb(void *obj, hid_t id, void *_op_data) hid_t H5VLregister_connector(const H5VL_class_t *cls, hid_t vipl_id) { - H5VL_get_connector_ud_t op_data; /* Callback info for connector search */ - hid_t ret_value = H5I_INVALID_HID; + hid_t ret_value = H5I_INVALID_HID; /* Return value */ FUNC_ENTER_API(H5I_INVALID_HID) H5TRACE2("i", "*xi", cls, vipl_id); @@ -161,25 +99,9 @@ H5VLregister_connector(const H5VL_class_t *cls, hid_t vipl_id) if (cls->wrap_cls.get_wrap_ctx && !cls->wrap_cls.free_wrap_ctx) HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "VOL connector must provide free callback for object wrapping contexts when a get callback is provided") - op_data.kind = H5VL_GET_CONNECTOR_BY_NAME; - op_data.u.name = cls->name; - op_data.found_id = H5I_INVALID_HID; - - /* check if connector is already registered */ - if (H5I_iterate(H5I_VOL, H5VL__get_connector_cb, &op_data, TRUE) < 0) - HGOTO_ERROR(H5E_VOL, H5E_BADITER, H5I_INVALID_HID, "can't iterate over VOL IDs") - - /* Increment the ref count on the existing VOL connector ID, if it's already registered */ - if(op_data.found_id != H5I_INVALID_HID) { - if (H5I_inc_ref(op_data.found_id, TRUE) < 0) - HGOTO_ERROR(H5E_VOL, H5E_CANTINC, H5I_INVALID_HID, "unable to increment ref count on VOL connector") - ret_value = op_data.found_id; - } /* end if */ - else { - /* Create a new class ID */ - if ((ret_value = H5VL_register_connector(cls, TRUE, vipl_id)) < 0) - HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register VOL connector") - } /* end else */ + /* Register connector */ + if((ret_value = H5VL__register_connector(cls, TRUE, vipl_id)) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register VOL connector") done: FUNC_LEAVE_API(ret_value) @@ -203,8 +125,7 @@ done: hid_t H5VLregister_connector_by_name(const char *name, hid_t vipl_id) { - H5VL_get_connector_ud_t op_data; /* Callback info for connector search */ - hid_t ret_value = H5I_INVALID_HID; + hid_t ret_value = H5I_INVALID_HID; /* Return value */ FUNC_ENTER_API(H5I_INVALID_HID) H5TRACE2("i", "*si", name, vipl_id); @@ -215,34 +136,9 @@ H5VLregister_connector_by_name(const char *name, hid_t vipl_id) if (0 == HDstrlen(name)) HGOTO_ERROR(H5E_ARGS, H5E_UNINITIALIZED, H5I_INVALID_HID, "zero-length VOL connector name is disallowed") - op_data.kind = H5VL_GET_CONNECTOR_BY_NAME; - op_data.u.name = name; - op_data.found_id = H5I_INVALID_HID; - - /* Check if connector is already registered */ - if(H5I_iterate(H5I_VOL, H5VL__get_connector_cb, &op_data, TRUE) < 0) - HGOTO_ERROR(H5E_VOL, H5E_BADITER, H5I_INVALID_HID, "can't iterate over VOL ids") - - /* If connector alread registered, increment ref count on ID and return ID */ - if(op_data.found_id != H5I_INVALID_HID) { - if(H5I_inc_ref(op_data.found_id, TRUE) < 0) - HGOTO_ERROR(H5E_VOL, H5E_CANTINC, H5I_INVALID_HID, "unable to increment ref count on VOL connector") - ret_value = op_data.found_id; - } /* end if */ - else { - H5PL_key_t key; - const H5VL_class_t *cls; - - /* Try loading the connector */ - key.vol.kind = H5VL_GET_CONNECTOR_BY_NAME; - key.vol.u.name = name; - if(NULL == (cls = (const H5VL_class_t *)H5PL_load(H5PL_TYPE_VOL, &key))) - HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, H5I_INVALID_HID, "unable to load VOL connector") - - /* Register the connector we loaded */ - if((ret_value = H5VL_register_connector(cls, TRUE, vipl_id)) < 0) - HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register VOL connector ID") - } /* end else */ + /* Register connector */ + if((ret_value = H5VL__register_connector_by_name(name, TRUE, vipl_id)) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register VOL connector") done: FUNC_LEAVE_API(ret_value) @@ -266,8 +162,7 @@ done: hid_t H5VLregister_connector_by_value(H5VL_class_value_t value, hid_t vipl_id) { - H5VL_get_connector_ud_t op_data; /* Callback info for connector search */ - hid_t ret_value = H5I_INVALID_HID; + hid_t ret_value = H5I_INVALID_HID; /* Return value */ FUNC_ENTER_API(H5I_INVALID_HID) H5TRACE2("i", "VCi", value, vipl_id); @@ -276,34 +171,9 @@ H5VLregister_connector_by_value(H5VL_class_value_t value, hid_t vipl_id) if(value < 0) HGOTO_ERROR(H5E_ARGS, H5E_UNINITIALIZED, H5I_INVALID_HID, "negative VOL connector value is disallowed") - op_data.kind = H5VL_GET_CONNECTOR_BY_VALUE; - op_data.u.value = value; - op_data.found_id = H5I_INVALID_HID; - - /* Check if connector is already registered */ - if(H5I_iterate(H5I_VOL, H5VL__get_connector_cb, &op_data, TRUE) < 0) - HGOTO_ERROR(H5E_VOL, H5E_BADITER, H5I_INVALID_HID, "can't iterate over VOL ids") - - /* If connector alread registered, increment ref count on ID and return ID */ - if(op_data.found_id != H5I_INVALID_HID) { - if(H5I_inc_ref(op_data.found_id, TRUE) < 0) - HGOTO_ERROR(H5E_VOL, H5E_CANTINC, H5I_INVALID_HID, "unable to increment ref count on VOL connector") - ret_value = op_data.found_id; - } /* end if */ - else { - H5PL_key_t key; - const H5VL_class_t *cls; - - /* Try loading the connector */ - key.vol.kind = H5VL_GET_CONNECTOR_BY_VALUE; - key.vol.u.value = value; - if(NULL == (cls = (const H5VL_class_t *)H5PL_load(H5PL_TYPE_VOL, &key))) - HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, H5I_INVALID_HID, "unable to load VOL connector") - - /* Register the connector we loaded */ - if((ret_value = H5VL_register_connector(cls, TRUE, vipl_id)) < 0) - HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register VOL connector ID") - } /* end else */ + /* Register connector */ + if((ret_value = H5VL__register_connector_by_value(value, TRUE, vipl_id)) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register VOL connector") done: FUNC_LEAVE_API(ret_value) @@ -315,33 +185,26 @@ done: * * Purpose: Tests whether a VOL class has been registered or not * - * Return: Positive if the VOL class has been registered - * - * Zero if it is unregistered + * Return: >0 if the VOL class has been registered + * 0 if it is unregistered + * <0 on error (if the class is not a valid class ID) * - * Negative on error (if the class is not a valid class ID) + * Programmer: Dana Robinson + * June 17, 2017 * *------------------------------------------------------------------------- */ htri_t H5VLis_connector_registered(const char *name) { - H5VL_get_connector_ud_t op_data; /* Callback info for connector search */ htri_t ret_value = FALSE; /* Return value */ FUNC_ENTER_API(FAIL) H5TRACE1("t", "*s", name); - op_data.kind = H5VL_GET_CONNECTOR_BY_NAME; - op_data.u.name = name; - op_data.found_id = H5I_INVALID_HID; - - /* Check arguments */ - if (H5I_iterate(H5I_VOL, H5VL__get_connector_cb, &op_data, TRUE) < 0) - HGOTO_ERROR(H5E_VOL, H5E_BADITER, FAIL, "can't iterate over VOL ids") - - if (op_data.found_id != H5I_INVALID_HID) - ret_value = TRUE; + /* Check if connector with this name is registered */ + if((ret_value = H5VL__is_connector_registered(name)) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "can't check for VOL") done: FUNC_LEAVE_API(ret_value) @@ -356,30 +219,22 @@ done: * Return: Positive if the VOL class has been registered * Negative on error (if the class is not a valid class or not registered) * + * Programmer: Dana Robinson + * June 17, 2017 + * *------------------------------------------------------------------------- */ hid_t H5VLget_connector_id(const char *name) { - H5VL_get_connector_ud_t op_data; /* Callback info for connector search */ hid_t ret_value = H5I_INVALID_HID; /* Return value */ FUNC_ENTER_API(H5I_INVALID_HID) H5TRACE1("i", "*s", name); - op_data.kind = H5VL_GET_CONNECTOR_BY_NAME; - op_data.u.name = name; - op_data.found_id = H5I_INVALID_HID; - - /* Check arguments */ - if (H5I_iterate(H5I_VOL, H5VL__get_connector_cb, &op_data, TRUE) < 0) - HGOTO_ERROR(H5E_VOL, H5E_BADITER, H5I_INVALID_HID, "can't iterate over VOL connector IDs") - - if (op_data.found_id != H5I_INVALID_HID) { - if (H5I_inc_ref(op_data.found_id, TRUE) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTINC, H5I_INVALID_HID, "unable to increment ref count on VOL connector") - ret_value = op_data.found_id; - } /* end if */ + /* Get connector ID with this name */ + if((ret_value = H5VL__get_connector_id(name, TRUE)) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTGET, H5I_INVALID_HID, "can't get VOL id") done: FUNC_LEAVE_API(ret_value) @@ -406,7 +261,8 @@ H5VLget_connector_name(hid_t obj_id, char *name/*out*/, size_t size) FUNC_ENTER_API(FAIL) H5TRACE3("Zs", "ixz", obj_id, name, size); - if ((ret_value = H5VL_get_connector_name(obj_id, name, size)) < 0) + /* Call internal routine */ + if((ret_value = H5VL__get_connector_name(obj_id, name, size)) < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "Can't get connector name") done: diff --git a/src/H5VLcallback.c b/src/H5VLcallback.c index 5a5d9ee..d77c9f6 100644 --- a/src/H5VLcallback.c +++ b/src/H5VLcallback.c @@ -506,20 +506,25 @@ done: *------------------------------------------------------------------------- */ herr_t -H5VL_free_connector_info(const H5VL_class_t *connector, void *info) +H5VL_free_connector_info(hid_t connector_id, void *info) { - herr_t ret_value = SUCCEED; /* Return value */ + H5VL_class_t *cls; /* VOL connector's class struct */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) - /* Sanity checks */ - HDassert(connector); + /* Sanity check */ + HDassert(connector_id > 0); + + /* Check args and get class pointer */ + if(NULL == (cls = (H5VL_class_t *)H5I_object_verify(connector_id, H5I_VOL))) + HGOTO_ERROR(H5E_VOL, H5E_BADTYPE, FAIL, "not a VOL connector ID") /* Only free info object, if it's non-NULL */ if(info) { /* Allow the connector to free info or do it ourselves */ - if(connector->info_cls.free) { - if((connector->info_cls.free)(info) < 0) + if(cls->info_cls.free) { + if((cls->info_cls.free)(info) < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "connector info free request failed") } /* end if */ else @@ -544,18 +549,13 @@ done: herr_t H5VLfree_connector_info(hid_t connector_id, void *info) { - H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API_NOINIT H5TRACE2("e", "i*x", connector_id, info); - /* Check args and get class pointer */ - if(NULL == (cls = (H5VL_class_t *)H5I_object_verify(connector_id, H5I_VOL))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a VOL connector ID") - /* Free the VOL connector info object */ - if(H5VL_free_connector_info(cls, info) < 0) + if(H5VL_free_connector_info(connector_id, info) < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "unable to release VOL connector info object") done: @@ -623,24 +623,9 @@ H5VLconnector_str_to_info(const char *str, hid_t connector_id, void **info) FUNC_ENTER_API_NOINIT H5TRACE3("e", "*si**x", str, connector_id, info); - /* Only deserialize string, if it's non-NULL */ - if(str) { - H5VL_class_t *cls; /* VOL connector's class struct */ - - /* Check args and get class pointer */ - if(NULL == (cls = (H5VL_class_t *)H5I_object_verify(connector_id, H5I_VOL))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a VOL connector ID") - - /* Allow the connector to deserialize info */ - if(cls->info_cls.from_str) { - if((cls->info_cls.from_str)(str, info) < 0) - HGOTO_ERROR(H5E_VOL, H5E_CANTUNSERIALIZE, FAIL, "can't deserialize connector info") - } /* end if */ - else - *info = NULL; - } /* end if */ - else - *info = NULL; + /* Call internal routine */ + if(H5VL__connector_str_to_info(str, connector_id, info) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTDECODE, FAIL, "can't deserialize connector info") done: FUNC_LEAVE_API_NOINIT(ret_value) diff --git a/src/H5VLint.c b/src/H5VLint.c index 5aa25d2..3d1be61 100644 --- a/src/H5VLint.c +++ b/src/H5VLint.c @@ -29,14 +29,19 @@ /* Headers */ /***********/ -#include "H5private.h" /* Generic Functions */ -#include "H5CXprivate.h" /* API Contexts */ -#include "H5Eprivate.h" /* Error handling */ -#include "H5FLprivate.h" /* Free lists */ -#include "H5Iprivate.h" /* IDs */ -#include "H5MMprivate.h" /* Memory management */ -#include "H5Tprivate.h" /* Datatypes */ -#include "H5VLpkg.h" /* Virtual Object Layer */ +#include "H5private.h" /* Generic Functions */ +#include "H5CXprivate.h" /* API Contexts */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5FLprivate.h" /* Free lists */ +#include "H5Iprivate.h" /* IDs */ +#include "H5MMprivate.h" /* Memory management */ +#include "H5PLprivate.h" /* Plugins */ +#include "H5Tprivate.h" /* Datatypes */ +#include "H5VLpkg.h" /* Virtual Object Layer */ + +/* VOL connectors */ +#include "H5VLnative.h" /* Native VOL connector */ +#include "H5VLpassthru.h" /* Pass-through VOL connector */ /****************/ @@ -55,6 +60,24 @@ typedef struct H5VL_wrap_ctx_t { void *obj_wrap_ctx; /* "wrap context" for outermost connector */ } H5VL_wrap_ctx_t; +/* Information needed for iterating over the registered VOL connector hid_t IDs. + * The name or value of the new VOL connector that is being registered is + * stored in the name (or value) field and the found_id field is initialized to + * H5I_INVALID_HID (-1). If we find a VOL connector with the same name / value, + * we set the found_id field to the existing ID for return to the function. + */ +typedef struct { + /* IN */ + H5VL_get_connector_kind_t kind; /* Which kind of connector search to make */ + union { + const char *name; /* The name of the VOL connector to check */ + H5VL_class_value_t value; /* The value of the VOL connector to check */ + } u; + + /* OUT */ + hid_t found_id; /* The connector ID, if we found a match */ +} H5VL_get_connector_ud_t; + /********************/ /* Package Typedefs */ @@ -65,6 +88,8 @@ typedef struct H5VL_wrap_ctx_t { /* Local Prototypes */ /********************/ static herr_t H5VL__free_cls(H5VL_class_t *cls); +static int H5VL__get_connector_cb(void *obj, hid_t id, void *_op_data); +static herr_t H5VL__set_def_conn(void); static void *H5VL__wrap_obj(void *obj, H5I_type_t obj_type); static H5VL_object_t *H5VL__new_vol_obj(H5I_type_t type, void *object, H5VL_t *vol_connector, hbool_t wrap_obj); @@ -83,6 +108,7 @@ hbool_t H5_PKG_INIT_VAR = FALSE; /* Library Private Variables */ /*****************************/ + /*******************/ /* Local Variables */ /*******************/ @@ -107,21 +133,27 @@ H5FL_DEFINE(H5VL_object_t); /* Declare a free list to manage the H5VL_wrap_ctx_t struct */ H5FL_DEFINE_STATIC(H5VL_wrap_ctx_t); +/* Default VOL connector */ +static H5VL_connector_prop_t H5VL_def_conn_s = {-1, NULL}; + /*------------------------------------------------------------------------- - * Function: H5VL_init + * Function: H5VL_init_phase1 * - * Purpose: Initialize the interface from some other package + * Purpose: Initialize the interface from some other package. This should + * be followed with a call to H5VL_init_phase2 after the H5P + * interface is completely set up, finish setting up the H5VL + * information. * - * Return: Success: Non-negative * + * Return: Success: Non-negative * Failure: Negative * *------------------------------------------------------------------------- */ herr_t -H5VL_init(void) +H5VL_init_phase1(void) { herr_t ret_value = SUCCEED; /* Return value */ @@ -131,7 +163,36 @@ H5VL_init(void) done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5VL_init() */ +} /* end H5VL_init_phase1() */ + + +/*------------------------------------------------------------------------- + * Function: H5VL_init_phase2 + * + * Purpose: Finish initializing the interface from some other package. + * + * Note: This is broken out as a separate routine to avoid a circular + * reference with the H5P package. + * + * Return: Success: Non-negative + * Failure: Negative + * + *------------------------------------------------------------------------- + */ +herr_t +H5VL_init_phase2(void) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Set up the default VOL connector in the default FAPL */ + if(H5VL__set_def_conn() < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "unable to set default VOL connector") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5VL_init_phase2() */ /*------------------------------------------------------------------------- @@ -148,12 +209,12 @@ done: herr_t H5VL__init_package(void) { - herr_t ret_value = SUCCEED; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Initialize the atom group for the VL IDs */ - if (H5I_register_type(H5I_VOL_CLS) < 0) + if(H5I_register_type(H5I_VOL_CLS) < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, FAIL, "unable to initialize H5VL interface") done: @@ -180,17 +241,27 @@ H5VL_term_package(void) FUNC_ENTER_NOAPI_NOINIT_NOERR if(H5_PKG_INIT_VAR) { - if (H5I_nmembers(H5I_VOL) > 0) { - (void)H5I_clear_type(H5I_VOL, FALSE, FALSE); + if(H5VL_def_conn_s.connector_id > 0) { + /* Release the default VOL connector */ + (void)H5VL_conn_free(&H5VL_def_conn_s); + H5VL_def_conn_s.connector_id = -1; + H5VL_def_conn_s.connector_info = NULL; n++; } /* end if */ else { - /* Destroy the VOL connector ID group */ - n += (H5I_dec_type_ref(H5I_VOL) > 0); - - /* Mark interface as closed */ - if (0 == n) - H5_PKG_INIT_VAR = FALSE; + if(H5I_nmembers(H5I_VOL) > 0) { + /* Unregister all VOL connectors */ + (void)H5I_clear_type(H5I_VOL, FALSE, FALSE); + n++; + } /* end if */ + else { + /* Destroy the VOL connector ID group */ + n += (H5I_dec_type_ref(H5I_VOL) > 0); + + /* Mark interface as closed */ + if(0 == n) + H5_PKG_INIT_VAR = FALSE; + } /* end else */ } /* end else */ } /* end if */ @@ -234,6 +305,182 @@ done: /*------------------------------------------------------------------------- + * Function: H5VL__get_connector_cb + * + * Purpose: Callback routine to search through registered VOLs + * + * Return: Success: H5_ITER_STOP if the class and op_data name + * members match. H5_ITER_CONT otherwise. + * Failure: Can't fail + * + * Programmer: Dana Robinson + * June 22, 2017 + * + *------------------------------------------------------------------------- + */ +static int +H5VL__get_connector_cb(void *obj, hid_t id, void *_op_data) +{ + H5VL_get_connector_ud_t *op_data = (H5VL_get_connector_ud_t *)_op_data; /* User data for callback */ + H5VL_class_t *cls = (H5VL_class_t *)obj; + int ret_value = H5_ITER_CONT; /* Callback return value */ + + FUNC_ENTER_STATIC_NOERR + + if(H5VL_GET_CONNECTOR_BY_NAME == op_data->kind) { + if(0 == HDstrcmp(cls->name, op_data->u.name)) { + op_data->found_id = id; + ret_value = H5_ITER_STOP; + } /* end if */ + } /* end if */ + else { + HDassert(H5VL_GET_CONNECTOR_BY_VALUE == op_data->kind); + if(cls->value == op_data->u.value) { + op_data->found_id = id; + ret_value = H5_ITER_STOP; + } /* end if */ + } /* end else */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5VL__get_connector_cb() */ + + +/*------------------------------------------------------------------------- + * Function: H5VL__set_def_conn + * + * Purpose: Parses a string that contains the default VOL connector for + * the library. + * + * Note: Usually from the environment variable "HDF5_VOL_CONNECTOR", + * but could be from elsewhere. + * + * Return: Success: 0 + * Failure: -1 + * + * Programmer: Jordan Henderson + * November 2018 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5VL__set_def_conn(void) +{ + H5P_genplist_t *def_fapl; /* Default file access property list */ + H5P_genclass_t *def_fapclass; /* Default file access property class */ + const char *env_var; /* Environment variable for default VOL connector */ + char *buf = NULL; /* Buffer for tokenizing string */ + hid_t connector_id = -1; /* VOL conntector ID */ + void *vol_info = NULL; /* VOL connector info */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity check */ + HDassert(H5VL_def_conn_s.connector_id == (-1)); + HDassert(H5VL_def_conn_s.connector_info == NULL); + + /* Check for environment variable set */ + env_var = HDgetenv("HDF5_VOL_CONNECTOR"); + + /* Only parse the string if it's set */ + if(env_var && *env_var) { + char *lasts = NULL; /* Context pointer for strtok_r() call */ + const char *tok = NULL; /* Token from strtok_r call */ + htri_t connector_is_registered; /* Whether connector is already registered */ + + /* Duplicate the string to parse, as it is modified as we go */ + if(NULL == (buf = H5MM_strdup(env_var))) + HGOTO_ERROR(H5E_VOL, H5E_CANTALLOC, FAIL, "can't allocate memory for environment variable string") + + /* Get the first 'word' of the environment variable. + * If it's nothing (environment variable was whitespace) return error. + */ + if(NULL == (tok = HDstrtok_r(buf, " \t\n\r", &lasts))) + HGOTO_ERROR(H5E_VOL, H5E_BADVALUE, FAIL, "VOL connector environment variable set empty?") + + /* First, check to see if the connector is already registered */ + if((connector_is_registered = H5VL__is_connector_registered(tok)) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "can't check if VOL connector already registered") + else if(connector_is_registered) { + /* Retrieve the ID of the already-registered VOL connector */ + if((connector_id = H5VL__get_connector_id(tok, FALSE)) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "can't get VOL connector ID") + } /* end else-if */ + else { + /* Check for VOL connectors that ship with the library */ + if(!HDstrcmp(tok, "native")) { + connector_id = H5VL_NATIVE; + if(H5I_inc_ref(connector_id, FALSE) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTINC, FAIL, "can't increment VOL connector refcount") + } /* end if */ + else if(!HDstrcmp(tok, "pass_through")) { + connector_id = H5VL_PASSTHRU; + if(H5I_inc_ref(connector_id, FALSE) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTINC, FAIL, "can't increment VOL connector refcount") + } /* end else-if */ + else { + /* Register the VOL connector */ + /* (NOTE: No provisions for vipl_id currently) */ + if((connector_id = H5VL__register_connector_by_name(tok, FALSE, H5P_DEFAULT)) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, FAIL, "can't register connector") + } /* end else */ + } /* end else */ + + /* Was there any connector info specified in the environment variable? */ + if(NULL != (tok = HDstrtok_r(NULL, " \t\n\r", &lasts))) + if(H5VL__connector_str_to_info(tok, connector_id, &vol_info) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTDECODE, FAIL, "can't deserialize connector info") + + /* Set the default VOL connector */ + H5VL_def_conn_s.connector_id = connector_id; + H5VL_def_conn_s.connector_info = vol_info; + } /* end if */ + else { + /* Set the default VOL connector */ + H5VL_def_conn_s.connector_id = H5_DEFAULT_VOL; + H5VL_def_conn_s.connector_info = NULL; + + /* Increment the ref count on the default connector */ + if(H5I_inc_ref(H5VL_def_conn_s.connector_id, FALSE) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTINC, FAIL, "can't increment VOL connector refcount") + } /* end else */ + + /* Get default file access pclass */ + if(NULL == (def_fapclass = (H5P_genclass_t *)H5I_object(H5P_FILE_ACCESS))) + HGOTO_ERROR(H5E_VOL, H5E_BADATOM, FAIL, "can't find object for default file access property class ID") + + /* Change the default VOL for the default file access pclass */ + if(H5P_reset_vol_class(def_fapclass, &H5VL_def_conn_s) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "can't set default VOL connector for default file access property class") + + /* Get default file access plist */ + if(NULL == (def_fapl = (H5P_genplist_t *)H5I_object(H5P_FILE_ACCESS_DEFAULT))) + HGOTO_ERROR(H5E_VOL, H5E_BADATOM, FAIL, "can't find object for default fapl ID") + + /* Change the default VOL for the default FAPL */ + if(H5P_set_vol(def_fapl, H5VL_def_conn_s.connector_id, H5VL_def_conn_s.connector_info) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "can't set default VOL connector for default FAPL") + +done: + /* Clean up on error */ + if(ret_value < 0) { + if(vol_info) + if(H5VL_free_connector_info(connector_id, vol_info) < 0) + HDONE_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "can't free VOL connector info") + if(connector_id >= 0) + /* The H5VL_class_t struct will be freed by this function */ + if(H5I_dec_ref(connector_id) < 0) + HDONE_ERROR(H5E_VOL, H5E_CANTDEC, FAIL, "unable to unregister VOL connector") + } /* end if */ + + /* Clean up */ + H5MM_xfree(buf); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5VL__set_def_conn() */ + + +/*------------------------------------------------------------------------- * Function: H5VL__wrap_obj * * Purpose: Wraps a library object with possible VOL connector wrappers, to @@ -393,29 +640,22 @@ done: *------------------------------------------------------------------------- */ herr_t -H5VL_conn_free(const H5VL_connector_prop_t *info) +H5VL_conn_free(const H5VL_connector_prop_t *connector_prop) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) - if(info) { + if(connector_prop) { /* Free the connector info (if it exists) and decrement the ID */ - if(info->connector_id > 0) { - if(info->connector_info) { - H5VL_class_t *connector; /* Pointer to connector */ - - /* Retrieve the connector for the ID */ - if(NULL == (connector = (H5VL_class_t *)H5I_object(info->connector_id))) - HGOTO_ERROR(H5E_VOL, H5E_BADTYPE, FAIL, "not a VOL connector ID") - + if(connector_prop->connector_id > 0) { + if(connector_prop->connector_info) /* Free the connector info */ - if(H5VL_free_connector_info(connector, (void *)info->connector_info) < 0) /* Casting away const OK - QAK */ + if(H5VL_free_connector_info(connector_prop->connector_id, (void *)connector_prop->connector_info) < 0) /* Casting away const OK - QAK */ HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "unable to release VOL connector info object") - } /* end if */ /* Decrement reference count for connector ID */ - if(H5I_dec_ref(info->connector_id) < 0) + if(H5I_dec_ref(connector_prop->connector_id) < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTDEC, FAIL, "can't decrement reference count for connector ID") } /* end if */ } /* end if */ @@ -595,6 +835,9 @@ done: * * Failure: H5I_INVALID_HID * + * Programmer: Dana Robinson + * June 22, 2017 + * *------------------------------------------------------------------------- */ hid_t @@ -610,7 +853,7 @@ H5VL_register_connector(const void *_cls, hbool_t app_ref, hid_t vipl_id) HDassert(cls); /* Copy the class structure so the caller can reuse or free it */ - if (NULL == (saved = H5FL_CALLOC(H5VL_class_t))) + if(NULL == (saved = H5FL_MALLOC(H5VL_class_t))) HGOTO_ERROR(H5E_VOL, H5E_CANTALLOC, H5I_INVALID_HID, "memory allocation failed for VOL connector class struct") HDmemcpy(saved, cls, sizeof(H5VL_class_t)); if(NULL == (saved->name = H5MM_strdup(cls->name))) @@ -621,23 +864,319 @@ H5VL_register_connector(const void *_cls, hbool_t app_ref, hid_t vipl_id) HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, H5I_INVALID_HID, "unable to init VOL connector") /* Create the new class ID */ - if ((ret_value = H5I_register(H5I_VOL, saved, app_ref)) < 0) + if((ret_value = H5I_register(H5I_VOL, saved, app_ref)) < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register VOL connector ID") done: - if (ret_value < 0 && saved) { - if (saved->name) + if(ret_value < 0 && saved) { + if(saved->name) H5MM_xfree((void *)(saved->name)); /* Casting away const OK -QAK */ H5FL_FREE(H5VL_class_t, saved); - } + } /* end if */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5VL_register_connector() */ /*------------------------------------------------------------------------- - * Function: H5VL_get_connector_name + * Function: H5VL__register_connector + * + * Purpose: Registers a new VOL connector as a member of the virtual object + * layer class. + * + * Return: Success: A VOL connector ID which is good until the + * library is closed or the connector is + * unregistered. + * + * Failure: H5I_INVALID_HID + * + * Programmer: Dana Robinson + * June 22, 2017 + * + *------------------------------------------------------------------------- + */ +hid_t +H5VL__register_connector(const H5VL_class_t *cls, hbool_t app_ref, hid_t vipl_id) +{ + H5VL_get_connector_ud_t op_data; /* Callback info for connector search */ + hid_t ret_value = H5I_INVALID_HID; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Set up op data for iteration */ + op_data.kind = H5VL_GET_CONNECTOR_BY_NAME; + op_data.u.name = cls->name; + op_data.found_id = H5I_INVALID_HID; + + /* Check if connector is already registered */ + if(H5I_iterate(H5I_VOL, H5VL__get_connector_cb, &op_data, TRUE) < 0) + HGOTO_ERROR(H5E_VOL, H5E_BADITER, H5I_INVALID_HID, "can't iterate over VOL IDs") + + /* Increment the ref count on the existing VOL connector ID, if it's already registered */ + if(op_data.found_id != H5I_INVALID_HID) { + if(H5I_inc_ref(op_data.found_id, app_ref) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTINC, H5I_INVALID_HID, "unable to increment ref count on VOL connector") + ret_value = op_data.found_id; + } /* end if */ + else { + /* Create a new class ID */ + if((ret_value = H5VL_register_connector(cls, app_ref, vipl_id)) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register VOL connector") + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5VL__register_connector() */ + + +/*------------------------------------------------------------------------- + * Function: H5VL__register_connector_by_name + * + * Purpose: Registers a new VOL connector as a member of the virtual object + * layer class. + * + * Return: Success: A VOL connector ID which is good until the + * library is closed or the connector is + * unregistered. + * + * Failure: H5I_INVALID_HID + * + * Programmer: Dana Robinson + * June 22, 2017 + * + *------------------------------------------------------------------------- + */ +hid_t +H5VL__register_connector_by_name(const char *name, hbool_t app_ref, hid_t vipl_id) +{ + H5VL_get_connector_ud_t op_data; /* Callback info for connector search */ + hid_t ret_value = H5I_INVALID_HID; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Set up op data for iteration */ + op_data.kind = H5VL_GET_CONNECTOR_BY_NAME; + op_data.u.name = name; + op_data.found_id = H5I_INVALID_HID; + + /* Check if connector is already registered */ + if(H5I_iterate(H5I_VOL, H5VL__get_connector_cb, &op_data, TRUE) < 0) + HGOTO_ERROR(H5E_VOL, H5E_BADITER, H5I_INVALID_HID, "can't iterate over VOL ids") + + /* If connector alread registered, increment ref count on ID and return ID */ + if(op_data.found_id != H5I_INVALID_HID) { + if(H5I_inc_ref(op_data.found_id, app_ref) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTINC, H5I_INVALID_HID, "unable to increment ref count on VOL connector") + ret_value = op_data.found_id; + } /* end if */ + else { + H5PL_key_t key; + const H5VL_class_t *cls; + + /* Try loading the connector */ + key.vol.kind = H5VL_GET_CONNECTOR_BY_NAME; + key.vol.u.name = name; + if(NULL == (cls = (const H5VL_class_t *)H5PL_load(H5PL_TYPE_VOL, &key))) + HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, H5I_INVALID_HID, "unable to load VOL connector") + + /* Register the connector we loaded */ + if((ret_value = H5VL_register_connector(cls, app_ref, vipl_id)) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register VOL connector ID") + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5VL__register_connector_by_name() */ + + +/*------------------------------------------------------------------------- + * Function: H5VL__register_connector_by_value + * + * Purpose: Registers a new VOL connector as a member of the virtual object + * layer class. + * + * Return: Success: A VOL connector ID which is good until the + * library is closed or the connector is + * unregistered. + * + * Failure: H5I_INVALID_HID + * + * Programmer: Dana Robinson + * June 22, 2017 + * + *------------------------------------------------------------------------- + */ +hid_t +H5VL__register_connector_by_value(H5VL_class_value_t value, hbool_t app_ref, hid_t vipl_id) +{ + H5VL_get_connector_ud_t op_data; /* Callback info for connector search */ + hid_t ret_value = H5I_INVALID_HID; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Set up op data for iteration */ + op_data.kind = H5VL_GET_CONNECTOR_BY_VALUE; + op_data.u.value = value; + op_data.found_id = H5I_INVALID_HID; + + /* Check if connector is already registered */ + if(H5I_iterate(H5I_VOL, H5VL__get_connector_cb, &op_data, TRUE) < 0) + HGOTO_ERROR(H5E_VOL, H5E_BADITER, H5I_INVALID_HID, "can't iterate over VOL ids") + + /* If connector alread registered, increment ref count on ID and return ID */ + if(op_data.found_id != H5I_INVALID_HID) { + if(H5I_inc_ref(op_data.found_id, app_ref) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTINC, H5I_INVALID_HID, "unable to increment ref count on VOL connector") + ret_value = op_data.found_id; + } /* end if */ + else { + H5PL_key_t key; + const H5VL_class_t *cls; + + /* Try loading the connector */ + key.vol.kind = H5VL_GET_CONNECTOR_BY_VALUE; + key.vol.u.value = value; + if(NULL == (cls = (const H5VL_class_t *)H5PL_load(H5PL_TYPE_VOL, &key))) + HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, H5I_INVALID_HID, "unable to load VOL connector") + + /* Register the connector we loaded */ + if((ret_value = H5VL_register_connector(cls, app_ref, vipl_id)) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register VOL connector ID") + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5VL__register_connector_by_value() */ + + +/*------------------------------------------------------------------------- + * Function: H5VL__is_connector_registered + * + * Purpose: Checks if a connector with a particular name is registered. + * + * Return: Success: 0 + * Failure: -1 + * + * Programmer: Dana Robinson + * June 17, 2017 + * + *------------------------------------------------------------------------- + */ +htri_t +H5VL__is_connector_registered(const char *name) +{ + H5VL_get_connector_ud_t op_data; /* Callback info for connector search */ + htri_t ret_value = FALSE; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Set up op data for iteration */ + op_data.kind = H5VL_GET_CONNECTOR_BY_NAME; + op_data.u.name = name; + op_data.found_id = H5I_INVALID_HID; + + /* Find connector with name */ + if(H5I_iterate(H5I_VOL, H5VL__get_connector_cb, &op_data, TRUE) < 0) + HGOTO_ERROR(H5E_VOL, H5E_BADITER, FAIL, "can't iterate over VOL connectors") + + /* Found a connector with that name */ + if(op_data.found_id != H5I_INVALID_HID) + ret_value = TRUE; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5VL__is_connector_registered() */ + + +/*------------------------------------------------------------------------- + * Function: H5VL__get_connector_id + * + * Purpose: Retrieves the ID for a registered VOL connector. + * + * Return: Positive if the VOL class has been registered + * Negative on error (if the class is not a valid class or not registered) + * + * Programmer: Dana Robinson + * June 17, 2017 + * + *------------------------------------------------------------------------- + */ +hid_t +H5VL__get_connector_id(const char *name, hbool_t is_api) +{ + H5VL_get_connector_ud_t op_data; /* Callback info for connector search */ + hid_t ret_value = H5I_INVALID_HID; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Set up op data for iteration */ + op_data.kind = H5VL_GET_CONNECTOR_BY_NAME; + op_data.u.name = name; + op_data.found_id = H5I_INVALID_HID; + + /* Find connector with name */ + if(H5I_iterate(H5I_VOL, H5VL__get_connector_cb, &op_data, TRUE) < 0) + HGOTO_ERROR(H5E_VOL, H5E_BADITER, H5I_INVALID_HID, "can't iterate over VOL connectors") + + /* Found a connector with that name */ + if(op_data.found_id != H5I_INVALID_HID) { + if(H5I_inc_ref(op_data.found_id, is_api) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTINC, H5I_INVALID_HID, "unable to increment ref count on VOL connector") + ret_value = op_data.found_id; + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5VL__get_connector_id() */ + + +/*------------------------------------------------------------------------- + * Function: H5VL__connector_str_to_info + * + * Purpose: Deserializes a string into a connector's info object + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Quincey Koziol + * March 2, 2019 + * + *------------------------------------------------------------------------- + */ +herr_t +H5VL__connector_str_to_info(const char *str, hid_t connector_id, void **info) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Only deserialize string, if it's non-NULL */ + if(str) { + H5VL_class_t *cls; /* VOL connector's class struct */ + + /* Check args and get class pointer */ + if(NULL == (cls = (H5VL_class_t *)H5I_object_verify(connector_id, H5I_VOL))) + HGOTO_ERROR(H5E_VOL, H5E_BADTYPE, FAIL, "not a VOL connector ID") + + /* Allow the connector to deserialize info */ + if(cls->info_cls.from_str) { + if((cls->info_cls.from_str)(str, info) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTUNSERIALIZE, FAIL, "can't deserialize connector info") + } /* end if */ + else + *info = NULL; + } /* end if */ + else + *info = NULL; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5VL__connector_str_to_info() */ + + +/*------------------------------------------------------------------------- + * Function: H5VL__get_connector_name * * Purpose: Private version of H5VLget_connector_name * @@ -647,14 +1186,14 @@ done: *------------------------------------------------------------------------- */ ssize_t -H5VL_get_connector_name(hid_t id, char *name /*out*/, size_t size) +H5VL__get_connector_name(hid_t id, char *name /*out*/, size_t size) { H5VL_object_t *vol_obj; const H5VL_class_t *cls; size_t len; ssize_t ret_value = -1; - FUNC_ENTER_NOAPI(FAIL) + FUNC_ENTER_PACKAGE /* get the object pointer */ if (NULL == (vol_obj = H5VL_vol_object(id))) @@ -674,7 +1213,7 @@ H5VL_get_connector_name(hid_t id, char *name /*out*/, size_t size) done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5VL_get_connector_name() */ +} /* end H5VL__get_connector_name() */ /*------------------------------------------------------------------------- diff --git a/src/H5VLpassthru.c b/src/H5VLpassthru.c index fe72000..a4c85cc 100644 --- a/src/H5VLpassthru.c +++ b/src/H5VLpassthru.c @@ -20,6 +20,11 @@ * include _any_ private HDF5 header files. This connector should * therefore only make public HDF5 API calls and use standard C / * POSIX calls. + * + * Note that the HDF5 error stack must be preserved on code paths + * that could be invoked when the underlying VOL connector's + * callback can fail. + * */ @@ -297,6 +302,9 @@ H5VL_pass_through_new_obj(void *under_obj, hid_t under_vol_id) * * Purpose: Release a pass through object * + * Note: Take care to preserve the current HDF5 error stack + * when calling HDF5 API calls. + * * Return: Success: 0 * Failure: -1 * @@ -308,7 +316,14 @@ H5VL_pass_through_new_obj(void *under_obj, hid_t under_vol_id) static herr_t H5VL_pass_through_free_obj(H5VL_pass_through_t *obj) { + hid_t err_id; + + err_id = H5Eget_current_stack(); + H5Idec_ref(obj->under_vol_id); + + H5Eset_current_stack(err_id); + free(obj); return 0; @@ -332,11 +347,8 @@ H5VL_pass_through_free_obj(H5VL_pass_through_t *obj) hid_t H5VL_pass_through_register(void) { - /* Clear the error stack */ - H5Eclear2(H5E_DEFAULT); - /* Singleton register the pass-through VOL connector ID */ - if(H5I_VOL != H5Iget_type(H5VL_PASSTHRU_g)) + if(H5VL_PASSTHRU_g < 0) H5VL_PASSTHRU_g = H5VLregister_connector(&H5VL_pass_through_g, H5P_DEFAULT); return H5VL_PASSTHRU_g; @@ -476,6 +488,9 @@ H5VL_pass_through_info_cmp(int *cmp_value, const void *_info1, const void *_info * * Purpose: Release an info object for the connector. * + * Note: Take care to preserve the current HDF5 error stack + * when calling HDF5 API calls. + * * Return: Success: 0 * Failure: -1 * @@ -485,16 +500,21 @@ static herr_t H5VL_pass_through_info_free(void *_info) { H5VL_pass_through_info_t *info = (H5VL_pass_through_info_t *)_info; + hid_t err_id; #ifdef ENABLE_PASSTHRU_LOGGING printf("------- PASS THROUGH VOL INFO Free\n"); #endif + err_id = H5Eget_current_stack(); + /* Release underlying VOL ID and info */ if(info->under_vol_info) H5VLfree_connector_info(info->under_vol_id, info->under_vol_info); H5Idec_ref(info->under_vol_id); + H5Eset_current_stack(err_id); + /* Free pass through info object itself */ free(info); @@ -695,6 +715,9 @@ H5VL_pass_through_wrap_object(void *obj, H5I_type_t obj_type, void *_wrap_ctx) * * Purpose: Release a "wrapper context" for an object * + * Note: Take care to preserve the current HDF5 error stack + * when calling HDF5 API calls. + * * Return: Success: 0 * Failure: -1 * @@ -704,16 +727,21 @@ static herr_t H5VL_pass_through_free_wrap_ctx(void *_wrap_ctx) { H5VL_pass_through_wrap_ctx_t *wrap_ctx = (H5VL_pass_through_wrap_ctx_t *)_wrap_ctx; + hid_t err_id; #ifdef ENABLE_PASSTHRU_LOGGING printf("------- PASS THROUGH VOL WRAP CTX Free\n"); #endif + err_id = H5Eget_current_stack(); + /* Release underlying VOL ID and wrap context */ if(wrap_ctx->under_wrap_ctx) H5VLfree_wrap_ctx(wrap_ctx->under_wrap_ctx, wrap_ctx->under_vol_id); H5Idec_ref(wrap_ctx->under_vol_id); + H5Eset_current_stack(err_id); + /* Free pass through wrap context object itself */ free(wrap_ctx); diff --git a/src/H5VLpkg.h b/src/H5VLpkg.h index bbdb0cc..69e51c2 100644 --- a/src/H5VLpkg.h +++ b/src/H5VLpkg.h @@ -28,21 +28,36 @@ /* Other private headers needed by this file */ + /**************************/ /* Package Private Macros */ /**************************/ + /****************************/ /* Package Private Typedefs */ /****************************/ + /*****************************/ /* Package Private Variables */ /*****************************/ + /******************************/ /* Package Private Prototypes */ /******************************/ +H5_DLL hid_t H5VL__register_connector(const H5VL_class_t *cls, hbool_t app_ref, + hid_t vipl_id); +H5_DLL hid_t H5VL__register_connector_by_name(const char *name, hbool_t app_ref, + hid_t vipl_id); +H5_DLL hid_t H5VL__register_connector_by_value(H5VL_class_value_t value, + hbool_t app_ref, hid_t vipl_id); +H5_DLL htri_t H5VL__is_connector_registered(const char *name); +H5_DLL hid_t H5VL__get_connector_id(const char *name, hbool_t is_api); +H5_DLL herr_t H5VL__connector_str_to_info(const char *str, hid_t connector_id, + void **info); +H5_DLL ssize_t H5VL__get_connector_name(hid_t id, char *name/*out*/, size_t size); #endif /* _H5VLpkg_H */ diff --git a/src/H5VLprivate.h b/src/H5VLprivate.h index 283c77a..6b948f6 100644 --- a/src/H5VLprivate.h +++ b/src/H5VLprivate.h @@ -18,10 +18,12 @@ /* Private headers needed by this file */ + /**************************/ /* Library Private Macros */ /**************************/ + /****************************/ /* Library Private Typedefs */ /****************************/ @@ -62,14 +64,14 @@ typedef enum H5VL_get_connector_kind_t { /******************************/ /* Utility functions */ -H5_DLL herr_t H5VL_init(void); +H5_DLL herr_t H5VL_init_phase1(void); +H5_DLL herr_t H5VL_init_phase2(void); H5_DLL herr_t H5VL_cmp_connector_cls(int *cmp_value, const H5VL_class_t *cls1, const H5VL_class_t *cls2); H5_DLL herr_t H5VL_conn_copy(H5VL_connector_prop_t *value); H5_DLL herr_t H5VL_conn_free(const H5VL_connector_prop_t *info); /* Functions that deal with VOL connectors */ H5_DLL hid_t H5VL_register_connector(const void *cls, hbool_t app_ref, hid_t vipl_id); -H5_DLL ssize_t H5VL_get_connector_name(hid_t id, char *name/*out*/, size_t size); /* NOTE: The object and ID functions below deal in VOL objects (i.e.; * H5VL_object_t). Similar non-VOL calls exist in H5Iprivate.h. Use @@ -112,7 +114,7 @@ H5_DLL int H5VL_copy_connector_info(const H5VL_class_t *connector, void **dst_in const void *src_info); H5_DLL herr_t H5VL_cmp_connector_info(const H5VL_class_t *connector, int *cmp_value, const void *info1, const void *info2); -H5_DLL herr_t H5VL_free_connector_info(const H5VL_class_t *connector, void *info); +H5_DLL herr_t H5VL_free_connector_info(hid_t connector_id, void *info); /* Attribute functions */ H5_DLL void *H5VL_attr_create(const H5VL_object_t *vol_obj, const H5VL_loc_params_t *loc_params, const char *attr_name, hid_t acpl_id, hid_t aapl_id, hid_t dxpl_id, void **req); |