summaryrefslogtreecommitdiffstats
path: root/src/H5F.c
diff options
context:
space:
mode:
authorQuincey Koziol <koziol@hdfgroup.org>2016-12-02 16:07:04 (GMT)
committerQuincey Koziol <koziol@hdfgroup.org>2016-12-02 16:07:04 (GMT)
commit64a339183f0e4532597744351548308203e993c8 (patch)
treeddfff2f15c0f3a01782f191a847665c6eceadd42 /src/H5F.c
parent5d7d029b97b36d1c380cef82d637342921bf3a1d (diff)
downloadhdf5-64a339183f0e4532597744351548308203e993c8.zip
hdf5-64a339183f0e4532597744351548308203e993c8.tar.gz
hdf5-64a339183f0e4532597744351548308203e993c8.tar.bz2
Bring SWMR support in to the main development branch. (Finally!) More tests
and the tool and API wrappers will be coming in over the weekend.
Diffstat (limited to 'src/H5F.c')
-rw-r--r--src/H5F.c240
1 files changed, 236 insertions, 4 deletions
diff --git a/src/H5F.c b/src/H5F.c
index 6b087ce..a43009b 100644
--- a/src/H5F.c
+++ b/src/H5F.c
@@ -456,9 +456,9 @@ H5Fcreate(const char *filename, unsigned flags, hid_t fcpl_id, hid_t fapl_id)
if(!filename || !*filename)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file name")
/* In this routine, we only accept the following flags:
- * H5F_ACC_EXCL and H5F_ACC_TRUNC
+ * H5F_ACC_EXCL, H5F_ACC_TRUNC and H5F_ACC_SWMR_WRITE
*/
- if(flags & ~(H5F_ACC_EXCL | H5F_ACC_TRUNC))
+ if(flags & ~(H5F_ACC_EXCL | H5F_ACC_TRUNC | H5F_ACC_SWMR_WRITE))
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid flags")
/* The H5F_ACC_EXCL and H5F_ACC_TRUNC flags are mutually exclusive */
if((flags & H5F_ACC_EXCL) && (flags & H5F_ACC_TRUNC))
@@ -563,6 +563,12 @@ H5Fopen(const char *filename, unsigned flags, hid_t fapl_id)
if((flags & ~H5F_ACC_PUBLIC_FLAGS) ||
(flags & H5F_ACC_TRUNC) || (flags & H5F_ACC_EXCL))
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file open flags")
+ /* Asking for SWMR write access on a read-only file is invalid */
+ if((flags & H5F_ACC_SWMR_WRITE) && 0 == (flags & H5F_ACC_RDWR))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "SWMR write access on a file open for read-only access is not allowed")
+ /* Asking for SWMR read access on a non-read-only file is invalid */
+ if((flags & H5F_ACC_SWMR_READ) && (flags & H5F_ACC_RDWR))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "SWMR read access on a file open for read-write access is not allowed")
/* Verify access property list and get correct dxpl */
if(H5P_verify_apl_and_dxpl(&fapl_id, H5P_CLS_FACC, &dxpl_id, H5I_INVALID_HID, TRUE) < 0)
@@ -857,10 +863,20 @@ H5Fget_intent(hid_t file_id, unsigned *intent_flags)
* Simplify things for them so that they only get either H5F_ACC_RDWR
* or H5F_ACC_RDONLY.
*/
- if(H5F_INTENT(file) & H5F_ACC_RDWR)
+ if(H5F_INTENT(file) & H5F_ACC_RDWR) {
*intent_flags = H5F_ACC_RDWR;
- else
+
+ /* Check for SWMR write access on the file */
+ if(H5F_INTENT(file) & H5F_ACC_SWMR_WRITE)
+ *intent_flags |= H5F_ACC_SWMR_WRITE;
+ } /* end if */
+ else {
*intent_flags = H5F_ACC_RDONLY;
+
+ /* Check for SWMR read access on the file */
+ if(H5F_INTENT(file) & H5F_ACC_SWMR_READ)
+ *intent_flags |= H5F_ACC_SWMR_READ;
+ } /* end else */
} /* end if */
done:
@@ -1541,6 +1557,222 @@ done:
/*-------------------------------------------------------------------------
+ * Function: H5Fstart_swmr_write
+ *
+ * Purpose: To enable SWMR writing mode for the file
+ * 1) Refresh opened objects: part 1
+ * 2) Flush & reset accumulator
+ * 3) Mark the file in SWMR writing mode
+ * 4) Set metadata read attempts and retries info
+ * 5) Disable accumulator
+ * 6) Evict all cache entries except the superblock
+ * 7) Refresh opened objects (part 2)
+ * 8) Unlock the file
+ *
+ * Pre-conditions:
+ * 1) The file being opened has v3 superblock
+ * 2) The file is opened with H5F_ACC_RDWR
+ * 3) The file is not already marked for SWMR writing
+ * 4) Current implementaion for opened objects:
+ * --only allow datasets and groups without attributes
+ * --disallow named datatype with/without attributes
+ * --disallow opened attributes attached to objects
+ * NOTE: Currently, only opened groups and datasets are allowed
+ * when enabling SWMR via H5Fstart_swmr_write().
+ * Will later implement a different approach--
+ * set up flush dependency/proxy even for file opened without
+ * SWMR to resolve issues with opened objects.
+ *
+ * Return: Non-negative on success/negative on failure
+ *
+ * Programmer:
+ * Vailin Choi; Feb 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fstart_swmr_write(hid_t file_id)
+{
+ H5F_t *file = NULL; /* File info */
+ size_t grp_dset_count=0; /* # of open objects: groups & datasets */
+ size_t nt_attr_count=0; /* # of opened named datatypes + opened attributes */
+ hid_t *obj_ids=NULL; /* List of ids */
+ H5G_loc_t *obj_glocs=NULL; /* Group location of the object */
+ H5O_loc_t *obj_olocs=NULL; /* Object location */
+ H5G_name_t *obj_paths=NULL; /* Group hierarchy path */
+ size_t u; /* Local index variable */
+ hbool_t setup = FALSE; /* Boolean flag to indicate whether SWMR setting is enabled */
+ H5F_io_info_t fio_info; /* I/O info for operation */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE1("e", "i", file_id);
+
+ /* check args */
+ if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file")
+
+ /* Should have write permission */
+ if((H5F_INTENT(file) & H5F_ACC_RDWR) == 0)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "no write intent on file")
+
+ if(file->shared->sblock->super_vers < HDF5_SUPERBLOCK_VERSION_3)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "file superblock version should be at least 3")
+ HDassert(file->shared->latest_flags == H5F_LATEST_ALL_FLAGS);
+
+ /* Should not be marked for SWMR writing mode already */
+ if(file->shared->sblock->status_flags & H5F_SUPER_SWMR_WRITE_ACCESS)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "file already in SWMR writing mode")
+
+ HDassert(file->shared->sblock->status_flags & H5F_SUPER_WRITE_ACCESS);
+
+ /* Flush data buffers */
+ if(H5F_flush(file, H5AC_ind_read_dxpl_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush file's cached information")
+
+ /* Get the # of opened named datatypes and attributes */
+ if(H5F_get_obj_count(file, H5F_OBJ_DATATYPE|H5F_OBJ_ATTR, FALSE, &nt_attr_count) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "H5F_get_obj_count failed")
+ if(nt_attr_count)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "named datatypes and/or attributes opened in the file")
+
+ /* Get the # of opened datasets and groups */
+ if(H5F_get_obj_count(file, H5F_OBJ_GROUP|H5F_OBJ_DATASET, FALSE, &grp_dset_count) < 0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "H5F_get_obj_count failed")
+
+ if(grp_dset_count) {
+ /* Allocate space for group and object locations */
+ if((obj_ids = (hid_t *) H5MM_malloc(grp_dset_count * sizeof(hid_t))) == NULL)
+ HGOTO_ERROR(H5E_FILE, H5E_NOSPACE, FAIL, "can't allocate buffer for hid_t")
+ if((obj_glocs = (H5G_loc_t *) H5MM_malloc(grp_dset_count * sizeof(H5G_loc_t))) == NULL)
+ HGOTO_ERROR(H5E_FILE, H5E_NOSPACE, FAIL, "can't allocate buffer for H5G_loc_t")
+ if((obj_olocs = (H5O_loc_t *) H5MM_malloc(grp_dset_count * sizeof(H5O_loc_t))) == NULL)
+ HGOTO_ERROR(H5E_FILE, H5E_NOSPACE, FAIL, "can't allocate buffer for H5O_loc_t")
+ if((obj_paths = (H5G_name_t *) H5MM_malloc(grp_dset_count * sizeof(H5G_name_t))) == NULL)
+ HGOTO_ERROR(H5E_FILE, H5E_NOSPACE, FAIL, "can't allocate buffer for H5G_name_t")
+
+ /* Get the list of opened object ids (groups & datasets) */
+ if(H5F_get_obj_ids(file, H5F_OBJ_GROUP|H5F_OBJ_DATASET, grp_dset_count, obj_ids, FALSE, &grp_dset_count) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "H5F_get_obj_ids failed")
+
+ /* Refresh opened objects (groups, datasets) in the file */
+ for(u = 0; u < grp_dset_count; u++) {
+ H5O_loc_t *oloc; /* object location */
+ H5G_loc_t tmp_loc;
+
+ /* Set up the id's group location */
+ obj_glocs[u].oloc = &obj_olocs[u];
+ obj_glocs[u].path = &obj_paths[u];
+ H5G_loc_reset(&obj_glocs[u]);
+
+ /* get the id's object location */
+ if((oloc = H5O_get_loc(obj_ids[u])) == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an object")
+
+ /* Make deep local copy of object's location information */
+ H5G_loc(obj_ids[u], &tmp_loc);
+ H5G_loc_copy(&obj_glocs[u], &tmp_loc, H5_COPY_DEEP);
+
+ /* Close the object */
+ if(H5I_dec_ref(obj_ids[u]) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTCLOSEOBJ, FAIL, "decrementing object ID failed")
+ } /* end for */
+ } /* end if */
+
+ /* Set up I/O info for operation */
+ fio_info.f = file;
+ if(NULL == (fio_info.dxpl = (H5P_genplist_t *)H5I_object(H5AC_ind_read_dxpl_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list")
+
+ /* Flush and reset the accumulator */
+ if(H5F__accum_reset(&fio_info, TRUE) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTRESET, FAIL, "can't reset accumulator")
+
+ /* Turn on SWMR write in shared file open flags */
+ file->shared->flags |= H5F_ACC_SWMR_WRITE;
+
+ /* Mark the file in SWMR writing mode */
+ file->shared->sblock->status_flags |= H5F_SUPER_SWMR_WRITE_ACCESS;
+
+ /* Set up metadata read attempts */
+ file->shared->read_attempts = H5F_SWMR_METADATA_READ_ATTEMPTS;
+
+ /* Initialize "retries" and "retries_nbins" */
+ if(H5F_set_retries(file) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "can't set retries and retries_nbins")
+
+ /* Turn off usage of accumulator */
+ file->shared->feature_flags &= ~(unsigned)H5FD_FEAT_ACCUMULATE_METADATA;
+ if(H5FD_set_feature_flags(file->shared->lf, file->shared->feature_flags) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "can't set feature_flags in VFD")
+
+ setup = TRUE;
+
+ /* Mark superblock as dirty */
+ if(H5F_super_dirty(file) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark superblock as dirty")
+
+ /* Flush the superblock */
+ if(H5F_flush_tagged_metadata(file, H5AC__SUPERBLOCK_TAG, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush superblock")
+
+ /* Evict all flushed entries in the cache except the pinned superblock */
+ if(H5F__evict_cache_entries(file, H5AC_ind_read_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to evict file's cached information")
+
+ /* Refresh (reopen) the objects (groups & datasets) in the file */
+ for(u = 0; u < grp_dset_count; u++)
+ if(H5O_refresh_metadata_reopen(obj_ids[u], &obj_glocs[u], H5AC_ind_read_dxpl_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CLOSEERROR, FAIL, "can't refresh-close object")
+
+ /* Unlock the file */
+ if(H5FD_unlock(file->shared->lf) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "unable to unlock the file")
+
+done:
+ if(ret_value < 0 && setup) {
+ HDassert(file);
+
+ /* Re-enable accumulator */
+ file->shared->feature_flags |= (unsigned)H5FD_FEAT_ACCUMULATE_METADATA;
+ if(H5FD_set_feature_flags(file->shared->lf, file->shared->feature_flags) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "can't set feature_flags in VFD")
+
+ /* Reset the # of read attempts */
+ file->shared->read_attempts = H5F_METADATA_READ_ATTEMPTS;
+ if(H5F_set_retries(file) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "can't set retries and retries_nbins")
+
+ /* Un-set H5F_ACC_SWMR_WRITE in shared open flags */
+ file->shared->flags &= ~H5F_ACC_SWMR_WRITE;
+
+ /* Unmark the file: not in SWMR writing mode */
+ file->shared->sblock->status_flags &= (uint8_t)(~H5F_SUPER_SWMR_WRITE_ACCESS);
+
+ /* Mark superblock as dirty */
+ if(H5F_super_dirty(file) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark superblock as dirty")
+
+ /* Flush the superblock */
+ if(H5F_flush_tagged_metadata(file, H5AC__SUPERBLOCK_TAG, H5AC_ind_read_dxpl_id) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush superblock")
+ } /* end if */
+
+ /* Free memory */
+ if(obj_ids)
+ H5MM_xfree(obj_ids);
+ if(obj_glocs)
+ H5MM_xfree(obj_glocs);
+ if(obj_olocs)
+ H5MM_xfree(obj_olocs);
+ if(obj_paths)
+ H5MM_xfree(obj_paths);
+
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fstart_swmr_write() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5Fstart_mdc_logging
*
* Purpose: Start metadata cache logging operations for a file.