From a9ca88d1564351db7ca9371eeede12473b26a6a6 Mon Sep 17 00:00:00 2001 From: Mike McGreevy Date: Tue, 2 Nov 2010 14:00:56 -0500 Subject: [svn-r19714] Purpose: Add API and supporting code to allow single object flushes and refreshes. Description: Added the following API calls: H5Dflush / H5Drefresh H5Gflush / H5Grefresh H5Tflush / H5Trefresh H5Oflush / H5Orefresh Each H5*flush API flushes the targeted object's metadata, while each H5*refresh evicts all metadata related to an object and reopens the object (re-loading needed metadata from disk). New files include src/H5Oflush.c, containing new internal H5O_* functions used by the above API calls. Also, a test file and test script template have been added, test/flushrefresh.c and test/testflushrefresh.sh.in. There is not (yet) a corresponding test script for windows as the current one isn't quite portable. Several H5C and H5AC-level functions have been added to support single object flushing and eviction, and the previously committed 'metadata tagging' code has been tweaked slightly to pull H5AC__* macros out of H5C.c and a few other fixes as necessary as well. Tag globality has been added to better encapsulate the meaning of global tags in the H5C layer of the code. Tested: h5committested. --- MANIFEST | 3 + configure | 3 +- configure.in | 1 + src/CMakeLists.txt | 1 + src/H5AC.c | 215 +++++++- src/H5ACprivate.h | 12 + src/H5C.c | 374 +++++++------ src/H5Cprivate.h | 23 +- src/H5D.c | 68 +++ src/H5Dpublic.h | 2 + src/H5Fio.c | 75 +++ src/H5Fprivate.h | 4 + src/H5G.c | 68 +++ src/H5Gpublic.h | 2 + src/H5I.c | 77 +++ src/H5Iprivate.h | 1 + src/H5Oflush.c | 291 ++++++++++ src/H5Oprivate.h | 4 + src/H5Opublic.h | 2 + src/H5Pdxpl.c | 7 +- src/H5T.c | 68 +++ src/H5Tpublic.h | 2 + src/Makefile.am | 2 +- src/Makefile.in | 21 +- test/Makefile.am | 10 +- test/Makefile.in | 57 +- test/flushrefresh.c | 1251 +++++++++++++++++++++++++++++++++++++++++++ test/testflushrefresh.sh.in | 162 ++++++ 28 files changed, 2602 insertions(+), 204 deletions(-) create mode 100644 src/H5Oflush.c create mode 100755 test/flushrefresh.c create mode 100755 test/testflushrefresh.sh.in diff --git a/MANIFEST b/MANIFEST index b01cffe..3a96b7f 100644 --- a/MANIFEST +++ b/MANIFEST @@ -683,6 +683,7 @@ ./src/H5Odtype.c ./src/H5Oefl.c ./src/H5Ofill.c +./src/H5Oflush.c ./src/H5Ofsinfo.c ./src/H5Oginfo.c ./src/H5Olayout.c @@ -855,6 +856,7 @@ ./test/filter_fail.c ./test/flush1.c ./test/flush2.c +./test/flushrefresh.c ./test/gen_bad_ohdr.c _DO_NOT_DISTRIBUTE_ ./test/gen_bogus.c _DO_NOT_DISTRIBUTE_ ./test/gen_cross.c _DO_NOT_DISTRIBUTE_ @@ -918,6 +920,7 @@ ./test/tcoords.c ./test/testcheck_version.sh.in ./test/testerror.sh.in +./test/testflushrefresh.sh.in ./test/testframe.c ./test/testhdf5.c ./test/testhdf5.h diff --git a/configure b/configure index 1869fbb..f22769b 100755 --- a/configure +++ b/configure @@ -28222,7 +28222,7 @@ if test -n "$TESTPARALLEL"; then fi fi -ac_config_files="$ac_config_files src/libhdf5.settings Makefile src/Makefile test/Makefile test/testcheck_version.sh test/testerror.sh test/H5srcdir_str.h test/testlibinfo.sh testpar/Makefile testpar/testph5.sh perform/Makefile tools/Makefile tools/h5dump/Makefile tools/h5dump/testh5dump.sh tools/h5dump/testh5dumpxml.sh tools/h5ls/testh5ls.sh tools/h5import/Makefile tools/h5diff/Makefile tools/h5jam/Makefile tools/h5jam/testh5jam.sh tools/h5repack/Makefile tools/h5repack/h5repack.sh tools/h5ls/Makefile tools/h5copy/Makefile tools/lib/Makefile tools/misc/Makefile tools/misc/h5cc tools/misc/testh5repart.sh tools/h5stat/testh5stat.sh tools/h5stat/Makefile examples/Makefile examples/run-c-ex.sh examples/testh5cc.sh c++/Makefile c++/src/Makefile c++/src/h5c++ c++/test/Makefile c++/test/H5srcdir_str.h c++/examples/Makefile c++/examples/run-c++-ex.sh c++/examples/testh5c++.sh fortran/Makefile fortran/src/h5fc fortran/src/Makefile fortran/test/Makefile fortran/testpar/Makefile fortran/examples/Makefile fortran/examples/run-fortran-ex.sh fortran/examples/testh5fc.sh hl/Makefile hl/src/Makefile hl/test/Makefile hl/test/H5srcdir_str.h hl/tools/Makefile hl/tools/gif2h5/Makefile hl/examples/Makefile hl/examples/run-hlc-ex.sh hl/c++/Makefile hl/c++/src/Makefile hl/c++/test/Makefile hl/c++/examples/Makefile hl/c++/examples/run-hlc++-ex.sh hl/fortran/Makefile hl/fortran/src/Makefile hl/fortran/test/Makefile hl/fortran/examples/Makefile hl/fortran/examples/run-hlfortran-ex.sh" +ac_config_files="$ac_config_files src/libhdf5.settings Makefile src/Makefile test/Makefile test/testcheck_version.sh test/testerror.sh test/testflushrefresh.sh test/H5srcdir_str.h test/testlibinfo.sh testpar/Makefile testpar/testph5.sh perform/Makefile tools/Makefile tools/h5dump/Makefile tools/h5dump/testh5dump.sh tools/h5dump/testh5dumpxml.sh tools/h5ls/testh5ls.sh tools/h5import/Makefile tools/h5diff/Makefile tools/h5jam/Makefile tools/h5jam/testh5jam.sh tools/h5repack/Makefile tools/h5repack/h5repack.sh tools/h5ls/Makefile tools/h5copy/Makefile tools/lib/Makefile tools/misc/Makefile tools/misc/h5cc tools/misc/testh5repart.sh tools/h5stat/testh5stat.sh tools/h5stat/Makefile examples/Makefile examples/run-c-ex.sh examples/testh5cc.sh c++/Makefile c++/src/Makefile c++/src/h5c++ c++/test/Makefile c++/test/H5srcdir_str.h c++/examples/Makefile c++/examples/run-c++-ex.sh c++/examples/testh5c++.sh fortran/Makefile fortran/src/h5fc fortran/src/Makefile fortran/test/Makefile fortran/testpar/Makefile fortran/examples/Makefile fortran/examples/run-fortran-ex.sh fortran/examples/testh5fc.sh hl/Makefile hl/src/Makefile hl/test/Makefile hl/test/H5srcdir_str.h hl/tools/Makefile hl/tools/gif2h5/Makefile hl/examples/Makefile hl/examples/run-hlc-ex.sh hl/c++/Makefile hl/c++/src/Makefile hl/c++/test/Makefile hl/c++/examples/Makefile hl/c++/examples/run-hlc++-ex.sh hl/fortran/Makefile hl/fortran/src/Makefile hl/fortran/test/Makefile hl/fortran/examples/Makefile hl/fortran/examples/run-hlfortran-ex.sh" cat >confcache <<\_ACEOF @@ -29454,6 +29454,7 @@ do "test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;; "test/testcheck_version.sh") CONFIG_FILES="$CONFIG_FILES test/testcheck_version.sh" ;; "test/testerror.sh") CONFIG_FILES="$CONFIG_FILES test/testerror.sh" ;; + "test/testflushrefresh.sh") CONFIG_FILES="$CONFIG_FILES test/testflushrefresh.sh" ;; "test/H5srcdir_str.h") CONFIG_FILES="$CONFIG_FILES test/H5srcdir_str.h" ;; "test/testlibinfo.sh") CONFIG_FILES="$CONFIG_FILES test/testlibinfo.sh" ;; "testpar/Makefile") CONFIG_FILES="$CONFIG_FILES testpar/Makefile" ;; diff --git a/configure.in b/configure.in index 0e37500..f9c1a05 100644 --- a/configure.in +++ b/configure.in @@ -4283,6 +4283,7 @@ AC_CONFIG_FILES([src/libhdf5.settings test/Makefile test/testcheck_version.sh test/testerror.sh + test/testflushrefresh.sh test/H5srcdir_str.h test/testlibinfo.sh testpar/Makefile diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 92469a3..3ba37c1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -344,6 +344,7 @@ SET (H5O_SRCS ${HDF5_SRC_DIR}/H5Odtype.c ${HDF5_SRC_DIR}/H5Oefl.c ${HDF5_SRC_DIR}/H5Ofill.c + ${HDF5_SRC_DIR}/H5Oflush.c ${HDF5_SRC_DIR}/H5Ofsinfo.c ${HDF5_SRC_DIR}/H5Oginfo.c ${HDF5_SRC_DIR}/H5Olayout.c diff --git a/src/H5AC.c b/src/H5AC.c index cba1615..e0813be 100644 --- a/src/H5AC.c +++ b/src/H5AC.c @@ -127,6 +127,10 @@ static herr_t H5AC_check_if_write_permitted(const H5F_t *f, static herr_t H5AC_ext_config_2_int_config(H5AC_cache_config_t * ext_conf_ptr, H5C_auto_size_ctl_t * int_conf_ptr); + +#if H5AC_DO_TAGGING_SANITY_CHECKS +static herr_t H5AC_verify_tag(hid_t dxpl_id, H5AC_class_t * type); +#endif /* H5AC_DO_TAGGING_SANITY_CHECKS */ #ifdef H5_HAVE_PARALLEL static herr_t H5AC_broadcast_candidate_list(H5AC_t * cache_ptr, @@ -990,6 +994,11 @@ H5AC_insert_entry(H5F_t *f, hid_t dxpl_id, const H5AC_class_t *type, haddr_t add } #endif /* H5AC__TRACE_FILE_ENABLED */ +#if H5AC_DO_TAGGING_SANITY_CHECKS + if (!f->shared->cache->ignore_tags && (H5AC_verify_tag(dxpl_id, type) < 0)) + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "Bad tag value") +#endif /* H5AC_DO_TAGGING_SANITY_CHECKS */ + /* Insert entry into metadata cache */ if(H5C_insert_entry(f, dxpl_id, H5AC_noblock_dxpl_id, type, addr, thing, flags) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, "H5C_insert_entry() failed") @@ -1375,6 +1384,11 @@ H5AC_protect(H5F_t *f, protect_flags |= H5C__READ_ONLY_FLAG; } +#if H5AC_DO_TAGGING_SANITY_CHECKS + if (!f->shared->cache->ignore_tags && (H5AC_verify_tag(dxpl_id, type) < 0)) + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, NULL, "Bad tag value") +#endif /* H5AC_DO_TAGGING_SANITY_CHECKS */ + thing = H5C_protect(f, dxpl_id, H5AC_noblock_dxpl_id, @@ -5226,8 +5240,9 @@ herr_t H5AC_tag(hid_t dxpl_id, haddr_t metadata_tag, haddr_t * prev_tag) { /* Variable Declarations */ - H5P_genplist_t *dxpl; /* dataset transfer property list */ - herr_t ret_value = SUCCEED; + H5P_genplist_t *dxpl = NULL; /* dataset transfer property list */ + int globality = 0; /* global tag value */ + herr_t ret_value = SUCCEED; /* return value */ /* Function Enter Macro */ FUNC_ENTER_NOAPI(H5AC_tag, FAIL) @@ -5245,6 +5260,25 @@ H5AC_tag(hid_t dxpl_id, haddr_t metadata_tag, haddr_t * prev_tag) /* Set the provided tag value in the dxpl_id. */ if(H5P_set(dxpl, "H5AC_metadata_tag", &metadata_tag) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set property in dxpl") + + /* Determine globality of tag */ + switch(metadata_tag) { + case H5AC__SUPERBLOCK_TAG: + case H5AC__SOHM_TAG: + case H5AC__GLOBALHEAP_TAG: + globality = H5C_GLOBALITY_MAJOR; + break; + case H5AC__FREESPACE_TAG: + globality = H5C_GLOBALITY_MINOR; + break; + default: + globality = H5C_GLOBALITY_NONE; + break; + } /* end switch */ + + /* Set globality in dxpl */ + if(H5P_set(dxpl, "H5C_tag_globality", &globality) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set property in dxpl") done: FUNC_LEAVE_NOAPI(ret_value) @@ -5277,10 +5311,183 @@ H5AC_retag_copied_metadata(H5F_t * f, haddr_t metadata_tag) HDassert(f); HDassert(f->shared); - /* Call cache-level function to retag entries */ - H5C_retag_copied_metadata(f->shared->cache, metadata_tag); + /* Call cache-level function to re-tag entries with the COPIED tag */ + H5C_retag_metadata(f->shared->cache, H5AC__COPIED_TAG, metadata_tag); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_retag_copied_metadata */ + +/*------------------------------------------------------------------------------ + * Function: H5AC_flush_tagged_metadata() + * + * Purpose: Wrapper for cache level function which flushes all metadata + * that contains the specific tag. + * + * Return: SUCCEED on success, FAIL otherwise. + * + * Programmer: Mike McGreevy + * May 19, 2010 + * + *------------------------------------------------------------------------------ + */ +herr_t +H5AC_flush_tagged_metadata(H5F_t * f, haddr_t metadata_tag, hid_t dxpl_id) +{ + /* Variable Declarations */ + herr_t ret_value = SUCCEED; + herr_t result; + + /* Function Enter Macro */ + FUNC_ENTER_NOAPI(H5AC_flush_tagged_metadata, FAIL) + + /* Assertions */ + HDassert(f); + HDassert(f->shared); + + /* Call cache level function to flush metadata entries with specified tag */ + if(H5C_flush_tagged_entries(f, dxpl_id, H5AC_dxpl_id, metadata_tag)<0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Cannot flush metadata") + +done: + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC_flush_tagged_metadata */ + + +/*------------------------------------------------------------------------------ + * Function: H5AC_evict_tagged_metadata() + * + * Purpose: Wrapper for cache level function which flushes all metadata + * that contains the specific tag. + * + * Return: SUCCEED on success, FAIL otherwise. + * + * Programmer: Mike McGreevy + * May 19, 2010 + * + *------------------------------------------------------------------------------ + */ +herr_t +H5AC_evict_tagged_metadata(H5F_t * f, haddr_t metadata_tag, hid_t dxpl_id) +{ + /* Variable Declarations */ + herr_t ret_value = SUCCEED; + + /* Function Enter Macro */ + FUNC_ENTER_NOAPI(H5AC_evict_tagged_metadata, FAIL) + + /* Assertions */ + HDassert(f); + HDassert(f->shared); + + /* Call cache level function to evict metadata entries with specified tag */ + if(H5C_evict_tagged_entries(f, dxpl_id, H5AC_dxpl_id, metadata_tag)<0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Cannot evict metadata") + +done: + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC_evict_tagged_metadata */ + +#if H5AC_DO_TAGGING_SANITY_CHECKS + +/*------------------------------------------------------------------------- + * + * Function: H5AC_verify_tag + * + * Purpose: Performs sanity checking on an entry type and tag value + * stored in a supplied dxpl_id. + * + * Return: SUCCEED or FAIL. + * + * Programmer: Mike McGreevy + * October 20, 2010 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5AC_verify_tag(hid_t dxpl_id, H5AC_class_t * type) +{ + haddr_t tag = HADDR_UNDEF; + int globality = -1; + H5P_genplist_t * dxpl; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5AC_verify_tag, FAIL) + + /* Get the dataset transfer property list */ + if(NULL == (dxpl = (H5P_genplist_t *)H5I_object_verify(dxpl_id, H5I_GENPROP_LST))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list") + + /* Get the tag from the DXPL */ + if( (H5P_get(dxpl, "H5AC_metadata_tag", &tag)) < 0 ) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to query property value"); + + /* Get the tag globality from the DXPL */ + if( (H5P_get(dxpl, "H5C_tag_globality", &globality)) < 0 ) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to query property value"); + + /* Perform some sanity checks on tag value. Certain entry + * types require certain tag values, so check that these + * constraints are met. */ + if(tag == H5AC__IGNORE_TAG) + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "cannot ignore a tag while doing verification.") + else if(tag == H5AC__INVALID_TAG) + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "no metadata tag provided") + else { + + /* Perform some sanity checks on tag value. Certain entry + * types require certain tag values, so check that these + * constraints are met. */ + + /* Superblock */ + if(type->id == H5AC_SUPERBLOCK_ID) { + if(tag != H5AC__SUPERBLOCK_TAG) + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "superblock not tagged with H5AC__SUPERBLOCK_TAG") + if(globality != H5C_GLOBALITY_MAJOR) + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "superblock globality not marked with H5C_GLOBALITY_MAJOR") + } + else { + if(tag == H5AC__SUPERBLOCK_TAG) + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "H5AC__SUPERBLOCK_TAG applied to non-superblock entry") + } + + /* Free Space Manager */ + if((type->id == H5AC_FSPACE_HDR_ID) || (type->id == H5AC_FSPACE_SINFO_ID)) { + if(tag != H5AC__FREESPACE_TAG) + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "freespace entry not tagged with H5AC__FREESPACE_TAG") + if(globality != H5C_GLOBALITY_MINOR) + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "freespace entry globality not marked with H5C_GLOBALITY_MINOR") + } + else { + if(tag == H5AC__FREESPACE_TAG) + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "H5AC__FREESPACE_TAG applied to non-freespace entry") + } + + /* SOHM */ + if((type->id == H5AC_SOHM_TABLE_ID) || (type->id == H5AC_SOHM_LIST_ID)) { + if(tag != H5AC__SOHM_TAG) + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "sohm entry not tagged with H5AC__SOHM_TAG") + if(globality != H5C_GLOBALITY_MAJOR) + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "sohm entry globality not marked with H5C_GLOBALITY_MAJOR") + } + + /* Global Heap */ + if(type->id == H5AC_GHEAP_ID) { + if(tag != H5AC__GLOBALHEAP_TAG) + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "global heap not tagged with H5AC__GLOBALHEAP_TAG") + if(globality != H5C_GLOBALITY_MAJOR) + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "global heap entry globality not marked with H5C_GLOBALITY_MAJOR") + } + else { + if(tag == H5AC__GLOBALHEAP_TAG) + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "H5AC__GLOBALHEAP_TAG applied to non-globalheap entry") + } + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5AC_verify_tag */ +#endif /* H5AC_DO_TAGGING_SANITY_CHECKS */ diff --git a/src/H5ACprivate.h b/src/H5ACprivate.h index 2a817a0..2c1e383 100644 --- a/src/H5ACprivate.h +++ b/src/H5ACprivate.h @@ -41,6 +41,7 @@ #define H5AC__TRACE_FILE_ENABLED 0 #endif /* H5_METADATA_TRACE_FILE */ +/* Define global metadata tag values */ #define H5AC__INVALID_TAG (haddr_t)0 #define H5AC__IGNORE_TAG (haddr_t)1 #define H5AC__SUPERBLOCK_TAG (haddr_t)2 @@ -108,6 +109,12 @@ typedef enum { #define H5AC__DEFAULT_MAX_CACHE_SIZE H5C__DEFAULT_MAX_CACHE_SIZE #define H5AC__DEFAULT_MIN_CLEAN_SIZE H5C__DEFAULT_MIN_CLEAN_SIZE +/* Check if we are sanity checking tagging */ +#if H5C_DO_TAGGING_SANITY_CHECKS +#define H5AC_DO_TAGGING_SANITY_CHECKS 1 +#else +#define H5AC_DO_TAGGING_SANITY_CHECKS 0 +#endif /* * Class methods pertaining to caching. Each type of cached object will @@ -206,6 +213,7 @@ typedef H5C_t H5AC_t; #define H5AC_LIBRARY_INTERNAL_DEF 0 #endif /* H5_HAVE_PARALLEL */ +/* Definitiions for "metadata tag" property */ #define H5AC_METADATA_TAG_NAME "H5AC_metadata_tag" #define H5AC_METADATA_TAG_SIZE sizeof(haddr_t) #define H5AC_METADATA_TAG_DEF H5AC__INVALID_TAG @@ -405,6 +413,10 @@ H5_DLL herr_t H5AC_retag_copied_metadata(H5F_t * f, haddr_t metadata_tag); H5_DLL herr_t H5AC_ignore_tags(H5F_t * f); +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); + #ifdef H5_HAVE_PARALLEL H5_DLL herr_t H5AC_add_candidate(H5AC_t * cache_ptr, haddr_t addr); #endif /* H5_HAVE_PARALLEL */ diff --git a/src/H5C.c b/src/H5C.c index aed2b90..2ff26e6 100644 --- a/src/H5C.c +++ b/src/H5C.c @@ -163,23 +163,19 @@ static herr_t H5C_tag_entry(H5C_t * cache_ptr, H5C_cache_entry_t * entry_ptr, hid_t dxpl_id); -static herr_t H5C_flush_tagged_entries(H5F_t * f, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id, - H5C_t * cache_ptr, - haddr_t tag); - static herr_t H5C_mark_tagged_entries(H5C_t * cache_ptr, - haddr_t tag); + haddr_t tag, + hbool_t mark_clean); static herr_t H5C_flush_marked_entries(H5F_t * f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, H5C_t * cache_ptr); -#if H5C_DO_TAGGING_SANITY_CHECKS -static herr_t H5C_verify_tag(int id, haddr_t tag); -#endif +static herr_t H5C_evict_marked_entries(H5F_t * f, + hid_t primary_dxpl_id, + hid_t secondary_dxpl_id, + H5C_t * cache_ptr); #if H5C_DO_EXTREME_SANITY_CHECKS static herr_t H5C_validate_lru_list(H5C_t * cache_ptr); @@ -3614,6 +3610,7 @@ H5C_protect(H5F_t * f, void * thing; H5C_cache_entry_t * entry_ptr; haddr_t tag = HADDR_UNDEF; + int globality = -1; H5P_genplist_t *dxpl; /* dataset transfer property list */ void * ret_value; /* Return value */ @@ -3655,31 +3652,6 @@ H5C_protect(H5F_t * f, if(entry_ptr->type != type) HGOTO_ERROR(H5E_CACHE, H5E_BADTYPE, NULL, "incorrect cache entry type") - #if H5C_DO_TAGGING_SANITY_CHECKS - /* The entry is already in the cache, but make sure that the tag value - being passed in via dxpl is still legal. This will ensure that had - the entry NOT been in the cache, tagging was still set up correctly - and it would have received a legal tag value after getting loaded - from disk. */ - - /* Get the dataset transfer property list */ - if(NULL == (dxpl = (H5P_genplist_t *)H5I_object_verify(primary_dxpl_id, H5I_GENPROP_LST))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a property list"); - - /* Get the tag from the DXPL */ - if( (H5P_get(dxpl, "H5AC_metadata_tag", &tag)) < 0 ) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "unable to query property value"); - - /* Verify tag value */ - if (cache_ptr->ignore_tags != TRUE) { - - /* Verify legal tag value */ - if ( (H5C_verify_tag(entry_ptr->type->id, tag)) < 0 ) - HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, NULL, "tag verification failed"); - - } /* end if */ - #endif - hit = TRUE; thing = (void *)entry_ptr; @@ -9165,6 +9137,7 @@ H5C_tag_entry(H5C_t * cache_ptr, H5C_cache_entry_t * entry_ptr, hid_t dxpl_id) { H5P_genplist_t *dxpl; /* dataset transfer property list */ haddr_t tag; /* Tag address */ + int globality; /* Tag globality */ hid_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(H5C_tag_entry, FAIL) @@ -9182,27 +9155,16 @@ H5C_tag_entry(H5C_t * cache_ptr, H5C_cache_entry_t * entry_ptr, hid_t dxpl_id) if((H5P_get(dxpl, "H5AC_metadata_tag", &tag)) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to query property value") - if(cache_ptr->ignore_tags != TRUE) { -#if H5C_DO_TAGGING_SANITY_CHECKS - /* Perform some sanity checks to ensure that a correct tag is being applied */ - if(H5C_verify_tag(entry_ptr->type->id, tag) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "tag verification failed") -#endif - } else { - /* if we're ignoring tags, it's because we're running - tests on internal functions and may not have inserted a tag - value into a given dxpl_id before creating some metadata. Thus, - in this case only, if a tag value has not been set, we can - arbitrarily set it to something for the sake of passing the tests. - If the tag value is set, then we'll just let it get assigned without - additional checking for correctness. */ - if(!tag) - tag = H5AC__IGNORE_TAG; - } /* end if */ + /* Get globality from the DXPL */ + if((H5P_get(dxpl, "H5C_tag_globality", &globality)) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to query property value") /* Apply the tag to the entry */ entry_ptr->tag = tag; + /* Apply the tag globality to the entry */ + entry_ptr->globality = globality; + done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C_tag_entry */ @@ -9212,33 +9174,34 @@ done: * * Function: H5C_flush_tagged_entries * - * WARNING: Not yet tested or used anywhere. (written awhile ago, - * will keep it around in anticipation of being used in - * subsequent changes to support flushing individual objects). - * * Purpose: Flushes all entries with the specified tag to disk. * * Return: FAIL if error is detected, SUCCEED otherwise. * * Programmer: Mike McGreevy - * November 3, 2009 + * August 19, 2010 * *------------------------------------------------------------------------- */ -static herr_t -H5C_flush_tagged_entries(H5F_t * f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, H5C_t * cache_ptr, haddr_t tag) +herr_t +H5C_flush_tagged_entries(H5F_t * f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, haddr_t tag) { + /* Variable Declarations */ + H5C_t *cache_ptr = NULL; + herr_t result; herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI(H5C_flush_tagged_entries, FAIL) /* Assertions */ - HDassert(0); /* This function is not yet used. We shouldn't be in here yet. */ - HDassert(cache_ptr != NULL); - HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + HDassert(f); + HDassert(f->shared); + + /* Get cache pointer */ + cache_ptr = f->shared->cache; /* Mark all entries with specified tag */ - if(H5C_mark_tagged_entries(cache_ptr, tag) < 0) + if ( (result = H5C_mark_tagged_entries(cache_ptr, tag, FALSE)) < 0 ) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't mark tagged entries") /* Flush all marked entries */ @@ -9252,44 +9215,109 @@ done: /*------------------------------------------------------------------------- * - * Function: H5C_mark_tagged_entries + * Function: H5C_evict_tagged_entries + * + * Purpose: Evicts all entries with the specified tag to disk. + * + * Return: FAIL if error is detected, SUCCEED otherwise. + * + * Programmer: Mike McGreevy + * August 19, 2010 + * + *------------------------------------------------------------------------- + */ +herr_t +H5C_evict_tagged_entries(H5F_t * f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, haddr_t tag) +{ + /* Variables */ + H5C_t *cache_ptr = NULL; + herr_t result; + herr_t ret_value = SUCCEED; + + /* Function Enter Macro */ + FUNC_ENTER_NOAPI(H5C_evict_tagged_entries, FAIL) + + /* Assertions */ + HDassert(f); + HDassert(f->shared); + + /* Get cache pointer */ + cache_ptr = f->shared->cache; + + /* Mark all entries with specified tag */ + if ( (result = H5C_mark_tagged_entries(cache_ptr, tag, TRUE)) < 0 ) + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't mark tagged entries") + + /* Evict all marked entries */ + if ( (result = H5C_evict_marked_entries(f, + primary_dxpl_id, + secondary_dxpl_id, + cache_ptr)) < 0 ) + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't evict marked entries") + +done: + + /* Function Leave Macro */ + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5C_evict_tagged_entries */ + + +/*------------------------------------------------------------------------- * - * WARNING: Not yet tested or used anywhere. (written awhile ago, - * will keep it around in anticipation of being used in - * subsequent changes to support flushing individual objects). + * Function: H5C_mark_tagged_entries * - * Purpose: Set the flush marker on entries in the cache that have - * the specified tag. + * Purpose: Set the flush marker on dirty entries in the cache that have + * the specified tag, as well as all globally tagged entries. + * If mark_clean is set, this function will also mark all clean + * entries, indicating they are to be evicted. * * Return: FAIL if error is detected, SUCCEED otherwise. * * Programmer: Mike McGreevy - * November 3, 2009 + * September 9, 2010 * *------------------------------------------------------------------------- */ static herr_t -H5C_mark_tagged_entries(H5C_t * cache_ptr, haddr_t tag) +H5C_mark_tagged_entries(H5C_t * cache_ptr, haddr_t tag, hbool_t mark_clean) { - H5C_cache_entry_t *next_entry_ptr; /* entry pointer */ - unsigned u; /* Local index variable */ + /* Variable Declarations */ + int u; /* Iterator */ + herr_t result; /* Result */ + H5C_cache_entry_t *entry_ptr = NULL; /* entry pointer */ + herr_t ret_value = SUCCEED; /* Return Value */ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5C_mark_tagged_entries) /* Assertions */ - HDassert(0); /* This function is not yet used. We shouldn't be in here yet. */ HDassert(cache_ptr != NULL); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); - /* Iterate through entries, marking those with specified tag. */ + /* Iterate through entries, marking those with specified tag, as + * well as any major global entries which should always be flushed + * when flushing based on tag value */ for(u = 0; u < H5C__HASH_TABLE_LEN; u++) { - next_entry_ptr = cache_ptr->index[u]; - while(next_entry_ptr != NULL) { - if(next_entry_ptr->tag == tag) - next_entry_ptr->flush_marker = TRUE; + entry_ptr = cache_ptr->index[u]; + + while ( entry_ptr != NULL ) { + + if (( entry_ptr->tag == tag ) || + ( entry_ptr->globality == H5C_GLOBALITY_MAJOR)) { + + /* We only want to set the flush marker on entries that + * actually need flushed (i.e., dirty ones), unless + * we've specified otherwise with the mark_clean flag */ + if (entry_ptr->is_dirty || mark_clean) { + + entry_ptr->flush_marker = TRUE; + + } /* end if */ + + } /* end if */ - next_entry_ptr = next_entry_ptr->ht_next; + entry_ptr = entry_ptr->ht_next; } /* end while */ } /* for */ @@ -9301,16 +9329,12 @@ H5C_mark_tagged_entries(H5C_t * cache_ptr, haddr_t tag) * * Function: H5C_flush_marked_entries * - * WARNING: Not yet tested or used anywhere. (written awhile ago, - * will keep it around in anticipation of being used in - * subsequent changes to support flushing individual objects). - * * Purpose: Flushes all marked entries in the cache. * * Return: FAIL if error is detected, SUCCEED otherwise. * * Programmer: Mike McGreevy - * November 3, 2009 + * November 3, 2010 * *------------------------------------------------------------------------- */ @@ -9322,7 +9346,6 @@ H5C_flush_marked_entries(H5F_t * f, hid_t primary_dxpl_id, hid_t secondary_dxpl_ FUNC_ENTER_NOAPI(H5C_flush_marked_entries, FAIL) /* Assertions */ - HDassert(0); /* This function is not yet used. We shouldn't be in here yet. */ HDassert(cache_ptr != NULL); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); @@ -9335,91 +9358,125 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C_flush_marked_entries */ -#if H5C_DO_TAGGING_SANITY_CHECKS /*------------------------------------------------------------------------- * - * Function: H5C_verify_tag + * Function: H5C_evict_marked_entries * - * Purpose: Performs sanity checking on an entrytype/tag pair. + * Purpose: Evicts all marked entries in the cache. * - * Return: SUCCEED or FAIL. + * Return: FAIL if error is detected, SUCCEED otherwise. * * Programmer: Mike McGreevy - * January 14, 2010 + * July 16, 2010 * *------------------------------------------------------------------------- */ static herr_t -H5C_verify_tag(int id, haddr_t tag) -{ +H5C_evict_marked_entries(H5F_t * f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, H5C_t * cache_ptr) +{ + /* Variable Declarations */ + herr_t status; herr_t ret_value = SUCCEED; + H5C_cache_entry_t * entry_ptr = NULL; + H5C_cache_entry_t * next_entry_ptr = NULL; + int i; + hbool_t evicted_entries_last_pass; + hbool_t pinned_entries_need_evicted; + hbool_t first_flush = TRUE; - FUNC_ENTER_NOAPI(H5C_verify_tag, FAIL) + /* Function Enter Macro */ + FUNC_ENTER_NOAPI(H5C_evict_marked_entries, FAIL) - /* Perform some sanity checks on tag value. Certain entry - * types require certain tag values, so check that these - * constraints are met. */ - if(tag == H5AC__IGNORE_TAG) - HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "cannot ignore a tag while doing verification.") - else if(tag == H5AC__INVALID_TAG) - HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "no metadata tag provided") - else { + /* Assertions */ + HDassert( cache_ptr != NULL ); + HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC ); - /* Perform some sanity checks on tag value. Certain entry - * types require certain tag values, so check that these - * constraints are met. */ + /* Start evicting entries */ + do { - /* Superblock */ - if(id == H5AC_SUPERBLOCK_ID) { - if(tag != H5AC__SUPERBLOCK_TAG) - HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "superblock not tagged with H5AC__SUPERBLOCK_TAG") - } - else { - if(tag == H5AC__SUPERBLOCK_TAG) - HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "H5AC__SUPERBLOCK_TAG applied to non-superblock entry") - } - - /* Free Space Manager */ - if((id == H5AC_FSPACE_HDR_ID) || (id == H5AC_FSPACE_SINFO_ID)) { - if(tag != H5AC__FREESPACE_TAG) - HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "freespace entry not tagged with H5AC__FREESPACE_TAG") - } - else { - if(tag == H5AC__FREESPACE_TAG) - HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "H5AC__FREESPACE_TAG applied to non-freespace entry") - } - - /* SOHM */ - if((id == H5AC_SOHM_TABLE_ID) || (id == H5AC_SOHM_LIST_ID)) { - if(tag != H5AC__SOHM_TAG) - HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "sohm entry not tagged with H5AC__SOHM_TAG") - } + /* Reset pinned/evicted trackers */ + pinned_entries_need_evicted = FALSE; + evicted_entries_last_pass = FALSE; + + /* Iterate through entries in the index. */ + for (i = 0; i < H5C__HASH_TABLE_LEN; i++) { + + next_entry_ptr = cache_ptr->index[i]; + + while ( next_entry_ptr != NULL ) { + + entry_ptr = next_entry_ptr; + next_entry_ptr = entry_ptr->ht_next; + + if ( entry_ptr->flush_marker == TRUE ) { + + /* This entry will need to be evicted */ + + if ( entry_ptr->is_protected ) { + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Cannot evict protected entry"); + } else if (entry_ptr->is_dirty) { + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Cannot evict dirty entry"); + } else if (entry_ptr->is_pinned) { + + /* Can't evict at this time, but let's note that we hit a pinned + entry and we'll loop back around again (as evicting other + entries will hopefully unpin this entry) */ - /* Global Heap */ - if(id == H5AC_GHEAP_ID) { - if(tag != H5AC__GLOBALHEAP_TAG) - HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "global heap not tagged with H5AC__GLOBALHEAP_TAG") - } - else { - if(tag == H5AC__GLOBALHEAP_TAG) - HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "H5AC__GLOBALHEAP_TAG applied to non-globalheap entry") - } - } /* end else */ + pinned_entries_need_evicted = TRUE; + + } else { + + /* Evict the Entry */ + + status = H5C_flush_single_entry(f, + primary_dxpl_id, + secondary_dxpl_id, + entry_ptr->type, + entry_ptr->addr, + H5C__FLUSH_INVALIDATE_FLAG | H5C__FLUSH_CLEAR_ONLY_FLAG, + &first_flush, + TRUE); + + if ( status < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "Entry eviction failed.") + + } + + evicted_entries_last_pass = TRUE; + + } /* end if */ + + } /* end if */ + + } /* end while */ + + } /* end for */ + + /* Keep doing this until we have stopped evicted entries */ + } while ((evicted_entries_last_pass == TRUE)); + + /* If we stop evicting entries and pinned entries still need evicted, + then we have a problem. */ + if (pinned_entries_need_evicted) { + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Pinned entries still need evicted?!"); + } /* end if */ done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5C_verify_tag */ -#endif + FUNC_LEAVE_NOAPI(ret_value); + +} /* H5C_evict_marked_entries */ /*------------------------------------------------------------------------- * - * Function: H5C_retag_copied_metadata + * Function: H5C_retag_metadata * * Purpose: Searches through cache index for all entries with the - * H5AC__COPIED_TAG, indicating that it was created as a - * result of an object copy, and applies the provided tag. + * value specified by src_tag and changes it to the value + * specified by dest_tag. * * Return: SUCCEED or FAIL. * @@ -9429,29 +9486,26 @@ done: *------------------------------------------------------------------------- */ void -H5C_retag_copied_metadata(H5C_t * cache_ptr, haddr_t metadata_tag) +H5C_retag_metadata(H5C_t * cache_ptr, haddr_t src_tag, haddr_t dest_tag) { unsigned u; /* Local index variable */ + H5C_cache_entry_t *entry_ptr = NULL; /* entry pointer */ - FUNC_ENTER_NOAPI_NOFUNC(H5C_retag_copied_metadata) - - HDassert(cache_ptr); + FUNC_ENTER_NOAPI_NOFUNC(H5C_retag_metadata) - /* Iterate through entries, retagging those with the H5AC__COPIED_TAG tag */ + /* Iterate through entries, retagging those with the src_tag tag */ for(u = 0; u < H5C__HASH_TABLE_LEN; u++) { - H5C_cache_entry_t *next_entry_ptr; /* entry pointer */ - - next_entry_ptr = cache_ptr->index[u]; - while(next_entry_ptr != NULL) { + entry_ptr = cache_ptr->index[u]; + while(entry_ptr != NULL) { if(cache_ptr->index[u] != NULL) { - if((cache_ptr->index[u])->tag == H5AC__COPIED_TAG) - (cache_ptr->index[u])->tag = metadata_tag; + if((cache_ptr->index[u])->tag == src_tag) { + (cache_ptr->index[u])->tag = dest_tag; + } } /* end if */ - - next_entry_ptr = next_entry_ptr->ht_next; + entry_ptr = entry_ptr->ht_next; } /* end while */ } /* end for */ FUNC_LEAVE_NOAPI_VOID -} /* H5C_retag_copied_metadata */ +} /* H5C_retag_metadata */ diff --git a/src/H5Cprivate.h b/src/H5Cprivate.h index 0c7631a..06f110b 100644 --- a/src/H5Cprivate.h +++ b/src/H5Cprivate.h @@ -88,11 +88,19 @@ #endif /* H5_HAVE_PARALLEL */ - /* Typedef for the main structure for the cache (defined in H5Cpkg.h) */ typedef struct H5C_t H5C_t; +/* Define metadata tag 'globality' values */ +#define H5C_GLOBALITY_NONE 0 +#define H5C_GLOBALITY_MINOR 1 +#define H5C_GLOBALITY_MAJOR 2 + +/* Definitions for metadata tag 'globality' property */ +#define H5C_GLOBALITY_NAME "H5C_tag_globality" +#define H5C_GLOBALITY_SIZE sizeof(int) +#define H5C_GLOBALITY_DEF H5C_GLOBALITY_NONE /* * Class methods pertaining to caching. Each type of cached object will @@ -579,6 +587,7 @@ typedef struct H5C_cache_entry_t size_t size; const H5C_class_t * type; haddr_t tag; + int globality; hbool_t is_dirty; hbool_t dirtied; hbool_t is_protected; @@ -1092,6 +1101,16 @@ H5_DLL herr_t H5C_flush_cache(H5F_t * f, hid_t secondary_dxpl_id, unsigned flags); +H5_DLL herr_t H5C_flush_tagged_entries(H5F_t * f, + hid_t primary_dxpl_id, + hid_t secondary_dxpl_id, + haddr_t tag); + +H5_DLL herr_t H5C_evict_tagged_entries(H5F_t * f, + hid_t primary_dxpl_id, + hid_t secondary_dxpl_id, + haddr_t tag); + H5_DLL herr_t H5C_flush_to_min_clean(H5F_t * f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id); @@ -1200,7 +1219,7 @@ H5_DLL herr_t H5C_validate_resize_config(H5C_auto_size_ctl_t * config_ptr, H5_DLL herr_t H5C_ignore_tags(H5C_t * cache_ptr); -H5_DLL void H5C_retag_copied_metadata(H5C_t * cache_ptr, haddr_t metadata_tag); +H5_DLL void H5C_retag_metadata(H5C_t * cache_ptr, haddr_t src_tag, haddr_t dest_tag); #endif /* !_H5Cprivate_H */ diff --git a/src/H5D.c b/src/H5D.c index 667fe1fb..c0966af 100644 --- a/src/H5D.c +++ b/src/H5D.c @@ -1100,4 +1100,72 @@ H5Dset_extent(hid_t dset_id, const hsize_t size[]) done: FUNC_LEAVE_API(ret_value) } /* end H5Dset_extent() */ + + +/*------------------------------------------------------------------------- + * Function: H5Dflush + * + * Purpose: Flushes all buffers associated with a dataset. + * + * Return: Non-negative on success, negative on failure + * + * Programmer: Mike McGreevy + * May 19, 2010 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Dflush(hid_t dset_id) +{ + H5D_t *dset; /* Dataset for this operation */ + herr_t ret_value = SUCCEED; /* return value */ + + FUNC_ENTER_API(H5Dflush, FAIL) + H5TRACE1("e", "i", dset_id); + + /* Check args */ + if(NULL == (dset = (H5D_t *)H5I_object_verify(dset_id, H5I_DATASET))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset") + + /* Call private function to flush dataset object */ + if (H5O_flush_metadata(&dset->oloc, H5AC_dxpl_id) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to flush dataset") + +done: + FUNC_LEAVE_API(ret_value) +} /* H5Dflush */ + + +/*------------------------------------------------------------------------- + * Function: H5Drefresh + * + * Purpose: Refreshes all buffers associated with a dataset. + * + * Return: Non-negative on success, negative on failure + * + * Programmer: Mike McGreevy + * July 21, 2010 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Drefresh(hid_t dset_id) +{ + H5D_t * dset = NULL; + hid_t ret_value = SUCCEED; /* return value */ + + FUNC_ENTER_API(H5Drefresh, FAIL) + H5TRACE1("e", "i", dset_id); + + /* Check args */ + if(NULL == (dset = (H5D_t *)H5I_object_verify(dset_id, H5I_DATASET))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset") + + /* Call private function to refresh dataset object */ + if ((H5O_refresh_metadata(dset_id, dset->oloc, H5AC_dxpl_id)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTLOAD, FAIL, "unable to refresh dataset") + +done: + FUNC_LEAVE_API(ret_value) +} /* H5Drefresh */ diff --git a/src/H5Dpublic.h b/src/H5Dpublic.h index f4c62c9..900046a 100644 --- a/src/H5Dpublic.h +++ b/src/H5Dpublic.h @@ -132,6 +132,8 @@ H5_DLL herr_t H5Dvlen_get_buf_size(hid_t dataset_id, hid_t type_id, hid_t space_ H5_DLL herr_t H5Dfill(const void *fill, hid_t fill_type, void *buf, hid_t buf_type, hid_t space); H5_DLL herr_t H5Dset_extent(hid_t dset_id, const hsize_t size[]); +H5_DLL herr_t H5Dflush(hid_t dset_id); +H5_DLL herr_t H5Drefresh(hid_t dset_id); H5_DLL herr_t H5Ddebug(hid_t dset_id); /* Symbols defined for compatibility with previous versions of the HDF5 API. diff --git a/src/H5Fio.c b/src/H5Fio.c index 231c4c9..2a456f1 100644 --- a/src/H5Fio.c +++ b/src/H5Fio.c @@ -159,3 +159,78 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5F_block_write() */ + +/*------------------------------------------------------------------------- + * Function: H5F_flush_tagged_metadata + * + * Purpose: Flushes metadata with specified tag in the metadata cache + * to disk. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Mike McGreevy + * September 9, 2010 + * + *------------------------------------------------------------------------- + */ +herr_t +H5F_flush_tagged_metadata(H5F_t * f, haddr_t tag, hid_t dxpl_id) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5F_flush_tagged_metadata, FAIL) + + /* Use tag to search for and flush associated metadata */ + if(H5AC_flush_tagged_metadata(f, tag, dxpl_id)<0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush tagged metadata") + + /* Flush out the metadata accumulator */ + if(H5F_accum_flush(f, dxpl_id) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTFLUSH, FAIL, "unable to flush metadata accumulator") + + /* Flush file buffers to disk. */ + if(H5FD_flush(f->shared->lf, dxpl_id, FALSE) < 0) + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "low level flush failed") + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5F_flush_tagged_metadata */ + + +/*------------------------------------------------------------------------- + * Function: H5F_evict_tagged_metadata + * + * Purpose: Evicts metadata from the cache with specified tag. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Mike McGreevy + * September 9, 2010 + * + *------------------------------------------------------------------------- + */ +herr_t +H5F_evict_tagged_metadata(H5F_t * f, haddr_t tag, hid_t dxpl_id) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5F_evict_tagged_metadata, FAIL) + + /* Unpin the superblock, as this will be marked for eviction and it can't + be pinned. */ + if(H5AC_unpin_entry(f->shared->sblock) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPIN, FAIL, "unable to unpin superblock") + f->shared->sblock = NULL; + + /* Evict the object's metadata */ + if(H5AC_evict_tagged_metadata(f, tag, dxpl_id)<0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTEXPUNGE, FAIL, "unable to evict tagged metadata") + + /* Re-read the superblock. */ + if (H5F_super_read(f, dxpl_id) < 0) + HGOTO_ERROR(H5E_FILE, H5E_READERROR, FAIL, "unable to read superblock") + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5F_evict_tagged_metadata */ + diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h index 2952bac..a07e7ce 100644 --- a/src/H5Fprivate.h +++ b/src/H5Fprivate.h @@ -525,6 +525,10 @@ H5_DLL herr_t H5F_block_read(const H5F_t *f, H5FD_mem_t type, haddr_t addr, H5_DLL herr_t H5F_block_write(const H5F_t *f, H5FD_mem_t type, haddr_t addr, size_t size, hid_t dxpl_id, const void *buf); +/* Functions that flush or evict */ +H5_DLL herr_t H5F_flush_tagged_metadata(H5F_t * f, haddr_t tag, hid_t dxpl_id); +H5_DLL herr_t H5F_evict_tagged_metadata(H5F_t * f, haddr_t tag, hid_t dxpl_id); + /* Address-related functions */ H5_DLL void H5F_addr_encode(const H5F_t *f, uint8_t **pp, haddr_t addr); H5_DLL void H5F_addr_encode_len(size_t addr_len, uint8_t **pp, haddr_t addr); diff --git a/src/H5G.c b/src/H5G.c index 6da8ec6..c6210bc 100644 --- a/src/H5G.c +++ b/src/H5G.c @@ -1902,4 +1902,72 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5G_visit() */ + + +/*------------------------------------------------------------------------- + * Function: H5Gflush + * + * Purpose: Flushes all buffers associated with a group to disk. + * + * Return: Non-negative on success, negative on failure + * + * Programmer: Mike McGreevy + * May 19, 2010 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Gflush(hid_t group_id) +{ + H5G_t *grp; /* Dataset for this operation */ + herr_t ret_value = SUCCEED; /* return value */ + + FUNC_ENTER_API(H5Gflush, FAIL) + H5TRACE1("e", "i", group_id); + + /* Check args */ + if(NULL == (grp = (H5G_t *)H5I_object_verify(group_id, H5I_GROUP))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a group") + + /* Call private function to flush group object */ + if (H5O_flush_metadata(&grp->oloc, H5AC_dxpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_CANTFLUSH, FAIL, "unable to flush group") + +done: + FUNC_LEAVE_API(ret_value) +} /* H5Gflush */ + + +/*------------------------------------------------------------------------- + * Function: H5Grefresh + * + * Purpose: Refreshes all buffers associated with a dataset. + * + * Return: Non-negative on success, negative on failure + * + * Programmer: Mike McGreevy + * July 21, 2010 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Grefresh(hid_t group_id) +{ + H5G_t * grp = NULL; + hid_t ret_value = SUCCEED; /* return value */ + + FUNC_ENTER_API(H5Grefresh, FAIL) + H5TRACE1("e", "i", group_id); + + /* Check args */ + if(NULL == (grp = (H5G_t *)H5I_object_verify(group_id, H5I_GROUP))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a group") + + /* Call private function to refresh group object */ + if ((H5O_refresh_metadata(group_id, grp->oloc, H5AC_dxpl_id)) < 0) + HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, FAIL, "unable to refresh group") + +done: + FUNC_LEAVE_API(ret_value) +} /* H5Grefresh */ diff --git a/src/H5Gpublic.h b/src/H5Gpublic.h index 5b8b054..10b07c0 100644 --- a/src/H5Gpublic.h +++ b/src/H5Gpublic.h @@ -167,6 +167,8 @@ H5_DLL herr_t H5Gget_objinfo(hid_t loc_id, const char *name, hbool_t follow_link, H5G_stat_t *statbuf/*out*/); H5_DLL ssize_t H5Gget_objname_by_idx(hid_t loc_id, hsize_t idx, char* name, size_t size); +H5_DLL herr_t H5Gflush(hid_t group_id); +H5_DLL herr_t H5Grefresh(hid_t group_id); H5_DLL H5G_obj_t H5Gget_objtype_by_idx(hid_t loc_id, hsize_t idx); #endif /* H5_NO_DEPRECATED_SYMBOLS */ diff --git a/src/H5I.c b/src/H5I.c index d87e89b..48d888c 100644 --- a/src/H5I.c +++ b/src/H5I.c @@ -884,6 +884,83 @@ done: /*------------------------------------------------------------------------- + * Function: H5I_register_with_id + * + * Purpose: Registers an OBJECT in a TYPE with the supplied ID for it. + * This routine will check to ensure the supplied ID is not already + * in use, and ensure that it is a valid ID for the given type, + * but will NOT check to ensure the OBJECT is not already + * registered (thus, it is possible to register one object under + * multiple IDs). + * + * Return: Success: 0 + * Failure: -1 + * + * Programmer: Mike McGreevy + * Wednesday, July 21, 2010 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5I_register_with_id(H5I_type_t type, const void *object, hbool_t app_ref, hid_t id) +{ + H5I_id_type_t *type_ptr; /*ptr to the type */ + H5I_id_info_t *id_ptr; /*ptr to the new ID information */ + unsigned hash_loc; /*new item's hash table location*/ + hid_t ret_value = SUCCEED; /*return value */ + + FUNC_ENTER_NOAPI(H5I_register_with_id, FAIL) + + /* Check arguments */ + + /* Make sure ID is not already in use */ + if(NULL != (id_ptr = H5I_find_id(id))) + HGOTO_ERROR(H5E_ATOM, H5E_BADRANGE, FAIL, "ID already in use?!") + + /* Make sure type number is valid */ + if(type <= H5I_BADID || type >= H5I_next_type) + HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number") + + /* Get type pointer from list of types */ + type_ptr = H5I_id_type_list_g[type]; + + if(NULL == type_ptr || type_ptr->count <= 0) + HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "invalid type") + + /* Make sure requested ID belongs to object's type */ + if(H5I_TYPE(id) != type) + HGOTO_ERROR(H5E_ATOM, H5E_BADRANGE, FAIL, "invalid type for provided ID") + + /* Allocate new structure to house this ID */ + if(NULL == (id_ptr = H5FL_MALLOC(H5I_id_info_t))) + HGOTO_ERROR(H5E_ATOM, H5E_NOSPACE, FAIL, "memory allocation failed") + + /* Create the struct & insert requested ID */ + id_ptr->id = id; + id_ptr->count = 1; /*initial reference count*/ + id_ptr->app_count = !!app_ref; + id_ptr->obj_ptr = object; + id_ptr->next = NULL; + + /* determine hash bucket location to store id */ + hash_loc = id % (unsigned)type_ptr->hash_size; + + /* hash bucket already full, prepend to front of chain */ + if(type_ptr->id_list[hash_loc] != NULL) + id_ptr->next = type_ptr->id_list[hash_loc]; + + /* Insert into the type */ + type_ptr->id_list[hash_loc] = id_ptr; + type_ptr->ids++; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5I_register_with_id() */ + + +/*------------------------------------------------------------------------- * Function: H5I_subst * * Purpose: Substitute a new object pointer for the specified ID. diff --git a/src/H5Iprivate.h b/src/H5Iprivate.h index 98423df..7b93d39 100644 --- a/src/H5Iprivate.h +++ b/src/H5Iprivate.h @@ -55,6 +55,7 @@ H5_DLL int H5I_nmembers(H5I_type_t type); H5_DLL herr_t H5I_clear_type(H5I_type_t type, hbool_t force, hbool_t app_ref); H5_DLL int H5I_destroy_type(H5I_type_t type); H5_DLL hid_t H5I_register(H5I_type_t type, const void *object, hbool_t app_ref); +H5_DLL herr_t H5I_register_with_id(H5I_type_t type, const void *object, hbool_t app_ref, hid_t id); H5_DLL void *H5I_subst(hid_t id, const void *new_object); H5_DLL void *H5I_object(hid_t id); H5_DLL void *H5I_object_verify(hid_t id, H5I_type_t id_type); diff --git a/src/H5Oflush.c b/src/H5Oflush.c new file mode 100644 index 0000000..2b9bd40 --- /dev/null +++ b/src/H5Oflush.c @@ -0,0 +1,291 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*------------------------------------------------------------------------- + * + * Created: H5Oflush.c + * Aug 19, 2010 + * Mike McGreevy + * + * Purpose: Object flush/refresh routines. + * + *------------------------------------------------------------------------- + */ + +/****************/ +/* Module Setup */ +/****************/ + +#define H5F_PACKAGE /* suppress error about including H5Fpkg */ +#define H5O_PACKAGE /* suppress error about including H5Opkg */ + +/***********/ +/* Headers */ +/***********/ + +#include "H5Dprivate.h" /* Datasets */ +#include "H5Eprivate.h" /* Errors */ +#include "H5Fpkg.h" /* Files */ +#include "H5Opkg.h" /* Objects */ + +/*************/ +/* Functions */ +/*************/ + + +/*------------------------------------------------------------------------- + * Function: H5Oflush + * + * Purpose: Flushes all buffers associated with an object to disk. + * + * Return: Non-negative on success, negative on failure + * + * Programmer: Mike McGreevy + * May 19, 2010 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Oflush(hid_t obj_id) +{ + H5O_loc_t *oloc; /* object location */ + herr_t ret_value = SUCCEED; /* return value */ + + FUNC_ENTER_API(H5Oflush, FAIL) + H5TRACE1("e", "i", obj_id); + + /* Check args */ + if((oloc = H5O_get_loc(obj_id)) == NULL) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an object") + + /* Private function */ + if (H5O_flush_metadata(oloc, H5AC_dxpl_id) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to flush object") + +done: + FUNC_LEAVE_API(ret_value) +} /* H5Oflush */ + + +/*------------------------------------------------------------------------- + * Function: H5O_flush_metadata + * + * Purpose: Flush any metadata associated with this object. + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Mike McGreevy + * May 19, 2010 + * + *------------------------------------------------------------------------- + */ +herr_t +H5O_flush_metadata(const H5O_loc_t *oloc, hid_t dxpl_id) +{ + H5O_t *oh = NULL; /* Object header */ + herr_t ret_value = SUCCEED; /* Return value */ + haddr_t tag = 0; + + FUNC_ENTER_NOAPI(H5O_flush_metadata, FAIL) + + /* Check args */ + HDassert(oloc); + + /* Get object header for object */ + if(NULL == (oh = H5O_protect(oloc, dxpl_id, H5AC_READ))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object's object header") + + /* Get object header's address (i.e. the tag value for this object) */ + if (HADDR_UNDEF == (tag = H5O_OH_GET_ADDR(oh))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to get address of object header") + + /* Unprotect object header before attempting to flush it */ + if(oh && H5O_unprotect(oloc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") + + /* Reset object header pointer */ + oh = NULL; + + /* Flush metadata based on tag value of the object */ + if (H5F_flush_tagged_metadata(oloc->file, tag, dxpl_id)<0) + HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush tagged metadata") + +done: + /* Unprotect object header on failure */ + if(oh && H5O_unprotect(oloc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_flush_metadata() */ + + +/*------------------------------------------------------------------------- + * Function: H5Orefresh + * + * Purpose: Refreshes all buffers associated with an object. + * + * Return: Non-negative on success, negative on failure + * + * Programmer: Mike McGreevy + * July 28, 2010 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Orefresh(hid_t oid) +{ + H5O_loc_t *oloc; /* object location */ + hid_t ret_value = SUCCEED; /* return value */ + + FUNC_ENTER_API(H5Orefresh, FAIL) + H5TRACE1("e", "i", oid); + + /* Check args */ + if((oloc = H5O_get_loc(oid)) == NULL) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an object") + + /* Private function */ + if ((H5O_refresh_metadata(oid, *oloc, H5AC_dxpl_id)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTLOAD, FAIL, "unable to refresh object") + +done: + FUNC_LEAVE_API(ret_value) +} /* H5Orefresh */ + + +/*------------------------------------------------------------------------- + * Function: H5O_refresh_metadata + * + * Purpose: Internal routine that refreshes all buffers associated with + * an object. + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Mike McGreevy + * July 28, 2010 + * + *------------------------------------------------------------------------- + */ +herr_t +H5O_refresh_metadata(hid_t oid, H5O_loc_t oloc, hid_t dxpl_id) +{ + void *object = NULL; /* Dataset for this operation */ + haddr_t tag = 0; + H5O_t *oh = NULL; + H5G_loc_t obj_loc; + H5G_loc_t tmp_loc; + H5G_name_t obj_path; + H5O_loc_t obj_oloc; + hid_t ret_value = SUCCEED; + H5I_type_t type; + + FUNC_ENTER_NOAPI(H5O_refresh_metadata, FAIL) + + /* Get the object's object header */ + if(NULL == (oh = H5O_protect(&oloc, dxpl_id, H5AC_READ))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object's object header") + + /* Get object's type */ + type = H5I_get_type(oid); + + /* Make deep local copy of object's location information */ + H5G_loc(oid, &tmp_loc); + obj_loc.oloc = &obj_oloc; + obj_loc.path = &obj_path; + H5G_loc_reset(&obj_loc); + H5G_loc_copy(&obj_loc, &tmp_loc, H5_COPY_DEEP); + + /* Get object header's address (i.e. the tag value for this object) */ + if (HADDR_UNDEF == (tag = H5O_OH_GET_ADDR(oh))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to get address of object header") + + /* Get object's type */ + type = H5I_get_type(oid); + + /* Unprotect object header before attempting to flush it */ + if(oh && H5O_unprotect(&oloc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") + + /* Reset object header pointer */ + oh = NULL; + + /* Close the object */ + if(H5I_dec_ref(oid, TRUE) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to close object") + + /* Flush the object's metadata before evicting it */ + if (H5O_flush_metadata(&oloc, dxpl_id) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to flush object's metadata") + + /* Evict the object's tagged metadata */ + if (H5F_evict_tagged_metadata(oloc.file, tag, dxpl_id)<0) + HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to evict metadata") + + switch (type) + { + case(H5I_GROUP): + + /* Re-open the group */ + if(NULL == (object = H5G_open(&obj_loc, dxpl_id))) + HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open group") + break; + + case(H5I_DATATYPE): + + /* Re-open the named datatype */ + if(NULL == (object = H5T_open(&obj_loc, dxpl_id))) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTOPENOBJ, FAIL, "unable to open named datatype") + break; + + case(H5I_DATASET): + + /* Re-open the dataset */ + if(NULL == (object = H5D_open(&obj_loc, H5P_DATASET_ACCESS_DEFAULT, dxpl_id))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open dataset") + break; + + case(H5I_UNINIT): + case(H5I_BADID): + case(H5I_FILE): + case(H5I_DATASPACE): + case(H5I_ATTR): + case(H5I_REFERENCE): + case(H5I_VFL): + case(H5I_GENPROP_CLS): + case(H5I_GENPROP_LST): + case(H5I_ERROR_CLASS): + case(H5I_ERROR_MSG): + case(H5I_ERROR_STACK): + case(H5I_NTYPES): + default: + HGOTO_ERROR(H5E_ARGS, H5E_CANTRELEASE, FAIL, "not a valid file object ID (dataset, group, or datatype)") + break; + + } /* end switch */ + + /* Re-register ID for the object */ + if((H5I_register_with_id(type, object, TRUE, oid)) < 0) + HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to re-register object atom") + +done: + /* Unprotect object header on failure */ + if(oh && H5O_unprotect(&oloc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") + + FUNC_LEAVE_NOAPI(ret_value); +} /* H5O_refresh_metadata */ + diff --git a/src/H5Oprivate.h b/src/H5Oprivate.h index b4d0e8d..19d22a6 100644 --- a/src/H5Oprivate.h +++ b/src/H5Oprivate.h @@ -792,6 +792,10 @@ H5_DLL int H5O_msg_get_chunkno(const H5O_loc_t *loc, unsigned type_id, hid_t dxp H5_DLL herr_t H5O_msg_lock(const H5O_loc_t *loc, unsigned type_id, hid_t dxpl_id); H5_DLL herr_t H5O_msg_unlock(const H5O_loc_t *loc, unsigned type_id, hid_t dxpl_id); +/* Object metadata flush/evict routines */ +H5_DLL herr_t H5O_flush_metadata(const H5O_loc_t *oloc, hid_t dxpl_id); +H5_DLL herr_t H5O_refresh_metadata(hid_t oid, H5O_loc_t oloc, hid_t dxpl_id); + /* Object copying routines */ H5_DLL herr_t H5O_copy_header_map(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */, hid_t dxpl_id, H5O_copy_t *cpy_info, hbool_t inc_depth, diff --git a/src/H5Opublic.h b/src/H5Opublic.h index c5ae3c1..d9e38fc 100644 --- a/src/H5Opublic.h +++ b/src/H5Opublic.h @@ -173,6 +173,8 @@ H5_DLL herr_t H5Ovisit_by_name(hid_t loc_id, const char *obj_name, H5_index_t idx_type, H5_iter_order_t order, H5O_iterate_t op, void *op_data, hid_t lapl_id); H5_DLL herr_t H5Oclose(hid_t object_id); +H5_DLL herr_t H5Oflush(hid_t obj_id); +H5_DLL herr_t H5Orefresh(hid_t oid); /* Symbols defined for compatibility with previous versions of the HDF5 API. * diff --git a/src/H5Pdxpl.c b/src/H5Pdxpl.c index 042951e..054ec6a 100644 --- a/src/H5Pdxpl.c +++ b/src/H5Pdxpl.c @@ -195,7 +195,8 @@ H5P_dxfr_reg_prop(H5P_genclass_t *pclass) hid_t def_vfl_id = H5D_XFER_VFL_ID_DEF; /* Default value for file driver ID */ void *def_vfl_info = H5D_XFER_VFL_INFO_DEF; /* Default value for file driver info */ size_t def_hyp_vec_size = H5D_XFER_HYPER_VECTOR_SIZE_DEF; /* Default value for vector size */ - haddr_t metadata_tag = H5AC_METADATA_TAG_DEF; /* Default value for metadata tag */ + haddr_t metadata_tag = H5AC_METADATA_TAG_DEF; /* Default value for metadata tag */ + int globality = H5C_GLOBALITY_DEF; /* Default value for metadata tag globality value */ #ifdef H5_HAVE_PARALLEL H5FD_mpio_xfer_t def_io_xfer_mode = H5D_XFER_IO_XFER_MODE_DEF; /* Default value for I/O transfer mode */ H5FD_mpio_chunk_opt_t def_mpio_chunk_opt_mode = H5D_XFER_MPIO_CHUNK_OPT_HARD_DEF; @@ -219,6 +220,10 @@ H5P_dxfr_reg_prop(H5P_genclass_t *pclass) if(H5P_register_real(pclass, H5AC_METADATA_TAG_NAME, H5AC_METADATA_TAG_SIZE, &metadata_tag, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class") + /* Register the tag globality property */ + if(H5P_register_real(pclass, H5C_GLOBALITY_NAME, H5C_GLOBALITY_SIZE, &globality, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class") + /* Register the type conversion buffer property */ if(H5P_register_real(pclass, H5D_XFER_TCONV_BUF_NAME, H5D_XFER_TCONV_BUF_SIZE, &def_tconv_buf, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class") diff --git a/src/H5T.c b/src/H5T.c index 1f962f0..130921c 100644 --- a/src/H5T.c +++ b/src/H5T.c @@ -5273,3 +5273,71 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5T_set_latest_version() */ + +/*------------------------------------------------------------------------- + * Function: H5Tflush + * + * Purpose: Flushes all buffers associated with a named datatype to disk. + * + * Return: Non-negative on success, negative on failure + * + * Programmer: Mike McGreevy + * May 19, 2010 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Tflush(hid_t type_id) +{ + H5T_t *dt; /* Datatype for this operation */ + herr_t ret_value = SUCCEED; /* return value */ + + FUNC_ENTER_API(H5Tflush, FAIL) + H5TRACE1("e", "i", type_id); + + /* Check args */ + if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype") + + /* Call private function to flush datatype object */ + if (H5O_flush_metadata(&dt->oloc, H5AC_dxpl_id) < 0) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTFLUSH, FAIL, "unable to flush datatype") + +done: + FUNC_LEAVE_API(ret_value) +} /* H5Tflush */ + + +/*------------------------------------------------------------------------- + * Function: H5Trefresh + * + * Purpose: Refreshes all buffers associated with a named datatype. + * + * Return: Non-negative on success, negative on failure + * + * Programmer: Mike McGreevy + * July 21, 2010 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Trefresh(hid_t type_id) +{ + H5T_t * dt = NULL; + hid_t ret_value = SUCCEED; /* return value */ + + FUNC_ENTER_API(H5Trefresh, FAIL) + H5TRACE1("e", "i", type_id); + + /* Check args */ + if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype") + + /* Call private function to refresh datatype object */ + if ((H5O_refresh_metadata(type_id, dt->oloc, H5AC_dxpl_id)) < 0) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTLOAD, FAIL, "unable to refresh datatype") + +done: + FUNC_LEAVE_API(ret_value) +} /* H5Trefresh */ + diff --git a/src/H5Tpublic.h b/src/H5Tpublic.h index d646ef1..df7ad41 100644 --- a/src/H5Tpublic.h +++ b/src/H5Tpublic.h @@ -511,6 +511,8 @@ H5_DLL hid_t H5Tget_create_plist(hid_t type_id); H5_DLL htri_t H5Tcommitted(hid_t type_id); H5_DLL herr_t H5Tencode(hid_t obj_id, void *buf, size_t *nalloc); H5_DLL hid_t H5Tdecode(const void *buf); +H5_DLL herr_t H5Tflush(hid_t type_id); +H5_DLL herr_t H5Trefresh(hid_t type_id); /* Operations defined on compound datatypes */ H5_DLL herr_t H5Tinsert(hid_t parent_id, const char *name, size_t offset, diff --git a/src/Makefile.am b/src/Makefile.am index 6f93c4e..b55c6eb 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -78,7 +78,7 @@ libhdf5_la_SOURCES= H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \ H5O.c H5Oainfo.c H5Oalloc.c H5Oattr.c \ H5Oattribute.c H5Obogus.c H5Obtreek.c H5Ocache.c H5Ochunk.c \ H5Ocont.c H5Ocopy.c H5Odbg.c H5Odrvinfo.c H5Odtype.c H5Oefl.c \ - H5Ofill.c H5Ofsinfo.c H5Oginfo.c \ + H5Ofill.c H5Oflush.c H5Ofsinfo.c H5Oginfo.c \ H5Olayout.c \ H5Olinfo.c H5Olink.c H5Omessage.c H5Omtime.c \ H5Oname.c H5Onull.c H5Opline.c H5Orefcount.c \ diff --git a/src/Makefile.in b/src/Makefile.in index 153e286..e2f3153 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -129,15 +129,15 @@ am_libhdf5_la_OBJECTS = H5.lo H5checksum.lo H5dbg.lo H5system.lo \ H5Oainfo.lo H5Oalloc.lo H5Oattr.lo H5Oattribute.lo H5Obogus.lo \ H5Obtreek.lo H5Ocache.lo H5Ochunk.lo H5Ocont.lo H5Ocopy.lo \ H5Odbg.lo H5Odrvinfo.lo H5Odtype.lo H5Oefl.lo H5Ofill.lo \ - H5Ofsinfo.lo H5Oginfo.lo H5Olayout.lo H5Olinfo.lo H5Olink.lo \ - H5Omessage.lo H5Omtime.lo H5Oname.lo H5Onull.lo H5Opline.lo \ - H5Orefcount.lo H5Osdspace.lo H5Oshared.lo H5Oshmesg.lo \ - H5Ostab.lo H5Ostorage.lo H5Otest.lo H5Ounknown.lo H5P.lo \ - H5Pacpl.lo H5Pdapl.lo H5Pdcpl.lo H5Pdeprec.lo H5Pdxpl.lo \ - H5Pfapl.lo H5Pfcpl.lo H5Pfmpl.lo H5Pgcpl.lo H5Pint.lo \ - H5Plapl.lo H5Plcpl.lo H5Pocpl.lo H5Pocpypl.lo H5Pstrcpl.lo \ - H5Ptest.lo H5R.lo H5Rdeprec.lo H5RC.lo H5RS.lo H5S.lo \ - H5Sall.lo H5Sdbg.lo H5Shyper.lo H5Smpio.lo H5Snone.lo \ + H5Oflush.lo H5Ofsinfo.lo H5Oginfo.lo H5Olayout.lo H5Olinfo.lo \ + H5Olink.lo H5Omessage.lo H5Omtime.lo H5Oname.lo H5Onull.lo \ + H5Opline.lo H5Orefcount.lo H5Osdspace.lo H5Oshared.lo \ + H5Oshmesg.lo H5Ostab.lo H5Ostorage.lo H5Otest.lo H5Ounknown.lo \ + H5P.lo H5Pacpl.lo H5Pdapl.lo H5Pdcpl.lo H5Pdeprec.lo \ + H5Pdxpl.lo H5Pfapl.lo H5Pfcpl.lo H5Pfmpl.lo H5Pgcpl.lo \ + H5Pint.lo H5Plapl.lo H5Plcpl.lo H5Pocpl.lo H5Pocpypl.lo \ + H5Pstrcpl.lo H5Ptest.lo H5R.lo H5Rdeprec.lo H5RC.lo H5RS.lo \ + H5S.lo H5Sall.lo H5Sdbg.lo H5Shyper.lo H5Smpio.lo H5Snone.lo \ H5Spoint.lo H5Sselect.lo H5Stest.lo H5SL.lo H5SM.lo \ H5SMbtree2.lo H5SMcache.lo H5SMmessage.lo H5SMtest.lo H5ST.lo \ H5T.lo H5Tarray.lo H5Tbit.lo H5Tcommit.lo H5Tcompound.lo \ @@ -510,7 +510,7 @@ libhdf5_la_SOURCES = H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \ H5O.c H5Oainfo.c H5Oalloc.c H5Oattr.c \ H5Oattribute.c H5Obogus.c H5Obtreek.c H5Ocache.c H5Ochunk.c \ H5Ocont.c H5Ocopy.c H5Odbg.c H5Odrvinfo.c H5Odtype.c H5Oefl.c \ - H5Ofill.c H5Ofsinfo.c H5Oginfo.c \ + H5Ofill.c H5Oflush.c H5Ofsinfo.c H5Oginfo.c \ H5Olayout.c \ H5Olinfo.c H5Olink.c H5Omessage.c H5Omtime.c \ H5Oname.c H5Onull.c H5Opline.c H5Orefcount.c \ @@ -848,6 +848,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Odtype.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oefl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ofill.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oflush.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ofsinfo.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oginfo.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Olayout.Plo@am__quote@ diff --git a/test/Makefile.am b/test/Makefile.am index 1a29873..5d0dcd2 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -24,7 +24,7 @@ include $(top_srcdir)/config/commence.am INCLUDES=-I$(top_srcdir)/src -I$(top_builddir)/src # Test script for error_test and err_compat -TEST_SCRIPT = testerror.sh testlibinfo.sh $(srcdir)/testswmr.sh testcheck_version.sh +TEST_SCRIPT = testerror.sh testlibinfo.sh $(srcdir)/testswmr.sh testcheck_version.sh testflushrefresh.sh check_SCRIPTS = $(TEST_SCRIPT) SCRIPT_DEPEND = error_test$(EXEEXT) err_compat$(EXEEXT) @@ -52,7 +52,7 @@ bin_PROGRAMS=swmr_generator swmr_reader swmr_writer # 'make check' doesn't run them directly, so they are not included in TEST_PROG. # Also build testmeta, which is used for timings test. It builds quickly, # and this lets automake keep all its test programs in one place. -check_PROGRAMS=$(TEST_PROG) error_test err_compat tcheck_version testmeta +check_PROGRAMS=$(TEST_PROG) error_test err_compat tcheck_version testmeta flushrefresh # These programs generate test files for the tests. They don't need to be @@ -129,7 +129,9 @@ CHECK_CLEANFILES+=accum.h5 cmpd_dset.h5 compact_dataset.h5 dataset.h5 \ dtransform.h5 test_filters.h5 get_file_name.h5 tstint[1-2].h5 \ unlink_chunked.h5 btree2.h5 objcopy_src.h5 objcopy_dst.h5 \ objcopy_ext.dat trefer1.h5 trefer2.h5 app_ref.h5 farray.h5 \ - earray.h5 swmr_data.h5 + earray.h5 swmr_data.h5 flushrefresh.h5 flushrefresh_VERIFICATION_START \ + flushrefresh_VERIFICATION_CHECKPOINT1 flushrefresh_VERIFICATION_CHECKPOINT2 \ + flushrefresh_VERIFICATION_DONE # Sources for testhdf5 executable testhdf5_SOURCES=testhdf5.c tarray.c tattr.c tchecksum.c tconfig.c tfile.c \ @@ -138,6 +140,6 @@ testhdf5_SOURCES=testhdf5.c tarray.c tattr.c tchecksum.c tconfig.c tfile.c \ tvlstr.c tvltypes.c # Temporary files. -DISTCLEANFILES=testerror.sh testlibinfo.sh testcheck_version.sh +DISTCLEANFILES=testerror.sh testlibinfo.sh testcheck_version.sh testflushrefresh.sh include $(top_srcdir)/config/conclude.am diff --git a/test/Makefile.in b/test/Makefile.in index 1d42982..a244c53 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -54,13 +54,14 @@ build_triplet = @build@ host_triplet = @host@ DIST_COMMON = $(srcdir)/H5srcdir_str.h.in $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/testcheck_version.sh.in \ - $(srcdir)/testerror.sh.in $(srcdir)/testlibinfo.sh.in \ - $(top_srcdir)/config/commence.am \ + $(srcdir)/testerror.sh.in $(srcdir)/testflushrefresh.sh.in \ + $(srcdir)/testlibinfo.sh.in $(top_srcdir)/config/commence.am \ $(top_srcdir)/config/conclude.am COPYING bin_PROGRAMS = swmr_generator$(EXEEXT) swmr_reader$(EXEEXT) \ swmr_writer$(EXEEXT) check_PROGRAMS = $(am__EXEEXT_1) error_test$(EXEEXT) \ - err_compat$(EXEEXT) tcheck_version$(EXEEXT) testmeta$(EXEEXT) + err_compat$(EXEEXT) tcheck_version$(EXEEXT) testmeta$(EXEEXT) \ + flushrefresh$(EXEEXT) @BUILD_ALL_CONDITIONAL_TRUE@noinst_PROGRAMS = $(am__EXEEXT_2) TESTS = $(check_PROGRAMS) $(check_SCRIPTS) subdir = test @@ -70,8 +71,8 @@ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/bin/mkinstalldirs CONFIG_HEADER = $(top_builddir)/src/H5config.h -CONFIG_CLEAN_FILES = testcheck_version.sh testerror.sh H5srcdir_str.h \ - testlibinfo.sh +CONFIG_CLEAN_FILES = testcheck_version.sh testerror.sh \ + testflushrefresh.sh H5srcdir_str.h testlibinfo.sh CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libh5test_la_LIBADD = @@ -210,6 +211,10 @@ flush2_SOURCES = flush2.c flush2_OBJECTS = flush2.$(OBJEXT) flush2_LDADD = $(LDADD) flush2_DEPENDENCIES = libh5test.la $(LIBHDF5) +flushrefresh_SOURCES = flushrefresh.c +flushrefresh_OBJECTS = flushrefresh.$(OBJEXT) +flushrefresh_LDADD = $(LDADD) +flushrefresh_DEPENDENCIES = libh5test.la $(LIBHDF5) freespace_SOURCES = freespace.c freespace_OBJECTS = freespace.$(OBJEXT) freespace_LDADD = $(LDADD) @@ -414,15 +419,15 @@ SOURCES = $(libh5test_la_SOURCES) accum.c app_ref.c big.c bittests.c \ cross_read.c dangle.c dsets.c dt_arith.c dtransform.c dtypes.c \ earray.c enum.c err_compat.c error_test.c extend.c external.c \ farray.c fheap.c fillval.c filter_fail.c flush1.c flush2.c \ - freespace.c gen_bad_ohdr.c gen_bogus.c gen_cross.c \ - gen_deflate.c gen_filespace.c gen_filters.c gen_idx.c \ - gen_new_array.c gen_new_fill.c gen_new_group.c gen_new_mtime.c \ - gen_new_super.c gen_noencoder.c gen_nullspace.c \ - gen_sizes_lheap.c gen_specmetaread.c gen_udlinks.c getname.c \ - gheap.c hyperslab.c istore.c lheap.c links.c mf.c mount.c \ - mtime.c ntypes.c objcopy.c ohdr.c pool.c reserved.c \ - set_extent.c space_overflow.c stab.c swmr_generator.c \ - swmr_reader.c swmr_writer.c tcheck_version.c \ + flushrefresh.c freespace.c gen_bad_ohdr.c gen_bogus.c \ + gen_cross.c gen_deflate.c gen_filespace.c gen_filters.c \ + gen_idx.c gen_new_array.c gen_new_fill.c gen_new_group.c \ + gen_new_mtime.c gen_new_super.c gen_noencoder.c \ + gen_nullspace.c gen_sizes_lheap.c gen_specmetaread.c \ + gen_udlinks.c getname.c gheap.c hyperslab.c istore.c lheap.c \ + links.c mf.c mount.c mtime.c ntypes.c objcopy.c ohdr.c pool.c \ + reserved.c set_extent.c space_overflow.c stab.c \ + swmr_generator.c swmr_reader.c swmr_writer.c tcheck_version.c \ $(testhdf5_SOURCES) testmeta.c $(ttsafe_SOURCES) unlink.c \ vfd.c DIST_SOURCES = $(libh5test_la_SOURCES) accum.c app_ref.c big.c \ @@ -430,10 +435,10 @@ DIST_SOURCES = $(libh5test_la_SOURCES) accum.c app_ref.c big.c \ cmpd_dset.c cross_read.c dangle.c dsets.c dt_arith.c \ dtransform.c dtypes.c earray.c enum.c err_compat.c \ error_test.c extend.c external.c farray.c fheap.c fillval.c \ - filter_fail.c flush1.c flush2.c freespace.c gen_bad_ohdr.c \ - gen_bogus.c gen_cross.c gen_deflate.c gen_filespace.c \ - gen_filters.c gen_idx.c gen_new_array.c gen_new_fill.c \ - gen_new_group.c gen_new_mtime.c gen_new_super.c \ + filter_fail.c flush1.c flush2.c flushrefresh.c freespace.c \ + gen_bad_ohdr.c gen_bogus.c gen_cross.c gen_deflate.c \ + gen_filespace.c gen_filters.c gen_idx.c gen_new_array.c \ + gen_new_fill.c gen_new_group.c gen_new_mtime.c gen_new_super.c \ gen_noencoder.c gen_nullspace.c gen_sizes_lheap.c \ gen_specmetaread.c gen_udlinks.c getname.c gheap.c hyperslab.c \ istore.c lheap.c links.c mf.c mount.c mtime.c ntypes.c \ @@ -742,11 +747,15 @@ CHECK_CLEANFILES = *.chkexe *.chklog *.clog accum.h5 cmpd_dset.h5 \ err_compat.h5 dtransform.h5 test_filters.h5 get_file_name.h5 \ tstint[1-2].h5 unlink_chunked.h5 btree2.h5 objcopy_src.h5 \ objcopy_dst.h5 objcopy_ext.dat trefer1.h5 trefer2.h5 \ - app_ref.h5 farray.h5 earray.h5 swmr_data.h5 + app_ref.h5 farray.h5 earray.h5 swmr_data.h5 flushrefresh.h5 \ + flushrefresh_VERIFICATION_START \ + flushrefresh_VERIFICATION_CHECKPOINT1 \ + flushrefresh_VERIFICATION_CHECKPOINT2 \ + flushrefresh_VERIFICATION_DONE INCLUDES = -I$(top_srcdir)/src -I$(top_builddir)/src # Test script for error_test and err_compat -TEST_SCRIPT = testerror.sh testlibinfo.sh $(srcdir)/testswmr.sh testcheck_version.sh +TEST_SCRIPT = testerror.sh testlibinfo.sh $(srcdir)/testswmr.sh testcheck_version.sh testflushrefresh.sh check_SCRIPTS = $(TEST_SCRIPT) SCRIPT_DEPEND = error_test$(EXEEXT) err_compat$(EXEEXT) @@ -801,7 +810,7 @@ testhdf5_SOURCES = testhdf5.c tarray.c tattr.c tchecksum.c tconfig.c tfile.c \ # Temporary files. -DISTCLEANFILES = testerror.sh testlibinfo.sh testcheck_version.sh +DISTCLEANFILES = testerror.sh testlibinfo.sh testcheck_version.sh testflushrefresh.sh # Automake needs to be taught how to build lib, progs, and tests targets. # These will be filled in automatically for the most part (e.g., @@ -856,6 +865,8 @@ testcheck_version.sh: $(top_builddir)/config.status $(srcdir)/testcheck_version. cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ testerror.sh: $(top_builddir)/config.status $(srcdir)/testerror.sh.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +testflushrefresh.sh: $(top_builddir)/config.status $(srcdir)/testflushrefresh.sh.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ H5srcdir_str.h: $(top_builddir)/config.status $(srcdir)/H5srcdir_str.h.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ testlibinfo.sh: $(top_builddir)/config.status $(srcdir)/testlibinfo.sh.in @@ -1013,6 +1024,9 @@ flush1$(EXEEXT): $(flush1_OBJECTS) $(flush1_DEPENDENCIES) flush2$(EXEEXT): $(flush2_OBJECTS) $(flush2_DEPENDENCIES) @rm -f flush2$(EXEEXT) $(LINK) $(flush2_OBJECTS) $(flush2_LDADD) $(LIBS) +flushrefresh$(EXEEXT): $(flushrefresh_OBJECTS) $(flushrefresh_DEPENDENCIES) + @rm -f flushrefresh$(EXEEXT) + $(LINK) $(flushrefresh_OBJECTS) $(flushrefresh_LDADD) $(LIBS) freespace$(EXEEXT): $(freespace_OBJECTS) $(freespace_DEPENDENCIES) @rm -f freespace$(EXEEXT) $(LINK) $(freespace_OBJECTS) $(freespace_LDADD) $(LIBS) @@ -1180,6 +1194,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filter_fail.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flush1.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flush2.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flushrefresh.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/freespace.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gen_bad_ohdr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gen_bogus.Po@am__quote@ diff --git a/test/flushrefresh.c b/test/flushrefresh.c new file mode 100755 index 0000000..1e6a008 --- /dev/null +++ b/test/flushrefresh.c @@ -0,0 +1,1251 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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 * + * access to either file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Programmer: Mike McGreevy + * June 30, 2010 + * + * Purpose: This test file contains routines used to test flushing and + * refreshing individual objects' metadata from the cache. + * + * Note: This file should NOT be run manually. Instead, invoke it + * via its associated test script, testflushrefresh.sh + * + */ + +/* ======== */ +/* Includes */ +/* ======== */ + +#include "testhdf5.h" + +/* ======= */ +/* Defines */ +/* ======= */ + +/* Name of Test File */ +#define FILENAME "flushrefresh.h5" + +/* Names of Signal Files */ +#define SIGNAL_TO_SCRIPT "flushrefresh_VERIFICATION_START" +#define SIGNAL_BETWEEN_PROCESSES_1 "flushrefresh_VERIFICATION_CHECKPOINT1" +#define SIGNAL_BETWEEN_PROCESSES_2 "flushrefresh_VERIFICATION_CHECKPOINT2" +#define SIGNAL_FROM_SCRIPT "flushrefresh_VERIFICATION_DONE" + +/* Signal Timeout Length in Secs */ +#define SIGNAL_TIMEOUT 100 + +/* Paths to Various Objects in the Testfile */ +#define RG "/" +#define D1 "/Dataset1" +#define D2 "/Group1/Dataset2" +#define D3 "/Group3/Dataset3" +#define G1 "/Group1" +#define G2 "/Group1/Group2" +#define G3 "/Group3" +#define T1 "/CommittedDatatype1" +#define T2 "/Group1/Group2/CommittedDatatype2" +#define T3 "/Group3/CommittedDatatype3" + +/* Flushed States */ +#define FLUSHED "FLUSHED" +#define NOT_FLUSHED "NOT_FLUSHED" + +/* Error Handling */ +/* For errors occuring in the main process, use the standard TEST_ERROR macro. + For errors occurring in the spawned process (from the test script), use + the PROCESS_ERROR macro, which will send a signal to the main process so the + main process can propogate errors correctly. */ +FILE * errorfile; +#define ERRFILE "flushrefresh_ERROR" +#define PROCESS_ERROR \ + { errorfile = fopen(ERRFILE, "w+"); \ + HDfprintf(errorfile, "Error occurred in flushrefresh.\n"); \ + HDfflush(errorfile); \ + HDfclose(errorfile); \ + TEST_ERROR; \ + } + +#define CLEANUP_FILES \ + { \ + HDremove(ERRFILE); \ + HDremove(FILENAME); \ + HDremove(SIGNAL_TO_SCRIPT); \ + HDremove(SIGNAL_BETWEEN_PROCESSES_1); \ + HDremove(SIGNAL_BETWEEN_PROCESSES_2); \ + HDremove(SIGNAL_FROM_SCRIPT); \ + } \ + +/* ===================== */ +/* Function Declarations */ +/* ===================== */ + +/* Main */ +int main(int argc, const char *argv[]); + +/* Flush Test Framework */ +herr_t test_flush(void); +herr_t flush_verification(const char * obj_pathname, const char * expected); +herr_t run_flush_verification_process(const char * obj_pathname, const char * expected); + +/* Refresh Test Framework */ +herr_t test_refresh(void); +herr_t refresh_verification(const char * obj_pathname); +herr_t start_refresh_verification_process(const char * obj_pathname); +herr_t end_refresh_verification_process(void); + +/* Other Helper Functions */ +herr_t check_for_errors(void); +herr_t end_verification(void); +herr_t wait_for_signal(const char * waitfor); +void send_signal(const char * send, const char * arg1, const char * arg2); + +/* ========= */ +/* Functions */ +/* ========= */ + + +/*------------------------------------------------------------------------- + * Function: main + * + * Purpose: This function coordinates the test of flush/refresh + * functionality verification. It accepts either one, two or + * no command line parameters. The main test routine runs + * with no command line parameters specified, while verification + * routines run with one or two command line parameters. + * + * Note: This program should not be run manually, as the + * test is controlled by the testflushrefresh.sh script. Running + * the flushrefresh program manually will result in failure, as + * it will time out waiting for a signal from the test script + * which will never come. + * + * Return: 0 on Success, 1 on Failure + * + * Programmer: Mike McGreevy + * July 1, 2010 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +int main(int argc, const char *argv[]) +{ + /* Variables */ + const char *envval = NULL; + + /* Parse command line options */ + if (argc == 1) { + + /* No arguments supplied. Run main test routines if + * using sec2 or stdio driver, otherwise don't run + * anything. */ + + /* Determine driver being used */ + envval = HDgetenv("HDF5_DRIVER"); + if(envval == NULL) + envval = ""; + + if (!HDstrcmp(envval, "sec2") || !HDstrcmp(envval, "stdio") || !HDstrcmp(envval, "")) { + + if (test_flush() != SUCCEED) TEST_ERROR; + if (test_refresh() != SUCCEED) TEST_ERROR; + + } /* end if */ + + else { + + HDfprintf(stdout, "Skipping all flush/refresh tests (only run with sec2 or stdio file drivers).\n"); + + /* Test script is expecting some signals, so send them out to end it. */ + if (end_verification() < 0) TEST_ERROR; + if (end_verification() < 0) TEST_ERROR; + + } /* end else */ + + } else if (argc == 3) { + + /* Two arguments supplied. Pass them to flush verification routine. */ + + if (flush_verification(argv[1], argv[2]) != 0) PROCESS_ERROR; + + } else if (argc == 2) { + + /* One argument supplied. Pass it to refresh verification routine. */ + + if (refresh_verification(argv[1]) != 0) PROCESS_ERROR; + + } else { + + /* Illegal number of arguments supplied. Error. */ + + HDfprintf(stderr, "Error. %d is an Invalid number of arguments to main().\n", argc); + PROCESS_ERROR + + } /* end if */ + + return SUCCEED; + +error: + + /* Return */ + return FAIL; + +} /* main */ + + +/*------------------------------------------------------------------------- + * Function: test_flush + * + * Purpose: This function tests flushing individual objects' metadata + * from the metadata cache. + * + * Return: 0 on Success, 1 on Failure + * + * Programmer: Mike McGreevy + * July 1, 2010 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t test_flush(void) +{ + /************************************************************************** + * + * Test Description: + * + * This test will build an HDF5 file with several objects in a varying + * hierarchical layout. It will then attempt to flush the objects + * in the file one by one, individually, using the four H5*flush + * routines (D,G,T, and O). After each call to either create or flush an + * object, a series of verifications will occur on each object in the file. + * + * Each verification consists of spawning off a new process and determining + * if the object can be opened and its information retreived in said + * alternate process. It reports the results, which are compared to an + * expected value (either that the object can be found on disk, or that it + * cannot). + * + * Note that to spawn a verification, this program sends a signal (by creating + * a file on disk) to the test script controlling it, indicating how to + * run the verification. + * + * Implementation is funky, but basically, an example: + * + * Step 1. Dataset is created. + * Step 2. Verify that dataset can't be opened by separate process, as + * it should not have been flushed to disk yet. + * Step 3. Group is created. + * Step 4. Verify that group can't be opened by separate process. + * Step 5. H5Gflush is called on the group. + * Step 6. Verify that group CAN be opened, but dataset still has + * yet to hit disk, and CANNOT be opened. Success! Only the group + * was flushed. + * + **************************************************************************/ + + /************************************************************************** + * Generated Test File will look like this: + * + * GROUP "/" + * DATASET "Dataset1" + * GROUP "Group1" { + * DATASET "Dataset2" + * GROUP "Group2" { + * DATATYPE "CommittedDatatype3" + * } + * } + * GROUP "Group3" { + * DATASET "Dataset3" + * DATATYPE "CommittedDatatype2" + * } + * DATATYPE "CommittedDatatype1" + **************************************************************************/ + + /* Variables */ + hid_t fid,gid,gid2,gid3,sid,tid1,tid2,tid3,did,did2,did3,rid,status = 0; + hsize_t dims[2] = {3,5}; + + /* Testing Message */ + HDfprintf(stdout, "Testing individual object flush behavior:\n"); + + /* Cleanup any old error or signal files */ + CLEANUP_FILES; + + /* ================ */ + /* CREATE TEST FILE */ + /* ================ */ + + /* Create file, open root group */ + if ((fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC|H5F_ACC_SWMR_WRITE, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + if ((rid = H5Gopen(fid, "/", H5P_DEFAULT)) < 0) TEST_ERROR; + + /* Create data space and types */ + if ((sid = H5Screate_simple(2, dims, dims)) < 0) TEST_ERROR; + if ((tid1 = H5Tcopy(H5T_NATIVE_INT)) < 0) TEST_ERROR; + if ((tid2 = H5Tcopy(H5T_NATIVE_CHAR)) < 0) TEST_ERROR; + if ((tid3 = H5Tcopy(H5T_NATIVE_LONG)) < 0) TEST_ERROR; + + /* Create Group1 */ + if ((gid = H5Gcreate(fid, "Group1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + + /* Create Group2 */ + if ((gid2 = H5Gcreate(gid, "Group2", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + + /* Create Group3 */ + if ((gid3 = H5Gcreate(fid, "Group3", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + + /* Create Dataset1 */ + if ((did = H5Dcreate2(fid, "Dataset1", tid1, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + + /* Create Dataset2 */ + if ((did2 = H5Dcreate2(gid, "Dataset2", tid3, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + + /* Create Dataset3 */ + if ((did3 = H5Dcreate2(gid3, "Dataset3", tid2, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + + /* Create CommittedDatatype1 */ + if ((status = H5Tcommit2(fid, "CommittedDatatype1", tid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + + /* Create CommittedDatatype2 */ + if ((status = H5Tcommit2(gid2, "CommittedDatatype2", tid2, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + + /* Create CommittedDatatype3 */ + if ((status = H5Tcommit2(gid3, "CommittedDatatype3", tid3, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + + /* ============ */ + /* FLUSH GROUPS */ + /* ============ */ + + /* Test */ + TESTING("to ensure H5Gflush correctly flushes single groups"); + + /* First, let's verify that nothing is currently flushed. */ + if (run_flush_verification_process(RG, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G1, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G2, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G3, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D1, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D2, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D3, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T1, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T2, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T3, NOT_FLUSHED) != 0) TEST_ERROR; + + /* Then, flush the root group and verify it's the only thing on disk */ + if ((status = H5Gflush(rid)) < 0) TEST_ERROR; + if (run_flush_verification_process(RG, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G1, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G2, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G3, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D1, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D2, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D3, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T1, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T2, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T3, NOT_FLUSHED) != 0) TEST_ERROR; + + /* Flush Group1 and Verify it is recently flushed, and nothing + * else has changed. */ + if ((status = H5Gflush(gid)) < 0) TEST_ERROR; + if (run_flush_verification_process(RG, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G1, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G2, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G3, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D1, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D2, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D3, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T1, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T2, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T3, NOT_FLUSHED) != 0) TEST_ERROR; + + /* Flush Group2 and Verify it is recently flushed, and nothing + * else has changed. */ + if ((status = H5Gflush(gid2)) < 0) TEST_ERROR; + if (run_flush_verification_process(RG, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G1, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G2, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G3, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D1, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D2, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D3, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T1, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T2, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T3, NOT_FLUSHED) != 0) TEST_ERROR; + + PASSED(); + + /* ============== */ + /* FLUSH DATASETS */ + /* ============== */ + + /* Test */ + TESTING("to ensure H5Dflush correctly flushes single datasets"); + + /* Flush Dataset1 and verify it's the only thing that hits disk. */ + if ((status = H5Dflush(did)) < 0) TEST_ERROR; + if (run_flush_verification_process(RG, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G1, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G2, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G3, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D1, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D2, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D3, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T1, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T2, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T3, NOT_FLUSHED) != 0) TEST_ERROR; + + /* Flush Dataset2 and verify it's the only thing that hits disk. */ + if ((status = H5Dflush(did2)) < 0) TEST_ERROR; + if (run_flush_verification_process(RG, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G1, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G2, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G3, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D1, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D2, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D3, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T1, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T2, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T3, NOT_FLUSHED) != 0) TEST_ERROR; + + PASSED(); + + /* =============== */ + /* FLUSH DATATYPES */ + /* =============== */ + + /* Test */ + TESTING("to ensure H5Tflush correctly flushes single datatypes"); + + /* Flush Datatype 1 and verify it's the only thing that hits disk. */ + if ((status = H5Tflush(tid1)) < 0) TEST_ERROR; + if (run_flush_verification_process(RG, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G1, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G2, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G3, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D1, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D2, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D3, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T1, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T2, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T3, NOT_FLUSHED) != 0) TEST_ERROR; + + /* Flush Datatype 2 and verify it's the only thing that hits disk. */ + if ((status = H5Tflush(tid2)) < 0) TEST_ERROR; + if (run_flush_verification_process(RG, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G1, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G2, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G3, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D1, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D2, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D3, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T1, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T2, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T3, NOT_FLUSHED) != 0) TEST_ERROR; + + PASSED(); + + /* ============= */ + /* FLUSH OBJECTS */ + /* ============= */ + + /* Test */ + TESTING("to ensure H5Oflush correctly flushes single objects"); + + /* Flush Group3 and verify it's the only thing that hits disk. */ + if ((status = H5Oflush(gid3)) < 0) TEST_ERROR; + if (run_flush_verification_process(RG, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G1, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G2, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G3, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D1, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D2, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D3, NOT_FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T1, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T2, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T3, NOT_FLUSHED) != 0) TEST_ERROR; + + /* Flush Dataset3 and verify it's the only thing that hits disk. */ + if ((status = H5Oflush(did3)) < 0) TEST_ERROR; + if (run_flush_verification_process(RG, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G1, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G2, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G3, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D1, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D2, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D3, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T1, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T2, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T3, NOT_FLUSHED) != 0) TEST_ERROR; + + /* Flush CommittedDatatype3 and verify it's the only thing that hits disk. */ + if ((status = H5Oflush(tid3)) < 0) TEST_ERROR; + if (run_flush_verification_process(RG, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G1, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G2, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(G3, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D1, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D2, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(D3, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T1, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T2, FLUSHED) != 0) TEST_ERROR; + if (run_flush_verification_process(T3, FLUSHED) != 0) TEST_ERROR; + + PASSED(); + + /* ================== */ + /* Cleanup and Return */ + /* ================== */ + if (H5Gclose(gid) < 0) TEST_ERROR; + if (H5Gclose(gid2) < 0) TEST_ERROR; + if (H5Dclose(did) < 0) TEST_ERROR; + if (H5Dclose(did2) < 0) TEST_ERROR; + if (H5Gclose(rid) < 0) TEST_ERROR; + if (H5Fclose(fid) < 0) TEST_ERROR; + + /* Delete test file */ + HDremove(FILENAME); + + if (end_verification() < 0) TEST_ERROR; + + return SUCCEED; + +error: + return FAIL; + +} /* end test_flush */ + + +/*------------------------------------------------------------------------- + * Function: test_refresh + * + * Purpose: This function tests refresh (evict/reload) of individual + * objects' metadata from the metadata cache. + * + * Return: 0 on Success, 1 on Failure + * + * Programmer: Mike McGreevy + * August 17, 2010 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t test_refresh(void) +{ + /************************************************************************** + * + * Test Description: + * + * This test will build an HDF5 file with several objects in a varying + * hierarchical layout. It will then flush the entire file to disk. Then, + * an attribute will be added to each object in the file. + * + * One by one, this process will flush each object to disk, individually. + * It will also be coordinating with another process, which will open + * the object before it is flushed by this process, and then refresh the + * object after it's been flushed, comparing the before and after object + * information to ensure that they are as expected. (i.e., most notably, + * that an attribute has been added, and is only visible after a + * successful call to a H5*refresh function). + * + * As with the flush case, the implemention is a bit tricky as it's + * dealing with signals going back and forth between the two processes + * to ensure the timing is correct, but basically, an example: + * + * Step 1. Dataset is created. + * Step 2. Dataset is flushed. + * Step 3. Attribute on Dataset is created. + * Step 4. Another process opens the dataset and verifies that it does + * not see an attribute (as the attribute hasn't been flushed yet). + * Step 5. This process flushes the dataset again (with Attribute attached). + * Step 6. The other process calls H5Drefresh, which should evict/reload + * the object's metadata, and thus pick up the attribute that's + * attached to it. Most other before/after object information is + * compared for sanity as well. + * Step 7. Rinse and Repeat for each object in the file. + * + **************************************************************************/ + + /************************************************************************** + * Generated Test File will look like this: + * + * GROUP "/" + * DATASET "Dataset1" + * GROUP "Group1" { + * DATASET "Dataset2" + * GROUP "Group2" { + * DATATYPE "CommittedDatatype3" + * } + * } + * GROUP "Group3" { + * DATASET "Dataset3" + * DATATYPE "CommittedDatatype2" + * } + * DATATYPE "CommittedDatatype1" + **************************************************************************/ + + /* Variables */ + hid_t aid,fid,sid,tid1,did,dcpl = 0; + hid_t gid,gid2,gid3,tid2,tid3,did2,did3,status = 0; + hsize_t dims[2] = {50,50}; + hsize_t cdims[2] = {1,1}; + int fillval = 2; + + /* Testing Message */ + HDfprintf(stdout, "Testing individual object refresh behavior:\n"); + + /* Cleanup any old error or signal files */ + CLEANUP_FILES; + + /* ================ */ + /* CREATE TEST FILE */ + /* ================ */ + + /* Create File */ + if ((fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC|H5F_ACC_SWMR_WRITE, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + + /* Create data space and types */ + if ((dcpl = H5Pcreate(H5P_DATASET_CREATE)) < 0) TEST_ERROR; + if ( H5Pset_chunk(dcpl, 2, cdims) < 0 ) TEST_ERROR; + if ( H5Pset_fill_value(dcpl, H5T_NATIVE_INT, &fillval) < 0 ) TEST_ERROR; + if ((sid = H5Screate_simple(2, dims, dims)) < 0) TEST_ERROR; + if ((tid1 = H5Tcopy(H5T_NATIVE_INT)) < 0) TEST_ERROR; + if ((tid2 = H5Tcopy(H5T_NATIVE_CHAR)) < 0) TEST_ERROR; + if ((tid3 = H5Tcopy(H5T_NATIVE_LONG)) < 0) TEST_ERROR; + + /* Create Group1 */ + if ((gid = H5Gcreate(fid, "Group1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + + /* Create Group2 */ + if ((gid2 = H5Gcreate(gid, "Group2", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + + /* Create Group3 */ + if ((gid3 = H5Gcreate(fid, "Group3", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + + /* Create Dataset1 */ + if ((did = H5Dcreate2(fid, "Dataset1", tid1, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT)) < 0) TEST_ERROR; + + /* Create Dataset2 */ + if ((did2 = H5Dcreate2(gid, "Dataset2", tid3, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + + /* Create Dataset3 */ + if ((did3 = H5Dcreate2(gid3, "Dataset3", tid2, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + + /* Create CommittedDatatype1 */ + if ((status = H5Tcommit2(fid, "CommittedDatatype1", tid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + + /* Create CommittedDatatype2 */ + if ((status = H5Tcommit2(gid2, "CommittedDatatype2", tid2, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + + /* Create CommittedDatatype3 */ + if ((status = H5Tcommit2(gid3, "CommittedDatatype3", tid3, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + + /* Flush File to Disk */ + if (H5Fflush(fid, H5F_SCOPE_GLOBAL) < 0) TEST_ERROR; + + /* Create an attribute on each object. These will not immediately hit disk, + and thus be unavailable to another process until this process flushes + the object and the other process refreshes from disk. */ + if ((aid = H5Acreate2(did, "Attribute", tid1, sid, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + if (H5Aclose(aid) < 0) TEST_ERROR; + if ((aid = H5Acreate2(did2, "Attribute", tid1, sid, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + if (H5Aclose(aid) < 0) TEST_ERROR; + if ((aid = H5Acreate2(did3, "Attribute", tid1, sid, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + if (H5Aclose(aid) < 0) TEST_ERROR; + if ((aid = H5Acreate2(gid, "Attribute", tid1, sid, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + if (H5Aclose(aid) < 0) TEST_ERROR; + if ((aid = H5Acreate2(gid2, "Attribute", tid1, sid, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + if (H5Aclose(aid) < 0) TEST_ERROR; + if ((aid = H5Acreate2(gid3, "Attribute", tid1, sid, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + if (H5Aclose(aid) < 0) TEST_ERROR; + if ((aid = H5Acreate2(tid1, "Attribute", tid1, sid, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + if (H5Aclose(aid) < 0) TEST_ERROR; + if ((aid = H5Acreate2(tid2, "Attribute", tid1, sid, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + if (H5Aclose(aid) < 0) TEST_ERROR; + if ((aid = H5Acreate2(tid3, "Attribute", tid1, sid, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; + if (H5Aclose(aid) < 0) TEST_ERROR; + + /* ================ */ + /* Refresh Datasets */ + /* ================ */ + + TESTING("to ensure that H5Drefresh correctly refreshes single datasets"); + + /* Verify First Dataset can be refreshed with H5Drefresh */ + if (start_refresh_verification_process(D1) != 0) TEST_ERROR; + if (H5Oflush(did) < 0) TEST_ERROR; + if (end_refresh_verification_process() != 0) TEST_ERROR; + + /* Verify Second Dataset can be refreshed with H5Drefresh */ + if (start_refresh_verification_process(D2) != 0) TEST_ERROR; + if (H5Oflush(did2) < 0) TEST_ERROR; + if (end_refresh_verification_process() != 0) TEST_ERROR; + + PASSED(); + + /* ============== */ + /* Refresh Groups */ + /* ============== */ + + TESTING("to ensure that H5Grefresh correctly refreshes single groups"); + + /* Verify First Group can be refreshed with H5Grefresh */ + if (start_refresh_verification_process(G1) != 0) TEST_ERROR; + if (H5Oflush(gid) < 0) TEST_ERROR; + if (end_refresh_verification_process() != 0) TEST_ERROR; + + /* Verify Second Group can be refreshed with H5Grefresh */ + if (start_refresh_verification_process(G2) != 0) TEST_ERROR; + if (H5Oflush(gid2) < 0) TEST_ERROR; + if (end_refresh_verification_process() != 0) TEST_ERROR; + + PASSED(); + + /* ================= */ + /* Refresh Datatypes */ + /* ================= */ + + TESTING("to ensure that H5Trefresh correctly refreshes single datatypes"); + + /* Verify First Committed Datatype can be refreshed with H5Trefresh */ + if (start_refresh_verification_process(T1) != 0) TEST_ERROR; + if (H5Oflush(tid1) < 0) TEST_ERROR; + if (end_refresh_verification_process() != 0) TEST_ERROR; + + /* Verify Second Committed Datatype can be refreshed with H5Trefresh */ + if (start_refresh_verification_process(T2) != 0) TEST_ERROR; + if (H5Oflush(tid2) < 0) TEST_ERROR; + if (end_refresh_verification_process() != 0) TEST_ERROR; + + PASSED(); + + /* =============== */ + /* Refresh Objects */ + /* =============== */ + + TESTING("to ensure that H5Orefresh correctly refreshes single objects"); + + /* Verify Third Dataset can be refreshed with H5Orefresh */ + if (start_refresh_verification_process(D3) != 0) TEST_ERROR; + if (H5Oflush(did3) < 0) TEST_ERROR; + if (end_refresh_verification_process() != 0) TEST_ERROR; + + /* Verify Third Group can be refreshed with H5Orefresh */ + if (start_refresh_verification_process(G3) != 0) TEST_ERROR; + if (H5Oflush(gid3) < 0) TEST_ERROR; + if (end_refresh_verification_process() != 0) TEST_ERROR; + + /* Verify Third Committed Datatype can be refreshed with H5Orefresh */ + if (start_refresh_verification_process(T3) != 0) TEST_ERROR; + if (H5Oflush(tid3) < 0) TEST_ERROR; + if (end_refresh_verification_process() != 0) TEST_ERROR; + + PASSED(); + + /* ================== */ + /* Cleanup and Return */ + /* ================== */ + + /* Close Stuff */ + if (H5Tclose(tid1) < 0) TEST_ERROR; + if (H5Tclose(tid2) < 0) TEST_ERROR; + if (H5Tclose(tid3) < 0) TEST_ERROR; + if (H5Dclose(did) < 0) TEST_ERROR; + if (H5Dclose(did2) < 0) TEST_ERROR; + if (H5Dclose(did3) < 0) TEST_ERROR; + if (H5Gclose(gid) < 0) TEST_ERROR; + if (H5Gclose(gid2) < 0) TEST_ERROR; + if (H5Gclose(gid3) < 0) TEST_ERROR; + if (H5Sclose(sid) < 0) TEST_ERROR; + if (H5Fclose(fid) < 0) TEST_ERROR; + + /* Delete Test File */ + HDremove(FILENAME); + + if (end_verification() < 0) TEST_ERROR; + + return SUCCEED; + +error: + /* Return */ + return FAIL; + +} /* test_refresh() */ + + +/*------------------------------------------------------------------------- + * Function: run_flush_verification_process + * + * Purpose: This function is used to communicate with the test script + * in order to spawn off a process to verify that a flush + * of an individual object was successful. + * + * Return: 0 on Success, 1 on Failure + * + * Programmer: Mike McGreevy + * July 16, 2010 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t run_flush_verification_process(const char * obj_pathname, const char * expected) +{ + /* Send Signal to SCRIPT indicating that it should kick off a verification process. */ + send_signal(SIGNAL_TO_SCRIPT, obj_pathname, expected); + + /* Wait for Signal from SCRIPT indicating that verification process has completed. */ + if (wait_for_signal(SIGNAL_FROM_SCRIPT) < 0) TEST_ERROR; + + /* Check to see if any errors occurred */ + if (check_for_errors() < 0) TEST_ERROR; + + /* Return */ + return SUCCEED; + +error: + return FAIL; + +} /* run_flush_verification_process */ + + +/*------------------------------------------------------------------------- + * Function: flush_verification + * + * Purpose: This function tries to open target object in the test file. + * It compares the success of the open function to the expected + * value, and succeeds if they are equal and fails if they differ. + * + * Note that full path to the object must be provided as the + * obj_pathname argument. + * + * Return: 0 on Success, 1 on Failure + * + * Programmer: Mike McGreevy + * July 16, 2010 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t flush_verification(const char * obj_pathname, const char * expected) +{ + /* Variables */ + hid_t oid,fid,status = 0; + H5O_info_t oinfo; + + /* Try to open the testfile and then obj_pathname within the file */ + H5E_BEGIN_TRY { + fid = H5Fopen(FILENAME, H5F_ACC_SWMR_READ, H5P_DEFAULT); + oid = H5Oopen(fid, obj_pathname, H5P_DEFAULT); + status = H5Oget_info(oid, &oinfo); + } H5E_END_TRY; + + /* Compare to expected result */ + if (strcmp(expected, FLUSHED) == 0) { + if ((oid < 0) || (status < 0)) { + HDfprintf(stderr, "Error! %s should be on disk, but was NOT!\n", obj_pathname); + PROCESS_ERROR; + } /* end if */ + } else if (strcmp(expected, NOT_FLUSHED) == 0) { + if ((oid > 0) || (status > 0)) { + HDfprintf(stderr, "Error! %s not expected to be flushed, but it was found on disk!\n", obj_pathname); + PROCESS_ERROR; + } /* end if */ + } else { + HDfprintf(stderr, "Error! Bad verification parameters. %s is an invalid expected outcome.\n", expected); + PROCESS_ERROR; + } /* end if */ + + /* Cleanup */ + H5E_BEGIN_TRY { + H5Oclose(oid); + H5Fclose(fid); + } H5E_END_TRY; + + return SUCCEED; + +error: + return FAIL; + +} /* flush_verification */ + + +/*------------------------------------------------------------------------- + * Function: start_refresh_verification_process + * + * Purpose: This function is used to communicate with the test script + * in order to spawn off a process which will test the + * H5*refresh routine. + * + * Return: 0 on Success, 1 on Failure + * + * Programmer: Mike McGreevy + * July 16, 2010 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t start_refresh_verification_process(const char * obj_pathname) +{ + /* Send Signal to SCRIPT indicating that it should kick off a refresh + verification process */ + send_signal(SIGNAL_TO_SCRIPT, obj_pathname, NULL); + + /* Wait for Signal from VERIFICATION PROCESS indicating that it's opened the + target object and ready for MAIN PROCESS to modify it */ + if (wait_for_signal(SIGNAL_BETWEEN_PROCESSES_1) < 0) TEST_ERROR; + + /* Check to see if any errors occurred */ + if (check_for_errors() < 0) TEST_ERROR; + + /* Return */ + return SUCCEED; + +error: + return FAIL; + +} /* start_refresh_verification_process */ + + +/*------------------------------------------------------------------------- + * Function: end_refresh_verification_process + * + * Purpose: This function is used to communicate with the verification + * process spawned by the start_refresh_verification_process + * function. It gives it the go-ahead to call H5*refresh + * on an object and conlcude the refresh verification. + * + * Return: 0 on Success, 1 on Failure + * + * Programmer: Mike McGreevy + * July 16, 2010 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t end_refresh_verification_process(void) +{ + /* Send Signal to REFRESH VERIFICATION PROCESS indicating that the object + has been modified and it should now attempt to refresh its metadata, + and verify the results. */ + send_signal(SIGNAL_BETWEEN_PROCESSES_2, NULL, NULL); + + /* Wait for Signal from SCRIPT indicating that the refresh verification + process has completed. */ + if (wait_for_signal(SIGNAL_FROM_SCRIPT) < 0) TEST_ERROR; + + /* Check to see if any errors occurred */ + if (check_for_errors() < 0) TEST_ERROR; + + /* Return */ + + return SUCCEED; + +error: + return FAIL; + +} /* end_refresh_verification_process */ + + +/*------------------------------------------------------------------------- + * Function: refresh_verification + * + * Purpose: This function opens the specified object, and checks to see + * that is does not have any attributes on it. It then sends + * a signal to the main process, which will flush the object + * (putting an attribute on the object on disk). This function + * will then refresh the object, and verify that it has picked + * up the new metadata reflective of the added attribute. + * + * Return: 0 on Success, 1 on Failure + * + * Programmer: Mike McGreevy + * July 16, 2010 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t refresh_verification(const char * obj_pathname) +{ + /* Variables */ + hid_t oid,fid,status = 0; + H5O_info_t flushed_oinfo; + H5O_info_t refreshed_oinfo; + + /* Open Object */ + if ((fid = H5Fopen(FILENAME, H5F_ACC_SWMR_READ, H5P_DEFAULT)) < 0) PROCESS_ERROR; + if ((oid = H5Oopen(fid, obj_pathname, H5P_DEFAULT)) < 0) PROCESS_ERROR; + + /* Get Object info */ + if ((status = H5Oget_info(oid, &flushed_oinfo)) < 0) PROCESS_ERROR; + + /* Make sure there are no attributes on the object. This is just a sanity + check to ensure we didn't erroneously flush the attribute before + starting the verification. */ + if (flushed_oinfo.num_attrs != 0) PROCESS_ERROR; + + /* Send Signal to MAIN PROCESS indicating that it can go ahead and modify the + object. */ + send_signal(SIGNAL_BETWEEN_PROCESSES_1, NULL, NULL); + + /* Wait for Signal from MAIN PROCESS indicating that it's modified the + object and we can run verification now. */ + if (wait_for_signal(SIGNAL_BETWEEN_PROCESSES_2) < 0) PROCESS_ERROR; + + /* Get object info again. This will NOT reflect what's on disk, only what's + in the cache. Thus, all values will be unchanged from above, despite + newer information being on disk. */ + if ((status = H5Oget_info(oid, &refreshed_oinfo)) < 0) PROCESS_ERROR; + + /* Verify that before doing a refresh, getting the object info returns stale + information. (i.e., unchanged from above, despite new info on disk). */ + if (flushed_oinfo.addr != refreshed_oinfo.addr) PROCESS_ERROR; + if (flushed_oinfo.type != refreshed_oinfo.type) PROCESS_ERROR; + if (flushed_oinfo.hdr.version != refreshed_oinfo.hdr.version) PROCESS_ERROR; + if (flushed_oinfo.hdr.flags != refreshed_oinfo.hdr.flags) PROCESS_ERROR; + if (flushed_oinfo.num_attrs != refreshed_oinfo.num_attrs) PROCESS_ERROR; + if (flushed_oinfo.hdr.nmesgs != refreshed_oinfo.hdr.nmesgs) PROCESS_ERROR; + if (flushed_oinfo.hdr.nchunks != refreshed_oinfo.hdr.nchunks) PROCESS_ERROR; + if (flushed_oinfo.hdr.space.total != refreshed_oinfo.hdr.space.total) PROCESS_ERROR; + + /* Refresh object */ + /* The H5*refresh function called depends on which object we are trying + * to refresh. (MIKE: add desired refresh call as parameter so adding new + * test cases is easy). */ + if ((strcmp(obj_pathname, D1) == 0) || + (strcmp(obj_pathname, D2) == 0)) { + if (H5Drefresh(oid) < 0) PROCESS_ERROR; + } /* end if */ + else if ((strcmp(obj_pathname, G1) == 0) || + (strcmp(obj_pathname, G2) == 0)) { + if (H5Grefresh(oid) < 0) PROCESS_ERROR; + } /* end if */ + else if ((strcmp(obj_pathname, T1) == 0) || + (strcmp(obj_pathname, T2) == 0)) { + if (H5Trefresh(oid) < 0) PROCESS_ERROR; + } /* end if */ + else if ((strcmp(obj_pathname, D3) == 0) || + (strcmp(obj_pathname, G3) == 0) || + (strcmp(obj_pathname, T3) == 0)) { + if (H5Orefresh(oid) < 0) PROCESS_ERROR; + } /* end if */ + else { + HDfprintf(stdout, "Error. %s is an unrecognized object.\n", obj_pathname); + PROCESS_ERROR; + } /* end else */ + + /* Get object info. This should now accurately reflect the refreshed object on disk. */ + if ((status = H5Oget_info(oid, &refreshed_oinfo)) < 0) PROCESS_ERROR; + + /* Confirm following attributes are the same: */ + if (flushed_oinfo.addr != refreshed_oinfo.addr) PROCESS_ERROR; + if (flushed_oinfo.type != refreshed_oinfo.type) PROCESS_ERROR; + if (flushed_oinfo.hdr.version != refreshed_oinfo.hdr.version) PROCESS_ERROR; + if (flushed_oinfo.hdr.flags != refreshed_oinfo.hdr.flags) PROCESS_ERROR; + + /* Confirm following attributes are different */ + if (flushed_oinfo.num_attrs == refreshed_oinfo.num_attrs) PROCESS_ERROR; + if (flushed_oinfo.hdr.nmesgs == refreshed_oinfo.hdr.nmesgs) PROCESS_ERROR; + if (flushed_oinfo.hdr.nchunks == refreshed_oinfo.hdr.nchunks) PROCESS_ERROR; + if (flushed_oinfo.hdr.space.total == refreshed_oinfo.hdr.space.total) PROCESS_ERROR; + + /* Close objects */ + if (H5Oclose(oid) < 0) PROCESS_ERROR; + if (H5Fclose(fid) < 0) PROCESS_ERROR; + + /* Return */ + return SUCCEED; + +error: + + return FAIL; + +} /* refresh_verification */ + + +/*------------------------------------------------------------------------- + * Function: check_for_errors() + * + * Purpose: This function checks the status of external verification + * processes to see if they've succeeded. It checks for the + * existance of flushrefresh_ERROR file. If present, that indicates + * an external verification process has failed, and this function + * thus fails as well. If not present, then nothing else has + * failed, and this function succeeds. + * + * Return: 0 on Success, 1 on Failure + * + * Programmer: Mike McGreevy + * July 1, 2010 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t check_for_errors(void) +{ + FILE * file; + + if ((file = fopen(ERRFILE, "r"))) + { + HDfclose(file); + HDremove(ERRFILE); + return FAIL; + } + + return SUCCEED; + +} /* check_for_errors */ + + +/*------------------------------------------------------------------------- + * Function: end_verification + * + * Purpose: Tells test script that verification routines are completed and + * that the test can wrap up. + * + * Return: void + * + * Programmer: Mike McGreevy + * July 16, 2010 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t end_verification(void) +{ + /* Send Signal to SCRIPT to indicate that we're done with verification. */ + send_signal(SIGNAL_TO_SCRIPT, "VERIFICATION_DONE", "VERIFICATION_DONE"); + + /* Wait for Signal from SCRIPT indicating that we can continue. */ + if (wait_for_signal(SIGNAL_FROM_SCRIPT) < 0) TEST_ERROR; + + return SUCCEED; + +error: + return FAIL; + +} /* end_verification */ + + +/*------------------------------------------------------------------------- + * Function: send_signal + * + * Purpose: Sends the specified signal. + * + * In terms of this test framework, a signal consists of a file + * on disk. Since there are multiple processes that need to + * communicate with each other, they do so by writing and + * reading signal files on disk, the names and contents of + * which are used to inform a process about when it can + * proceed and what it should do next. + * + * This function writes a signal file. The first argument is + * the name of the signal file, and the second and third + * arguments are the contents of the first two lines of the + * signal file. The last two arguments may be NULL. + * + * Return: void + * + * Programmer: Mike McGreevy + * August 18, 2010 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void send_signal(const char * send, const char * arg1, const char * arg2) +{ + FILE *signalfile; + + /* Create signal file (which will send signal to some other process) */ + signalfile = fopen(send, "w+"); + HDfprintf(signalfile, "%s\n%s\n", arg1, arg2); + HDfflush(signalfile); + HDfclose(signalfile); + +} /* send_signal */ + + +/*------------------------------------------------------------------------- + * Function: wait_for_signal + * + * Purpose: Waits for the specified signal. + * + * In terms of this test framework, a signal consists of a file + * on disk. Since there are multiple processes that need to + * communicate with each other, they do so by writing and + * reading signal files on disk, the names and contents of + * which are used to inform a process about when it can + * proceed and what it should do next. + * + * This function continuously attempts to read the specified + * signal file from disk, and only continues once it has + * successfully done so (i.e., only after another process has + * called the "send_signal" function to write the signal file). + * This functon will then immediately remove the file (i.e., + * to indicate that it has been received and can be reused), + * and then exits, allowing the calling function to continue. + * + * Return: void + * + * Programmer: Mike McGreevy + * August 18, 2010 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t wait_for_signal(const char * waitfor) +{ + FILE *returnfile; + time_t t0,t1; + + /* Start timer. If this function runs for too long (i.e., + expected signal is never received), it will + return failure */ + time(&t0); + + /* Wait for return signal from some other process */ + while ((returnfile = fopen(waitfor, "r")) == NULL) { + + /* make note of current time. */ + time(&t1); + + /* If we've been waiting for a signal for too long, then + it was likely never sent and we should fail rather + than loop infinitely */ + if (difftime(t1,t0) > SIGNAL_TIMEOUT) { + HDfprintf(stdout, "Error communicating between processes. Make sure test script is running.\n"); + TEST_ERROR; + } /* end if */ + + } /* end while */ + + HDfclose(returnfile); + HDunlink(waitfor); + + return SUCCEED; + +error: + return FAIL; + +} /* wait_for_signal */ diff --git a/test/testflushrefresh.sh.in b/test/testflushrefresh.sh.in new file mode 100755 index 0000000..ca34ebe --- /dev/null +++ b/test/testflushrefresh.sh.in @@ -0,0 +1,162 @@ +#! /bin/sh +# +# 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. +# +# +# Test script for the flush/evict single objects feature. +# +# This test file doesn't actually perform any tests, rather, it acts +# as a process manager for the 'flushrefresh' test file, which is where +# the tests are actually housed. The reason this script exists is because +# the verification of this feature needs to occur in separate processes +# from the one in which the file is being manipulated in. (i.e., we have +# a single writer process, and various reader processes spawning off +# and doing the verification that individual objects are being +# correctly flushed). +# +# Programmer: +# Mike McGreevy +# Tuesday, July 20, 2010 + +############################################################################### +## test variables +############################################################################### + +nerrors=0 + +############################################################################### +## Main +############################################################################### +# The build (current) directory might be different than the source directory. +if test -z "$srcdir"; then + srcdir=. +fi + +# ======================== +# Launch the Test Program. +# ======================== +./flushrefresh & +pid_main=$! + +# ================================================= +# Set up/initialize some variables to be used later +# ================================================= +startsignal=flushrefresh_VERIFICATION_START +endsignal=flushrefresh_VERIFICATION_DONE +timeout_length=100 +timedout=0 +verification_done=0 + +# ======================================= +# Run flush verification on test program. +# ======================================= + +# start timer +before=`date +%s` +until [ $verification_done -eq 1 ]; do + + # Wait for signal from test program that verification routine can run. + until [ -f $startsignal ]; do + after=`date +%s` + timediff=`expr $after - $before` + if [ $timediff -gt $timeout_length ]; then + nerrors=`expr $nerrors + 1` + timedout=1 + break + fi + done + + # Check to see if we timed out looking for the signal before continuing. + if [ $timedout -gt 0 ]; then + echo timed out waiting for signal from test program. + break + fi + + # Read in test routine parameters from signal file, then delete signal file. + param1=`head -n 1 $startsignal` + param2=`tail -n 1 $startsignal` + rm $startsignal + + # Check if we're done with verifications, otherwise run the specified verification. + if [ "$param1" = "VERIFICATION_DONE" ]; then + verification_done=1 + echo "all flush verification complete" > $endsignal + else + ./flushrefresh $param1 $param2 + echo "verification flush process done" > $endsignal + fi + +done + +# ========================================= +# Run refresh verification on test program. +# ========================================= +if [ $timedout -eq 0 ]; then + # start timer + before=`date +%s` + until [ $verification_done -eq 2 ]; do + + # Wait for signal from test program that verification routine can run. + until [ -f $startsignal ]; do + after=`date +%s` + timediff=`expr $after - $before` + if [ $timediff -gt $timeout_length ]; then + nerrors=`expr $nerrors + 1` + timedout=1 + break + fi + done + + # Check to see if we timed out looking for the signal before continuing. + if [ $timedout -gt 0 ]; then + echo timed out waiting for signal from test program. + break + fi + + # Read in test routine parameter from signal file, then delete signal file. + param1=`head -n 1 $startsignal` + rm $startsignal + + # Check if we're done with verifications, otherwise run the specified verification. + if [ "$param1" = "VERIFICATION_DONE" ]; then + verification_done=2 + echo "all refresh verification complete" > $endsignal + else + ./flushrefresh $param1 + echo "refresh verifiction process done" > $endsignal + fi + + done +fi + +# ============================================ +# Wait for main to finish up, and end testing. +# ============================================ +wait $pid_main +if test $? -ne 0; then + echo flushrefresh had error + nerrors=`expr $nerrors + 1` +fi + +############################################################################### +## Report and exit +############################################################################### + +if test $nerrors -eq 0 ; then + echo "flush/refresh objects tests passed." + exit 0 +else + echo "flush/refresh objects tests failed with $nerrors errors." + exit 1 +fi -- cgit v0.12