summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorQuincey Koziol <koziol@hdfgroup.org>2016-06-14 23:07:03 (GMT)
committerQuincey Koziol <koziol@hdfgroup.org>2016-06-14 23:07:03 (GMT)
commitd3396a79532601bf22e385f94b12e55dfb2c3bd0 (patch)
treededf3566ea2ebf40c2d7475e8a50a3f2f0d57774 /src
parent7a9e13afdb134bafc070cf8bd2087a84fd0d2334 (diff)
downloadhdf5-d3396a79532601bf22e385f94b12e55dfb2c3bd0.zip
hdf5-d3396a79532601bf22e385f94b12e55dfb2c3bd0.tar.gz
hdf5-d3396a79532601bf22e385f94b12e55dfb2c3bd0.tar.bz2
[svn-r30075] Description:
Bring object/dataset/group/named datatype features from revise_chunks branch to trunk. Also CMake support for h5format_convert and a bunch of misc. cleanups. Tested on: MacOSX/64 10.11.5 (amazon) w/serial, parallel & production (h5committest forthcoming)
Diffstat (limited to 'src')
-rw-r--r--src/H5AC.c34
-rw-r--r--src/H5ACpkg.h10
-rw-r--r--src/H5ACprivate.h1
-rw-r--r--src/H5Cprivate.h1
-rw-r--r--src/H5Ctag.c111
-rw-r--r--src/H5D.c34
-rw-r--r--src/H5Dint.c187
-rw-r--r--src/H5Dpkg.h10
-rw-r--r--src/H5Dprivate.h2
-rw-r--r--src/H5Dpublic.h1
-rw-r--r--src/H5Dvirtual.c220
-rw-r--r--src/H5Fint.c2
-rw-r--r--src/H5Fio.c38
-rw-r--r--src/H5Fpkg.h2
-rw-r--r--src/H5Fprivate.h1
-rw-r--r--src/H5Fsuper.c24
-rw-r--r--src/H5I.c67
-rw-r--r--src/H5Iprivate.h1
-rw-r--r--src/H5Oflush.c255
-rw-r--r--src/H5Oprivate.h3
-rw-r--r--src/H5Opublic.h1
21 files changed, 995 insertions, 10 deletions
diff --git a/src/H5AC.c b/src/H5AC.c
index 118fc1b..2dfb7de 100644
--- a/src/H5AC.c
+++ b/src/H5AC.c
@@ -2473,6 +2473,40 @@ done:
} /* 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(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, metadata_tag) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Cannot evict metadata")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_evict_tagged_metadata() */
+
/*------------------------------------------------------------------------------
* Function: H5AC_expunge_tag_type_metadata()
diff --git a/src/H5ACpkg.h b/src/H5ACpkg.h
index 1051373..6b964d6 100644
--- a/src/H5ACpkg.h
+++ b/src/H5ACpkg.h
@@ -402,8 +402,15 @@ typedef struct H5AC_aux_t
void (* sync_point_done)(int num_writes,
haddr_t * written_entries_tbl);
} H5AC_aux_t; /* struct H5AC_aux_t */
+#endif /* H5_HAVE_PARALLEL */
+
+
+/******************************/
+/* Package Private Prototypes */
+/******************************/
-/* Package scoped functions */
+#ifdef H5_HAVE_PARALLEL
+/* Parallel I/O routines */
H5_DLL herr_t H5AC__log_deleted_entry(const H5AC_info_t *entry_ptr);
H5_DLL herr_t H5AC__log_dirtied_entry(const H5AC_info_t *entry_ptr);
H5_DLL herr_t H5AC__log_flushed_entry(H5C_t *cache_ptr, haddr_t addr,
@@ -417,7 +424,6 @@ H5_DLL herr_t H5AC__set_sync_point_done_callback(H5C_t *cache_ptr,
void (*sync_point_done)(int num_writes, haddr_t *written_entries_tbl));
H5_DLL herr_t H5AC__set_write_done_callback(H5C_t * cache_ptr,
void (* write_done)(void));
-
#endif /* H5_HAVE_PARALLEL */
#endif /* _H5ACpkg_H */
diff --git a/src/H5ACprivate.h b/src/H5ACprivate.h
index 4d78938..be20bef 100644
--- a/src/H5ACprivate.h
+++ b/src/H5ACprivate.h
@@ -363,6 +363,7 @@ H5_DLL herr_t H5AC_validate_config(H5AC_cache_config_t *config_ptr);
/* Tag & Ring routines */
H5_DLL herr_t H5AC_tag(hid_t dxpl_id, haddr_t metadata_tag, haddr_t *prev_tag);
H5_DLL herr_t H5AC_flush_tagged_metadata(H5F_t * f, haddr_t metadata_tag, hid_t dxpl_id);
+H5_DLL herr_t H5AC_evict_tagged_metadata(H5F_t * f, haddr_t metadata_tag, hid_t dxpl_id);
H5_DLL herr_t H5AC_retag_copied_metadata(const H5F_t *f, haddr_t metadata_tag);
H5_DLL herr_t H5AC_ignore_tags(const H5F_t *f);
H5_DLL herr_t H5AC_cork(H5F_t *f, haddr_t obj_addr, unsigned action, hbool_t *corked);
diff --git a/src/H5Cprivate.h b/src/H5Cprivate.h
index 0974384..066977f 100644
--- a/src/H5Cprivate.h
+++ b/src/H5Cprivate.h
@@ -1979,6 +1979,7 @@ H5_DLL herr_t H5C_expunge_entry(H5F_t *f, hid_t dxpl_id,
const H5C_class_t *type, haddr_t addr, unsigned flags);
H5_DLL herr_t H5C_flush_cache(H5F_t *f, hid_t dxpl_id, unsigned flags);
H5_DLL herr_t H5C_flush_tagged_entries(H5F_t * f, hid_t dxpl_id, haddr_t tag);
+H5_DLL herr_t H5C_evict_tagged_entries(H5F_t * f, hid_t dxpl_id, haddr_t tag);
H5_DLL herr_t H5C_expunge_tag_type_metadata(H5F_t *f, hid_t dxpl_id, haddr_t tag, int type_id, unsigned flags);
#if H5C_DO_TAGGING_SANITY_CHECKS
herr_t H5C_verify_tag(int id, haddr_t tag, H5C_tag_globality_t globality);
diff --git a/src/H5Ctag.c b/src/H5Ctag.c
index 4748156..d560e25 100644
--- a/src/H5Ctag.c
+++ b/src/H5Ctag.c
@@ -54,6 +54,14 @@
/* Local Typedefs */
/******************/
+/* Typedef for tagged entry iterator callback context - evict tagged entries */
+typedef struct {
+ H5F_t * f; /* File pointer for evicting entry */
+ hid_t dxpl_id; /* DXPL for evicting entry */
+ hbool_t evicted_entries_last_pass; /* Flag to indicate that an entry was evicted when iterating over cache */
+ hbool_t pinned_entries_need_evicted; /* Flag to indicate that a pinned entry was attempted to be evicted */
+} H5C_tag_iter_evict_ctx_t;
+
/* Typedef for tagged entry iterator callback context - retag tagged entries */
typedef struct {
haddr_t dest_tag; /* New tag value for matching entries */
@@ -285,6 +293,109 @@ done:
/*-------------------------------------------------------------------------
*
+ * Function: H5C__evict_tagged_entries_cb
+ *
+ * Purpose: Callback for evicting tagged entries
+ *
+ * Return: H5_ITER_ERROR if error is detected, H5_ITER_CONT otherwise.
+ *
+ * Programmer: Mike McGreevy
+ * August 19, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5C__evict_tagged_entries_cb(H5C_cache_entry_t *entry, void *_ctx)
+{
+ H5C_tag_iter_evict_ctx_t *ctx = (H5C_tag_iter_evict_ctx_t *)_ctx; /* Get pointer to iterator context */
+ int ret_value = H5_ITER_CONT; /* Return value */
+
+ /* Function enter macro */
+ FUNC_ENTER_STATIC
+
+ /* Santify checks */
+ HDassert(entry);
+ HDassert(ctx);
+
+ /* Attempt to evict entry */
+ if(entry->is_protected)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, H5_ITER_ERROR, "Cannot evict protected entry")
+ else if(entry->is_dirty)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, H5_ITER_ERROR, "Cannot evict dirty entry")
+ else if(entry->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) */
+ ctx->pinned_entries_need_evicted = TRUE;
+ else
+ /* Evict the Entry */
+ if(H5C__flush_single_entry(ctx->f, ctx->dxpl_id, entry, H5C__FLUSH_INVALIDATE_FLAG | H5C__FLUSH_CLEAR_ONLY_FLAG | H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, H5_ITER_ERROR, "Entry eviction failed.")
+ ctx->evicted_entries_last_pass = TRUE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C__evict_tagged_entries_cb() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_evict_tagged_entries
+ *
+ * Purpose: Evicts all entries with the specified tag from cache
+ *
+ * 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 dxpl_id, haddr_t tag)
+{
+ H5C_t *cache; /* Pointer to cache structure */
+ H5C_tag_iter_evict_ctx_t ctx; /* Context for iterator callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /* Function enter macro */
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(f);
+ HDassert(f->shared);
+ cache = f->shared->cache; /* Get cache pointer */
+ HDassert(cache != NULL);
+ HDassert(cache->magic == H5C__H5C_T_MAGIC);
+
+ /* Construct context for iterator callbacks */
+ ctx.f = f;
+ ctx.dxpl_id = dxpl_id;
+
+ /* Start evicting entries */
+ do {
+ /* Reset pinned/evicted tracking flags */
+ ctx.pinned_entries_need_evicted = FALSE;
+ ctx.evicted_entries_last_pass = FALSE;
+
+ /* Iterate through entries in the cache */
+ if(H5C__iter_tagged_entries(cache, tag, TRUE, H5C__evict_tagged_entries_cb, &ctx) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_BADITER, FAIL, "Iteration of tagged entries failed")
+
+ /* Keep doing this until we have stopped evicted entries */
+ } while(TRUE == ctx.evicted_entries_last_pass);
+
+ /* Fail if we have finished evicting entries and pinned entries still need evicted */
+ if(ctx.pinned_entries_need_evicted)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Pinned entries still need evicted?!")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_evict_tagged_entries() */
+
+
+/*-------------------------------------------------------------------------
+ *
* Function: H5C__mark_tagged_entries_cb
*
* Purpose: Callback to set the flush marker on dirty entries in the cache
diff --git a/src/H5D.c b/src/H5D.c
index aa932b1..23397ad 100644
--- a/src/H5D.c
+++ b/src/H5D.c
@@ -957,6 +957,40 @@ done:
/*-------------------------------------------------------------------------
+ * 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; /* Dataset to refresh */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(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 the dataset object */
+ if((H5D__refresh(dset_id, dset, H5AC_ind_read_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTLOAD, FAIL, "unable to refresh dataset")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Drefresh() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5Dformat_convert (Internal)
*
* Purpose: For chunked:
diff --git a/src/H5Dint.c b/src/H5Dint.c
index a324873..6f088af 100644
--- a/src/H5Dint.c
+++ b/src/H5Dint.c
@@ -1955,6 +1955,139 @@ done:
/*-------------------------------------------------------------------------
+ * Function: H5D_mult_refresh_close
+ *
+ * Purpose: Closing down the needed information when the dataset has
+ * multiple opens. (From H5O_refresh_metadata_close())
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * 12/24/15
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_mult_refresh_close(hid_t dset_id, hid_t dxpl_id)
+{
+ H5D_t *dataset; /* Dataset to refresh */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ if(NULL == (dataset = (H5D_t *)H5I_object_verify(dset_id, H5I_DATASET)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset")
+
+ /* check args */
+ HDassert(dataset && dataset->oloc.file && dataset->shared);
+ HDassert(dataset->shared->fo_count > 0);
+
+ if(dataset->shared->fo_count > 1) {
+ /* Free cached information for each kind of dataset */
+ switch(dataset->shared->layout.type) {
+ case H5D_CONTIGUOUS:
+ /* Free the data sieve buffer, if it's been allocated */
+ if(dataset->shared->cache.contig.sieve_buf)
+ dataset->shared->cache.contig.sieve_buf = (unsigned char *)H5FL_BLK_FREE(sieve_buf,dataset->shared->cache.contig.sieve_buf);
+ break;
+
+ case H5D_CHUNKED:
+ /* Check for skip list for iterating over chunks during I/O to close */
+ if(dataset->shared->cache.chunk.sel_chunks) {
+ HDassert(H5SL_count(dataset->shared->cache.chunk.sel_chunks) == 0);
+ H5SL_close(dataset->shared->cache.chunk.sel_chunks);
+ dataset->shared->cache.chunk.sel_chunks = NULL;
+ } /* end if */
+
+ /* Check for cached single chunk dataspace */
+ if(dataset->shared->cache.chunk.single_space) {
+ (void)H5S_close(dataset->shared->cache.chunk.single_space);
+ dataset->shared->cache.chunk.single_space = NULL;
+ } /* end if */
+
+ /* Check for cached single element chunk info */
+ if(dataset->shared->cache.chunk.single_chunk_info) {
+ dataset->shared->cache.chunk.single_chunk_info = H5FL_FREE(H5D_chunk_info_t, dataset->shared->cache.chunk.single_chunk_info);
+ dataset->shared->cache.chunk.single_chunk_info = NULL;
+ } /* end if */
+ break;
+
+ case H5D_COMPACT:
+ case H5D_VIRTUAL:
+ /* Nothing special to do (info freed in the layout destroy) */
+ break;
+
+ case H5D_LAYOUT_ERROR:
+ case H5D_NLAYOUTS:
+ default:
+ HDassert("not implemented yet" && 0);
+#ifdef NDEBUG
+ HGOTO_ERROR(H5E_IO, H5E_UNSUPPORTED, FAIL, "unsupported storage layout")
+#endif /* NDEBUG */
+ } /* end switch */ /*lint !e788 All appropriate cases are covered */
+
+ /* Destroy any cached layout information for the dataset */
+ if(dataset->shared->layout.ops->dest && (dataset->shared->layout.ops->dest)(dataset, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "unable to destroy layout info")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_mult_refresh_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_mult_refresh_reopen
+ *
+ * Purpose: Re-initialize the needed info when the dataset has multiple
+ * opens. (From H5O_refresh_metadata_reopen())
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi
+ * 12/24/15
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_mult_refresh_reopen(H5D_t *dataset, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(dataset && dataset->oloc.file && dataset->shared);
+ HDassert(dataset->shared->fo_count > 0);
+
+ if(dataset->shared->fo_count > 1) {
+ /* Release dataspace info */
+ if(H5S_close(dataset->shared->space) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "unable to release dataspace")
+
+ /* Re-load dataspace info */
+ if(NULL == (dataset->shared->space = H5S_read(&(dataset->oloc), dxpl_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to load dataspace info from dataset header")
+
+ /* Cache the dataset's dataspace info */
+ if(H5D__cache_dataspace_info(dataset) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't cache dataspace info")
+
+ /* Release layout info */
+ if(H5O_msg_reset(H5O_LAYOUT_ID, &dataset->shared->layout) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTRESET, FAIL, "unable to reset layout info")
+
+ /* Re-load layout message info */
+ if(NULL == H5O_msg_read(&(dataset->oloc), H5O_LAYOUT_ID, &(dataset->shared->layout), dxpl_id))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to read data layout message")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D_mult_refresh_reopen() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5D_oloc
*
* Purpose: Returns a pointer to the object location for a dataset.
@@ -3475,3 +3608,57 @@ done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5D_get_type() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__refresh
+ *
+ * Purpose: Refreshes all buffers associated with a dataset.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Dana Robinson
+ * November 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__refresh(hid_t dset_id, H5D_t *dset, hid_t dxpl_id)
+{
+ H5D_virtual_held_file_t *head = NULL; /* Pointer to list of files held open */
+ hbool_t virt_dsets_held = FALSE; /* Whether virtual datasets' files are held open */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(dset);
+
+ /* If the layout is virtual... */
+ if(dset->shared->layout.type == H5D_VIRTUAL) {
+ /* Hold open the source datasets' files */
+ if(H5D__virtual_hold_source_dset_files(dset, &head) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINC, FAIL, "unable to hold VDS source files open")
+ virt_dsets_held = TRUE;
+
+ /* Refresh source datasets for virtual dataset */
+ if(H5D__virtual_refresh_source_dsets(dset, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to refresh VDS source datasets")
+ } /* end if */
+
+ /* Refresh dataset object */
+ if((H5O_refresh_metadata(dset_id, dset->oloc, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to refresh dataset")
+
+done:
+ /* Release hold on virtual datasets' files */
+ if(virt_dsets_held) {
+ /* Sanity check */
+ HDassert(dset->shared->layout.type == H5D_VIRTUAL);
+
+ /* Release the hold on source datasets' files */
+ if(H5D__virtual_release_source_dset_files(head) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTDEC, FAIL, "can't release VDS source files held open")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__refresh() */
+
diff --git a/src/H5Dpkg.h b/src/H5Dpkg.h
index 3b2727f..05f49d1 100644
--- a/src/H5Dpkg.h
+++ b/src/H5Dpkg.h
@@ -394,6 +394,12 @@ typedef struct H5D_chunk_cached_t {
unsigned filter_mask; /*excluded filters */
} H5D_chunk_cached_t;
+/* List of files held open during refresh operations */
+typedef struct H5D_virtual_held_file_t {
+ H5F_t *file; /* Pointer to file held open */
+ struct H5D_virtual_held_file_t *next; /* Pointer to next node in list */
+} H5D_virtual_held_file_t;
+
/* The raw data chunk cache */
struct H5D_rdcc_ent_t; /* Forward declaration of struct used below */
typedef struct H5D_rdcc_t {
@@ -579,6 +585,7 @@ H5_DLL herr_t H5D__get_dxpl_cache(hid_t dxpl_id, H5D_dxpl_cache_t **cache);
H5_DLL herr_t H5D__flush_sieve_buf(H5D_t *dataset, hid_t dxpl_id);
H5_DLL herr_t H5D__flush_real(H5D_t *dataset, hid_t dxpl_id);
H5_DLL herr_t H5D__mark(const H5D_t *dataset, hid_t dxpl_id, unsigned flags);
+H5_DLL herr_t H5D__refresh(hid_t dset_id, H5D_t *dataset, hid_t dxpl_id);
#ifdef H5_DEBUG_BUILD
H5_DLL herr_t H5D_set_io_info_dxpls(H5D_io_info_t *io_info, hid_t dxpl_id);
#endif /* H5_DEBUG_BUILD */
@@ -696,6 +703,9 @@ H5_DLL herr_t H5D__virtual_copy(H5F_t *f_src, H5O_layout_t *layout_dst,
H5_DLL herr_t H5D__virtual_init(H5F_t *f, hid_t dxpl_id, const H5D_t *dset,
hid_t dapl_id);
H5_DLL hbool_t H5D__virtual_is_space_alloc(const H5O_storage_t *storage);
+H5_DLL herr_t H5D__virtual_hold_source_dset_files(const H5D_t *dset, H5D_virtual_held_file_t **head);
+H5_DLL herr_t H5D__virtual_refresh_source_dsets(H5D_t *dset, hid_t dxpl_id);
+H5_DLL herr_t H5D__virtual_release_source_dset_files(H5D_virtual_held_file_t *head);
/* Functions that operate on EFL (External File List)*/
H5_DLL hbool_t H5D__efl_is_space_alloc(const H5O_storage_t *storage);
diff --git a/src/H5Dprivate.h b/src/H5Dprivate.h
index d1468dd..ea2b8c8 100644
--- a/src/H5Dprivate.h
+++ b/src/H5Dprivate.h
@@ -173,6 +173,8 @@ typedef struct H5D_append_flush_t {
H5_DLL herr_t H5D_init(void);
H5_DLL H5D_t *H5D_open(const H5G_loc_t *loc, hid_t dapl_id, hid_t dxpl_id);
H5_DLL herr_t H5D_close(H5D_t *dataset);
+H5_DLL herr_t H5D_mult_refresh_close(hid_t dset_id, hid_t dxpl_id);
+H5_DLL herr_t H5D_mult_refresh_reopen(H5D_t *dataset, hid_t dxpl_id);
H5_DLL H5O_loc_t *H5D_oloc(H5D_t *dataset);
H5_DLL H5G_name_t *H5D_nameof(H5D_t *dataset);
H5_DLL H5T_t *H5D_typeof(const H5D_t *dset);
diff --git a/src/H5Dpublic.h b/src/H5Dpublic.h
index 831e811..81ae67d 100644
--- a/src/H5Dpublic.h
+++ b/src/H5Dpublic.h
@@ -161,6 +161,7 @@ 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 H5Dscatter(H5D_scatter_func_t op, void *op_data, hid_t type_id,
hid_t dst_space_id, void *dst_buf);
H5_DLL herr_t H5Dgather(hid_t src_space_id, const void *src_buf, hid_t type_id,
diff --git a/src/H5Dvirtual.c b/src/H5Dvirtual.c
index c516c58..9a90fa7 100644
--- a/src/H5Dvirtual.c
+++ b/src/H5Dvirtual.c
@@ -144,6 +144,9 @@ const H5D_layout_ops_t H5D_LOPS_VIRTUAL[1] = {{
/* Declare a free list to manage the H5O_storage_virtual_name_seg_t struct */
H5FL_DEFINE(H5O_storage_virtual_name_seg_t);
+/* Declare a static free list to manage H5D_virtual_file_list_t structs */
+H5FL_DEFINE_STATIC(H5D_virtual_held_file_t);
+
/*-------------------------------------------------------------------------
@@ -2725,3 +2728,220 @@ done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5D__virtual_flush() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_hold_source_dset_files
+ *
+ * Purpose: Hold open the source files that are open, during a refresh event
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * November 7, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__virtual_hold_source_dset_files(const H5D_t *dset, H5D_virtual_held_file_t **head)
+{
+ H5O_storage_virtual_t *storage; /* Convenient pointer into layout struct */
+ H5D_virtual_held_file_t *tmp; /* Temporary held file node */
+ size_t i; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(dset);
+ HDassert(head && NULL == *head);
+
+ /* Set the convenience pointer */
+ storage = &dset->shared->layout.storage.u.virt;
+
+ /* Hold only files for open datasets */
+ for(i = 0; i < storage->list_nused; i++)
+ /* Check for "printf" source dataset resolution */
+ if(storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) {
+ size_t j; /* Local index variable */
+
+ /* Iterate over sub-source dsets */
+ for(j = 0; j < storage->list[i].sub_dset_nused; j++)
+ if(storage->list[i].sub_dset[j].dset) {
+ /* Hold open the file */
+ H5F_INCR_NOPEN_OBJS(storage->list[i].sub_dset[j].dset->oloc.file);
+
+ /* Allocate a node for this file */
+ if(NULL == (tmp = H5FL_MALLOC(H5D_virtual_held_file_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate held file node")
+
+ /* Set up node & connect to list */
+ tmp->file = storage->list[i].sub_dset[j].dset->oloc.file;
+ tmp->next = *head;
+ *head = tmp;
+ } /* end if */
+ } /* end if */
+ else
+ if(storage->list[i].source_dset.dset) {
+ /* Hold open the file */
+ H5F_INCR_NOPEN_OBJS(storage->list[i].source_dset.dset->oloc.file);
+
+ /* Allocate a node for this file */
+ if(NULL == (tmp = H5FL_MALLOC(H5D_virtual_held_file_t)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate held file node")
+
+ /* Set up node & connect to list */
+ tmp->file = storage->list[i].source_dset.dset->oloc.file;
+ tmp->next = *head;
+ *head = tmp;
+ } /* end if */
+
+done:
+ if(ret_value < 0) {
+ /* Release hold on files and delete list on error */
+ if(*head)
+ if(H5D__virtual_release_source_dset_files(*head) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't release source datasets' files held open")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_hold_source_dset_files() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_refresh_source_dset
+ *
+ * Purpose: Refresh a source dataset
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * November 7, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__virtual_refresh_source_dset(H5D_t **dset, hid_t dxpl_id)
+{
+ hid_t dset_id; /* Temporary dataset identifier */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(dset && *dset);
+
+ /* Get a temporary identifier for this source dataset */
+ if((dset_id = H5I_register(H5I_DATASET, *dset, FALSE)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "can't register source dataset ID")
+
+ /* Refresh source dataset */
+ if(H5D__refresh(dset_id, *dset, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to refresh source dataset")
+
+ /* Discard the identifier & replace the dataset */
+ if(NULL == (*dset = (H5D_t *)H5I_remove(dset_id)))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTREMOVE, FAIL, "can't unregister source dataset ID")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_refresh_source_dsets() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_refresh_source_dsets
+ *
+ * Purpose: Refresh the source datasets
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Dana Robinson
+ * November, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__virtual_refresh_source_dsets(H5D_t *dset, hid_t dxpl_id)
+{
+ H5O_storage_virtual_t *storage; /* Convenient pointer into layout struct */
+ size_t i; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Sanity check */
+ HDassert(dset);
+
+ /* Set convenience pointer */
+ storage = &dset->shared->layout.storage.u.virt;
+
+ /* Refresh only open datasets */
+ for(i = 0; i < storage->list_nused; i++)
+ /* Check for "printf" source dataset resolution */
+ if(storage->list[i].psfn_nsubs || storage->list[i].psdn_nsubs) {
+ size_t j; /* Local index variable */
+
+ /* Iterate over sub-source datasets */
+ for(j = 0; j < storage->list[i].sub_dset_nused; j++)
+ /* Check if sub-source dataset is open */
+ if(storage->list[i].sub_dset[j].dset)
+ /* Refresh sub-source dataset */
+ if(H5D__virtual_refresh_source_dset(&storage->list[i].sub_dset[j].dset, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to refresh source dataset")
+ } /* end if */
+ else
+ /* Check if source dataset is open */
+ if(storage->list[i].source_dset.dset)
+ /* Refresh source dataset */
+ if(H5D__virtual_refresh_source_dset(&storage->list[i].source_dset.dset, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to refresh source dataset")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_refresh_source_dsets() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D__virtual_release_source_dset_files
+ *
+ * Purpose: Release the hold on source files that are open, during a refresh event
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * November 7, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D__virtual_release_source_dset_files(H5D_virtual_held_file_t *head)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Release hold on files and delete list */
+ while(head) {
+ H5D_virtual_held_file_t *tmp = head->next; /* Temporary pointer to next node */
+
+ /* Release hold on file */
+ H5F_DECR_NOPEN_OBJS(head->file);
+
+ /* Attempt to close the file */
+ /* (Should always succeed, since the 'top' source file pointer is
+ * essentially "private" to the virtual dataset, since it wasn't
+ * opened through an API routine -QAK)
+ */
+ if(H5F_try_close(head->file) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEFILE, FAIL, "problem attempting file close")
+
+ /* Delete node */
+ (void)H5FL_FREE(H5D_virtual_held_file_t, head);
+
+ /* Advance to next node */
+ head = tmp;
+ } /* end while */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__virtual_release_source_dset_files() */
+
diff --git a/src/H5Fint.c b/src/H5Fint.c
index 9ca472d..80c593b 100644
--- a/src/H5Fint.c
+++ b/src/H5Fint.c
@@ -1085,7 +1085,7 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id,
} else if (1 == shared->nrefs) {
/* Read the superblock if it hasn't been read before. */
- if(H5F__super_read(file, dxpl_id) < 0)
+ if(H5F__super_read(file, dxpl_id, TRUE) < 0)
HGOTO_ERROR(H5E_FILE, H5E_READERROR, NULL, "unable to read superblock")
/* Open the root group */
diff --git a/src/H5Fio.c b/src/H5Fio.c
index 1fb3459..b9bd354 100644
--- a/src/H5Fio.c
+++ b/src/H5Fio.c
@@ -244,3 +244,41 @@ 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(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, FALSE) < 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/H5Fpkg.h b/src/H5Fpkg.h
index e2874d1..c5aed3b 100644
--- a/src/H5Fpkg.h
+++ b/src/H5Fpkg.h
@@ -356,7 +356,7 @@ H5_DLL herr_t H5F_mount_count_ids(H5F_t *f, unsigned *nopen_files, unsigned *nop
/* Superblock related routines */
H5_DLL herr_t H5F__super_init(H5F_t *f, hid_t dxpl_id);
-H5_DLL herr_t H5F__super_read(H5F_t *f, hid_t dxpl_id);
+H5_DLL herr_t H5F__super_read(H5F_t *f, hid_t dxpl_id, hbool_t initial_read);
H5_DLL herr_t H5F__super_size(H5F_t *f, hid_t dxpl_id, hsize_t *super_size, hsize_t *super_ext_size);
H5_DLL herr_t H5F__super_free(H5F_super_t *sblock);
diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h
index 7d45ed9..34a5277 100644
--- a/src/H5Fprivate.h
+++ b/src/H5Fprivate.h
@@ -698,6 +698,7 @@ H5_DLL herr_t H5F_block_write(const H5F_t *f, H5FD_mem_t type, haddr_t addr,
/* 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);
/* Routine to invoke callback function upon object flush */
H5_DLL herr_t H5F_object_flush_cb(H5F_t *f, hid_t obj_id);
diff --git a/src/H5Fsuper.c b/src/H5Fsuper.c
index 4aca221..23b7f78 100644
--- a/src/H5Fsuper.c
+++ b/src/H5Fsuper.c
@@ -239,7 +239,7 @@ done:
*-------------------------------------------------------------------------
*/
herr_t
-H5F__super_read(H5F_t *f, hid_t dxpl_id)
+H5F__super_read(H5F_t *f, hid_t dxpl_id, hbool_t initial_read)
{
H5P_genplist_t *dxpl = NULL; /* DXPL object */
H5AC_ring_t ring, orig_ring = H5AC_RING_INV;
@@ -400,12 +400,24 @@ H5F__super_read(H5F_t *f, hid_t dxpl_id)
* possible is if the first file of a family of files was opened
* individually.
*/
- if(HADDR_UNDEF == (eof = H5FD_get_eof(f->shared->lf, H5FD_MEM_DEFAULT)))
- HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to determine file size")
+ /* Can skip this test when it is not the initial file open--
+ * H5F_super_read() call from H5F_evict_tagged_metadata() for
+ * refreshing object.
+ * When flushing file buffers and fractal heap is involved,
+ * the library will allocate actual space for tmp addresses
+ * via the file layer. The aggregator allocates a block,
+ * thus the eoa might be greater than eof.
+ * Note: the aggregator is changed again after being reset
+ * earlier before H5AC_flush due to allocation of tmp addresses.
+ */
+ if(initial_read) {
+ if(HADDR_UNDEF == (eof = H5FD_get_eof(f->shared->lf, H5FD_MEM_DEFAULT)))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to determine file size")
- /* (Account for the stored EOA being absolute offset -QAK) */
- if((eof + sblock->base_addr) < udata.stored_eof)
- HGOTO_ERROR(H5E_FILE, H5E_TRUNCATED, FAIL, "truncated file: eof = %llu, sblock->base_addr = %llu, stored_eoa = %llu", (unsigned long long)eof, (unsigned long long)sblock->base_addr, (unsigned long long)udata.stored_eof)
+ /* (Account for the stored EOA being absolute offset -QAK) */
+ if((eof + sblock->base_addr) < udata.stored_eof)
+ HGOTO_ERROR(H5E_FILE, H5E_TRUNCATED, FAIL, "truncated file: eof = %llu, sblock->base_addr = %llu, stored_eof = %llu", (unsigned long long)eof, (unsigned long long)sblock->base_addr, (unsigned long long)udata.stored_eof)
+ } /* end if */
/*
* Tell the file driver how much address space has already been
diff --git a/src/H5I.c b/src/H5I.c
index a53b13b..0fe9782 100644
--- a/src/H5I.c
+++ b/src/H5I.c
@@ -789,6 +789,73 @@ 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
+ *
+ *-------------------------------------------------------------------------
+ */
+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 */
+ herr_t ret_value = SUCCEED; /*return value */
+
+ FUNC_ENTER_NOAPI(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->init_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;
+
+ /* Insert into the type */
+ if(H5SL_insert(type_ptr->ids, id_ptr, &id_ptr->id) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTINSERT, FAIL, "can't insert ID node into skip list")
+ type_ptr->id_count++;
+
+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 f438581..c916f31 100644
--- a/src/H5Iprivate.h
+++ b/src/H5Iprivate.h
@@ -69,6 +69,7 @@ H5_DLL herr_t H5I_register_type(const H5I_class_t *cls);
H5_DLL int64_t 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 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
index 0bec096..6484dfd 100644
--- a/src/H5Oflush.c
+++ b/src/H5Oflush.c
@@ -54,6 +54,53 @@ static herr_t H5O_oh_tag(const H5O_loc_t *oloc, hid_t dxpl_id, haddr_t *tag);
/*-------------------------------------------------------------------------
+ * 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 */
+ void *obj_ptr; /* Pointer to object */
+ const H5O_obj_class_t *obj_class = NULL; /* Class of object */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", obj_id);
+
+ /* Check args */
+ if(NULL == (oloc = H5O_get_loc(obj_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an object")
+
+ /* Get the object pointer */
+ if(NULL == (obj_ptr = H5I_object(obj_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid object identifier")
+
+ /* Get the object class */
+ if(NULL == (obj_class = H5O_obj_class(oloc, H5AC_ind_read_dxpl_id)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object class")
+
+ /* Flush the object of this class */
+ if(obj_class->flush && obj_class->flush(obj_ptr, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object")
+
+ /* Flush the object metadata and invoke flush callback */
+ if(H5O_flush_common(oloc, obj_id, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object and object flush callback")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Oflush() */
+
+/*-------------------------------------------------------------------------
* Function: H5O_flush_common
*
* Purpose: Flushes the object's metadata
@@ -130,3 +177,211 @@ done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5O_oh_tag() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_refresh_metadata
+ *
+ * Purpose: Refreshes all buffers associated with an object.
+ *
+ * Note: This is based on the original H5O_refresh_metadata() but
+ * is split into 2 routines.
+ * This is done so that H5Fstart_swmr_write() can use these
+ * 2 routines to refresh opened objects. This may be
+ * restored back to the original code when H5Fstart_swmr_write()
+ * uses a different approach to handle issues with opened objects.
+ * H5Fstart_swmr_write() no longer calls the 1st routine. (12/24/15)
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Mike McGreevy/Vailin Choi
+ * July 28, 2010/Feb 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_refresh_metadata(hid_t oid, H5O_loc_t oloc, hid_t dxpl_id)
+{
+ hbool_t objs_incr = FALSE; /* Whether the object count in the file was incremented */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* If the file is opened with write access, no need to perform refresh actions. */
+ if(!(H5F_INTENT(oloc.file) & H5F_ACC_RDWR)) {
+ H5G_loc_t obj_loc;
+ H5O_loc_t obj_oloc;
+ H5G_name_t obj_path;
+
+ /* Create empty object location */
+ obj_loc.oloc = &obj_oloc;
+ obj_loc.path = &obj_path;
+ H5G_loc_reset(&obj_loc);
+
+ /* "Fake" another open object in the file, so that it doesn't get closed
+ * if this object is the only thing holding the file open.
+ */
+ H5F_incr_nopen_objs(oloc.file);
+ objs_incr = TRUE;
+
+ /* Close object & evict its metadata */
+ if((H5O_refresh_metadata_close(oid, oloc, &obj_loc, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to refresh object")
+
+ /* Re-open the object, re-fetching its metadata */
+ if((H5O_refresh_metadata_reopen(oid, &obj_loc, dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to refresh object")
+ } /* end if */
+
+done:
+ if(objs_incr)
+ H5F_decr_nopen_objs(oloc.file);
+
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5O_refresh_metadata() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_refresh_metadata_close
+ *
+ * Purpose: This is the first part of the original routine H5O_refresh_metadata().
+ * (1) Save object location information.
+ * (2) Handle multiple dataset opens
+ * (3) Get object cork status
+ * (4) Close the object
+ * (5) Flush and evict object metadata
+ * (6) Re-cork the object if needed
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Mike McGreevy/Vailin Choi
+ * July 28, 2010/Feb 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_refresh_metadata_close(hid_t oid, H5O_loc_t oloc, H5G_loc_t *obj_loc, hid_t dxpl_id)
+{
+ haddr_t tag = 0; /* Tag for object */
+ hbool_t corked = FALSE; /* Whether object's metadata is corked */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Make deep local copy of object's location information */
+ if(obj_loc) {
+ H5G_loc_t tmp_loc;
+
+ H5G_loc(oid, &tmp_loc);
+ H5G_loc_copy(obj_loc, &tmp_loc, H5_COPY_DEEP);
+ } /* end if */
+
+ /* Get object's type */
+ if(H5I_get_type(oid) == H5I_DATASET)
+ if(H5D_mult_refresh_close(oid, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to prepare refresh for dataset")
+
+ /* Retrieve tag for object */
+ if(H5O_oh_tag(&oloc, dxpl_id, &tag) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to get object header address")
+
+ /* Get cork status of the object with tag */
+ if(H5AC_cork(oloc.file, tag, H5AC__GET_CORKED, &corked) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_SYSTEM, FAIL, "unable to retrieve an object's cork status")
+
+ /* Close the object */
+ if(H5I_dec_ref(oid) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to close object")
+
+ /* 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")
+
+ /* 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")
+
+ /* Re-cork object with tag */
+ if(corked)
+ if(H5AC_cork(oloc.file, tag, H5AC__SET_CORK, &corked) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_SYSTEM, FAIL, "unable to cork the object")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5O_refresh_metadata_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_refresh_metadata_reopen
+ *
+ * Purpose: This is the second part of the original routine H5O_refresh_metadata().
+ * (1) Re-open object with the saved object location information.
+ * (2) Re-register object ID with the re-opened object.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Mike McGreevy/Vailin Choi
+ * July 28, 2010/Feb 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_refresh_metadata_reopen(hid_t oid, H5G_loc_t *obj_loc, hid_t dxpl_id)
+{
+ void *object = NULL; /* Dataset for this operation */
+ H5I_type_t type; /* Type of object for the ID */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Get object's type */
+ type = H5I_get_type(oid);
+
+ 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")
+ if(H5D_mult_refresh_reopen((H5D_t *)object, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to finish refresh for 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:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5O_refresh_metadata_reopen() */
+
diff --git a/src/H5Oprivate.h b/src/H5Oprivate.h
index 9ad8662..44b4998 100644
--- a/src/H5Oprivate.h
+++ b/src/H5Oprivate.h
@@ -904,6 +904,9 @@ H5_DLL herr_t H5O_msg_unlock(const H5O_loc_t *loc, unsigned type_id, hid_t dxpl_
/* Object metadata flush/refresh routines */
H5_DLL herr_t H5O_flush_common(H5O_loc_t *oloc, hid_t obj_id, hid_t dxpl_id);
+H5_DLL herr_t H5O_refresh_metadata(hid_t oid, H5O_loc_t oloc, hid_t dxpl_id);
+H5_DLL herr_t H5O_refresh_metadata_close(hid_t oid, H5O_loc_t oloc, H5G_loc_t *obj_loc, hid_t dxpl_id);
+H5_DLL herr_t H5O_refresh_metadata_reopen(hid_t oid, H5G_loc_t *obj_loc, 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 */,
diff --git a/src/H5Opublic.h b/src/H5Opublic.h
index 9debdbc..1d2ab7b 100644
--- a/src/H5Opublic.h
+++ b/src/H5Opublic.h
@@ -182,6 +182,7 @@ 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 H5Odisable_mdc_flushes(hid_t object_id);
H5_DLL herr_t H5Oenable_mdc_flushes(hid_t object_id);
H5_DLL herr_t H5Oare_mdc_flushes_disabled(hid_t object_id, hbool_t *are_disabled);