summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike McGreevy <mamcgree@hdfgroup.org>2010-11-02 19:00:56 (GMT)
committerMike McGreevy <mamcgree@hdfgroup.org>2010-11-02 19:00:56 (GMT)
commita9ca88d1564351db7ca9371eeede12473b26a6a6 (patch)
treecaff74657cad616101e47989359faac2c53dbc26
parent8e04644abdc73446e85bac72bcced171a927b1f0 (diff)
downloadhdf5-a9ca88d1564351db7ca9371eeede12473b26a6a6.zip
hdf5-a9ca88d1564351db7ca9371eeede12473b26a6a6.tar.gz
hdf5-a9ca88d1564351db7ca9371eeede12473b26a6a6.tar.bz2
[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.
-rw-r--r--MANIFEST3
-rwxr-xr-xconfigure3
-rw-r--r--configure.in1
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/H5AC.c215
-rw-r--r--src/H5ACprivate.h12
-rw-r--r--src/H5C.c374
-rw-r--r--src/H5Cprivate.h23
-rw-r--r--src/H5D.c68
-rw-r--r--src/H5Dpublic.h2
-rw-r--r--src/H5Fio.c75
-rw-r--r--src/H5Fprivate.h4
-rw-r--r--src/H5G.c68
-rw-r--r--src/H5Gpublic.h2
-rw-r--r--src/H5I.c77
-rw-r--r--src/H5Iprivate.h1
-rw-r--r--src/H5Oflush.c291
-rw-r--r--src/H5Oprivate.h4
-rw-r--r--src/H5Opublic.h2
-rw-r--r--src/H5Pdxpl.c7
-rw-r--r--src/H5T.c68
-rw-r--r--src/H5Tpublic.h2
-rwxr-xr-xsrc/Makefile.am2
-rw-r--r--src/Makefile.in21
-rw-r--r--test/Makefile.am10
-rw-r--r--test/Makefile.in57
-rwxr-xr-xtest/flushrefresh.c1251
-rwxr-xr-xtest/testflushrefresh.sh.in162
28 files changed, 2602 insertions, 204 deletions
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 <mamcgree@hdfgroup.org>
+ *
+ * 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