diff options
author | Dana Robinson <derobins@hdfgroup.org> | 2016-09-30 18:17:08 (GMT) |
---|---|---|
committer | Dana Robinson <derobins@hdfgroup.org> | 2016-09-30 18:17:08 (GMT) |
commit | ce3997f0419663feea776c230bbb8094550539be (patch) | |
tree | baaa000b45158680564df521d95297587d6c8941 | |
parent | 30ca70b0969ae0ab63104d7910523818e5385ac6 (diff) | |
parent | cbc260e636e258cc55d9fb8fdafd3bff0877ac23 (diff) | |
download | hdf5-ce3997f0419663feea776c230bbb8094550539be.zip hdf5-ce3997f0419663feea776c230bbb8094550539be.tar.gz hdf5-ce3997f0419663feea776c230bbb8094550539be.tar.bz2 |
Merge pull request #52 in HDFFV/hdf5 from ~DEROBINS/hdf5_der:develop to develop
Merged evict-on-close feature from branch (via develop in cloned repo).
* commit 'cbc260e636e258cc55d9fb8fdafd3bff0877ac23': (21 commits)
- Removed BRANCH.txt and MANIFEST entry - Fixed a missing line in H5Dint.c
- Removed non-implemented code from H5Gint.c - Removed commented-out debug code from H5Dint.c - Added blank lines to eliminate delta in a fortran file.
Added full implementation of EoC cache test.
Added code to create the test file for all chunk index and layout types.
Fleshed out evict on close test that inspects cache.
Added the beginnings of a file generator to the test.
Fixed typo
Added "Purpose:" information to the API call comments for the new functions.
Cleaned up feature for dissemination to LLNL: - Removed support for datatypes. - Commented out support for groups - General change clean-up - Added a list of improvements to BRANCH.txt
Removed blank line in Fortran file (leftover from last commit)
Reverted H5T code since datatypes will not be supported at this time.
Fixed format_convert and fortran files (bad merge?).
Updated manifest. Was missing BRANCH.txt.
Added missing evict on close test file line to test/CMakeLists.txt.
[svn-r30110] Added missing evict_on_close.c file to test/.
[svn-r30108] Moved group flush and evict code to H5G_close from H5Gclose.
[svn-r30107] Moved dataset flush and evict code to H5D_close from H5Dclose.
[svn-r30106] Moved datatype close code to new internal function. H5Oclose() now supports evict-on-close for datatypes.
[svn-r30105] Datatypes and Groups now support evict-on-close.
[svn-r30084] First pass at the evict-on-close feature.
...
-rw-r--r-- | MANIFEST | 1 | ||||
-rw-r--r-- | src/H5AC.c | 4 | ||||
-rw-r--r-- | src/H5ACprivate.h | 2 | ||||
-rw-r--r-- | src/H5Cprivate.h | 2 | ||||
-rw-r--r-- | src/H5Ctag.c | 14 | ||||
-rw-r--r-- | src/H5D.c | 20 | ||||
-rw-r--r-- | src/H5Dint.c | 37 | ||||
-rw-r--r-- | src/H5Dpkg.h | 1 | ||||
-rw-r--r-- | src/H5Dtest.c | 41 | ||||
-rw-r--r-- | src/H5Fint.c | 16 | ||||
-rw-r--r-- | src/H5Fio.c | 2 | ||||
-rw-r--r-- | src/H5Fpkg.h | 1 | ||||
-rw-r--r-- | src/H5Fprivate.h | 4 | ||||
-rw-r--r-- | src/H5Fquery.c | 27 | ||||
-rw-r--r-- | src/H5G.c | 4 | ||||
-rw-r--r-- | src/H5Gint.c | 4 | ||||
-rw-r--r-- | src/H5O.c | 2 | ||||
-rw-r--r-- | src/H5Pfapl.c | 99 | ||||
-rw-r--r-- | src/H5Ppublic.h | 2 | ||||
-rw-r--r-- | test/CMakeLists.txt | 1 | ||||
-rw-r--r-- | test/CMakeTests.cmake | 2 | ||||
-rw-r--r-- | test/Makefile.am | 2 | ||||
-rw-r--r-- | test/evict_on_close.c | 779 | ||||
-rw-r--r-- | test/h5test.c | 2 |
24 files changed, 1027 insertions, 42 deletions
@@ -906,6 +906,7 @@ ./test/enc_dec_plist.c ./test/enc_dec_plist_cross_platform.c ./test/enum.c +./test/evict_on_close.c ./test/extend.c ./test/external.c ./test/error_test.c @@ -2383,7 +2383,7 @@ done: *------------------------------------------------------------------------------ */ herr_t -H5AC_evict_tagged_metadata(H5F_t * f, haddr_t metadata_tag, hid_t dxpl_id) +H5AC_evict_tagged_metadata(H5F_t * f, haddr_t metadata_tag, hbool_t match_global, hid_t dxpl_id) { /* Variable Declarations */ herr_t ret_value = SUCCEED; @@ -2396,7 +2396,7 @@ H5AC_evict_tagged_metadata(H5F_t * f, haddr_t metadata_tag, hid_t dxpl_id) HDassert(f->shared); /* Call cache level function to evict metadata entries with specified tag */ - if(H5C_evict_tagged_entries(f, dxpl_id, metadata_tag) < 0) + if(H5C_evict_tagged_entries(f, dxpl_id, metadata_tag, match_global) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Cannot evict metadata") done: diff --git a/src/H5ACprivate.h b/src/H5ACprivate.h index d1d41c9..84c9e93 100644 --- a/src/H5ACprivate.h +++ b/src/H5ACprivate.h @@ -364,7 +364,7 @@ H5_DLL herr_t H5AC_validate_config(H5AC_cache_config_t *config_ptr); /* Tag & Ring routines */ H5_DLL herr_t H5AC_tag(hid_t dxpl_id, haddr_t metadata_tag, haddr_t *prev_tag); H5_DLL herr_t H5AC_flush_tagged_metadata(H5F_t * f, haddr_t metadata_tag, hid_t dxpl_id); -H5_DLL herr_t H5AC_evict_tagged_metadata(H5F_t * f, haddr_t metadata_tag, hid_t dxpl_id); +H5_DLL herr_t H5AC_evict_tagged_metadata(H5F_t * f, haddr_t metadata_tag, hbool_t match_global, hid_t dxpl_id); H5_DLL herr_t H5AC_retag_copied_metadata(const H5F_t *f, haddr_t metadata_tag); H5_DLL herr_t H5AC_ignore_tags(const H5F_t *f); H5_DLL herr_t H5AC_cork(H5F_t *f, haddr_t obj_addr, unsigned action, hbool_t *corked); diff --git a/src/H5Cprivate.h b/src/H5Cprivate.h index 975ea3e..4137edf 100644 --- a/src/H5Cprivate.h +++ b/src/H5Cprivate.h @@ -1970,7 +1970,7 @@ H5_DLL herr_t H5C_expunge_entry(H5F_t *f, hid_t dxpl_id, const H5C_class_t *type, haddr_t addr, unsigned flags); H5_DLL herr_t H5C_flush_cache(H5F_t *f, hid_t dxpl_id, unsigned flags); H5_DLL herr_t H5C_flush_tagged_entries(H5F_t * f, hid_t dxpl_id, haddr_t tag); -H5_DLL herr_t H5C_evict_tagged_entries(H5F_t * f, hid_t dxpl_id, haddr_t tag); +H5_DLL herr_t H5C_evict_tagged_entries(H5F_t * f, hid_t dxpl_id, haddr_t tag, hbool_t match_global); H5_DLL herr_t H5C_expunge_tag_type_metadata(H5F_t *f, hid_t dxpl_id, haddr_t tag, int type_id, unsigned flags); #if H5C_DO_TAGGING_SANITY_CHECKS herr_t H5C_verify_tag(int id, haddr_t tag, H5C_tag_globality_t globality); diff --git a/src/H5Ctag.c b/src/H5Ctag.c index d560e25..e1b4df6 100644 --- a/src/H5Ctag.c +++ b/src/H5Ctag.c @@ -352,7 +352,7 @@ done: *------------------------------------------------------------------------- */ herr_t -H5C_evict_tagged_entries(H5F_t * f, hid_t dxpl_id, haddr_t tag) +H5C_evict_tagged_entries(H5F_t * f, hid_t dxpl_id, haddr_t tag, hbool_t match_global) { H5C_t *cache; /* Pointer to cache structure */ H5C_tag_iter_evict_ctx_t ctx; /* Context for iterator callback */ @@ -374,15 +374,15 @@ H5C_evict_tagged_entries(H5F_t * f, hid_t dxpl_id, haddr_t tag) /* Start evicting entries */ do { - /* Reset pinned/evicted tracking flags */ - ctx.pinned_entries_need_evicted = FALSE; - ctx.evicted_entries_last_pass = FALSE; + /* Reset pinned/evicted tracking flags */ + ctx.pinned_entries_need_evicted = FALSE; + ctx.evicted_entries_last_pass = FALSE; - /* Iterate through entries in the cache */ - if(H5C__iter_tagged_entries(cache, tag, TRUE, H5C__evict_tagged_entries_cb, &ctx) < 0) + /* Iterate through entries in the cache */ + if(H5C__iter_tagged_entries(cache, tag, match_global, H5C__evict_tagged_entries_cb, &ctx) < 0) HGOTO_ERROR(H5E_CACHE, H5E_BADITER, FAIL, "Iteration of tagged entries failed") - /* Keep doing this until we have stopped evicted entries */ + /* Keep doing this until we have stopped evicted entries */ } while(TRUE == ctx.evicted_entries_last_pass); /* Fail if we have finished evicting entries and pinned entries still need evicted */ @@ -308,37 +308,37 @@ done: /*------------------------------------------------------------------------- - * Function: H5Dclose + * Function: H5Dclose * - * Purpose: Closes access to a dataset (DATASET_ID) and releases - * resources used by it. It is illegal to subsequently use that - * same dataset ID in calls to other dataset functions. + * Purpose: Closes access to a dataset (DATASET_ID) and releases + * resources used by it. It is illegal to subsequently use that + * same dataset ID in calls to other dataset functions. * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * - * Programmer: Robb Matzke - * Thursday, December 4, 1997 + * Programmer: Robb Matzke + * Thursday, December 4, 1997 * *------------------------------------------------------------------------- */ herr_t H5Dclose(hid_t dset_id) { - herr_t ret_value = SUCCEED; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(FAIL) H5TRACE1("e", "i", dset_id); /* Check args */ if(NULL == H5I_object_verify(dset_id, H5I_DATASET)) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset") + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset") /* * Decrement the counter on the dataset. It will be freed if the count * reaches zero. */ if(H5I_dec_app_ref_always_close(dset_id) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTDEC, FAIL, "can't decrement count on dataset ID") + HGOTO_ERROR(H5E_DATASET, H5E_CANTDEC, FAIL, "can't decrement count on dataset ID") done: FUNC_LEAVE_API(ret_value) diff --git a/src/H5Dint.c b/src/H5Dint.c index 8a00be2..59fe3e9 100644 --- a/src/H5Dint.c +++ b/src/H5Dint.c @@ -1780,9 +1780,9 @@ done: herr_t H5D_close(H5D_t *dataset) { - hbool_t free_failed = FALSE; - hbool_t corked; /* Whether the dataset is corked or not */ - herr_t ret_value = SUCCEED; /* Return value */ + hbool_t free_failed = FALSE; /* Set if freeing sub-components failed */ + hbool_t corked; /* Whether the dataset is corked or not */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) @@ -1797,6 +1797,7 @@ H5D_close(H5D_t *dataset) dataset->shared->fo_count--; if(dataset->shared->fo_count == 0) { + /* Flush the dataset's information. Continue to close even if it fails. */ if(H5D__flush_real(dataset, H5AC_ind_read_dxpl_id) < 0) HDONE_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to flush cached dataset info") @@ -1891,12 +1892,12 @@ H5D_close(H5D_t *dataset) (H5O_msg_reset(H5O_FILL_ID, &dataset->shared->dcpl_cache.fill) < 0) || (H5O_msg_reset(H5O_EFL_ID, &dataset->shared->dcpl_cache.efl) < 0); - /* Uncork cache entries with object address tag */ - if(H5AC_cork(dataset->oloc.file, dataset->oloc.addr, H5AC__GET_CORKED, &corked) < 0) - HDONE_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to retrieve an object's cork status") - if(corked) - if(H5AC_cork(dataset->oloc.file, dataset->oloc.addr, H5AC__UNCORK, NULL) < 0) - HDONE_ERROR(H5E_DATASET, H5E_CANTUNCORK, FAIL, "unable to uncork an object") + /* Uncork cache entries with object address tag */ + if(H5AC_cork(dataset->oloc.file, dataset->oloc.addr, H5AC__GET_CORKED, &corked) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to retrieve an object's cork status") + if(corked) + if(H5AC_cork(dataset->oloc.file, dataset->oloc.addr, H5AC__UNCORK, NULL) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTUNCORK, FAIL, "unable to uncork an object") /* * Release datatype, dataspace and creation property list -- there isn't @@ -1917,6 +1918,14 @@ H5D_close(H5D_t *dataset) if(H5O_close(&(dataset->oloc)) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release object header") + /* Evict dataset metadata if evicting on close */ + if(H5F_SHARED(dataset->oloc.file) && H5F_EVICT_ON_CLOSE(dataset->oloc.file)) { + if(H5AC_flush_tagged_metadata(dataset->oloc.file, dataset->oloc.addr, H5AC_ind_read_dxpl_id) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush tagged metadata") + if(H5AC_evict_tagged_metadata(dataset->oloc.file, dataset->oloc.addr, FALSE, H5AC_ind_read_dxpl_id) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to evict tagged metadata") + } /* end if */ + /* * Free memory. Before freeing the memory set the file pointer to NULL. * We always check for a null file pointer in other H5D functions to be @@ -1924,8 +1933,8 @@ H5D_close(H5D_t *dataset) * above). */ dataset->oloc.file = NULL; - dataset->shared = H5FL_FREE(H5D_shared_t, dataset->shared); + } /* end if */ else { /* Decrement the ref. count for this object in the top file */ @@ -1943,16 +1952,16 @@ H5D_close(H5D_t *dataset) HGOTO_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "problem attempting to free location") } /* end else */ - /* Release the dataset's path info */ - if(H5G_name_free(&(dataset->path)) < 0) - free_failed = TRUE; + /* Release the dataset's path info */ + if(H5G_name_free(&(dataset->path)) < 0) + free_failed = TRUE; /* Free the dataset's memory structure */ dataset = H5FL_FREE(H5D_t, dataset); /* Check if anything failed in the middle... */ if(free_failed) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "couldn't free a component of the dataset, but the dataset was freed anyway.") + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "couldn't free a component of the dataset, but the dataset was freed anyway.") done: FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5Dpkg.h b/src/H5Dpkg.h index 05f49d1..2190f8c 100644 --- a/src/H5Dpkg.h +++ b/src/H5Dpkg.h @@ -770,6 +770,7 @@ H5_DLL htri_t H5D__mpio_opt_possible(const H5D_io_info_t *io_info, H5_DLL herr_t H5D__layout_version_test(hid_t did, unsigned *version); H5_DLL herr_t H5D__layout_contig_size_test(hid_t did, hsize_t *size); H5_DLL herr_t H5D__layout_idx_type_test(hid_t did, H5D_chunk_index_t *idx_type); +H5_DLL herr_t H5D__layout_type_test(hid_t did, H5D_layout_t *layout_type); H5_DLL herr_t H5D__current_cache_size_test(hid_t did, size_t *nbytes_used, int *nused); #endif /* H5D_TESTING */ diff --git a/src/H5Dtest.c b/src/H5Dtest.c index c3b0b19..56f14f7 100644 --- a/src/H5Dtest.c +++ b/src/H5Dtest.c @@ -144,6 +144,47 @@ done: /*-------------------------------------------------------------------------- NAME + H5D__layout_type_test + PURPOSE + Determine the storage layout type for a dataset + USAGE + herr_t H5D__layout_type_test(did, layout_type) + hid_t did; IN: Dataset to query + H5D_layout_t *layout_type; OUT: Pointer to location to place layout info + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Checks the layout type for a dataset. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5D__layout_type_test(hid_t did, H5D_layout_t *layout_type) +{ + H5D_t *dset; /* Pointer to dataset to query */ + herr_t ret_value = SUCCEED; /* return value */ + + FUNC_ENTER_PACKAGE + + HDassert(layout_type); + + /* Check args */ + if(NULL == (dset = (H5D_t *)H5I_object_verify(did, H5I_DATASET))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset") + + if(layout_type) + *layout_type = dset->shared->layout.type; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5D__layout_type_test() */ + + +/*-------------------------------------------------------------------------- + NAME H5D__layout_idx_type_test PURPOSE Determine the storage layout index type for a dataset's layout information diff --git a/src/H5Fint.c b/src/H5Fint.c index 80c593b..5b7fdda 100644 --- a/src/H5Fint.c +++ b/src/H5Fint.c @@ -954,6 +954,7 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id, H5FD_class_t *drvr; /*file driver class info */ H5P_genplist_t *a_plist; /*file access property list */ H5F_close_degree_t fc_degree; /*file close degree */ + hbool_t evict_on_close; /* evict on close value from plist */ H5F_t *ret_value = NULL; /*actual return value */ FUNC_ENTER_NOAPI(NULL) @@ -1118,6 +1119,21 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id, HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "file close degree doesn't match") } /* end if */ + /* Record the evict-on-close MDC behavior. If it's the first time opening + * the file, set it to access property list value; if it's the second time + * or later, verify that the access property list value matches the value + * in shared file structure. + */ + if(H5P_get(a_plist, H5F_ACS_EVICT_ON_CLOSE_FLAG_NAME, &evict_on_close) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get evict on close value") + + if(shared->nrefs == 1) { + shared->evict_on_close = evict_on_close; + } else if(shared->nrefs > 1) { + if(shared->evict_on_close != evict_on_close) + HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "file evict-on-close value doesn't match") + } /* end if */ + /* Formulate the absolute path for later search of target file for external links */ if(H5_build_extpath(name, &file->extpath) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to build extpath") diff --git a/src/H5Fio.c b/src/H5Fio.c index b9bd354..2ccd3f3 100644 --- a/src/H5Fio.c +++ b/src/H5Fio.c @@ -271,7 +271,7 @@ H5F_evict_tagged_metadata(H5F_t * f, haddr_t tag, hid_t dxpl_id) f->shared->sblock = NULL; /* Evict the object's metadata */ - if(H5AC_evict_tagged_metadata(f, tag, dxpl_id)<0) + if(H5AC_evict_tagged_metadata(f, tag, TRUE, dxpl_id) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTEXPUNGE, FAIL, "unable to evict tagged metadata") /* Re-read the superblock. */ diff --git a/src/H5Fpkg.h b/src/H5Fpkg.h index c5aed3b..8ec2a93 100644 --- a/src/H5Fpkg.h +++ b/src/H5Fpkg.h @@ -261,6 +261,7 @@ struct H5F_file_t { /* not change thereafter. */ hid_t fcpl_id; /* File creation property list ID */ H5F_close_degree_t fc_degree; /* File close behavior degree */ + hbool_t evict_on_close; /* If the file's objects should be evicted from the metadata cache on close */ size_t rdcc_nslots; /* Size of raw data chunk cache (slots) */ size_t rdcc_nbytes; /* Size of raw data chunk cache (bytes) */ double rdcc_w0; /* Preempt read chunks first? [0.0..1.0]*/ diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h index b5c24e9..40e5ff2 100644 --- a/src/H5Fprivate.h +++ b/src/H5Fprivate.h @@ -303,6 +303,7 @@ #define H5F_SET_SOHM_NINDEXES(F, N) ((F)->shared->sohm_nindexes = (N)) #define H5F_FCPL(F) ((F)->shared->fcpl_id) #define H5F_GET_FC_DEGREE(F) ((F)->shared->fc_degree) +#define H5F_EVICT_ON_CLOSE(F) ((F)->shared->evict_on_close) #define H5F_RDCC_NSLOTS(F) ((F)->shared->rdcc_nslots) #define H5F_RDCC_NBYTES(F) ((F)->shared->rdcc_nbytes) #define H5F_RDCC_W0(F) ((F)->shared->rdcc_w0) @@ -348,6 +349,7 @@ #define H5F_SET_SOHM_NINDEXES(F, N) (H5F_set_sohm_nindexes((F), (N))) #define H5F_FCPL(F) (H5F_get_fcpl(F)) #define H5F_GET_FC_DEGREE(F) (H5F_get_fc_degree(F)) +#define H5F_EVICT_ON_CLOSE(F) (H5F_get_evict_on_close(F)) #define H5F_RDCC_NSLOTS(F) (H5F_rdcc_nslots(F)) #define H5F_RDCC_NBYTES(F) (H5F_rdcc_nbytes(F)) #define H5F_RDCC_W0(F) (H5F_rdcc_w0(F)) @@ -463,6 +465,7 @@ #define H5F_ACS_EFC_SIZE_NAME "efc_size" /* Size of external file cache */ #define H5F_ACS_FILE_IMAGE_INFO_NAME "file_image_info" /* struct containing initial file image and callback info */ #define H5F_ACS_CORE_WRITE_TRACKING_FLAG_NAME "core_write_tracking_flag" /* Whether or not core VFD backing store write tracking is enabled */ +#define H5F_ACS_EVICT_ON_CLOSE_FLAG_NAME "evict_on_close_flag" /* Whether or not the metadata cache will evict objects on close */ #define H5F_ACS_CORE_WRITE_TRACKING_PAGE_SIZE_NAME "core_write_tracking_page_size" /* The page size in kiB when core VFD write tracking is enabled */ #define H5F_ACS_COLL_MD_WRITE_FLAG_NAME "collective_metadata_write" /* property indicating whether metadata writes are done collectively or not */ @@ -660,6 +663,7 @@ H5_DLL unsigned H5F_get_sohm_nindexes(const H5F_t *f); H5_DLL herr_t H5F_set_sohm_nindexes(H5F_t *f, unsigned nindexes); H5_DLL hid_t H5F_get_fcpl(const H5F_t *f); H5_DLL H5F_close_degree_t H5F_get_fc_degree(const H5F_t *f); +H5_DLL hbool_t H5F_get_evict_on_close(const H5F_t *f); H5_DLL size_t H5F_rdcc_nbytes(const H5F_t *f); H5_DLL size_t H5F_rdcc_nslots(const H5F_t *f); H5_DLL double H5F_rdcc_w0(const H5F_t *f); diff --git a/src/H5Fquery.c b/src/H5Fquery.c index dd6e8e3..f59a9b7 100644 --- a/src/H5Fquery.c +++ b/src/H5Fquery.c @@ -835,6 +835,33 @@ H5F_get_fc_degree(const H5F_t *f) /*------------------------------------------------------------------------- + * Function: H5F_get_evict_on_close + * + * Purpose: Retrieve the 'file close degree' for the file. + * + * Return: Success: Flag indicating whether the evict-on-close + * property was set for the file. + * Failure: (can't happen) + * + * Programmer: Dana Robinson + * Spring 2016 + * + *------------------------------------------------------------------------- + */ +hbool_t +H5F_get_evict_on_close(const H5F_t *f) +{ + /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + HDassert(f); + HDassert(f->shared); + + FUNC_LEAVE_NOAPI(f->shared->evict_on_close) +} /* end H5F_get_evict_on_close() */ + + +/*------------------------------------------------------------------------- * Function: H5F_store_msg_crt_idx * * Purpose: Retrieve the 'store message creation index' flag for the file. @@ -715,14 +715,14 @@ done: herr_t H5Gclose(hid_t group_id) { - herr_t ret_value = SUCCEED; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(FAIL) H5TRACE1("e", "i", group_id); /* Check args */ if(NULL == H5I_object_verify(group_id,H5I_GROUP)) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a group") + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a group") /* * Decrement the counter on the group atom. It will be freed if the count diff --git a/src/H5Gint.c b/src/H5Gint.c index f5bccc3..a0e06f3 100644 --- a/src/H5Gint.c +++ b/src/H5Gint.c @@ -486,7 +486,7 @@ H5G_close(H5G_t *grp) if(0 == grp->shared->fo_count) { HDassert(grp != H5G_rootof(H5G_fileof(grp))); - /* Uncork cache entries with object address tag */ + /* Uncork cache entries with object address tag */ if(H5AC_cork(grp->oloc.file, grp->oloc.addr, H5AC__GET_CORKED, &corked) < 0) HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to retrieve an object's cork status") if(corked) @@ -500,6 +500,8 @@ H5G_close(H5G_t *grp) HGOTO_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "can't remove group from list of open objects") if(H5O_close(&(grp->oloc)) < 0) HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to close") + + /* Free memory */ grp->shared = H5FL_FREE(H5G_shared_t, grp->shared); } else { /* Decrement the ref. count for this object in the top file */ @@ -1051,7 +1051,7 @@ done: * the same effect as calling H5Gclose, H5Dclose, or H5Tclose. * * Return: Success: Non-negative - * Failure: Negative + * Failure: Negative * * Programmer: James Laird * July 14 2006 diff --git a/src/H5Pfapl.c b/src/H5Pfapl.c index 96de39c..8801061 100644 --- a/src/H5Pfapl.c +++ b/src/H5Pfapl.c @@ -181,6 +181,11 @@ /* Definition for object flush callback */ #define H5F_ACS_OBJECT_FLUSH_CB_SIZE sizeof(H5F_object_flush_t) #define H5F_ACS_OBJECT_FLUSH_CB_DEF {NULL, NULL} +/* Definition for evict on close property */ +#define H5F_ACS_EVICT_ON_CLOSE_FLAG_SIZE sizeof(hbool_t) +#define H5F_ACS_EVICT_ON_CLOSE_FLAG_DEF FALSE +#define H5F_ACS_EVICT_ON_CLOSE_FLAG_ENC H5P__encode_hbool_t +#define H5F_ACS_EVICT_ON_CLOSE_FLAG_DEC H5P__decode_hbool_t #ifdef H5_HAVE_PARALLEL /* Definition of collective metadata read mode flag */ #define H5F_ACS_COLL_MD_READ_FLAG_SIZE sizeof(H5P_coll_md_read_flag_t) @@ -296,6 +301,7 @@ static const H5FD_file_image_info_t H5F_def_file_image_info_g = H5F_ACS_FILE_IMA static const hbool_t H5F_def_core_write_tracking_flag_g = H5F_ACS_CORE_WRITE_TRACKING_FLAG_DEF; /* Default setting for core VFD write tracking */ static const size_t H5F_def_core_write_tracking_page_size_g = H5F_ACS_CORE_WRITE_TRACKING_PAGE_SIZE_DEF; /* Default core VFD write tracking page size */ static const H5F_object_flush_t H5F_def_object_flush_cb_g = H5F_ACS_OBJECT_FLUSH_CB_DEF; /* Default setting for object flush callback */ +static const hbool_t H5F_def_evict_on_close_flag_g = H5F_ACS_EVICT_ON_CLOSE_FLAG_DEF; /* Default setting for evict on close property */ #ifdef H5_HAVE_PARALLEL static const H5P_coll_md_read_flag_t H5F_def_coll_md_read_flag_g = H5F_ACS_COLL_MD_READ_FLAG_DEF; /* Default setting for the collective metedata read flag */ static const hbool_t H5F_def_coll_md_write_flag_g = H5F_ACS_COLL_MD_WRITE_FLAG_DEF; /* Default setting for the collective metedata write flag */ @@ -462,6 +468,12 @@ H5P__facc_reg_prop(H5P_genclass_t *pclass) NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class") + /* Register the evict on close flag */ + if(H5P_register_real(pclass, H5F_ACS_EVICT_ON_CLOSE_FLAG_NAME, H5F_ACS_EVICT_ON_CLOSE_FLAG_SIZE, &H5F_def_evict_on_close_flag_g, + NULL, NULL, NULL, H5F_ACS_EVICT_ON_CLOSE_FLAG_ENC, H5F_ACS_EVICT_ON_CLOSE_FLAG_DEC, + NULL, NULL, NULL, NULL) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class") + #ifdef H5_HAVE_PARALLEL /* Register the metadata collective read flag */ if(H5P_register_real(pclass, H5_COLL_MD_READ_FLAG_NAME, H5F_ACS_COLL_MD_READ_FLAG_SIZE, &H5F_def_coll_md_read_flag_g, @@ -3605,6 +3617,93 @@ done: FUNC_LEAVE_API(ret_value) } /* H5Pget_obj_flush_cb() */ + +/*------------------------------------------------------------------------- + * Function: H5Pset_evict_on_close + * + * Purpose: Sets the evict_on_close property value. + * + * When this property is set, closing an HDF5 object will + * cause the object's metadata cache entries to be flushed + * and evicted from the cache. + * + * Currently only implemented for datasets. + * + * Return: SUCCEED/FAIL + * + * Programmer: Dana Robinson + * Spring 2016 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Pset_evict_on_close(hid_t fapl_id, hbool_t evict_on_close) +{ + H5P_genplist_t *plist; /* property list pointer */ + herr_t ret_value = SUCCEED; /* return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE2("e", "ib", fapl_id, evict_on_close); + + /* Compare the property list's class against the other class */ + if(TRUE != H5P_isa_class(fapl_id, H5P_FILE_ACCESS)) + HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "property list is not a file access plist") + + /* Get the plist structure */ + if(NULL == (plist = (H5P_genplist_t *)H5I_object(fapl_id))) + HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID") + + /* Set values */ + if(H5P_set(plist, H5F_ACS_EVICT_ON_CLOSE_FLAG_NAME, &evict_on_close) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set evict on close property") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Pset_evict_on_close() */ + + +/*------------------------------------------------------------------------- + * Function: H5Pget_evict_on_close + * + * Purpose: Gets the evict_on_close property value. + * + * When this property is set, closing an HDF5 object will + * cause the object's metadata cache entries to be flushed + * and evicted from the cache. + * + * Currently only implemented for datasets. + * + * Return: SUCCEED/FAIL + * + * Programmer: Dana Robinson + * Spring 2016 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Pget_evict_on_close(hid_t fapl_id, hbool_t *evict_on_close) +{ + H5P_genplist_t *plist; /* property list pointer */ + herr_t ret_value = SUCCEED; /* return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE2("e", "i*b", fapl_id, evict_on_close); + + /* Compare the property list's class against the other class */ + if(TRUE != H5P_isa_class(fapl_id, H5P_FILE_ACCESS)) + HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "property list is not an access plist") + + /* Get the plist structure */ + if(NULL == (plist = (H5P_genplist_t *)H5I_object(fapl_id))) + HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID") + + if(H5P_get(plist, H5F_ACS_EVICT_ON_CLOSE_FLAG_NAME, evict_on_close) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get evict on close property") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Pget_evict_on_close() */ + #ifdef H5_HAVE_PARALLEL /*------------------------------------------------------------------------- diff --git a/src/H5Ppublic.h b/src/H5Ppublic.h index 0318c8f..b807a37 100644 --- a/src/H5Ppublic.h +++ b/src/H5Ppublic.h @@ -353,6 +353,8 @@ H5_DLL herr_t H5Pset_core_write_tracking(hid_t fapl_id, hbool_t is_enabled, size H5_DLL herr_t H5Pget_core_write_tracking(hid_t fapl_id, hbool_t *is_enabled, size_t *page_size); H5_DLL herr_t H5Pset_object_flush_cb(hid_t plist_id, H5F_flush_cb_t func, void *udata); H5_DLL herr_t H5Pget_object_flush_cb(hid_t plist_id, H5F_flush_cb_t *func, void **udata); +H5_DLL herr_t H5Pset_evict_on_close(hid_t fapl_id, hbool_t evict_on_close); +H5_DLL herr_t H5Pget_evict_on_close(hid_t fapl_id, hbool_t *evict_on_close); #ifdef H5_HAVE_PARALLEL H5_DLL herr_t H5Pset_all_coll_metadata_ops(hid_t plist_id, hbool_t is_collective); H5_DLL herr_t H5Pget_all_coll_metadata_ops(hid_t plist_id, hbool_t *is_collective); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1ab4165..6e6a0b9 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -204,6 +204,7 @@ set (H5_TESTS ohdr stab gheap + evict_on_close farray earray btree2 diff --git a/test/CMakeTests.cmake b/test/CMakeTests.cmake index ca890ba..1e7940a 100644 --- a/test/CMakeTests.cmake +++ b/test/CMakeTests.cmake @@ -513,6 +513,7 @@ set (H5TEST_TESTS ohdr stab gheap + evict_on_close farray earray btree2 @@ -865,6 +866,7 @@ if (HDF5_TEST_VFD) ohdr stab gheap + evict_on_close pool # accum farray diff --git a/test/Makefile.am b/test/Makefile.am index 9e0f9c5..7d062f4 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -42,7 +42,7 @@ 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_tagging lheap ohdr stab gheap \ - farray earray btree2 fheap \ + evict_on_close farray earray btree2 fheap \ pool accum hyperslab istore bittests dt_arith \ dtypes dsets cmpd_dset filter_fail extend external efc objcopy links unlink \ big mtime fillval mount flush1 flush2 app_ref enum \ diff --git a/test/evict_on_close.c b/test/evict_on_close.c new file mode 100644 index 0000000..0657b1b --- /dev/null +++ b/test/evict_on_close.c @@ -0,0 +1,779 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Programmer: Dana Robinson + * Spring 2016 + * + * Purpose: Tests the basic operation of the evict-on-close cache + * behavior. Tests that ensure the tagging is handled correctly + * are located in cache.c. + */ + +#define H5C_FRIEND /*suppress error about including H5Cpkg */ +#define H5D_FRIEND /*suppress error about including H5Dpkg */ +#define H5D_TESTING +#define H5F_FRIEND /*suppress error about including H5Fpkg */ +#define H5F_TESTING +#define H5I_FRIEND /*suppress error about including H5Ipkg */ +#define H5I_TESTING + + +#include "h5test.h" +#include "H5Cpkg.h" +#include "H5Dpkg.h" +#include "H5Fpkg.h" +#include "H5Ipkg.h" + +/* Uncomment to manually inspect cache states */ +/* #define EOC_MANUAL_INSPECTION */ + +const char *FILENAMES[] = { + "evict-on-close", /* 0 */ + NULL +}; +#define FILENAME_BUF_SIZE 1024 + +/* Dataset names */ +#define DSET_COMPACT_NAME "compact" +#define DSET_CONTIGUOUS_NAME "contiguous" +#define DSET_BTREE_NAME "v1_btree" +#define DSET_EARRAY_NAME "earray" +#define DSET_BT2_NAME "v2_btree" +#define DSET_FARRAY_NAME "farray" +#define DSET_SINGLE_NAME "single" + +/* All datasets store 1000 elements */ +#define NELEMENTS 1024 + +static hbool_t verify_tag_not_in_cache(H5F_t *f, haddr_t tag); +static herr_t check_evict_on_close_api(void); +static hid_t generate_eoc_test_file(hid_t fapl_id); +static herr_t check_configuration(hid_t fid, const char *dset_name); + + +/*------------------------------------------------------------------------- + * Function: verify_tag_not_in_cache() + * + * Purpose: Ensure that metadata cache entries with a given tag are not + * present in the cache. + * + * Return: TRUE/FALSE + * + * Programmer: Dana Robinson + * Fall 2016 + * + *------------------------------------------------------------------------- + */ +static hbool_t +verify_tag_not_in_cache(H5F_t *f, haddr_t tag) +{ + H5C_t *cache_ptr = NULL; /* cache pointer */ + int i = 0; /* iterator */ + H5C_cache_entry_t *entry_ptr = NULL; /* entry pointer */ + + cache_ptr = f->shared->cache; + + for(i = 0; i < H5C__HASH_TABLE_LEN; i++) { + + entry_ptr = cache_ptr->index[i]; + + while(entry_ptr != NULL) { + + if(tag == entry_ptr->tag) + return TRUE; + else + entry_ptr = entry_ptr->ht_next; + + } /* end while */ + } /* end for */ + + return FALSE; + +} /* end verify_tag_not_in_cache() */ + + +/*------------------------------------------------------------------------- + * Function: generate_eoc_test_file() + * + * Purpose: Generate the evict-on-close test file. + * + * Return: Success: The file ID of the created file + * Failure: -1 + * + * Programmer: Dana Robinson + * Fall 2016 + * + *------------------------------------------------------------------------- + */ +static hid_t +generate_eoc_test_file(hid_t fapl_id) +{ + char filename[FILENAME_BUF_SIZE]; /* decorated file name */ + hid_t fid = -1; /* file ID (returned) */ + hid_t fapl_copy_id = -1; /* ID of copied fapl */ + hid_t sid = -1; /* dataspace ID */ + hid_t dcpl_id = -1; /* dataset creation plist */ + hid_t did = -1; /* dataset ID */ + int rank; /* # of array dimensions */ + hsize_t current_dims[2]; /* current dataset size */ + hsize_t maximum_dims[2]; /* maximum dataset size */ + hsize_t chunk_dims[2]; /* chunk dimensions */ + H5D_chunk_index_t idx_type; /* dataset chunk index type */ + H5D_layout_t layout_type; /* dataset layout type */ + int *data = NULL; /* buffer for fake data */ + int n; /* # of data elements */ + + TESTING("generating evict-on-close test file"); + + /* Get a VFD-specific filename */ + h5_fixname(FILENAMES[0], fapl_id, filename, sizeof(filename)); + + /* Create file */ + if((fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0) + TEST_ERROR; + + /***********************************************************/ + /* Generate datasets and ensure that the scheme is correct */ + /***********************************************************/ + + /* Create the data buffer */ + if(NULL == (data = (int *)HDcalloc(NELEMENTS, sizeof(int)))) + TEST_ERROR; + + /****************************************************/ + /* Old file format data structures (v1 B-tree only) */ + /****************************************************/ + + /********************/ + /* Version 1 B-tree */ + /********************/ + + /* Create dataspace */ + n = NELEMENTS; + rank = 1; + current_dims[0] = (hsize_t)n; + maximum_dims[0] = H5S_UNLIMITED; + if((sid = H5Screate_simple(rank, current_dims, maximum_dims)) < 0) + TEST_ERROR; + + /* Create dcpl and set up chunking */ + if((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + chunk_dims[0] = 1; + if(H5Pset_chunk(dcpl_id, rank, chunk_dims) < 0) + TEST_ERROR; + + /* Create dataset */ + if((did = H5Dcreate(fid, DSET_BTREE_NAME, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) + TEST_ERROR; + + /* Ensure we're using the correct chunk indexing scheme */ + if(H5D__layout_idx_type_test(did, &idx_type) < 0) + TEST_ERROR; + if(idx_type != H5D_CHUNK_IDX_BTREE) + FAIL_PUTS_ERROR("should be using version 1 B-tree as the chunk index"); + + /* Write a bunch of fake data */ + if(H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data) < 0) + TEST_ERROR; + + /* Close IDs for this dataset */ + if(H5Dclose(did) < 0) + TEST_ERROR; + if(H5Sclose(sid) < 0) + TEST_ERROR; + if(H5Pclose(dcpl_id) < 0) + TEST_ERROR; + + /***********************************/ + /* New file format data structures */ + /***********************************/ + + /* Close the file */ + if(H5Fclose(fid) < 0) + TEST_ERROR; + + /* Copy the fapl and set the latest file format */ + if((fapl_copy_id = H5Pcopy(fapl_id)) < 0) + TEST_ERROR; + if(H5Pset_libver_bounds(fapl_copy_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) + TEST_ERROR; + + /* Reopen the file */ + if((fid = H5Fopen(filename, H5F_ACC_RDWR, fapl_copy_id)) < 0) + TEST_ERROR; + + /********************/ + /* Extensible Array */ + /********************/ + + /* Create dataspace */ + n = NELEMENTS; + rank = 1; + current_dims[0] = (hsize_t)n; + maximum_dims[0] = H5S_UNLIMITED; + if((sid = H5Screate_simple(rank, current_dims, maximum_dims)) < 0) + TEST_ERROR; + + /* Create dcpl and set up chunking */ + if((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + chunk_dims[0] = 1; + if(H5Pset_chunk(dcpl_id, rank, chunk_dims) < 0) + TEST_ERROR; + + /* Create dataset */ + if((did = H5Dcreate(fid, DSET_EARRAY_NAME, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) + TEST_ERROR; + + /* Ensure we're using the correct chunk indexing scheme */ + if(H5D__layout_idx_type_test(did, &idx_type) < 0) + TEST_ERROR; + if(idx_type != H5D_CHUNK_IDX_EARRAY) + FAIL_PUTS_ERROR("should be using extensible array as the chunk index"); + + /* Write a bunch of fake data */ + if(H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data) < 0) + TEST_ERROR; + + /* Close IDs for this dataset */ + if(H5Dclose(did) < 0) + TEST_ERROR; + if(H5Sclose(sid) < 0) + TEST_ERROR; + if(H5Pclose(dcpl_id) < 0) + TEST_ERROR; + + /********************/ + /* Version 2 B-Tree */ + /********************/ + + /* Create dataspace */ + n = NELEMENTS; + rank = 2; + current_dims[0] = (hsize_t)2; + current_dims[1] = (hsize_t)(n/2); + maximum_dims[0] = H5S_UNLIMITED; + maximum_dims[1] = H5S_UNLIMITED; + if((sid = H5Screate_simple(rank, current_dims, maximum_dims)) < 0) + TEST_ERROR; + + /* Create dcpl and set up chunking */ + if((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + chunk_dims[0] = 1; + chunk_dims[1] = 1; + if(H5Pset_chunk(dcpl_id, rank, chunk_dims) < 0) + TEST_ERROR; + + /* Create dataset */ + if((did = H5Dcreate(fid, DSET_BT2_NAME, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) + TEST_ERROR; + + /* Ensure we're using the correct chunk indexing scheme */ + if(H5D__layout_idx_type_test(did, &idx_type) < 0) + TEST_ERROR; + if(idx_type != H5D_CHUNK_IDX_BT2) + FAIL_PUTS_ERROR("should be using version 2 B-tree as the chunk index"); + + /* Write a bunch of fake data */ + if(H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data) < 0) + TEST_ERROR; + + /* Close IDs for this dataset */ + if(H5Dclose(did) < 0) + TEST_ERROR; + if(H5Sclose(sid) < 0) + TEST_ERROR; + if(H5Pclose(dcpl_id) < 0) + TEST_ERROR; + + /***************/ + /* Fixed Array */ + /***************/ + + /* Create dataspace */ + n = NELEMENTS; + rank = 1; + current_dims[0] = (hsize_t)n; + maximum_dims[0] = (hsize_t)n; + if((sid = H5Screate_simple(rank, current_dims, maximum_dims)) < 0) + TEST_ERROR; + + /* Create dcpl and set up chunking */ + if((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + chunk_dims[0] = 1; + chunk_dims[1] = 1; + if(H5Pset_chunk(dcpl_id, rank, chunk_dims) < 0) + TEST_ERROR; + + /* Create dataset */ + if((did = H5Dcreate(fid, DSET_FARRAY_NAME, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) + TEST_ERROR; + + /* Ensure we're using the correct chunk indexing scheme */ + if(H5D__layout_idx_type_test(did, &idx_type) < 0) + TEST_ERROR; + if(idx_type != H5D_CHUNK_IDX_FARRAY) + FAIL_PUTS_ERROR("should be using fixed array as the chunk index"); + + /* Write a bunch of fake data */ + if(H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data) < 0) + TEST_ERROR; + + /* Close IDs for this dataset */ + if(H5Dclose(did) < 0) + TEST_ERROR; + if(H5Sclose(sid) < 0) + TEST_ERROR; + if(H5Pclose(dcpl_id) < 0) + TEST_ERROR; + + /****************/ + /* Single Chunk */ + /****************/ + + /* Create dataspace */ + n = NELEMENTS; + rank = 1; + current_dims[0] = (hsize_t)n; + maximum_dims[0] = (hsize_t)n; + if((sid = H5Screate_simple(rank, current_dims, maximum_dims)) < 0) + TEST_ERROR; + + /* Create dcpl and set up chunking */ + if((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + chunk_dims[0] = (hsize_t)n; + chunk_dims[1] = (hsize_t)n; + if(H5Pset_chunk(dcpl_id, rank, chunk_dims) < 0) + TEST_ERROR; + + /* Create dataset */ + if((did = H5Dcreate(fid, DSET_SINGLE_NAME, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) + TEST_ERROR; + + /* Ensure we're using the correct chunk indexing scheme */ + if(H5D__layout_idx_type_test(did, &idx_type) < 0) + TEST_ERROR; + if(idx_type != H5D_CHUNK_IDX_SINGLE) + FAIL_PUTS_ERROR("should be using single chunk as the chunk index"); + + /* Write a bunch of fake data */ + if(H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data) < 0) + TEST_ERROR; + + /* Close IDs for this dataset */ + if(H5Dclose(did) < 0) + TEST_ERROR; + if(H5Sclose(sid) < 0) + TEST_ERROR; + if(H5Pclose(dcpl_id) < 0) + TEST_ERROR; + + /**************/ + /* Contiguous */ + /**************/ + + /* Create dataspace */ + n = NELEMENTS; + rank = 1; + current_dims[0] = (hsize_t)n; + maximum_dims[0] = (hsize_t)n; + if((sid = H5Screate_simple(rank, current_dims, maximum_dims)) < 0) + TEST_ERROR; + + /* Create dataset */ + if((did = H5Dcreate(fid, DSET_CONTIGUOUS_NAME, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR; + + /* Ensure we're using the correct layout scheme */ + if(H5D__layout_type_test(did, &layout_type) < 0) + TEST_ERROR; + if(layout_type != H5D_CONTIGUOUS) + FAIL_PUTS_ERROR("should be using contiguous layout"); + + /* Write a bunch of fake data */ + if(H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data) < 0) + TEST_ERROR; + + /* Close IDs for this dataset */ + if(H5Dclose(did) < 0) + TEST_ERROR; + if(H5Sclose(sid) < 0) + TEST_ERROR; + + /***********/ + /* Compact */ + /***********/ + + /* Create dataspace */ + n = 1; + rank = 1; + current_dims[0] = (hsize_t)n; + maximum_dims[0] = (hsize_t)n; + if((sid = H5Screate_simple(rank, current_dims, maximum_dims)) < 0) + TEST_ERROR; + + /* Create dcpl and set up compact layout */ + if((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + if(H5Pset_layout(dcpl_id, H5D_COMPACT) < 0) + TEST_ERROR; + + /* Create dataset */ + if((did = H5Dcreate(fid, DSET_COMPACT_NAME, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) + TEST_ERROR; + + /* Ensure we're using the correct layout scheme */ + if(H5D__layout_type_test(did, &layout_type) < 0) + TEST_ERROR; + if(layout_type != H5D_COMPACT) + FAIL_PUTS_ERROR("should be using compact layout"); + + /* Write a bunch of fake data */ + if(H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data) < 0) + TEST_ERROR; + + /* Close IDs for this dataset */ + if(H5Dclose(did) < 0) + TEST_ERROR; + if(H5Sclose(sid) < 0) + TEST_ERROR; + if(H5Pclose(dcpl_id) < 0) + TEST_ERROR; + + /********/ + /* DONE */ + /********/ + + /* Close/free everything else */ + if(H5Pclose(fapl_copy_id) < 0) + TEST_ERROR; + + HDfree(data); + + PASSED(); + return fid; + +error: + H5E_BEGIN_TRY { + H5Fclose(fid); + H5Dclose(did); + H5Sclose(sid); + H5Pclose(dcpl_id); + H5Pclose(fapl_copy_id); + } H5E_END_TRY; + + HDfree(data); + + H5_FAILED(); + return -1; + +} /* end generate_eoc_test_file() */ + + +/*------------------------------------------------------------------------- + * Function: check_configuration() + * + * Purpose: Verify that the evict-on-close feature works for a given + * dataset layout and/or chunk index. + * + * Return: SUCCEED/FAIL + * + * Programmer: Dana Robinson + * Fall 2016 + * + *------------------------------------------------------------------------- + */ +static herr_t +check_configuration(hid_t fid, const char *dset_name) +{ + H5F_t *file_ptr = NULL; /* ptr to internal file struct */ + hid_t did = -1; /* dataset ID */ + H5D_t *dset_ptr = NULL; /* ptr to internal dset struct */ + haddr_t tag; /* MD cache tag for dataset */ + int *data = NULL; /* buffer for fake data */ + int32_t before, during, after; /* cache sizes */ + + /* NOTE: The TESTING() macro is called in main() */ + + /* Get a pointer to the file struct */ + if(NULL == (file_ptr = (H5F_t *)H5I_object_verify(fid, H5I_FILE))) + TEST_ERROR; + + /* Create the data buffer */ + if(NULL == (data = (int *)HDcalloc(NELEMENTS, sizeof(int)))) + TEST_ERROR; + + /* Record the number of cache entries */ + before = file_ptr->shared->cache->index_len; + +#ifdef EOC_MANUAL_INSPECTION + HDprintf("\nCACHE BEFORE DATASET OPEN:\n"); + if(H5AC_dump_cache(file_ptr) < 0) + TEST_ERROR; + HDprintf("NUMBER OF CACHE ENTRIES: %d\n", before); +#endif + + /* Open dataset and get the metadata tag */ + if((did = H5Dopen2(fid, dset_name, H5P_DEFAULT)) < 0) + TEST_ERROR; + if(NULL == (dset_ptr = (H5D_t *)H5I_object_verify(did, H5I_DATASET))) + TEST_ERROR; + tag = dset_ptr->oloc.addr; + + /* Read data from the dataset so the cache gets populated with chunk + * and the like. + */ + if(H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data) < 0) + TEST_ERROR; + + /* Record the number of cache entries */ + during = file_ptr->shared->cache->index_len; + +#ifdef EOC_MANUAL_INSPECTION + HDprintf("\nCACHE AFTER DATA READ (WHILE OPEN):\n"); + if(H5AC_dump_cache(file_ptr) < 0) + TEST_ERROR; + HDprintf("TAG: %#X\n", tag); + HDprintf("NUMBER OF CACHE ENTRIES: %d\n", during); +#endif + + /* Close the dataset */ + if(H5Dclose(did) < 0) + TEST_ERROR; + + /* Record the number of cache entries */ + after = file_ptr->shared->cache->index_len; + +#ifdef EOC_MANUAL_INSPECTION + HDprintf("\nCACHE AFTER DATASET CLOSE:\n"); + if(H5AC_dump_cache(file_ptr) < 0) + TEST_ERROR; + HDprintf("NUMBER OF CACHE ENTRIES: %d\n", after); +#endif + + /* Ensure that the cache does not contain data items with the tag */ + if(TRUE == verify_tag_not_in_cache(file_ptr, tag)) + TEST_ERROR; + + /* Compare the number of cache entries */ + if(before != after || before == during) + TEST_ERROR; + + HDfree(data); + + PASSED(); + return SUCCEED; + +error: + H5E_BEGIN_TRY { + H5Dclose(did); + } H5E_END_TRY; + + H5_FAILED(); + return FAIL; + +} /* check_configuration() */ + + +/*------------------------------------------------------------------------- + * Function: check_evict_on_close_api() + * + * Purpose: Verify that the H5Pset/get_evict_on_close() calls behave + * correctly. + * + * Return: SUCCEED/FAIL + * + * Programmer: Dana Robinson + * Spring 2016 + * + *------------------------------------------------------------------------- + */ +static herr_t +check_evict_on_close_api(void) +{ + hid_t fapl_id = -1; + hid_t dapl_id = -1; + hbool_t evict_on_close; + herr_t status; + + TESTING("evict on close API"); + + /* Create a fapl */ + if((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) + TEST_ERROR; + + /* Check the default */ + evict_on_close = TRUE; + if(H5Pget_evict_on_close(fapl_id, &evict_on_close) < 0) + TEST_ERROR; + if(evict_on_close != FALSE) + FAIL_PUTS_ERROR("Incorrect default evict on close value."); + + /* Set the evict on close property */ + evict_on_close = TRUE; + if(H5Pset_evict_on_close(fapl_id, evict_on_close) < 0) + TEST_ERROR; + + /* Make sure we can get it back out */ + evict_on_close = FALSE; + if(H5Pget_evict_on_close(fapl_id, &evict_on_close) < 0) + TEST_ERROR; + if(evict_on_close != TRUE) + FAIL_PUTS_ERROR("Incorrect evict on close value."); + + /* close fapl */ + if(H5Pclose(fapl_id) < 0) + TEST_ERROR; + + /**********************************************/ + /* Trying passing in a non-fapl property list */ + /**********************************************/ + + if((dapl_id = H5Pcreate(H5P_DATASET_ACCESS)) < 0) + TEST_ERROR; + + /* ensure using an incorrect access plist fails */ + H5E_BEGIN_TRY { + status = H5Pset_evict_on_close(dapl_id, evict_on_close); + } H5E_END_TRY; + if(status >= 0) + FAIL_PUTS_ERROR("H5Pset_evict_on_close() accepted invalid access plist."); + + /* ensure an invalid plist fails */ + H5E_BEGIN_TRY { + status = H5Pget_evict_on_close((hid_t)-1, &evict_on_close); + } H5E_END_TRY; + if(status >= 0) + FAIL_PUTS_ERROR("H5Pget_evict_on_close() accepted invalid hid_t."); + + /* close dapl */ + if(H5Pclose(dapl_id) < 0) + TEST_ERROR; + + PASSED(); + return SUCCEED; + +error: + H5_FAILED(); + return FAIL; + +} /* check_evict_on_close_api() */ + + +/*------------------------------------------------------------------------- + * Function: main + * + * Return: EXIT_FAILURE/EXIT_SUCCESS + * + * Programmer: Dana Robinson + * Spring 2016 + * + *------------------------------------------------------------------------- + */ +int +main(void) +{ + hid_t fapl_id = -1; /* VFD-specific fapl */ + hid_t fid = -1; /* file ID */ + unsigned nerrors = 0; /* number of test errors */ + + HDprintf("Testing evict-on-close cache behavior.\n"); + + /* Initialize */ + h5_reset(); + + /* Test H5P call to set up EoC (does not require VFD-specific fapl) */ + nerrors += check_evict_on_close_api() < 0 ? 1 : 0; + + /* Set up VFD-specific fapl */ + if((fapl_id = h5_fileaccess()) < 0) { + nerrors++; + PUTS_ERROR("Unable to get VFD-specific fapl\n"); + } /* end if */ + + /* Set evict-on-close property */ + if(H5Pset_evict_on_close(fapl_id, TRUE) < 0) { + nerrors++; + PUTS_ERROR("Unable to set evict-on-close property\n"); + } /* end if */ + + /*************************/ + /* Test EoC for datasets */ + /*************************/ + + /* Generate the test file */ + if((fid = generate_eoc_test_file(fapl_id)) < 0) { + nerrors++; + PUTS_ERROR("Unable to generate test file\n"); + } /* end if */ + + /* Run tests with a variety of dataset configurations + * PASSED() and H5_FAILED() are handled in check_configuration() + */ + TESTING("evict on close with version 1 B-tree chunk index"); + nerrors += check_configuration(fid, DSET_BTREE_NAME) < 0 ? 1 : 0; + TESTING("evict on close with extensible array chunk index"); + nerrors += check_configuration(fid, DSET_EARRAY_NAME) < 0 ? 1 : 0; + TESTING("evict on close with version 2 B-tree chunk index"); + nerrors += check_configuration(fid, DSET_BT2_NAME) < 0 ? 1 : 0; + TESTING("evict on close with fixed array chunk index"); + nerrors += check_configuration(fid, DSET_FARRAY_NAME) < 0 ? 1 : 0; + TESTING("evict on close with \'single chunk\' chunk index"); + nerrors += check_configuration(fid, DSET_SINGLE_NAME) < 0 ? 1 : 0; + TESTING("evict on close with contiguous layout"); + nerrors += check_configuration(fid, DSET_CONTIGUOUS_NAME) < 0 ? 1 : 0; + TESTING("evict on close with compact layout"); + nerrors += check_configuration(fid, DSET_COMPACT_NAME) < 0 ? 1 : 0; + + /* Close the test file */ + if(H5Fclose(fid) < 0) { + nerrors++; + PUTS_ERROR("Unable to close the test file.\n"); + } /* end if */ + + /* Clean up files and close the VFD-specific fapl */ + h5_delete_all_test_files(FILENAMES, fapl_id); + if(H5Pclose(fapl_id) < 0) { + nerrors++; + PUTS_ERROR("Unable to close VFD-specific fapl.\n"); + } /* end if */ + + if(nerrors) + goto error; + + HDprintf("All evict-on-close tests passed.\n"); + + return EXIT_SUCCESS; + +error: + + HDprintf("***** %u evict-on-close test%s FAILED! *****\n", + nerrors, nerrors > 1 ? "S" : ""); + + h5_delete_all_test_files(FILENAMES, fapl_id); + H5E_BEGIN_TRY { + H5Fclose(fid); + H5Pclose(fapl_id); + } H5E_END_TRY; + + return EXIT_FAILURE; + +} /* end main() */ + diff --git a/test/h5test.c b/test/h5test.c index 2ab8855..c126da8 100644 --- a/test/h5test.c +++ b/test/h5test.c @@ -199,7 +199,7 @@ h5_clean_files(const char *base_name[], hid_t fapl) * * Purpose Clean up temporary test files. * - * When a test calls h5_fixname() get a VFD-dependent + * When a test calls h5_fixname() to get a VFD-dependent * test file name, this function can be used to clean it up. * * Return: void |