From 602dd3ac15c9f5cd47fc78985266ce66a68a8789 Mon Sep 17 00:00:00 2001 From: Jacob Smith Date: Tue, 11 Sep 2018 16:37:14 -0500 Subject: Stash work on object header reduction code and tests. CMake stuff is not verified. --- MANIFEST | 1 + src/H5Dint.c | 306 +++++++++++++++++++++++++++++++++++++++- src/H5Dprivate.h | 1 + src/H5F.c | 94 +++++++++++++ src/H5Fint.c | 3 + src/H5Fpkg.h | 1 + src/H5Fpublic.h | 2 + src/H5Oint.c | 382 ++++++++++++++++++++++++++++++++++++++------------ src/H5Oprivate.h | 12 ++ src/H5Pdcpl.c | 126 +++++++++++++++++ src/H5Ppublic.h | 2 + test/CMakeLists.txt | 1 + test/CMakeTests.cmake | 2 + test/Makefile.am | 15 +- test/dsets.c | 109 ++++++++++++++ test/enc_dec_plist.c | 3 + test/gen_plist.c | 3 + test/tfile.c | 139 ++++++++++++++++++ 18 files changed, 1101 insertions(+), 101 deletions(-) diff --git a/MANIFEST b/MANIFEST index 1165240..68763aa 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1041,6 +1041,7 @@ ./test/none.h5 ./test/ntypes.c ./test/ohdr.c +./test/ohdr_min.c ./test/objcopy.c ./test/page_buffer.c ./test/paged_nopersist.h5 diff --git a/src/H5Dint.c b/src/H5Dint.c index e8874a2..6d095aa 100644 --- a/src/H5Dint.c +++ b/src/H5Dint.c @@ -61,7 +61,9 @@ static herr_t H5D__init_storage(const H5D_io_info_t *io_info, hbool_t full_overw static herr_t H5D__get_storage_size_real(const H5D_t *dset, hsize_t *storage_size); static herr_t H5D__append_flush_setup(H5D_t *dset, hid_t dapl_id); static herr_t H5D__close_cb(H5D_t *dataset); - +static herr_t H5D__use_minimized_dset_headers(H5F_t *file, H5D_t *dset, hbool_t *minimize); +static herr_t H5D__prepare_minimized_oh(H5F_t *file, H5D_t *dset, H5O_loc_t *oloc); +static size_t H5D__calculate_minimum_header_size(H5F_t *file, H5D_t *dset, H5O_t *ohdr); /*********************/ /* Package Variables */ /*********************/ @@ -662,6 +664,272 @@ done: /*------------------------------------------------------------------------- + * Function: H5D__use_minimized_dset_headers + * + * Purpose: Compartmentalize check for file- or dcpl-set values indicating + * to create a "minimized" dataset object header. + * Upon success, write resulting value to out pointer `minimize`. + * + * Return: Success: SUCCEED (0) (non-negative value) + * Failure: FAIL (-1) (negative value) + * + * Programmer: Jacob Smith + * 16 August 2018 + *------------------------------------------------------------------------- + */ +static herr_t +H5D__use_minimized_dset_headers( \ + H5F_t *file, \ + H5D_t *dset, \ + hbool_t *minimize) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT; + + HDassert(file); + HDassert(dset); + HDassert(minimize); + + if (FAIL == H5Pget_dset_no_attrs_hint(dset->shared->dcpl_id, minimize)) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, + "can't get minimize value from dcpl") + +#if 1 /* TODO: problem getting file id? */ + /* error kicks in when tring to create dset through external link */ + if (FALSE == *minimize) { +#if 1 /* API or direct */ + /* problems getting/verifying object id */ + hid_t file_id = -1; + file_id = H5F_get_file_id((const H5F_t *)file); + if (0 > file_id) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, + "can't get file id") + +#if 1 /* which file-id verification */ + if (NULL == H5I_object(file_id)) + HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, + "file id seems to be invalid") +#else + if (NULL == H5I_object_verify(file_id, H5I_FILE)) + HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, + "file id seems to be invalid") +#endif /* which file-id verification */ + + if (FAIL == H5Fget_dset_no_attrs_hint(file_id, minimize)) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, + "can't get minimize value from file") +#else + /* direct access -- "incomplete type" */ + HDassert(file->shared); + minimize = file->shared->crt_dset_min_ohdr_flag; +#endif /* API or direct */ + } /* if to look in file for flag */ +#endif /* TODO */ + +done: + if (FAIL == ret_value) + *minimize = FALSE; + FUNC_LEAVE_NOAPI(ret_value); +} /* H5D__use_minimized_dset_headers */ + + +/*------------------------------------------------------------------------- + * Function: H5D__calculate_minimium_header_size + * + * Purpose: Calculate the size required for the minimized object header. + * + * Return: Success: SUCCEED (0) (non-negative value) + * Failure: FAIL (-1) (negative value) + * + * Programmer: Jacob Smith + * 16 August 2018 + *------------------------------------------------------------------------- + */ +static size_t +H5D__calculate_minimum_header_size( \ + H5F_t *file, \ + H5D_t *dset, \ + H5O_t *ohdr) +{ + H5T_t *type = NULL; + H5O_fill_t *fill_prop = NULL; + hbool_t use_at_least_v18 = FALSE; + size_t ret_value = 0; + + FUNC_ENTER_NOAPI_NOINIT_NOERR; + + HDassert(file); + HDassert(dset); + HDassert(ohdr); + + type = dset->shared->type; + fill_prop = &(dset->shared->dcpl_cache.fill); + use_at_least_v18 = (H5F_LOW_BOUND(file) >= H5F_LIBVER_V18); + + /* Datatype message size */ + ret_value += H5O_msg_size_oh( + file, + ohdr, + H5O_DTYPE_ID, + type, + 0); + + /* Shared Dataspace message size */ + ret_value += H5O_msg_size_oh( + file, + ohdr, + H5O_SDSPACE_ID, + dset->shared->space, + 0); + + /* "Layout" message size */ + ret_value += H5O_msg_size_oh( + file, + ohdr, + H5O_LAYOUT_ID, + &dset->shared->layout, + 0); + + /* Fill Value message size */ + ret_value += H5O_msg_size_oh( + file, + ohdr, + H5O_FILL_NEW_ID, + fill_prop, + 0); + +#if 1 /* DEBUG H5Omessage */ + /* "Continuation" message size */ +#if 0 + ret_value += H5O_msg_raw_size( + file, + H5O_CONT_ID, + FALSE, + NULL); +#else + { + char tmp[1] = "\0"; + ret_value += H5O_msg_size_oh( + file, + ohdr, + H5O_CONT_ID, + tmp, /* NULL, */ /* UNUSED? */ /*intercepted by assert before passed through */ + 0); + } +#endif +#endif /* DEBUG H5Omessage */ + + /* Fill Value (backwards compatability) message size */ + if (fill_prop->buf && !use_at_least_v18) { + H5O_fill_t old_fill_prop; /* Copy for writing "old" fill value */ + + /* Shallow copy the fill value property */ + /* guards against shared component modification */ + HDmemcpy(&old_fill_prop, fill_prop, sizeof(old_fill_prop)); + + H5O_msg_reset_share(H5O_FILL_ID, &old_fill_prop); + + ret_value += H5O_msg_size_oh( + file, + ohdr, + H5O_FILL_ID, + &old_fill_prop, + 0); + } + + /* Filter/Pipeline message size */ + if (H5D_CHUNKED == dset->shared->layout.type) { + H5O_pline_t *pline = &dset->shared->dcpl_cache.pline; + if (pline->nused > 0) { + ret_value += H5O_msg_size_oh( + file, + ohdr, + H5O_PLINE_ID, + pline, + 0); + } + } + + /* External File Link message size */ + if (dset->shared->dcpl_cache.efl.nused > 0) { + ret_value += H5O_msg_size_oh( + file, + ohdr, + H5O_EFL_ID, + &dset->shared->dcpl_cache.efl, + 0); + } + + /* Modification Time message size */ + if ((H5O_OH_GET_VERSION(ohdr) > 1) && /* TODO: H5O_VERSION_1 in H5Opkg.h */ + (H5O_HDR_STORE_TIMES & H5O_OH_GET_FLAGS(ohdr))) + { + time_t mtime = H5O_OH_GET_MTIME(ohdr); + ret_value += H5O_msg_size_oh( + file, + ohdr, + H5O_MTIME_NEW_ID, + &mtime, + 0); + } + + FUNC_LEAVE_NOAPI(ret_value); +} /* H5D__calculate_minimum_header_size */ + + +/*------------------------------------------------------------------------- + * Function: H5D__prepare_minimized_oh + * + * Purpose: Create an object header (H5O_t) allocated with the smallest + * possible size. + * + * Return: Success: SUCCEED (0) (non-negative value) + * Failure: FAIL (-1) (negative value) + * + * Programmer: Jacob Smith + * 16 August 2018 + *------------------------------------------------------------------------- + */ +static herr_t +H5D__prepare_minimized_oh( \ + H5F_t *file, \ + H5D_t *dset, \ + H5O_loc_t *oloc) +{ + H5O_t *oh = NULL; + size_t ohdr_size = 0; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT; + + HDassert(file); + HDassert(dset); + HDassert(oloc); + + oh = H5O__create_ohdr(file, dset->shared->dcpl_id); + if (NULL == oh) + HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, + "can't instantiate object header") + + ohdr_size = H5D__calculate_minimum_header_size(file, dset, oh); + + if (FAIL == H5O__apply_ohdr( + file, + oh, + dset->shared->dcpl_id, + ohdr_size, + (size_t)1, + oloc)) + HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, + "can't apply object header to file") + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5D_prepare_minimized_oh */ + + +/*------------------------------------------------------------------------- * Function: H5D__update_oh_info * * Purpose: Create and fill object header for dataset @@ -683,6 +951,7 @@ H5D__update_oh_info(H5F_t *file, H5D_t *dset, hid_t dapl_id) hbool_t fill_changed = FALSE; /* Flag indicating the fill value was changed */ hbool_t layout_init = FALSE; /* Flag to indicate that chunk information was initialized */ hbool_t use_at_least_v18; /* Flag indicating to use at least v18 format versions */ + hbool_t minimize_header = FALSE; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC @@ -751,19 +1020,42 @@ H5D__update_oh_info(H5F_t *file, H5D_t *dset, hid_t dapl_id) HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set fill value info") } /* end if */ - /* Add the dataset's raw data size to the size of the header, if the raw data will be stored as compact */ - if(layout->type == H5D_COMPACT) - ohdr_size += layout->storage.u.compact.size; + if (FAIL == H5D__use_minimized_dset_headers(file, dset, &minimize_header)) + HGOTO_ERROR(H5E_ARGS, H5E_CANTGET, FAIL, + "can't get minimize settings") + if (TRUE == minimize_header) { + if (FAIL == H5D__prepare_minimized_oh(file, dset, oloc)) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, + "can't create minimized dataset object header") + } else { + /* Add the dataset's raw data size to the size of the header, if the + * raw data will be stored as compact + */ + if (H5D_COMPACT == layout->type) + ohdr_size += layout->storage.u.compact.size; + + /* Create an object header for the dataset */ + if (0 > H5O_create( + file, + ohdr_size, + (size_t)1, + dset->shared->dcpl_id, + oloc/*out*/)) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, + "unable to create dataset object header") + } /* If use minimum/standard object header space */ - /* Create an object header for the dataset */ - if(H5O_create(file, ohdr_size, (size_t)1, dset->shared->dcpl_id, oloc/*out*/) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create dataset object header") HDassert(file == dset->oloc.file); /* Pin the object header */ if(NULL == (oh = H5O_pin(oloc))) HGOTO_ERROR(H5E_DATASET, H5E_CANTPIN, FAIL, "unable to pin dataset object header") +#if 0 + HDprintf("DATATYPE SIZE: %lu\n", + H5O_msg_size_oh(file, oh, H5O_DTYPE_ID, type, 0)); +#endif /* TESTING DEBUG */ + /* Write the dataspace header message */ if(H5S_append(file, oh, dset->shared->space) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to update dataspace header message") diff --git a/src/H5Dprivate.h b/src/H5Dprivate.h index cbee0de..e136c80 100644 --- a/src/H5Dprivate.h +++ b/src/H5Dprivate.h @@ -45,6 +45,7 @@ #define H5D_CRT_FILL_VALUE_NAME "fill_value" /* Fill value */ #define H5D_CRT_ALLOC_TIME_STATE_NAME "alloc_time_state" /* Space allocation time state */ #define H5D_CRT_EXT_FILE_LIST_NAME "efl" /* External file list */ +#define H5D_CRT_MIN_DSET_HDR_SIZE_NAME "dset_oh_minimize"/* Minimize object header */ /* ======== Dataset access property names ======== */ #define H5D_ACS_DATA_CACHE_NUM_SLOTS_NAME "rdcc_nslots" /* Size of raw data chunk cache(slots) */ diff --git a/src/H5F.c b/src/H5F.c index 01fd7db..7e206bb 100644 --- a/src/H5F.c +++ b/src/H5F.c @@ -1713,3 +1713,97 @@ H5Fincrement_filesize(hid_t file_id, hsize_t increment) done: FUNC_LEAVE_API(ret_value) } /* H5Fincrement_filesize() */ + + +/*------------------------------------------------------------------------- + * Function: H5Fget_dset_no_attrs_hint + * + * Purpose: + * + * Get the file-level setting to create minimized dataset object headers. + * Result is stored at pointer `minimize`. + * + * Return: + * + * Success: SUCCEED (0) (non-negative value) + * Failure: FAIL (-1) (negative value) + * + * Programmer: + * + * Jacob Smith + * 15 August 2018 + * + * Changes: None. + *------------------------------------------------------------------------- + */ +herr_t +H5Fget_dset_no_attrs_hint(hid_t file_id, + hbool_t *minimize) +{ + H5F_t *f = NULL; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_API(FAIL) + H5TRACE2("e", "i*b", file_id, minimize); + + if (NULL == minimize) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, + "out pointer 'minimize' cannot be NULL") + + f = (H5F_t *)H5I_object_verify(file_id, H5I_FILE); + if (NULL == f) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, + "can't get file from id") + + HDassert(f->shared); + + *minimize = f->shared->crt_dset_min_ohdr_flag; + +done: + FUNC_LEAVE_API(ret_value) +} /* H5Fget_dset_no_attrs_hint */ + + +/*------------------------------------------------------------------------- + * Function: H5Fset_dset_no_attrs_hint + * + * Purpose: + * + * Set the file-level setting to create minimized dataset object headers. + * + * Return: + * + * Success: SUCCEED (0) (non-negative value) + * Failure: FAIL (-1) (negative value) + * + * Programmer: + * + * Jacob Smith + * 15 August 2018 + * + * Changes: None. + *------------------------------------------------------------------------- + */ +herr_t +H5Fset_dset_no_attrs_hint(hid_t file_id, + hbool_t minimize) +{ + H5F_t *f = NULL; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_API(FAIL) + H5TRACE2("e", "ib", file_id, minimize); + + f = (H5F_t *)H5I_object_verify(file_id, H5I_FILE); + if (NULL == f) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, + "can't get file from id") + + HDassert(f->shared); + + f->shared->crt_dset_min_ohdr_flag = minimize; + +done: + FUNC_LEAVE_API(ret_value) +} /* H5Fset_dset_no_attrs_hint */ + diff --git a/src/H5Fint.c b/src/H5Fint.c index abc638a..c3fe07a 100644 --- a/src/H5Fint.c +++ b/src/H5Fint.c @@ -880,6 +880,9 @@ H5F__new(H5F_file_t *shared, unsigned flags, hid_t fcpl_id, hid_t fapl_id, H5FD_ /* intialize point of no return */ f->shared->point_of_no_return = FALSE; + /* set default value for minimizing dataset object headers */ + f->shared->crt_dset_min_ohdr_flag = FALSE; + /* Copy the file creation and file access property lists into the * new file handle. We do this early because some values might need * to change as the file is being opened. diff --git a/src/H5Fpkg.h b/src/H5Fpkg.h index 2ab41de..edbd460 100644 --- a/src/H5Fpkg.h +++ b/src/H5Fpkg.h @@ -353,6 +353,7 @@ struct H5F_file_t { /* Object flush info */ H5F_object_flush_t object_flush; /* Information for object flush callback */ + hbool_t crt_dset_min_ohdr_flag; /* flag to minimize created dataset object header */ }; /* diff --git a/src/H5Fpublic.h b/src/H5Fpublic.h index 73c59f5..6274eb0 100644 --- a/src/H5Fpublic.h +++ b/src/H5Fpublic.h @@ -273,6 +273,8 @@ H5_DLL herr_t H5Freset_page_buffering_stats(hid_t file_id); H5_DLL herr_t H5Fget_page_buffering_stats(hid_t file_id, unsigned accesses[2], unsigned hits[2], unsigned misses[2], unsigned evictions[2], unsigned bypasses[2]); H5_DLL herr_t H5Fget_mdc_image_info(hid_t file_id, haddr_t *image_addr, hsize_t *image_size); +H5_DLL herr_t H5Fget_dset_no_attrs_hint(hid_t file_id, hbool_t *minimize); +H5_DLL herr_t H5Fset_dset_no_attrs_hint(hid_t file_id, hbool_t minimize); #ifdef H5_HAVE_PARALLEL H5_DLL herr_t H5Fset_mpi_atomicity(hid_t file_id, hbool_t flag); diff --git a/src/H5Oint.c b/src/H5Oint.c index 2752a25..1d07415 100644 --- a/src/H5Oint.c +++ b/src/H5Oint.c @@ -83,7 +83,6 @@ static herr_t H5O__visit_cb(hid_t group, const char *name, const H5L_info_t *lin void *_udata); static const H5O_obj_class_t *H5O__obj_class_real(const H5O_t *oh); - /*********************/ /* Package Variables */ /*********************/ @@ -277,130 +276,276 @@ done: * matzke@llnl.gov * Aug 5 1997 * + * Changes: 17 August 2018 + * Jacob Smith + * Refactor out the operations into two separate steps -- + * preparation and application -- to facilitate overriding the + * library-default size allocated for the object header. This + * function is retained as a wrapper, to minimize changes to + * unaffected calling functions. + * *------------------------------------------------------------------------- */ herr_t -H5O_create(H5F_t *f, size_t size_hint, size_t initial_rc, hid_t ocpl_id, - H5O_loc_t *loc/*out*/) +H5O_create( \ + H5F_t *f, \ + size_t size_hint, \ + size_t initial_rc, \ + hid_t ocpl_id, \ + H5O_loc_t *loc) /*out*/ { - H5P_genplist_t *oc_plist; /* Object creation property list */ - H5O_t *oh = NULL; /* Object header created */ - haddr_t oh_addr; /* Address of initial object header */ - size_t oh_size; /* Size of initial object header */ - uint8_t oh_flags; /* Object header's initial status flags */ - unsigned insert_flags = H5AC__NO_FLAGS_SET; /* Flags for inserting object header into cache */ - hbool_t store_msg_crt_idx; /* Whether to always store message creation indices for this file */ - herr_t ret_value = SUCCEED; /* return value */ + H5O_t *oh = NULL; + herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI(FAIL) - /* check args */ HDassert(f); HDassert(loc); HDassert(TRUE == H5P_isa_class(ocpl_id, H5P_OBJECT_CREATE)); + /* create object header in freelist + * header version is set internally + */ + oh = H5O__create_ohdr(f, ocpl_id); + if (NULL == oh) + HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, + "Can't instantiate object header") + + /* apply object header information to file + */ + if (0 > H5O__apply_ohdr( + f, + oh, + ocpl_id, + size_hint, + initial_rc, + loc)) + { + HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, + "Can't apply object header to file") + } + +done: + if (FAIL == ret_value && + NULL != oh && + 0 > H5O__free(oh)) + { + HDONE_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, + "can't delete object header") + } + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_create() */ + + +/*----------------------------------------------------------------------------- + * Function: H5O__create_ohdr + * + * Purpose: Create the object header, set version and flags. + * + * Return: Success: Pointer to the newly-crated header object. + * Failure: NULL + * + * Programmer: Jacob Smith + * 17 August 2018 + * + *----------------------------------------------------------------------------- + */ +H5O_t * +H5O__create_ohdr( \ + H5F_t *f, \ + hid_t ocpl_id) +{ + H5P_genplist_t *oc_plist; + H5O_t *oh = NULL; /* Object header in Freelist */ + uint8_t oh_flags; /* Initial status flags */ + H5O_t *ret_value = NULL; + + FUNC_ENTER_NOAPI(NULL) + + HDassert(f); + HDassert(TRUE == H5P_isa_class(ocpl_id, H5P_OBJECT_CREATE)); + /* Check for invalid access request */ - if(0 == (H5F_INTENT(f) & H5F_ACC_RDWR)) - HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "no write intent on file") + if (0 == (H5F_INTENT(f) & H5F_ACC_RDWR)) + HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, + "no write intent on file") - /* Make certain we allocate at least a reasonable size for the object header */ - size_hint = H5O_ALIGN_F(f, MAX(H5O_MIN_SIZE, size_hint)); + oh = H5FL_CALLOC(H5O_t); + if (NULL == oh) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, + "memory allocation failed") - /* Get the property list */ - if(NULL == (oc_plist = (H5P_genplist_t *)H5I_object(ocpl_id))) - HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a property list") + oc_plist = (H5P_genplist_t *)H5I_object(ocpl_id); + if (NULL == oc_plist) + HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, NULL, + "not a property list") /* Get any object header status flags set by properties */ - if(H5P_get(oc_plist, H5O_CRT_OHDR_FLAGS_NAME, &oh_flags) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get object header flags") + if (0 > H5P_get(oc_plist, H5O_CRT_OHDR_FLAGS_NAME, &oh_flags)) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, + "can't get object header flags") - /* Allocate the object header and zero out header fields */ - if(NULL == (oh = H5FL_CALLOC(H5O_t))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + if (0 > H5O_set_version(f, oh, oh_flags, H5F_STORE_MSG_CRT_IDX(f))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, NULL, + "can't set version of object header") - /* Initialize file-specific information for object header */ - store_msg_crt_idx = H5F_STORE_MSG_CRT_IDX(f); + oh->flags = oh_flags; - if(H5O_set_version(f, oh, oh_flags, store_msg_crt_idx) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't set version of objecdt header") + ret_value = oh; + +done: + if (NULL == ret_value && + NULL != oh && + 0 > H5O__free(oh)) + { + HDONE_ERROR(H5E_OHDR, H5E_CANTFREE, NULL, + "can't delete object header") + } + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5O__create_ohdr */ + + +/*----------------------------------------------------------------------------- + * Function: H5O__apply_ohdr + * + * Purpose: Initialize and set the object header in the file. + * Record some information at `loc_out`. + * + * Return: Success: SUCCEED (0) (non-negative value) + * Failure: FAI (-1) (negative value) + * + * Programmer: Jacob Smith + * 17 August 2018 + * + *----------------------------------------------------------------------------- + */ +herr_t +H5O__apply_ohdr( \ + H5F_t *f, \ + H5O_t *oh, \ + hid_t ocpl_id, \ + size_t size_hint, \ + size_t initial_rc, \ + H5O_loc_t *loc_out) +{ + haddr_t oh_addr; + size_t oh_size; + H5P_genplist_t *oc_plist = NULL; + unsigned insert_flags = H5AC__NO_FLAGS_SET; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(FAIL) + + HDassert(f); + HDassert(loc_out); + HDassert(oh); + HDassert(TRUE == H5P_isa_class(ocpl_id, H5P_OBJECT_CREATE)); + + /* Allocate at least a reasonable size for the object header */ + size_hint = H5O_ALIGN_F(f, MAX(H5O_MIN_SIZE, size_hint)); oh->sizeof_size = H5F_SIZEOF_SIZE(f); oh->sizeof_addr = H5F_SIZEOF_ADDR(f); - oh->swmr_write = !!(H5F_INTENT(f) & H5F_ACC_SWMR_WRITE); + oh->swmr_write = !!(H5F_INTENT(f) & H5F_ACC_SWMR_WRITE); /* funky cast */ + #ifdef H5O_ENABLE_BAD_MESG_COUNT - /* Check whether the "bad message count" property is set */ - if(H5P_exist_plist(oc_plist, H5O_BAD_MESG_COUNT_NAME) > 0) { - /* Retrieve bad message count flag */ - if(H5P_get(oc_plist, H5O_BAD_MESG_COUNT_NAME, &oh->store_bad_mesg_count) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't get bad message count flag") + if (0 < H5P_exist_plist(oc_plist, H5O_BAD_MESG_COUNT_NAME)) { + /* Set bad message count flag -- from property list */ + if (0 > H5P_get(oc_plist, + H5O_BAD_MESG_COUNT_NAME, + &oh->store_bad_mesg_count)) + { + HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, + "can't get bad message count flag") + } } #endif /* H5O_ENABLE_BAD_MESG_COUNT */ /* Create object header proxy if doing SWMR writes */ - if(oh->swmr_write) { - /* Create virtual entry, for use as proxy */ - if(NULL == (oh->proxy = H5AC_proxy_entry_create())) - HGOTO_ERROR(H5E_OHDR, H5E_CANTCREATE, FAIL, "can't create object header proxy") - } - else + if (oh->swmr_write) { + oh->proxy = H5AC_proxy_entry_create(); + if (NULL == oh->proxy) + HGOTO_ERROR(H5E_OHDR, H5E_CANTCREATE, FAIL, + "can't create object header proxy") + } else { oh->proxy = NULL; + } - /* Set initial status flags */ - oh->flags = oh_flags; + oc_plist = (H5P_genplist_t *)H5I_object(ocpl_id); + if (NULL == oc_plist) + HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, + "not a property list") /* Initialize version-specific fields */ - if(oh->version > H5O_VERSION_1) { - /* Initialize all time fields with current time, if we are storing them */ - if(oh->flags & H5O_HDR_STORE_TIMES) + if (oh->version > H5O_VERSION_1) { + /* Initialize all time fields */ + if (oh->flags & H5O_HDR_STORE_TIMES) oh->atime = oh->mtime = oh->ctime = oh->btime = H5_now(); else oh->atime = oh->mtime = oh->ctime = oh->btime = 0; - /* Make certain attribute creation order tracking is enabled if - * attributes can be shared in this file. - */ - if(store_msg_crt_idx) + if (H5F_STORE_MSG_CRT_IDX(f)) + /* flag to record message creation indices */ oh->flags |= H5O_HDR_ATTR_CRT_ORDER_TRACKED; - /* Retrieve attribute storage phase change values from property list */ - if(H5P_get(oc_plist, H5O_CRT_ATTR_MAX_COMPACT_NAME, &oh->max_compact) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get max. # of compact attributes") - if(H5P_get(oc_plist, H5O_CRT_ATTR_MIN_DENSE_NAME, &oh->min_dense) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get min. # of dense attributes") + /* Set attribute storage phase change values -- from property list */ + if (0 > H5P_get(oc_plist, + H5O_CRT_ATTR_MAX_COMPACT_NAME, + &oh->max_compact)) + { + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, + "can't get max. # of compact attributes") + } + if (0 > H5P_get(oc_plist, + H5O_CRT_ATTR_MIN_DENSE_NAME, + &oh->min_dense)) + { + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, + "can't get min. # of dense attributes") + } /* Check for non-default attribute storage phase change values */ - if(oh->max_compact != H5O_CRT_ATTR_MAX_COMPACT_DEF || oh->min_dense != H5O_CRT_ATTR_MIN_DENSE_DEF) + if (H5O_CRT_ATTR_MAX_COMPACT_DEF != oh->max_compact || \ + H5O_CRT_ATTR_MIN_DENSE_DEF != oh->min_dense ) + { oh->flags |= H5O_HDR_ATTR_STORE_PHASE_CHANGE; + } /* Determine correct value for chunk #0 size bits */ /* Avoid compiler warning on 32-bit machines */ #if H5_SIZEOF_SIZE_T > H5_SIZEOF_INT32_T - if(size_hint > 4294967295UL) + if (size_hint > 4294967295UL) oh->flags |= H5O_HDR_CHUNK0_8; else #endif /* H5_SIZEOF_SIZE_T > H5_SIZEOF_INT32_T */ - if(size_hint > 65535) + if (size_hint > 65535) oh->flags |= H5O_HDR_CHUNK0_4; - else if(size_hint > 255) + else if (size_hint > 255) oh->flags |= H5O_HDR_CHUNK0_2; - } /* end if */ - else { + } else { /* Reset unused time fields */ oh->atime = oh->mtime = oh->ctime = oh->btime = 0; - } /* end else */ + } /* end if/else header version >1 */ /* Compute total size of initial object header */ /* (i.e. object header prefix and first chunk) */ oh_size = (size_t)H5O_SIZEOF_HDR(oh) + size_hint; /* Allocate disk space for header and first chunk */ - if(HADDR_UNDEF == (oh_addr = H5MF_alloc(f, H5FD_MEM_OHDR, (hsize_t)oh_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for object header") + oh_addr = H5MF_alloc(f, H5FD_MEM_OHDR, (hsize_t)oh_size); + if (HADDR_UNDEF == oh_addr) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, + "file allocation failed for object header") /* Create the chunk list */ - oh->nchunks = oh->alloc_nchunks = 1; - if(NULL == (oh->chunk = H5FL_SEQ_MALLOC(H5O_chunk_t, (size_t)oh->alloc_nchunks))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + oh->nchunks = 1; + oh->alloc_nchunks = 1; + oh->chunk = H5FL_SEQ_MALLOC(H5O_chunk_t, (size_t)oh->alloc_nchunks); + if (NULL == oh->chunk) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, + "memory allocation failed") /* Initialize the first chunk */ oh->chunk[0].addr = oh_addr; @@ -409,30 +554,37 @@ H5O_create(H5F_t *f, size_t size_hint, size_t initial_rc, hid_t ocpl_id, /* Allocate enough space for the first chunk */ /* (including space for serializing the object header prefix */ - if(NULL == (oh->chunk[0].image = H5FL_BLK_CALLOC(chunk_image, oh_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + oh->chunk[0].image = H5FL_BLK_CALLOC(chunk_image, oh_size); + if(NULL == oh->chunk[0].image) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, + "memory allocation failed") oh->chunk[0].chunk_proxy = NULL; /* Put magic # for object header in first chunk */ - if(oh->version > H5O_VERSION_1) + if (H5O_VERSION_1 < oh->version) HDmemcpy(oh->chunk[0].image, H5O_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC); /* Create the message list */ oh->nmesgs = 1; oh->alloc_nmesgs = H5O_NMESGS; - if(NULL == (oh->mesg = H5FL_SEQ_CALLOC(H5O_mesg_t, oh->alloc_nmesgs))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + oh->mesg = H5FL_SEQ_CALLOC(H5O_mesg_t, oh->alloc_nmesgs); + if (NULL == oh->mesg) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, + "memory allocation failed") - /* Initialize the initial "null" message, covering the entire first chunk */ + /* Initialize the initial "null" message; covers the entire first chunk */ oh->mesg[0].type = H5O_MSG_NULL; oh->mesg[0].dirty = TRUE; oh->mesg[0].native = NULL; - oh->mesg[0].raw = oh->chunk[0].image + (H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh)) + H5O_SIZEOF_MSGHDR_OH(oh); + oh->mesg[0].raw = oh->chunk[0].image \ + + H5O_SIZEOF_HDR(oh) \ + - H5O_SIZEOF_CHKSUM_OH(oh) \ + + H5O_SIZEOF_MSGHDR_OH(oh); oh->mesg[0].raw_size = size_hint - (size_t)H5O_SIZEOF_MSGHDR_OH(oh); oh->mesg[0].chunkno = 0; /* Check for non-zero initial refcount on the object header */ - if(initial_rc > 0) { + if (initial_rc > 0) { /* Set the initial refcount & pin the header when its inserted */ oh->rc = initial_rc; insert_flags |= H5AC__PIN_ENTRY_FLAG; @@ -442,9 +594,11 @@ H5O_create(H5F_t *f, size_t size_hint, size_t initial_rc, hid_t ocpl_id, H5_BEGIN_TAG(oh_addr); /* Cache object header */ - if(H5AC_insert_entry(f, H5AC_OHDR, oh_addr, oh, insert_flags) < 0) - HGOTO_ERROR_TAG(H5E_OHDR, H5E_CANTINSERT, FAIL, "unable to cache object header") + if (0 > H5AC_insert_entry(f, H5AC_OHDR, oh_addr, oh, insert_flags)) + HGOTO_ERROR_TAG(H5E_OHDR, H5E_CANTINSERT, FAIL, + "unable to cache object header") + /* TODO: is this relevant to the BEGIN/END TAG region? if not, delete */ /* Reset object header pointer, now that it's been inserted into the cache */ oh = NULL; @@ -452,20 +606,16 @@ H5O_create(H5F_t *f, size_t size_hint, size_t initial_rc, hid_t ocpl_id, H5_END_TAG /* Set up object location */ - loc->file = f; - loc->addr = oh_addr; + loc_out->file = f; + loc_out->addr = oh_addr; - /* Open it */ - if(H5O_open(loc) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open object header") + if (0 > H5O_open(loc_out)) + HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, + "unable to open object header") done: - if(ret_value < 0 && oh) - if(H5O__free(oh) < 0) - HDONE_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header data") - - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5O_create() */ + FUNC_LEAVE_NOAPI(ret_value); +} /* H5O__apply_ohdr */ /*------------------------------------------------------------------------- @@ -2686,6 +2836,64 @@ H5O_get_oh_addr(const H5O_t *oh) /*------------------------------------------------------------------------- + * Function: H5O_get_oh_flags + * + * Programmer: Jacob Smith + * 17 August 2018 + * + *------------------------------------------------------------------------- + */ +uint8_t +H5O_get_oh_flags(const H5O_t *oh) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + HDassert(oh); + HDassert(oh->flags); + FUNC_LEAVE_NOAPI(oh->flags); +} + + +/*------------------------------------------------------------------------- + * Function: H5O_get_oh_mtime + * + * Purpose: Retrieve an object's modification time. Assumes that the + * caller has verified that accessing this variable is appropriate + * to the header in question. + * + * Programmer: Jacob Smith + * 17 August 2018 + * + *------------------------------------------------------------------------- + */ +time_t +H5O_get_oh_mtime(const H5O_t *oh) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + HDassert(oh); + HDassert(oh->mtime); + FUNC_LEAVE_NOAPI(oh->mtime); +} + + +/*------------------------------------------------------------------------- + * Function: H5O_get_oh_version + * + * Programmer: Jacob Smith + * 17 August 2018 + * + *------------------------------------------------------------------------- + */ +uint8_t +H5O_get_oh_version(const H5O_t *oh) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + HDassert(oh); + HDassert(oh->version); + FUNC_LEAVE_NOAPI(oh->version); +} + + +/*------------------------------------------------------------------------- * Function: H5O_get_rc_and_type * * Purpose: Retrieve an object's reference count and type diff --git a/src/H5Oprivate.h b/src/H5Oprivate.h index 10063d5..f8154c4 100644 --- a/src/H5Oprivate.h +++ b/src/H5Oprivate.h @@ -120,8 +120,14 @@ typedef struct H5O_mesg_t H5O_mesg_t; /* If the module using this macro is allowed access to the private variables, access them directly */ #ifdef H5O_MODULE #define H5O_OH_GET_ADDR(O) ((O)->chunk[0].addr) +#define H5O_OH_GET_VERSION(O) ((O)->version) +#define H5O_OH_GET_FLAGS(O) ((O)->flags) +#define H5O_OH_GET_MTIME(O) ((O)->mtime) #else /* H5O_MODULE */ #define H5O_OH_GET_ADDR(O) (H5O_get_oh_addr(O)) +#define H5O_OH_GET_VERSION(O) (H5O_get_oh_version(O)) +#define H5O_OH_GET_FLAGS(O) (H5O_get_oh_flags(O)) +#define H5O_OH_GET_MTIME(O) (H5O_get_oh_mtime(O)) #endif /* H5O_MODULE */ /* Set the fields in a shared message structure */ @@ -865,6 +871,9 @@ struct H5P_genplist_t; H5_DLL herr_t H5O_init(void); H5_DLL herr_t H5O_create(H5F_t *f, size_t size_hint, size_t initial_rc, hid_t ocpl_id, H5O_loc_t *loc/*out*/); +H5_DLL H5O_t *H5O__create_ohdr(H5F_t *f, hid_t ocpl_id); +H5_DLL herr_t H5O__apply_ohdr(H5F_t *f, H5O_t *oh, hid_t ocpl_id, + size_t size_hint, size_t initial_rc, H5O_loc_t *loc_out); H5_DLL herr_t H5O_open(H5O_loc_t *loc); H5_DLL herr_t H5O_close(H5O_loc_t *loc, hbool_t *file_closed/*out*/); H5_DLL int H5O_link(const H5O_loc_t *loc, int adjust); @@ -888,6 +897,9 @@ H5_DLL hid_t H5O_open_name(const H5G_loc_t *loc, const char *name, hbool_t app_r H5_DLL herr_t H5O_get_nlinks(const H5O_loc_t *loc, hsize_t *nlinks); H5_DLL void *H5O_obj_create(H5F_t *f, H5O_type_t obj_type, void *crt_info, H5G_loc_t *obj_loc); H5_DLL haddr_t H5O_get_oh_addr(const H5O_t *oh); +H5_DLL uint8_t H5O_get_oh_flags(const H5O_t *oh); +H5_DLL time_t H5O_get_oh_mtime(const H5O_t *oh); +H5_DLL uint8_t H5O_get_oh_version(const H5O_t *oh); H5_DLL herr_t H5O_get_rc_and_type(const H5O_loc_t *oloc, unsigned *rc, H5O_type_t *otype); H5_DLL H5AC_proxy_entry_t *H5O_get_proxy(const H5O_t *oh); diff --git a/src/H5Pdcpl.c b/src/H5Pdcpl.c index cb13ff3..a1799ad 100644 --- a/src/H5Pdcpl.c +++ b/src/H5Pdcpl.c @@ -119,6 +119,11 @@ #define H5D_CRT_EXT_FILE_LIST_COPY H5P__dcrt_ext_file_list_copy #define H5D_CRT_EXT_FILE_LIST_CMP H5P__dcrt_ext_file_list_cmp #define H5D_CRT_EXT_FILE_LIST_CLOSE H5P__dcrt_ext_file_list_close +/* Definitions for dataset object header minimization */ +#define H5D_CRT_MIN_DSET_HDR_SIZE_SIZE sizeof(hbool_t) +#define H5D_CRT_MIN_DSET_HDR_SIZE_DEF FALSE +#define H5D_CRT_MIN_DSET_HDR_SIZE_ENC H5P__encode_hbool_t +#define H5D_CRT_MIN_DSET_HDR_SIZE_DEC H5P__decode_hbool_t /******************/ @@ -211,6 +216,7 @@ static const H5O_layout_t H5D_def_layout_g = H5D_CRT_LAYOUT_DEF; /* Defau static const H5O_fill_t H5D_def_fill_g = H5D_CRT_FILL_VALUE_DEF; /* Default fill value */ static const unsigned H5D_def_alloc_time_state_g = H5D_CRT_ALLOC_TIME_STATE_DEF; /* Default allocation time state */ static const H5O_efl_t H5D_def_efl_g = H5D_CRT_EXT_FILE_LIST_DEF; /* Default external file list */ +static const H5O_ohdr_min_g = H5D_CRT_MIN_DSET_HDR_SIZE_DEF; /* Default object header minimization */ /* Defaults for each type of layout */ #ifdef H5_HAVE_C99_DESIGNATED_INITIALIZER @@ -270,6 +276,26 @@ H5P__dcrt_reg_prop(H5P_genclass_t *pclass) H5D_CRT_EXT_FILE_LIST_DEL, H5D_CRT_EXT_FILE_LIST_COPY, H5D_CRT_EXT_FILE_LIST_CMP, H5D_CRT_EXT_FILE_LIST_CLOSE) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class") + /* Register the object header minimization property */ + if (0 > H5P_register_real( + pclass, /* class */ + H5D_CRT_MIN_DSET_HDR_SIZE_NAME, /* name */ + H5D_CRT_MIN_DSET_HDR_SIZE_SIZE, /* size */ + &H5O_ohdr_min_g, /* default */ + NULL, /* create */ + NULL, /* set */ + NULL, /* get */ + H5D_CRT_MIN_DSET_HDR_SIZE_ENC, /* encode */ + H5D_CRT_MIN_DSET_HDR_SIZE_DEC, /* decode */ + NULL, /* delete */ + NULL, /* copy */ + NULL, /* compare */ + NULL)) /* close */ + { + HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, + "can't insert property into class") + } + done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5P__dcrt_reg_prop() */ @@ -3733,3 +3759,103 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Pget_fill_time() */ + +/*----------------------------------------------------------------------------- + * Function: H5Pget_dset_no_attrs_hint + * + * Purpose: + * + * Access the flag for whether or not datasets created by the given dcpl + * will be created with a "minimized" object header. + * + * Return: + * + * Failure: Negative value (FAIL) + * Success: Non-negative value (SUCCEED) + * + * Programmer: Jacob Smith + * 14 August 2018 + * + * Modifications: None. + * + *----------------------------------------------------------------------------- + */ +herr_t +H5Pget_dset_no_attrs_hint(hid_t dcpl_id, + hbool_t *minimize) +{ + hbool_t setting = FALSE; + H5P_genplist_t *plist = NULL; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_API(FAIL) + H5TRACE2("e", "i*b", dcpl_id, minimize); + + if (NULL == minimize) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, + "receiving pointer cannot be NULL") + + plist = H5P_object_verify(dcpl_id, H5P_DATASET_CREATE); + if (NULL == plist) + HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, + "can't find object for ID") + + if (0 > H5P_peek(plist, H5D_CRT_MIN_DSET_HDR_SIZE_NAME, &setting)) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, + "can't get dset oh minimize flag value") + + *minimize = setting; + +done: + FUNC_LEAVE_API(ret_value) +} /* H5Pget_dset_no_attrs_hint */ + + +/*----------------------------------------------------------------------------- + * Function: H5Pset_dset_no_attrs_hint + * + * Purpose: + * + * Set the dcpl to minimize (or explicitly to not minimized) dataset object + * headers upon creation. + * + * Return: + * + * Failure: Negative value (FAIL) + * Success: Non-negative value (SUCCEED) + * + * Programmer: Jacob Smith + * 14 August 2018 + * + * Modifications: None. + * + *----------------------------------------------------------------------------- + */ +herr_t +H5Pset_dset_no_attrs_hint(hid_t dcpl_id, + hbool_t minimize) +{ + H5P_genplist_t *plist = NULL; + hbool_t prev_set = FALSE; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_API(FAIL) + H5TRACE2("e", "ib", dcpl_id, minimize); + + plist = H5P_object_verify(dcpl_id, H5P_DATASET_CREATE); + if (NULL == plist) + HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, + "can't find object for ID") + + if (0 > H5P_peek(plist, H5D_CRT_MIN_DSET_HDR_SIZE_NAME, &prev_set)) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, + "can't get extant dset oh minimize flag value") + + if (0 > H5P_poke(plist, H5D_CRT_MIN_DSET_HDR_SIZE_NAME, &minimize)) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, + "can't get dset oh minimize flag value") + +done: + FUNC_LEAVE_API(ret_value) +} /* H5Pset_dset_no_attrs_hint */ + diff --git a/src/H5Ppublic.h b/src/H5Ppublic.h index c5596e5..c2f9b4c 100644 --- a/src/H5Ppublic.h +++ b/src/H5Ppublic.h @@ -409,6 +409,8 @@ H5_DLL herr_t H5Pget_alloc_time(hid_t plist_id, H5D_alloc_time_t H5_DLL herr_t H5Pset_fill_time(hid_t plist_id, H5D_fill_time_t fill_time); H5_DLL herr_t H5Pget_fill_time(hid_t plist_id, H5D_fill_time_t *fill_time/*out*/); +H5_DLL herr_t H5Pget_dset_no_attrs_hint(hid_t dcpl_id, hbool_t *minimize); +H5_DLL herr_t H5Pset_dset_no_attrs_hint(hid_t dcpl_id, hbool_t minimize); /* Dataset access property list (DAPL) routines */ H5_DLL herr_t H5Pset_chunk_cache(hid_t dapl_id, size_t rdcc_nslots, diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 517a620..6c1e0eb 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -234,6 +234,7 @@ set (H5_TESTS cache_logging cork swmr + ohdr_min ) macro (ADD_H5_EXE file) diff --git a/test/CMakeTests.cmake b/test/CMakeTests.cmake index cc6ebb8..44494e9 100644 --- a/test/CMakeTests.cmake +++ b/test/CMakeTests.cmake @@ -359,6 +359,8 @@ set (test_CLEANFILES lheap.h5 fheap.h5 ohdr.h5 + ohdr_min_a.h5 + ohdr_min_b.h5 stab.h5 extern_*.h5 extern_*.raw diff --git a/test/Makefile.am b/test/Makefile.am index b9aa3fb..551c5ee 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -52,15 +52,15 @@ check_SCRIPTS = $(TEST_SCRIPT) # As an exception, long-running tests should occur earlier in the list. # This gives them more time to run when tests are executing in parallel. TEST_PROG= testhdf5 \ - cache cache_api cache_image cache_tagging lheap ohdr stab gheap \ - evict_on_close farray earray btree2 fheap \ + cache cache_api cache_image cache_tagging lheap ohdr ohdr_min stab \ + gheap evict_on_close farray earray btree2 fheap \ pool accum hyperslab istore bittests dt_arith page_buffer \ dtypes dsets cmpd_dset filter_fail extend direct_chunk external efc \ - objcopy links unlink twriteorder big mtime fillval mount \ - flush1 flush2 app_ref enum set_extent ttsafe enc_dec_plist \ - enc_dec_plist_cross_platform getname vfd ntypes dangle dtransform \ - reserved cross_read freespace mf vds file_image unregister \ - cache_logging cork swmr + objcopy links unlink twriteorder big mtime fillval mount \ + flush1 flush2 app_ref enum set_extent ttsafe enc_dec_plist \ + enc_dec_plist_cross_platform getname vfd ntypes dangle dtransform \ + reserved cross_read freespace mf vds file_image unregister \ + cache_logging cork swmr # List programs to be built when testing here. # error_test and err_compat are built at the same time as the other tests, but executed by testerror.sh. @@ -165,6 +165,7 @@ CHECK_CLEANFILES+=accum.h5 cmpd_dset.h5 compact_dataset.h5 dataset.h5 dset_offse extend.h5 istore.h5 extlinks*.h5 frspace.h5 links*.h5 \ sys_file1 tfile[1-7].h5 th5s[1-4].h5 lheap.h5 fheap.h5 ohdr.h5 \ stab.h5 extern_[1-5].h5 extern_[1-4][rw].raw gheap[0-4].h5 \ + ohdr_min_a.h5 ohdr_min_b.h5 \ dt_arith[1-2] links.h5 links[0-6]*.h5 extlinks[0-15].h5 tmp \ big.data big[0-9][0-9][0-9][0-9][0-9].h5 \ stdio.h5 sec2.h5 dtypes[0-9].h5 dtypes1[0].h5 dt_arith[1-2].h5 tattr.h5 \ diff --git a/test/dsets.c b/test/dsets.c index d23f438..94c967e 100644 --- a/test/dsets.c +++ b/test/dsets.c @@ -13034,6 +13034,113 @@ test_versionbounds() return -1; } /* test_versionbounds() */ + +/*----------------------------------------------------------------------------- + * Function: test_object_header_minimization_dcpl + * + * Purpose: Test the "datset object header minimization" property as part of + * the DCPL. + * + * Return: Success/pass: 0 + * Failure/error: -1 + * + * Programmer: Jacob Smith + * 15 Aug 2018 + * + * Changes: None. + *----------------------------------------------------------------------------- + */ +static herr_t +test_object_header_minimization_dcpl(void) +{ + hid_t dcpl_id = -1; + hid_t file_id = -1; + hbool_t minimize = FALSE; + + TESTING("dcpl flags to minimize dataset object header"); + + /*********/ + /* SETUP */ + /*********/ + + file_id = H5Fcreate( + "some_arbitrary_filename", + H5F_ACC_TRUNC, + H5P_DEFAULT, + H5P_DEFAULT); + if (0 > file_id) + FAIL_PUTS_ERROR("unable to create test file\n"); + + dcpl_id = H5Pcreate(H5P_DATASET_CREATE); + if (0 > dcpl_id) + FAIL_PUTS_ERROR("unable to create DCPL\n"); + + /*********/ + /* TESTS */ + /*********/ + + /* TEST default value (not set explicitly) + */ + if (FAIL == H5Pget_dset_no_attrs_hint(dcpl_id, &minimize)) + FAIL_PUTS_ERROR("unable to get minimize value\n"); + if (FALSE != minimize) + FAIL_PUTS_ERROR("Expected FALSE default but was not!\n"); + + /* TEST FALSE-set value + */ + if (FAIL == H5Pset_dset_no_attrs_hint(dcpl_id, FALSE)) + FAIL_PUTS_ERROR("unable to set minimize value to FALSE\n"); + if (FAIL == H5Pget_dset_no_attrs_hint(dcpl_id, &minimize)) + FAIL_PUTS_ERROR("unable to get minimize value\n"); + if (FALSE != minimize) + FAIL_PUTS_ERROR("Expected FALSE default but was not!\n"); + + /* TEST TRUE-set value + */ + if (FAIL == H5Pset_dset_no_attrs_hint(dcpl_id, TRUE)) + FAIL_PUTS_ERROR("unable to set minimize value to TRUE\n"); + if (FAIL == H5Pget_dset_no_attrs_hint(dcpl_id, &minimize)) + FAIL_PUTS_ERROR("unable to get minimize value\n"); + if (TRUE != minimize) + FAIL_PUTS_ERROR("Expected TRUE default but was not!\n"); + + /* TEST error cases + */ + H5E_BEGIN_TRY { + if (SUCCEED == H5Pget_dset_no_attrs_hint(-1, &minimize)) + FAIL_PUTS_ERROR("Invalid DCPL ID should fail\n"); + + if (SUCCEED == H5Pset_dset_no_attrs_hint(-1, FALSE)) + FAIL_PUTS_ERROR("Invalid DCPL ID should fail\n"); + + if (SUCCEED == H5Pset_dset_no_attrs_hint(-1, TRUE)) + FAIL_PUTS_ERROR("Invalid DCPL ID should fail\n"); + + if (SUCCEED == H5Pget_dset_no_attrs_hint(dcpl_id, NULL)) + FAIL_PUTS_ERROR("NULL out pointer should fail\n"); + } H5E_END_TRY; + + /************/ + /* TEARDOWN */ + /************/ + + if (FAIL == H5Fclose(file_id)) + FAIL_PUTS_ERROR("can't close FILE"); + + if (FAIL == H5Pclose(dcpl_id)) + FAIL_PUTS_ERROR("unable to close DCPL\n"); + + PASSED(); + return 0; + +error: + H5E_BEGIN_TRY { + H5Pclose(dcpl_id); + H5Fclose(file_id); + } H5E_END_TRY; + return -1; +} /* test_object_header_minimization_dcpl */ + /*------------------------------------------------------------------------- * Function: main @@ -13234,6 +13341,8 @@ main(void) /* Tests version bounds using its own file */ nerrors += (test_versionbounds() < 0 ? 1 : 0); + nerrors += (test_object_header_minimization_dcpl() < 0 ? 1 : 0); + /* Run misc tests */ nerrors += dls_01_main(); diff --git a/test/enc_dec_plist.c b/test/enc_dec_plist.c index 36db2d0..cee38f3 100644 --- a/test/enc_dec_plist.c +++ b/test/enc_dec_plist.c @@ -146,6 +146,9 @@ main(void) if((H5Pset_fill_value(dcpl, H5T_NATIVE_DOUBLE, &fill)) < 0) FAIL_STACK_ERROR + if((H5Pset_dset_no_attrs_hint(dcpl, FALSE)) < 0) + FAIL_STACK_ERROR + max_size[0] = 100; if((H5Pset_external(dcpl, "ext1.data", (off_t)0, (hsize_t)(max_size[0] * sizeof(int)/4))) < 0) diff --git a/test/gen_plist.c b/test/gen_plist.c index 62693bd..d8096e3 100644 --- a/test/gen_plist.c +++ b/test/gen_plist.c @@ -125,6 +125,9 @@ main(void) if((ret = H5Pset_fill_value(dcpl1, H5T_STD_I32BE, &fill)) < 0) assert(ret > 0); + if((ret = H5Pset_dset_no_attrs_hint(dcpl1, FALSE)) < 0) + assert(ret > 0); + max_size[0] = 100; if((ret = H5Pset_external(dcpl1, "ext1.data", (off_t)0, (hsize_t)(max_size[0] * sizeof(int)/4))) < 0) diff --git a/test/tfile.c b/test/tfile.c index d3134f8..96e469c 100644 --- a/test/tfile.c +++ b/test/tfile.c @@ -7051,6 +7051,144 @@ test_incr_filesize(void) /**************************************************************** ** +** test_min_dset_ohdr(): +** Test API calls to toggle dataset object header minimization. +** +** TODO (as separate function?): +** + setting persists between close and (re)open? +** + dataset header sizes created while changing value of toggle +** +****************************************************************/ +static void +test_min_dset_ohdr(void) +{ + const char my_filename[] = "some_arbitrary_filename"; + hid_t file_id = -1; + hid_t file2_id = -1; + hbool_t minimize; + + MESSAGE(5, ("Testing dataset object header minimization\n")); + + /*********/ + /* SETUP */ + /*********/ + + file_id = H5Fcreate( + my_filename, + H5F_ACC_TRUNC, + H5P_DEFAULT, + H5P_DEFAULT); + CHECK_I(file_id, "H5Fcreate"); + + /*********/ + /* TESTS */ + /*********/ + + /*---------------------------------------- + * TEST default value + */ + VERIFY(H5Fget_dset_no_attrs_hint(file_id, &minimize), + SUCCEED, + "H5Fget_dset_no_attrs_hint"); + VERIFY(minimize, + FALSE, + "getting default dset minimize flag value"); + + /*---------------------------------------- + * TEST set to TRUE + */ + VERIFY(H5Fset_dset_no_attrs_hint(file_id, TRUE), + SUCCEED, + "H5Fset_dset_no_attrs_hint"); + VERIFY(H5Fget_dset_no_attrs_hint(file_id, &minimize), + SUCCEED, + "H5Fget_dset_no_attrs_hint"); + VERIFY(minimize, + TRUE, + "getting set-TRUE dset minimize flag value"); + + /*---------------------------------------- + * TEST second file open on same filename + */ + file2_id = H5Fopen( + my_filename, + H5F_ACC_RDWR, + H5P_DEFAULT); + CHECK_I(file2_id, "H5Fopen"); + + /* verify TRUE setting on second open */ + VERIFY(H5Fget_dset_no_attrs_hint(file_id, &minimize), + SUCCEED, + "H5Fget_dset_no_attrs_hint"); + VERIFY(minimize, + TRUE, + "getting set-TRUE dset minimize flag value"); + + /* re-set to FALSE on first open */ + VERIFY(H5Fset_dset_no_attrs_hint(file_id, FALSE), + SUCCEED, + "H5Fset_dset_no_attrs_hint"); + + /* verify FALSE set on both opens */ + VERIFY(H5Fget_dset_no_attrs_hint(file_id, &minimize), + SUCCEED, + "H5Fget_dset_no_attrs_hint"); + VERIFY(minimize, + FALSE, + "getting set-FALSE dset minimize flag value"); + VERIFY(H5Fget_dset_no_attrs_hint(file2_id, &minimize), + SUCCEED, + "H5Fget_dset_no_attrs_hint"); + VERIFY(minimize, + FALSE, + "getting set-FALSE dset minimize flag value"); + + /* re-set to TRUE on second open */ + VERIFY(H5Fset_dset_no_attrs_hint(file2_id, TRUE), + SUCCEED, + "H5Fset_dset_no_attrs_hint"); + + /* verify TRUE set on both opens */ + VERIFY(H5Fget_dset_no_attrs_hint(file_id, &minimize), + SUCCEED, + "H5Fget_dset_no_attrs_hint"); + VERIFY(minimize, + TRUE, + "getting set-FALSE dset minimize flag value"); + VERIFY(H5Fget_dset_no_attrs_hint(file2_id, &minimize), + SUCCEED, + "H5Fget_dset_no_attrs_hint"); + VERIFY(minimize, + TRUE, + "getting set-FALSE dset minimize flag value"); + + /*---------------------------------------- + * TEST error cases + */ + H5E_BEGIN_TRY { + VERIFY(H5Fset_dset_no_attrs_hint(-1, TRUE), + FAIL, + "trying to set with invalid file ID"); + + VERIFY(H5Fget_dset_no_attrs_hint(-1, &minimize), + FAIL, + "trying to get with invalid file ID"); + + VERIFY(H5Fget_dset_no_attrs_hint(file_id, NULL), + FAIL, + "trying to get with invalid pointer"); + } H5E_END_TRY; + + /************/ + /* TEARDOWN */ + /************/ + + VERIFY(H5Fclose(file_id), SUCCEED, "H5Fclose"); + VERIFY(H5Fclose(file2_id), SUCCEED, "H5Fclose"); +} /* end test_min_dset_ohdr() */ + +/**************************************************************** +** ** test_deprec(): ** Test deprecated functionality. ** @@ -7336,6 +7474,7 @@ test_file(void) test_libver_macros(); /* Test the macros for library version comparison */ test_libver_macros2(); /* Test the macros for library version comparison */ test_incr_filesize(); /* Test H5Fincrement_filesize() and H5Fget_eoa() */ + test_min_dset_ohdr(); /* Test datset object header minimization */ #ifndef H5_NO_DEPRECATED_SYMBOLS test_deprec(); /* Test deprecated routines */ #endif /* H5_NO_DEPRECATED_SYMBOLS */ -- cgit v0.12