summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/H5AC.c33
-rw-r--r--src/H5ACprivate.h2
-rw-r--r--src/H5C.c39
-rw-r--r--src/H5Cprivate.h4
-rw-r--r--src/H5D.c14
-rw-r--r--src/H5Dint.c97
-rw-r--r--src/H5Doh.c25
-rw-r--r--src/H5Dpkg.h1
-rw-r--r--src/H5Dprivate.h9
-rw-r--r--src/H5Dpublic.h3
-rw-r--r--src/H5F.c382
-rw-r--r--src/H5FD.c58
-rw-r--r--src/H5FDcore.c79
-rw-r--r--src/H5FDdirect.c78
-rw-r--r--src/H5FDprivate.h2
-rw-r--r--src/H5FDpublic.h4
-rw-r--r--src/H5FDsec2.c72
-rw-r--r--src/H5Fio.c49
-rw-r--r--src/H5Fpkg.h21
-rw-r--r--src/H5Fprivate.h13
-rw-r--r--src/H5Fpublic.h5
-rw-r--r--src/H5Fsuper.c2
-rw-r--r--src/H5G.c5
-rw-r--r--src/H5Ocopy.c29
-rw-r--r--src/H5Oflush.c54
-rw-r--r--src/H5Opkg.h2
-rw-r--r--src/H5Oprivate.h2
-rw-r--r--src/H5Pdapl.c130
-rw-r--r--src/H5Pfapl.c111
-rw-r--r--src/H5Ppublic.h7
-rw-r--r--src/H5T.c6
-rw-r--r--src/H5config.h.in3
-rw-r--r--src/H5private.h10
33 files changed, 1256 insertions, 95 deletions
diff --git a/src/H5AC.c b/src/H5AC.c
index 46b5785..18da8de 100644
--- a/src/H5AC.c
+++ b/src/H5AC.c
@@ -730,6 +730,39 @@ done:
/*-------------------------------------------------------------------------
+ * Function: H5AC_evict
+ *
+ * Purpose: Evict all entries except the pinned entries
+ * in the cache.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Dec 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_evict(H5F_t *f, hid_t dxpl_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+ HDassert(f->shared->cache);
+
+ /* Evict all entries in the cache except the pinned superblock entry */
+ if(H5C_evict(f, dxpl_id, H5AC_noblock_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, "can't evict cache")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5AC_evict() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5AC_expunge_entry
*
* Purpose: Expunge the target entry from the cache without writing it
diff --git a/src/H5ACprivate.h b/src/H5ACprivate.h
index ae4b9fc..acb3adc 100644
--- a/src/H5ACprivate.h
+++ b/src/H5ACprivate.h
@@ -333,6 +333,7 @@ H5_DLLVAR hid_t H5AC_ind_dxpl_id;
#define H5AC__TAKE_OWNERSHIP_FLAG H5C__TAKE_OWNERSHIP_FLAG
#define H5AC__FLUSH_LAST_FLAG H5C__FLUSH_LAST_FLAG
#define H5AC__FLUSH_COLLECTIVELY_FLAG H5C__FLUSH_COLLECTIVELY_FLAG
+#define H5AC__EVICT_ALLOW_LAST_PINS_FLAG H5C__EVICT_ALLOW_LAST_PINS_FLAG
/* #defines of flags used to report entry status in the
@@ -371,6 +372,7 @@ H5_DLL herr_t H5AC_move_entry(H5F_t *f, const H5AC_class_t *type,
haddr_t old_addr, haddr_t new_addr);
H5_DLL herr_t H5AC_dest(H5F_t *f, hid_t dxpl_id);
+H5_DLL herr_t H5AC_evict(H5F_t *f, hid_t dxpl_id);
H5_DLL herr_t H5AC_expunge_entry(H5F_t *f, hid_t dxpl_id,
const H5AC_class_t *type, haddr_t addr,
diff --git a/src/H5C.c b/src/H5C.c
index a76dbc4..cd2345c 100644
--- a/src/H5C.c
+++ b/src/H5C.c
@@ -1561,7 +1561,41 @@ done:
/*-------------------------------------------------------------------------
+ * Function: H5C_evict
*
+ * Purpose: Evict all except pinned entries in the cache
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Dec 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_evict(H5F_t * f,
+ hid_t primary_dxpl_id,
+ hid_t secondary_dxpl_id)
+{
+ H5C_t *cache_ptr = f->shared->cache;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(cache_ptr);
+ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
+
+ /* Flush and invalidate all cache entries except the pinned entries */
+ if(H5C_flush_invalidate_cache(f, primary_dxpl_id, secondary_dxpl_id,
+ H5C__EVICT_ALLOW_LAST_PINS_FLAG) < 0 )
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to evict entries in the cache")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5C_evict() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5C_expunge_entry
*
* Purpose: Use this function to tell the cache to expunge an entry
@@ -7534,6 +7568,7 @@ H5C_flush_invalidate_cache(H5F_t * f,
int32_t cur_pel_len;
int32_t old_pel_len;
unsigned cooked_flags;
+ unsigned evict_flags;
H5SL_node_t * node_ptr = NULL;
H5C_cache_entry_t * entry_ptr = NULL;
H5C_cache_entry_t * next_entry_ptr = NULL;
@@ -7556,6 +7591,7 @@ H5C_flush_invalidate_cache(H5F_t * f,
* At present, only the H5C__FLUSH_CLEAR_ONLY_FLAG is kept.
*/
cooked_flags = flags & H5C__FLUSH_CLEAR_ONLY_FLAG;
+ evict_flags = flags & H5C__EVICT_ALLOW_LAST_PINS_FLAG;
/* remove ageout markers if present */
if ( cache_ptr->epoch_markers_active > 0 ) {
@@ -7932,6 +7968,8 @@ end_of_inner_loop:
if ( ( cur_pel_len > 0 ) && ( cur_pel_len >= old_pel_len ) ) {
+ if(evict_flags) HGOTO_DONE(TRUE)
+
/* The number of pinned entries is positive, and it is not
* declining. Scream and die.
*/
@@ -9664,7 +9702,6 @@ done:
FUNC_LEAVE_NOAPI(ret_value)
} /* H5C__mark_flush_dep_clean() */
-
#ifndef NDEBUG
/*-------------------------------------------------------------------------
diff --git a/src/H5Cprivate.h b/src/H5Cprivate.h
index b3aab86..581e89d 100644
--- a/src/H5Cprivate.h
+++ b/src/H5Cprivate.h
@@ -1069,6 +1069,7 @@ typedef struct H5C_auto_size_ctl_t
#define H5C__TAKE_OWNERSHIP_FLAG 0x1000
#define H5C__FLUSH_LAST_FLAG 0x2000
#define H5C__FLUSH_COLLECTIVELY_FLAG 0x4000
+#define H5C__EVICT_ALLOW_LAST_PINS_FLAG 0x8000
#ifdef H5_HAVE_PARALLEL
H5_DLL herr_t H5C_apply_candidate_list(H5F_t * f,
@@ -1106,6 +1107,9 @@ H5_DLL void H5C_def_auto_resize_rpt_fcn(H5C_t * cache_ptr,
H5_DLL herr_t H5C_dest(H5F_t * f,
hid_t primary_dxpl_id,
hid_t secondary_dxpl_id);
+H5_DLL herr_t H5C_evict(H5F_t * f,
+ hid_t primary_dxpl_id,
+ hid_t secondary_dxpl_id);
H5_DLL herr_t H5C_expunge_entry(H5F_t * f,
hid_t primary_dxpl_id,
diff --git a/src/H5D.c b/src/H5D.c
index 0eff024..ee251bf 100644
--- a/src/H5D.c
+++ b/src/H5D.c
@@ -766,12 +766,21 @@ H5Dget_access_plist(hid_t dset_id)
/* If the dataset is chunked then copy the rdcc parameters */
if (dset->shared->layout.type == H5D_CHUNKED) {
+ H5D_append_flush_t info;
+
if (H5P_set(new_plist, H5D_ACS_DATA_CACHE_NUM_SLOTS_NAME, &(dset->shared->cache.chunk.nslots)) < 0)
HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set data cache number of slots")
if (H5P_set(new_plist, H5D_ACS_DATA_CACHE_BYTE_SIZE_NAME, &(dset->shared->cache.chunk.nbytes_max)) < 0)
HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set data cache byte size")
if (H5P_set(new_plist, H5D_ACS_PREEMPT_READ_CHUNKS_NAME, &(dset->shared->cache.chunk.w0)) < 0)
HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set preempt read chunks")
+
+ info.ndims = dset->shared->append_flush.ndims;
+ info.func = dset->shared->append_flush.func;
+ info.udata = dset->shared->append_flush.udata;
+ HDmemcpy(info.boundary, dset->shared->append_flush.boundary, sizeof(dset->shared->append_flush.boundary));
+ if(H5P_set(new_plist, H5D_ACS_APPEND_FLUSH_NAME, &info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set append flush property")
} /* end if */
/* Set the return value */
@@ -1176,9 +1185,8 @@ H5Dflush(hid_t dset_id)
if(H5D__flush_real(dset, H5AC_dxpl_id) < 0)
HDONE_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to flush cached dataset info")
- /* 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")
+ if(H5O_flush_common(&dset->oloc, dset_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to flush dataset and object flush callback")
done:
FUNC_LEAVE_API(ret_value)
diff --git a/src/H5Dint.c b/src/H5Dint.c
index cbab788..71af859 100644
--- a/src/H5Dint.c
+++ b/src/H5Dint.c
@@ -70,7 +70,7 @@ static herr_t H5D__update_oh_info(H5F_t *file, hid_t dxpl_id, H5D_t *dset,
static herr_t H5D__open_oid(H5D_t *dataset, hid_t dapl_id, hid_t dxpl_id);
static herr_t H5D__init_storage(H5D_t *dataset, hbool_t full_overwrite,
hsize_t old_dim[], hid_t dxpl_id);
-
+static herr_t H5D__append_flush_setup(H5D_t *dset, hid_t dapl_id);
/*********************/
/* Package Variables */
@@ -1163,6 +1163,9 @@ H5D__create(H5F_t *file, hid_t type_id, const H5S_t *space, hid_t dcpl_id,
/* Indicate that the layout information was initialized */
layout_init = TRUE;
+ if(H5D__append_flush_setup(new_dset, dapl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINC, NULL, "unable to set up flush append property")
+
/* Add the dataset to the list of opened objects in the file */
if(H5FO_top_incr(new_dset->oloc.file, new_dset->oloc.addr) < 0)
HGOTO_ERROR(H5E_DATASET, H5E_CANTINC, NULL, "can't incr object ref. count")
@@ -1264,6 +1267,7 @@ H5D_open(const H5G_loc_t *loc, hid_t dapl_id, hid_t dxpl_id)
/* We're the first dataset to use the the shared info */
dataset->shared->fo_count = 1;
+
} /* end if */
else {
/* Point to shared info */
@@ -1282,6 +1286,7 @@ H5D_open(const H5G_loc_t *loc, hid_t dapl_id, hid_t dxpl_id)
/* Increment object count for the object in the top file */
if(H5FO_top_incr(dataset->oloc.file, dataset->oloc.addr) < 0)
HGOTO_ERROR(H5E_DATASET, H5E_CANTINC, NULL, "can't increment object count")
+
} /* end else */
ret_value = dataset;
@@ -1306,6 +1311,84 @@ done:
} /* end H5D_open() */
+/*
+ *-------------------------------------------------------------------------
+ * Function: H5D__flush_append_setup
+ *
+ * Purpose:
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__append_flush_setup(H5D_t *dset, hid_t dapl_id)
+{
+ H5P_genplist_t *dapl; /* data access property list object pointer */
+ hsize_t curr_dims[H5S_MAX_RANK]; /* current dimension sizes */
+ hsize_t max_dims[H5S_MAX_RANK]; /* current dimension sizes */
+ int rank; /* dataspace # of dimensions */
+ int i; /* local index variable */
+ H5D_append_flush_t info;
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* check args */
+ HDassert(dset);
+ HDassert(dset->shared);
+
+ dset->shared->append_flush.ndims = 0;
+ dset->shared->append_flush.func = NULL;
+ dset->shared->append_flush.udata = NULL;
+ HDmemset(dset->shared->append_flush.boundary, 0, sizeof(dset->shared->append_flush.boundary));
+
+ if(dapl_id != H5P_DATASET_ACCESS_DEFAULT && dset->shared->layout.type == H5D_CHUNKED) {
+ /* Get dataset access property list */
+ if(NULL == (dapl = (H5P_genplist_t *)H5I_object(dapl_id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for dapl ID");
+
+ /* Check if append flush property exists */
+ if(H5P_exist_plist(dapl, H5D_ACS_APPEND_FLUSH_NAME) > 0) {
+
+ /* Get append flush property */
+ if(H5P_get(dapl, H5D_ACS_APPEND_FLUSH_NAME, &info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get append flush info")
+ else if(info.ndims > 0) {
+
+ /* Get dataset rank */
+ if((rank = H5S_get_simple_extent_dims(dset->shared->space, curr_dims, max_dims)) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get dataset dimensions")
+
+ if(info.ndims != rank)
+ HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "boundary dimension rank does not match dataset rank")
+
+ /* Validate boundary sizes */
+ for(i = 0; i < info.ndims; i++) {
+ if(info.boundary[i] != 0) /* when a non-zero boundary is set */
+ /* the dimension is extendible? */
+ if(max_dims[i] != H5S_UNLIMITED && max_dims[i] == curr_dims[i])
+ break;
+ }
+
+ if(i != info.ndims) /* at least one boundary dimension is not extendible */
+ HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "boundary dimension is not valid")
+
+ dset->shared->append_flush.ndims = info.ndims;
+ dset->shared->append_flush.func = info.func;
+ dset->shared->append_flush.udata = info.udata;
+ HDmemcpy(dset->shared->append_flush.boundary, info.boundary, sizeof(info.boundary));
+ }
+ }
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5D__append_flush_setup() */
+
+
/*-------------------------------------------------------------------------
* Function: H5D__open_oid
*
@@ -1325,6 +1408,7 @@ H5D__open_oid(H5D_t *dataset, hid_t dapl_id, hid_t dxpl_id)
H5O_fill_t *fill_prop; /* Pointer to dataset's fill value info */
unsigned alloc_time_state; /* Allocation time state */
htri_t msg_exists; /* Whether a particular type of message exists */
+ hbool_t layout_init = FALSE; /* Flag to indicate that chunk information was initialized */
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_STATIC_TAG(dxpl_id, dataset->oloc.addr, FAIL)
@@ -1362,6 +1446,13 @@ H5D__open_oid(H5D_t *dataset, hid_t dapl_id, hid_t dxpl_id)
if(H5D__layout_oh_read(dataset, dxpl_id, dapl_id, plist) < 0)
HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get layout/pline/efl info")
+ /* Indicate that the layout information was initialized */
+ layout_init = TRUE;
+
+ /* Set up flush append property */
+ if(H5D__append_flush_setup(dataset, dapl_id))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINC, FAIL, "unable to set up flush append property")
+
/* Point at dataset's copy, to cache it for later */
fill_prop = &dataset->shared->dcpl_cache.fill;
@@ -1441,6 +1532,10 @@ done:
if(H5F_addr_defined(dataset->oloc.addr) && H5O_close(&(dataset->oloc)) < 0)
HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release object header")
if(dataset->shared) {
+ if(dataset->shared->layout.type == H5D_CHUNKED && layout_init) {
+ if(H5D__chunk_dest(dataset->oloc.file, dxpl_id, dataset) < 0)
+ HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "unable to destroy chunk cache")
+ } /* end if */
if(dataset->shared->space && H5S_close(dataset->shared->space) < 0)
HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release dataspace")
if(dataset->shared->type) {
diff --git a/src/H5Doh.c b/src/H5Doh.c
index df4eed2..b7706b3 100644
--- a/src/H5Doh.c
+++ b/src/H5Doh.c
@@ -55,7 +55,7 @@ static void *H5O__dset_create(H5F_t *f, void *_crt_info, H5G_loc_t *obj_loc,
static H5O_loc_t *H5O__dset_get_oloc(hid_t obj_id);
static herr_t H5O__dset_bh_info(H5F_t *f, hid_t dxpl_id, H5O_t *oh,
H5_ih_info_t *bh_info);
-static herr_t H5O__dset_flush(H5G_loc_t *obj_loc, hid_t dxpl_id);
+static herr_t H5O__dset_flush(void *_obj_ptr, hid_t dxpl_id);
/*********************/
@@ -457,34 +457,25 @@ done:
*-------------------------------------------------------------------------
*/
static herr_t
-H5O__dset_flush(H5G_loc_t *obj_loc, hid_t dxpl_id)
+H5O__dset_flush(void *_obj_ptr, hid_t dxpl_id)
{
- H5D_t *dset = NULL; /* Dataset opened */
- H5O_type_t obj_type; /* Type of object at location */
- herr_t ret_value = SUCCEED; /* Return value */
+ H5D_t *dset = (H5D_t *)_obj_ptr; /* Pointer to dataset object */
+ H5O_type_t obj_type; /* Type of object at location */
+ herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_STATIC
- HDassert(obj_loc);
- HDassert(obj_loc->oloc);
+ HDassert(dset);
+ HDassert(&dset->oloc);
/* Check that the object found is the correct type */
- if(H5O_obj_type(obj_loc->oloc, &obj_type, dxpl_id) < 0)
+ if(H5O_obj_type(&dset->oloc, &obj_type, dxpl_id) < 0)
HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get object type")
-
if(obj_type != H5O_TYPE_DATASET)
HGOTO_ERROR(H5E_DATASET, H5E_BADTYPE, FAIL, "not a dataset")
- /* Open the dataset */
- if(NULL == (dset = H5D_open(obj_loc, H5P_DATASET_ACCESS_DEFAULT, dxpl_id)))
- HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open dataset")
-
if(H5D__flush_real(dset, dxpl_id) < 0)
HDONE_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to flush cached dataset info")
-
done:
- if(dset && H5D_close(dset) < 0)
- HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "unable to release dataset")
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5O__dset_flush() */
-
diff --git a/src/H5Dpkg.h b/src/H5Dpkg.h
index 46d545d..ad0eb4d 100644
--- a/src/H5Dpkg.h
+++ b/src/H5Dpkg.h
@@ -461,6 +461,7 @@ typedef struct H5D_shared_t {
*/
H5D_rdcc_t chunk; /* Information about chunked data */
} cache;
+ H5D_append_flush_t append_flush; /* Append flush property information */
} H5D_shared_t;
struct H5D_t {
diff --git a/src/H5Dprivate.h b/src/H5Dprivate.h
index e154f60..0c7f1aa 100644
--- a/src/H5Dprivate.h
+++ b/src/H5Dprivate.h
@@ -52,6 +52,7 @@
#define H5D_ACS_DATA_CACHE_NUM_SLOTS_NAME "rdcc_nslots" /* Size of raw data chunk cache(slots) */
#define H5D_ACS_DATA_CACHE_BYTE_SIZE_NAME "rdcc_nbytes" /* Size of raw data chunk cache(bytes) */
#define H5D_ACS_PREEMPT_READ_CHUNKS_NAME "rdcc_w0" /* Preemption read chunks first */
+#define H5D_ACS_APPEND_FLUSH_NAME "append_flush" /* Append flush actions */
/* ======== Data transfer properties ======== */
#define H5D_XFER_MAX_TEMP_BUF_NAME "max_temp_buf" /* Maximum temp buffer size */
@@ -146,6 +147,14 @@ typedef struct H5D_copy_file_ud_t {
H5O_layout_t *src_layout; /* Copy of layout for dataset */
} H5D_copy_file_ud_t;
+/* Structure for dataset append flush property (H5Pset_append_flush) */
+typedef struct H5D_append_flush_t {
+ int ndims; /* The # of dimensions for "boundary" */
+ hsize_t boundary[H5S_MAX_RANK]; /* The dimension sizes for determining boundary */
+ H5D_append_cb_t func; /* The callback function */
+ void *udata; /* User data */
+} H5D_append_flush_t;
+
/*****************************/
/* Library Private Variables */
diff --git a/src/H5Dpublic.h b/src/H5Dpublic.h
index 44af139..62bae80 100644
--- a/src/H5Dpublic.h
+++ b/src/H5Dpublic.h
@@ -100,6 +100,9 @@ typedef enum H5D_fill_value_t {
H5D_FILL_VALUE_USER_DEFINED =2
} H5D_fill_value_t;
+/* Callback for H5Pset_append_flush() in a dataset access property list */
+typedef herr_t (*H5D_append_cb_t)(hid_t dataset_id, hsize_t *cur_dims, void *op_data);
+
/********************/
/* Public Variables */
/********************/
diff --git a/src/H5F.c b/src/H5F.c
index 46442b7..7760a21 100644
--- a/src/H5F.c
+++ b/src/H5F.c
@@ -83,6 +83,7 @@ static herr_t H5F_build_actual_name(const H5F_t *f, const H5P_genplist_t *fapl,
const char *name, char ** /*out*/ actual_name);
static herr_t H5F_dest(H5F_t *f, hid_t dxpl_id, hbool_t flush);
static herr_t H5F_close(H5F_t *f);
+static herr_t H5F_set_retries(H5F_t *f);
/*********************/
@@ -323,11 +324,12 @@ done:
hid_t
H5F_get_access_plist(H5F_t *f, hbool_t app_ref)
{
- H5P_genplist_t *new_plist; /* New property list */
- H5P_genplist_t *old_plist; /* Old property list */
+ H5P_genplist_t *new_plist; /* New property list */
+ H5P_genplist_t *old_plist; /* Old property list */
void *driver_info=NULL;
unsigned efc_size = 0;
- hid_t ret_value = SUCCEED;
+ H5F_object_flush_t flush_info; /* Object flush property values */
+ hid_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI(FAIL)
@@ -367,6 +369,15 @@ H5F_get_access_plist(H5F_t *f, hbool_t app_ref)
HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set 'latest format' flag")
if(H5P_set(new_plist, H5F_ACS_METADATA_READ_ATTEMPTS_NAME, &(f->shared->read_attempts)) < 0)
HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set 'latest format' flag")
+
+ /* Obtain object flush property values */
+ flush_info.func = f->shared->object_flush.func;
+ flush_info.udata = f->shared->object_flush.udata;
+
+ /* Set values */
+ if(H5P_set(new_plist, H5F_ACS_OBJECT_FLUSH_CB_NAME, &flush_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set object flush callback")
+
if(f->shared->efc)
efc_size = H5F_efc_max_nfiles(f->shared->efc);
if(H5P_set(new_plist, H5F_ACS_EFC_SIZE_NAME, &efc_size) < 0)
@@ -1012,28 +1023,24 @@ H5F_new(H5F_file_t *shared, unsigned flags, hid_t fcpl_id, hid_t fapl_id, H5FD_t
/* When opening file without SWMR access, the # of read attempts is always H5F_METADATA_READ_ATTEMPTS (set or not set) */
if(H5F_INTENT(f) & (H5F_ACC_SWMR_READ | H5F_ACC_SWMR_WRITE)) {
/* If no value for read attempts has been set, use the default */
- if(!f->shared->read_attempts)
- f->shared->read_attempts = H5F_SWMR_METADATA_READ_ATTEMPTS;
+ if(!f->shared->read_attempts)
+ f->shared->read_attempts = H5F_SWMR_METADATA_READ_ATTEMPTS;
- /* Turn off accumulator with SWMR */
- f->shared->feature_flags = lf->feature_flags & ~(unsigned)H5FD_FEAT_ACCUMULATE_METADATA;
- if(H5FD_set_feature_flags(lf, f->shared->feature_flags) < 0)
- HGOTO_ERROR(H5E_FILE, H5E_CANTSET, NULL, "can't set feature_flags in VFD")
+ /* Turn off accumulator with SWMR */
+ f->shared->feature_flags &= ~(unsigned)H5FD_FEAT_ACCUMULATE_METADATA;
+ if(H5FD_set_feature_flags(f->shared->lf, f->shared->feature_flags) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTSET, NULL, "can't set feature_flags in VFD")
} /* end if */
else
f->shared->read_attempts = H5F_METADATA_READ_ATTEMPTS;
- /* Determine the # of bins for metdata read retries */
- f->shared->retries_nbins = 0;
- if(f->shared->read_attempts > 1) {
- double tmp;
-
- tmp = HDlog10((double)(f->shared->read_attempts - 1));
- f->shared->retries_nbins = (unsigned)tmp + 1;
- } /* end if */
+ /* Determine the # of bins for metdata read retries */
+ if(H5F_set_retries(f) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "can't set retries and retries_nbins")
- /* Initialize the tracking for metadata read retries */
- HDmemset(f->shared->retries, 0, sizeof(f->shared->retries));
+ /* Get object flush callback information */
+ if(H5P_get(plist, H5F_ACS_OBJECT_FLUSH_CB_NAME, &(f->shared->object_flush)) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "can't get the # of read attempts")
/*
* Create a metadata cache with the specified number of elements.
@@ -1143,10 +1150,19 @@ H5F_dest(H5F_t *f, hid_t dxpl_id, hbool_t flush)
/* Flush the file again (if requested), as shutting down the
* free space manager may dirty some data structures again.
*/
- if(flush)
+ if(flush) {
+ /* Clear status_flags */
+ f->shared->sblock->status_flags &= ~H5F_SUPER_WRITE_ACCESS;
+ f->shared->sblock->status_flags &= ~H5F_SUPER_SWMR_WRITE_ACCESS;
+ /* Mark superblock dirty in cache, so change will get encoded */
+ /* Push error, but keep going*/
+ if(H5F_super_dirty(f) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark superblock as dirty")
+
if(H5F_flush(f, dxpl_id, TRUE) < 0)
/* Push error, but keep going*/
HDONE_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush cache")
+ }
} /* end if */
/* Unpin the superblock, since we're about to destroy the cache */
@@ -1277,6 +1293,37 @@ H5F_dest(H5F_t *f, hid_t dxpl_id, hbool_t flush)
* The ACCESS_PARMS argument is optional. A null pointer will
* cause the default file access parameters to be used.
*
+ * The following two tables show results of file opens for single and concurrent access:
+ *
+ * SINGLE PROCESS ACCESS CONCURRENT ACCESS
+ *
+ * #1st open# #1st open#
+ * -- SR SR -- -- SR SR -- -- SR SR -- -- SR SR --
+ * -- -- SW SW SW SW -- -- -- -- SW SW SW SW -- --
+ * W W W W R R R R W W W W R R R R
+ * #2nd open# #2nd open#
+ * -------------------------- --------------------------
+ * -- -- W | s x x s x x f f | -- -- W | f x x f x x f f |
+ * SR -- W | x x x x x x x x | SR -- W | x x x x x x x x |
+ * SR SW W | x x x x x x x x | SR SW W | x x x x x x x x |
+ * -- SW W | f x x s x x f f | -- SW W | f x x f x x f f |
+ * -- SW R | x x x x x x x x | -- SW R | x x x x x x x x |
+ * SR SW R | x x x x x x x x | SR SW R | x x x x x x x x |
+ * SR -- R | s x x s x x s f | SR -- R | f x x s x x s s |
+ * -- -- R | s x x s x x s s | -- -- R | f x x f x x s s |
+ * -------------------------- --------------------------
+ *
+ * Notations:
+ * W: H5F_ACC_RDWR
+ * R: H5F_ACC_RDONLY
+ * SW: H5F_ACC_SWMR_WRITE
+ * SR: H5F_ACC_SWMR_READ
+ *
+ * x: the first open or second open itself fails due to invalid flags combination
+ * f: the open fails with flags combination from both the first and second opens
+ * s: the open succeeds with flags combination from both the first and second opens
+ *
+ *
* Return: Success: A new file pointer.
* Failure: NULL
*
@@ -1296,6 +1343,8 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id,
H5FD_class_t *drvr; /*file driver class info */
H5P_genplist_t *a_plist; /*file access property list */
H5F_close_degree_t fc_degree; /*file close degree */
+ hbool_t set_flag = FALSE; /*set the status_flags in the superblock */
+ hbool_t clear = FALSE; /*clear the status_flags */
H5F_t *ret_value; /*actual return value */
FUNC_ENTER_NOAPI(NULL)
@@ -1370,11 +1419,10 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id,
HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "file exists")
if((flags & H5F_ACC_RDWR) && 0 == (shared->flags & H5F_ACC_RDWR))
HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "file is already open for read-only")
- if(((flags & H5F_ACC_SWMR_WRITE) && 0 == (shared->flags & H5F_ACC_SWMR_WRITE))
- || (0 == (flags & H5F_ACC_SWMR_WRITE) && (shared->flags & H5F_ACC_SWMR_WRITE)))
+
+ if((flags & H5F_ACC_SWMR_WRITE) && 0 == (shared->flags & H5F_ACC_SWMR_WRITE))
HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "SWMR write access flag not the same for file that is already open")
- if(((flags & H5F_ACC_SWMR_READ) && 0 == (shared->flags & H5F_ACC_SWMR_READ))
- || (0 == (flags & H5F_ACC_SWMR_READ) && (shared->flags & H5F_ACC_SWMR_READ)))
+ if((flags & H5F_ACC_SWMR_READ) && !((shared->flags & H5F_ACC_SWMR_WRITE) || (shared->flags & H5F_ACC_SWMR_READ) || (shared->flags & H5F_ACC_RDWR)))
HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "SWMR read access flag not the same for file that is already open")
/* Allocate new "high-level" file struct */
@@ -1389,18 +1437,24 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id,
* open it are different than the desired flags. Close the tentative
* file and open it for real.
*/
- if(H5FD_close(lf) < 0) {
- file = NULL; /*to prevent destruction of wrong file*/
+ if(H5FD_close(lf) < 0)
HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to close low-level file info")
- } /* end if */
- if(NULL == (lf = H5FD_open(name, flags, fapl_id, HADDR_UNDEF))) {
- file = NULL; /*to prevent destruction of wrong file*/
+
+ if(NULL == (lf = H5FD_open(name, flags, fapl_id, HADDR_UNDEF)))
HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to open file")
- } /* end if */
+
} /* end if */
- if(NULL == (file = H5F_new(NULL, flags, fcpl_id, fapl_id, lf)))
- HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to create new file object")
+ /* Place an advisory lock on the file */
+ if((H5FD_lock(lf, (hbool_t)((flags & H5F_ACC_RDWR) ? TRUE : FALSE)) < 0) ||
+ (NULL == (file = H5F_new(NULL, flags, fcpl_id, fapl_id, lf)))) {
+ if(H5FD_close(lf) < 0) /* Closing will remove the lock */
+ HDONE_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to close low-level file info")
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to lock the file or initialize file structure")
+ }
+
+ /* Need to set status_flags in the superblock */
+ set_flag = TRUE;
} /* end else */
/* Retain the name the file was opened with */
@@ -1432,6 +1486,7 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id,
if(H5G_mkroot(file, dxpl_id, TRUE) < 0)
HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to create/open root group")
} else if (1 == shared->nrefs) {
+
/* Read the superblock if it hasn't been read before. */
if(H5F_super_read(file, dxpl_id) < 0)
HGOTO_ERROR(H5E_FILE, H5E_READERROR, NULL, "unable to read superblock")
@@ -1455,6 +1510,16 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id,
if(H5P_get(a_plist, H5F_ACS_CLOSE_DEGREE_NAME, &fc_degree) < 0)
HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get file close degree")
+ /* This is a private property to clear the status_flags in the super block */
+ /* Use by h5clear and a routine in test/flush2.c to clear the test file's status_flags */
+ if(H5P_exist_plist(a_plist, H5F_ACS_CLEAR_STATUS_FLAGS_NAME) > 0) {
+ if(H5P_get(a_plist, H5F_ACS_CLEAR_STATUS_FLAGS_NAME, &clear) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get clearance for status_flags")
+ else if(clear) {
+ file->shared->sblock->status_flags = 0;
+ }
+ }
+
if(shared->nrefs == 1) {
if(fc_degree == H5F_CLOSE_DEFAULT)
shared->fc_degree = lf->cls->fc_degree;
@@ -1475,13 +1540,42 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id,
if(H5F_build_actual_name(file, a_plist, name, &file->actual_name) < 0)
HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to build actual name")
+ if(set_flag) {
+ if(H5F_INTENT(file) & H5F_ACC_RDWR) { /* Set and check consistency of status_flags */
+ if(file->shared->sblock->status_flags & H5F_SUPER_WRITE_ACCESS ||
+ file->shared->sblock->status_flags & H5F_SUPER_SWMR_WRITE_ACCESS)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "file is already open for write or SWMR write")
+
+ file->shared->sblock->status_flags |= H5F_SUPER_WRITE_ACCESS;
+
+ if(H5F_INTENT(file) & H5F_ACC_SWMR_WRITE) { /* Remove the file lock for SWMR_WRITE */
+ file->shared->sblock->status_flags |= H5F_SUPER_SWMR_WRITE_ACCESS;
+ if(H5FD_unlock(file->shared->lf) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to unlock the file")
+ }
+ /* Flush the superblock */
+ if(H5F_super_dirty(file) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, NULL, "unable to mark superblock as dirty")
+ if(H5F_flush_tagged_metadata(file, (haddr_t)0, H5AC_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, NULL, "unable to flush superblock")
+ } else { /* H5F_ACC_RDONLY */
+ if(H5F_INTENT(file) & H5F_ACC_SWMR_READ) { /* Check consistency of status_flags */
+ if((file->shared->sblock->status_flags & H5F_SUPER_WRITE_ACCESS && !(file->shared->sblock->status_flags & H5F_SUPER_SWMR_WRITE_ACCESS))
+ || (!(file->shared->sblock->status_flags & H5F_SUPER_WRITE_ACCESS) && file->shared->sblock->status_flags & H5F_SUPER_SWMR_WRITE_ACCESS))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "file is not already open for SWMR writing")
+ } else if((file->shared->sblock->status_flags & H5F_SUPER_WRITE_ACCESS) ||
+ (file->shared->sblock->status_flags & H5F_SUPER_SWMR_WRITE_ACCESS))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "file is already open for writing")
+ }
+ } /* end if set_flag */
+
/* Success */
ret_value = file;
done:
if(!ret_value && file)
- if(H5F_dest(file, dxpl_id, FALSE) < 0)
- HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, NULL, "problems closing file")
+ if(H5F_dest(file, dxpl_id, FALSE) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, NULL, "problems closing file")
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5F_open() */
@@ -2116,9 +2210,17 @@ H5Fclose(hid_t file_id)
if((f->shared->nrefs > 1) && (H5F_INTENT(f) & H5F_ACC_RDWR)) {
if((nref = H5I_get_ref(file_id, FALSE)) < 0)
HGOTO_ERROR(H5E_ATOM, H5E_CANTGET, FAIL, "can't get ID ref count")
- if(nref == 1)
+ if(nref == 1) {
+ if(f->shared->sblock) { /* Clear status_flags */
+ f->shared->sblock->status_flags &= ~H5F_SUPER_WRITE_ACCESS;
+ f->shared->sblock->status_flags &= ~H5F_SUPER_SWMR_WRITE_ACCESS;
+ /* Mark superblock dirty in cache, so change will get encoded */
+ if(H5F_super_dirty(f) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark superblock as dirty")
+ }
if(H5F_flush(f, H5AC_dxpl_id, FALSE) < 0)
HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush cache")
+ }
} /* end if */
/*
@@ -2820,6 +2922,8 @@ H5Fget_file_image(hid_t file_id, void *buf_ptr, size_t buf_len)
/* test to see if a buffer was provided -- if not, we are done */
if(buf_ptr != NULL) {
size_t space_needed; /* size of file image */
+ hsize_t tmp;
+ size_t tmp_size;
/* Check for buffer too small */
if((haddr_t)buf_len < eoa)
@@ -2829,8 +2933,18 @@ H5Fget_file_image(hid_t file_id, void *buf_ptr, size_t buf_len)
/* read in the file image */
/* (Note compensation for base address addition in internal routine) */
- if(H5FD_read(fd_ptr, H5AC_ind_dxpl_id, H5FD_MEM_DEFAULT, 0, space_needed, buf_ptr) < 0)
+ if(H5FD_read(fd_ptr, H5AC_ind_dxpl_id, H5FD_MEM_DEFAULT, (haddr_t)0, space_needed, buf_ptr) < 0)
HGOTO_ERROR(H5E_FILE, H5E_READERROR, FAIL, "file image read request failed")
+
+ /* Offset to "status_flags" in the superblock */
+ tmp = H5F_SUPER_STATUS_FLAGS_OFF(file->shared->sblock->super_vers);
+ /* Size of "status_flags" depends on the superblock version */
+ tmp_size = H5F_SUPER_STATUS_FLAGS_SIZE(file->shared->sblock->super_vers);
+
+ /* Clear "status_flags" */
+ HDmemset((uint8_t *)(buf_ptr) + tmp, 0, tmp_size);
+
+
} /* end if */
done:
@@ -3551,3 +3665,199 @@ done:
FUNC_LEAVE_NOAPI(ret_value)
} /* H5F_track_metadata_read_retries() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_set_retries
+ *
+ * Purpose: To initialize data structures for read retries:
+ * --zero out "retries"
+ * --set up "retries_nbins" based on read_attempts
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Vailin Choi; November 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F_set_retries(H5F_t *f)
+{
+ double tmp; /* Temporary variable */
+
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Sanity check */
+ HDassert(f);
+
+ /* Initialize the tracking for metadata read retries */
+ HDmemset(f->shared->retries, 0, sizeof(f->shared->retries));
+
+ /* Initialize the # of bins for retries */
+ f->shared->retries_nbins = 0;
+ if(f->shared->read_attempts > 1) {
+ tmp = HDlog10((double)(f->shared->read_attempts - 1));
+ f->shared->retries_nbins = (unsigned)tmp + 1;
+ }
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5F_set_retries() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5Fstart_swmr_write
+ *
+ * Purpose: To enable SWMR writing mode for the file
+ * 1) Mark the file in SWMR writing mode
+ * 2) Set metadata read attempts and retries info
+ * 3) Disable accumulator
+ * 4) Flush the data buffers
+ * 5) Evict all cache entries except the superblock
+ * 6) Unlock the file
+ * Fail when:
+ * 1) There are opened objects
+ * 2) The file is not opened with latest library format
+ * 3) The file is not opened with H5F_ACC_RDWR
+ * 4) The file is already marked for SWMR writing
+ *
+ * Return: Non-negative on success/negative on failure
+ *
+ * Programmer:
+ * Vailin Choi; Dec 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Fstart_swmr_write(hid_t file_id)
+{
+ H5F_t *file; /* File info */
+ hbool_t setup = FALSE;
+ 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")
+
+ /* ???How about nopen_files from (H5F_mount_count_ids(file, &nopen_files, &nopen_objs) */
+ /* For now, just check nopen_objs */
+ if((H5F_addr_defined(file->shared->sblock->ext_addr) && file->nopen_objs > 1) ||
+ (!H5F_addr_defined(file->shared->sblock->ext_addr) && file->nopen_objs > 0))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't start SWMR writing, there are objects still open")
+
+ /* Should have write permission */
+ if((H5F_INTENT(file) & H5F_ACC_RDWR) == 0)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "no write intent on file")
+
+ /* Should be using latest library format */
+ if(!H5F_use_latest_format(file))
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "file not opened with latest library format")
+
+ /* 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);
+
+ /* 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;
+
+ setup = TRUE;
+
+ /* 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")
+
+ /* Flush and reset the accumulator */
+ if(H5F_accum_reset(file, H5AC_dxpl_id, TRUE) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTRESET, FAIL, "can't reset accumulator")
+
+ /* 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")
+
+ /* Mark superblock as dirty */
+ if(H5F_super_dirty(file) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark superblock as dirty")
+
+ /* Flush data buffers */
+ if(H5F_flush(file, H5AC_dxpl_id, FALSE) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush file's cached information")
+
+ /* Evict all flushed entries in the cache except the pinned superblock */
+ if(H5F_evict_cache_entries(file, H5AC_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to evict file's cached information")
+
+ /* 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 && file && setup) {
+
+ /* 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, (haddr_t)0, H5AC_dxpl_id) < 0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush superblock")
+ }
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Fstart_swmr_write() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_object_flush_cb
+ *
+ * Purpose: To invoke the callback function for object flush that is set
+ * in the file's access property list.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Vailin Choi; October 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_object_flush_cb(H5F_t *f, hid_t obj_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(f);
+ HDassert(f->shared);
+
+ /* Invoke object flush callback if there is one */
+ if(f->shared->object_flush.func && f->shared->object_flush.func(obj_id, f->shared->object_flush.udata) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "object flush callback returns error")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5F_object_flush_cb() */
diff --git a/src/H5FD.c b/src/H5FD.c
index 5f447ec..d677543 100644
--- a/src/H5FD.c
+++ b/src/H5FD.c
@@ -1909,6 +1909,64 @@ done:
/*-------------------------------------------------------------------------
+ * Function: H5FD_lock
+ *
+ * Purpose: Private version of H5FDlock()
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_lock(H5FD_t *file, hbool_t rw)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(file && file->cls);
+
+ if(file->cls->lock && (file->cls->lock)(file, rw) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTUPDATE, FAIL, "driver lock request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_lock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_unlock
+ *
+ * Purpose: Private version of H5FDunlock()
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5FD_unlock(H5FD_t *file)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(file && file->cls);
+
+ if(file->cls->unlock && (file->cls->unlock)(file) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTUPDATE, FAIL, "driver unlock request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_unlock() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5FD_get_fileno
*
* Purpose: Quick and dirty routine to retrieve the file's 'fileno' value
diff --git a/src/H5FDcore.c b/src/H5FDcore.c
index 559af82..8e4f05b 100644
--- a/src/H5FDcore.c
+++ b/src/H5FDcore.c
@@ -137,6 +137,8 @@ static herr_t H5FD_core_write(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, had
size_t size, const void *buf);
static herr_t H5FD_core_flush(H5FD_t *_file, hid_t dxpl_id, unsigned closing);
static herr_t H5FD_core_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
+static herr_t H5FD_core_lock(H5FD_t *_file, hbool_t rw);
+static herr_t H5FD_core_unlock(H5FD_t *_file);
static const H5FD_class_t H5FD_core_g = {
"core", /* name */
@@ -168,8 +170,8 @@ static const H5FD_class_t H5FD_core_g = {
H5FD_core_write, /* write */
H5FD_core_flush, /* flush */
H5FD_core_truncate, /* truncate */
- NULL, /* lock */
- NULL, /* unlock */
+ H5FD_core_lock, /* lock */
+ H5FD_core_unlock, /* unlock */
H5FD_FLMAP_DICHOTOMY /* fl_map */
};
@@ -1244,3 +1246,76 @@ H5FD_core_truncate(H5FD_t *_file, hid_t UNUSED dxpl_id, hbool_t closing)
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FD_core_truncate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_core_lock
+ *
+ * Purpose: To place an advisory lock on a file.
+ * The lock type to apply depends on the parameter "rw":
+ * TRUE--opens for write: an exclusive lock
+ * FALSE--opens for read: a shared lock
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi; May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_core_lock(H5FD_t *_file, hbool_t rw)
+{
+ H5FD_core_t *file = (H5FD_core_t*)_file; /* VFD file struct */
+ int lock; /* The type of lock */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+ if(file->fd >= 0) {
+
+ /* Determine the type of lock */
+ lock = rw ? LOCK_EX : LOCK_SH;
+
+ /* Place the lock with non-blocking */
+ if(HDflock(file->fd, lock | LOCK_NB) < 0)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to flock file")
+ }
+ /* Otherwise a noop */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_core_lock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_core_unlock
+ *
+ * Purpose: To remove the existing lock on the file
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi; May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_core_unlock(H5FD_t *_file)
+{
+ H5FD_core_t *file = (H5FD_core_t*)_file; /* VFD file struct */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+
+ if(file->fd >= 0) {
+
+ if(HDflock(file->fd, LOCK_UN) < 0)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to flock (unlock) file")
+ }
+ /* Otherwise a noop */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_core_unlock() */
diff --git a/src/H5FDdirect.c b/src/H5FDdirect.c
index 3aa1c4f..a5a8426 100644
--- a/src/H5FDdirect.c
+++ b/src/H5FDdirect.c
@@ -147,6 +147,9 @@ static herr_t H5FD_direct_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, ha
static herr_t H5FD_direct_write(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr,
size_t size, const void *buf);
static herr_t H5FD_direct_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
+static herr_t H5FD_direct_lock(H5FD_t *_file, hbool_t rw);
+static herr_t H5FD_direct_unlock(H5FD_t *_file);
+
static const H5FD_class_t H5FD_direct_g = {
"direct", /*name */
@@ -177,10 +180,10 @@ static const H5FD_class_t H5FD_direct_g = {
H5FD_direct_read, /*read */
H5FD_direct_write, /*write */
NULL, /*flush */
- H5FD_direct_truncate, /*truncate */
- NULL, /*lock */
- NULL, /*unlock */
- H5FD_FLMAP_DICHOTOMY /*fl_map */
+ H5FD_direct_truncate, /*truncate */
+ H5FD_direct_lock, /*lock */
+ H5FD_direct_unlock, /*unlock */
+ H5FD_FLMAP_DICHOTOMY /*fl_map */
};
/* Declare a free list to manage the H5FD_direct_t struct */
@@ -1342,5 +1345,72 @@ H5FD_direct_truncate(H5FD_t *_file, hid_t UNUSED dxpl_id, hbool_t UNUSED closing
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FD_direct_truncate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_direct_lock
+ *
+ * Purpose: To place an advisory lock on a file.
+ * The lock type to apply depends on the parameter "rw":
+ * TRUE--opens for write: an exclusive lock
+ * FALSE--opens for read: a shared lock
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi; May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_direct_lock(H5FD_t *_file, hbool_t rw)
+{
+ H5FD_direct_t *file = (H5FD_direct_t*)_file; /* VFD file struct */
+ int lock; /* The type of lock */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+
+ /* Determine the type of lock */
+ int lock = rw ? LOCK_EX : LOCK_SH;
+
+ /* Place the lock with non-blocking */
+ if(HDflock(file->fd, lock | LOCK_NB) < 0)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to flock file")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_direct_lock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_direct_unlock
+ *
+ * Purpose: To remove the existing lock on the file
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi; May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_direct_unlock(H5FD_t *_file)
+{
+ H5FD_direct_t *file = (H5FD_direct_t*)_file; /* VFD file struct */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+
+ if(HDflock(file->fd, LOCK_UN) < 0)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to flock (unlock) file")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_direct_unlock() */
+
#endif /* H5_HAVE_DIRECT */
diff --git a/src/H5FDprivate.h b/src/H5FDprivate.h
index b21ecca..1fb6033 100644
--- a/src/H5FDprivate.h
+++ b/src/H5FDprivate.h
@@ -142,6 +142,8 @@ H5_DLL herr_t H5FD_write(H5FD_t *file, hid_t dxpl_id, H5FD_mem_t type,
haddr_t addr, size_t size, const void *buf);
H5_DLL herr_t H5FD_flush(H5FD_t *file, hid_t dxpl_id, hbool_t closing);
H5_DLL herr_t H5FD_truncate(H5FD_t *file, hid_t dxpl_id, hbool_t closing);
+H5_DLL herr_t H5FD_lock(H5FD_t *file, hbool_t rw);
+H5_DLL herr_t H5FD_unlock(H5FD_t *file);
H5_DLL herr_t H5FD_get_fileno(const H5FD_t *file, unsigned long *filenum);
H5_DLL herr_t H5FD_get_vfd_handle(H5FD_t *file, hid_t fapl, void** file_handle);
H5_DLL herr_t H5FD_set_base_addr(H5FD_t *file, haddr_t base_addr);
diff --git a/src/H5FDpublic.h b/src/H5FDpublic.h
index ed50bc7..d54aae8 100644
--- a/src/H5FDpublic.h
+++ b/src/H5FDpublic.h
@@ -275,8 +275,8 @@ typedef struct H5FD_class_t {
haddr_t addr, size_t size, const void *buffer);
herr_t (*flush)(H5FD_t *file, hid_t dxpl_id, unsigned closing);
herr_t (*truncate)(H5FD_t *file, hid_t dxpl_id, hbool_t closing);
- herr_t (*lock)(H5FD_t *file, unsigned char *oid, unsigned lock_type, hbool_t last);
- herr_t (*unlock)(H5FD_t *file, unsigned char *oid, hbool_t last);
+ herr_t (*lock)(H5FD_t *file, hbool_t rw);
+ herr_t (*unlock)(H5FD_t *file);
H5FD_mem_t fl_map[H5FD_MEM_NTYPES];
} H5FD_class_t;
diff --git a/src/H5FDsec2.c b/src/H5FDsec2.c
index 86ef6c6..ec0bd97 100644
--- a/src/H5FDsec2.c
+++ b/src/H5FDsec2.c
@@ -148,6 +148,8 @@ static herr_t H5FD_sec2_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, hadd
static herr_t H5FD_sec2_write(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr,
size_t size, const void *buf);
static herr_t H5FD_sec2_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
+static herr_t H5FD_sec2_lock(H5FD_t *_file, hbool_t rw);
+static herr_t H5FD_sec2_unlock(H5FD_t *_file);
static const H5FD_class_t H5FD_sec2_g = {
"sec2", /* name */
@@ -179,8 +181,8 @@ static const H5FD_class_t H5FD_sec2_g = {
H5FD_sec2_write, /* write */
NULL, /* flush */
H5FD_sec2_truncate, /* truncate */
- NULL, /* lock */
- NULL, /* unlock */
+ H5FD_sec2_lock, /* lock */
+ H5FD_sec2_unlock, /* unlock */
H5FD_FLMAP_DICHOTOMY /* fl_map */
};
@@ -938,3 +940,69 @@ H5FD_sec2_truncate(H5FD_t *_file, hid_t UNUSED dxpl_id, hbool_t UNUSED closing)
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FD_sec2_truncate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_sec2_lock
+ *
+ * Purpose: To place an advisory lock on a file.
+ * The lock type to apply depends on the parameter "rw":
+ * TRUE--opens for write: an exclusive lock
+ * FALSE--opens for read: a shared lock
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi; May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_sec2_lock(H5FD_t *_file, hbool_t rw)
+{
+ H5FD_sec2_t *file = (H5FD_sec2_t *)_file; /* VFD file struct */
+ int lock; /* The type of lock */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+
+ /* Determine the type of lock */
+ lock = rw ? LOCK_EX : LOCK_SH;
+
+ /* Place the lock with non-blocking */
+ if(HDflock(file->fd, lock | LOCK_NB) < 0)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to flock file")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_sec2_lock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_sec2_unlock
+ *
+ * Purpose: To remove the existing lock on the file
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi; May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_sec2_unlock(H5FD_t *_file)
+{
+ H5FD_sec2_t *file = (H5FD_sec2_t *)_file; /* VFD file struct */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+
+ if(HDflock(file->fd, LOCK_UN) < 0)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to flock (unlock) file")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_sec2_unlock() */
diff --git a/src/H5Fio.c b/src/H5Fio.c
index 5faeaca..d12a919 100644
--- a/src/H5Fio.c
+++ b/src/H5Fio.c
@@ -238,6 +238,55 @@ done:
/*-------------------------------------------------------------------------
+ * Function: H5F_evict_cache_entries
+ *
+ * Purpose: To revict all cache entries except the pinned superblock entry
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Dec 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_evict_cache_entries(H5F_t *f, hid_t dxpl_id)
+{
+ unsigned status = 0;
+ int32_t cur_num_entries;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(f);
+ HDassert(f->shared);
+
+ /* Evict all except pinned entries in the cache */
+ if(H5AC_evict(f, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTEXPUNGE, FAIL, "unable to evict all except pinned entries")
+
+ /* Retrieve status of the superblock */
+ if(H5AC_get_entry_status(f, (haddr_t)0, &status) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to get entry status")
+
+ /* Verify status of the superblock entry in the cache */
+ if(!(status & H5AC_ES__IN_CACHE) || !(status & H5AC_ES__IS_PINNED) ||
+ (status & H5AC_ES__IS_DIRTY) || (status & H5AC_ES__IS_PROTECTED))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to get entry status")
+
+ /* Get the number of cache entries */
+ if(H5AC_get_cache_size(f->shared->cache, NULL, NULL, NULL, &cur_num_entries) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5AC_get_cache_size() failed.")
+
+ /* Should be the only one left in the cache */
+ if(cur_num_entries != 1)
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "number of cache entries is not correct")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5F_evict_cache_entries() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5F_get_checksums
*
* Purpose: Decode checksum stored in the buffer
diff --git a/src/H5Fpkg.h b/src/H5Fpkg.h
index 1cc631c..1407c27 100644
--- a/src/H5Fpkg.h
+++ b/src/H5Fpkg.h
@@ -60,7 +60,9 @@
/* Superblock status flags */
#define H5F_SUPER_WRITE_ACCESS 0x01
#define H5F_SUPER_FILE_OK 0x02
-#define H5F_SUPER_ALL_FLAGS (H5F_SUPER_WRITE_ACCESS | H5F_SUPER_FILE_OK)
+#define H5F_SUPER_SWMR_WRITE_ACCESS 0x04
+#define H5F_SUPER_ALL_FLAGS (H5F_SUPER_WRITE_ACCESS | H5F_SUPER_FILE_OK | H5F_SUPER_SWMR_WRITE_ACCESS)
+
/* Mask for removing private file access flags */
#define H5F_ACC_PUBLIC_FLAGS 0x007fu
@@ -126,6 +128,22 @@
#define H5F_SUPERBLOCK_SIZE(v, f) ( H5F_SUPERBLOCK_FIXED_SIZE \
+ H5F_SUPERBLOCK_VARLEN_SIZE(v, f))
+/* For superblock version 0 & 1:
+ Offset to the file consistency flags (status_flags) in the superblock (excluding H5F_SUPERBLOCK_FIXED_SIZE) */
+#define H5F_SUPER_STATUS_OFF_V01 \
+ (2 /* freespace, and root group versions */ \
+ + 1 /* reserved */ \
+ + 3 /* shared header vers, size of address, size of lengths */ \
+ + 1 /* reserved */ \
+ + 4) /* group leaf k, group internal k */
+
+#define H5F_SUPER_STATUS_OFF(v) (v >= 2 ? 2 : H5F_SUPER_STATUS_OFF_V01)
+
+/* Offset to the file consistency flags (status_flags) in the superblock */
+#define H5F_SUPER_STATUS_FLAGS_OFF(v) (H5F_SUPERBLOCK_FIXED_SIZE + H5F_SUPER_STATUS_OFF(v))
+
+/* Size of file consistency flags (status_flags) in the superblock */
+#define H5F_SUPER_STATUS_FLAGS_SIZE(v) (v >= 2 ? 1 : 4)
/* Forward declaration external file cache struct used below (defined in
* H5Fefc.c) */
@@ -260,6 +278,7 @@ struct H5F_file_t {
unsigned read_attempts; /* The # of reads to try when reading metadata with checksum */
unsigned retries_nbins; /* # of bins for each retries[] */
uint32_t *retries[H5AC_NTYPES]; /* Track # of read retries for metdata items with checksum */
+ H5F_object_flush_t object_flush; /* Information for object flush callback */
};
/*
diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h
index 8dd6ec3..140aa8a 100644
--- a/src/H5Fprivate.h
+++ b/src/H5Fprivate.h
@@ -41,6 +41,11 @@ typedef struct H5F_file_t H5F_file_t;
/* Block aggregation structure */
typedef struct H5F_blk_aggr_t H5F_blk_aggr_t;
+/* Structure for object flush callback property (H5Pset_object_flush_cb)*/
+typedef struct H5F_object_flush_t {
+ H5F_flush_cb_t func; /* The callback function */
+ void *udata; /* User data */
+} H5F_object_flush_t;
/*
* Encode and decode macros for file meta-data.
@@ -463,8 +468,10 @@ typedef struct H5F_blk_aggr_t H5F_blk_aggr_t;
#define H5F_ACS_LATEST_FORMAT_NAME "latest_format" /* 'Use latest format version' flag */
#define H5F_ACS_WANT_POSIX_FD_NAME "want_posix_fd" /* Internal: query the file descriptor from the core VFD, instead of the memory address */
#define H5F_ACS_METADATA_READ_ATTEMPTS_NAME "metadata_read_attempts" /* # of metadata read attempts */
+#define H5F_ACS_OBJECT_FLUSH_CB_NAME "object_flush_cb" /* Object flush callback */
#define H5F_ACS_EFC_SIZE_NAME "efc_size" /* Size of external file cache */
#define H5F_ACS_FILE_IMAGE_INFO_NAME "file_image_info" /* struct containing initial file image and callback info */
+#define H5F_ACS_CLEAR_STATUS_FLAGS_NAME "clear_status_flags" /* Whether to clear superblock status_flags (private property only used by h5clear) */
/* ======================== File Mount properties ====================*/
#define H5F_MNT_SYM_LOCAL_NAME "local" /* Whether absolute symlinks local to file. */
@@ -640,6 +647,8 @@ 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);
+H5_DLL herr_t H5F_evict_cache_entries(H5F_t *f, hid_t dxpl_id);
+
/* Functions that read & verify a piece of metadata with checksum */
H5_DLL herr_t H5F_read_check_metadata(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type,
@@ -650,6 +659,10 @@ H5_DLL herr_t H5F_get_checksums(const uint8_t *buf, size_t chk_size, uint32_t *s
/* Routine to track the # of retries */
H5_DLL herr_t H5F_track_metadata_read_retries(H5F_t *f, unsigned actype, unsigned retries);
+/* Routine to invoke callback function upon object flush */
+H5_DLL herr_t H5F_object_flush_cb(H5F_t *f, hid_t obj_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/H5Fpublic.h b/src/H5Fpublic.h
index c1d96ca..7db8cfe 100644
--- a/src/H5Fpublic.h
+++ b/src/H5Fpublic.h
@@ -193,6 +193,10 @@ typedef struct H5F_retry_info_t {
uint32_t *retries[H5F_NUM_METADATA_READ_RETRY_TYPES];
} H5F_retry_info_t;
+/* Callback for H5Pset_object_flush_cb() in a file access property list */
+typedef herr_t (*H5F_flush_cb_t)(hid_t object_id, void *udata);
+
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -231,6 +235,7 @@ H5_DLL herr_t H5Freset_mdc_hit_rate_stats(hid_t file_id);
H5_DLL ssize_t H5Fget_name(hid_t obj_id, char *name, size_t size);
H5_DLL herr_t H5Fget_info2(hid_t obj_id, H5F_info2_t *finfo);
H5_DLL herr_t H5Fget_metadata_read_retry_info(hid_t file_id, H5F_retry_info_t *info);
+H5_DLL herr_t H5Fstart_swmr_write(hid_t file_id);
H5_DLL ssize_t H5Fget_free_sections(hid_t file_id, H5F_mem_t type,
size_t nsects, H5F_sect_info_t *sect_info/*out*/);
H5_DLL herr_t H5Fclear_elink_file_cache(hid_t file_id);
diff --git a/src/H5Fsuper.c b/src/H5Fsuper.c
index a1c67ec..7858530 100644
--- a/src/H5Fsuper.c
+++ b/src/H5Fsuper.c
@@ -204,7 +204,7 @@ H5F_super_ext_create(H5F_t *f, hid_t dxpl_id, H5O_loc_t *ext_ptr)
* extension.
*/
H5O_loc_reset(ext_ptr);
- if(H5O_create(f, dxpl_id, 0, (size_t)1, H5P_GROUP_CREATE_DEFAULT, ext_ptr) < 0)
+ if(H5O_create(f, dxpl_id, (size_t)0, (size_t)1, H5P_GROUP_CREATE_DEFAULT, ext_ptr) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTCREATE, FAIL, "unable to create superblock extension")
/* Record the address of the superblock extension */
diff --git a/src/H5G.c b/src/H5G.c
index e16847d..30f498a 100644
--- a/src/H5G.c
+++ b/src/H5G.c
@@ -843,9 +843,8 @@ H5Gflush(hid_t group_id)
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")
+ if(H5O_flush_common(&grp->oloc, group_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTFLUSH, FAIL, "unable to flush group and object flush callback")
done:
FUNC_LEAVE_API(ret_value)
diff --git a/src/H5Ocopy.c b/src/H5Ocopy.c
index 24eed35..13902aa 100644
--- a/src/H5Ocopy.c
+++ b/src/H5Ocopy.c
@@ -362,20 +362,33 @@ H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out*/,
/* Check if the object at the address is already open in the file */
if(H5FO_opened(oloc_src->file, oloc_src->addr) != NULL) {
- H5G_loc_t tmp_loc; /* Location of object */
- H5O_loc_t tmp_oloc; /* Location of object */
- H5G_name_t tmp_path; /* Object's path */
+ H5G_loc_t tmp_loc; /* Location of object */
+ H5O_loc_t tmp_oloc; /* Location of object */
+ H5G_name_t tmp_path; /* Object's path */
+ void *obj_ptr = NULL; /* Object pointer */
+ hid_t tmp_id = -1; /* Object ID */
tmp_loc.oloc = &tmp_oloc;
tmp_loc.path = &tmp_path;
tmp_oloc.file = oloc_src->file;
tmp_oloc.addr = oloc_src->addr;
- tmp_oloc.holding_file = oloc_src->holding_file;
+ tmp_oloc.holding_file = FALSE;
H5G_name_reset(tmp_loc.path);
- /* Flush the object of this class */
- if(obj_class->flush && obj_class->flush(&tmp_loc, dxpl_id) < 0)
+ /* Get a temporary ID */
+ if((tmp_id = obj_class->open(&tmp_loc, H5P_DEFAULT, dxpl_id, FALSE)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to open object")
+
+ /* Get object pointer */
+ obj_ptr = H5I_object(tmp_id);
+
+ /* Flush the object */
+ if(obj_class->flush && obj_class->flush(obj_ptr, dxpl_id) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object")
+
+ /* Release the temporary ID */
+ if(tmp_id != -1 && H5I_dec_app_ref(tmp_id))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "unable to close temporary ID")
}
/* Get source object header */
@@ -476,7 +489,7 @@ H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out*/,
oh_dst->alloc_nchunks = oh_dst->nchunks = 0;
/* Allocate memory for the chunk array - always start with 1 chunk */
- if(NULL == (oh_dst->chunk = H5FL_SEQ_MALLOC(H5O_chunk_t, 1)))
+ if(NULL == (oh_dst->chunk = H5FL_SEQ_MALLOC(H5O_chunk_t, (size_t)1)))
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
/* Update number of allocated chunks. There are still no chunks used. */
@@ -1665,7 +1678,7 @@ H5O_copy_search_comm_dt_check(H5O_loc_t *obj_oloc,
attr_op.u.lib_op = H5O_copy_search_comm_dt_attr_cb;
udata->obj_oloc.file = obj_oloc->file;
udata->obj_oloc.addr = obj_oloc->addr;
- if(H5O_attr_iterate_real((hid_t)-1, obj_oloc, udata->dxpl_id, H5_INDEX_NAME, H5_ITER_NATIVE, 0, NULL, &attr_op, udata) < 0)
+ if(H5O_attr_iterate_real((hid_t)-1, obj_oloc, udata->dxpl_id, H5_INDEX_NAME, H5_ITER_NATIVE, (hsize_t)0, NULL, &attr_op, udata) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_BADITER, FAIL, "error iterating over attributes");
done:
diff --git a/src/H5Oflush.c b/src/H5Oflush.c
index 06448fe..489afb2 100644
--- a/src/H5Oflush.c
+++ b/src/H5Oflush.c
@@ -48,7 +48,7 @@
/*-------------------------------------------------------------------------
- * Function: H5Oflush
+ * Function: H5Oflush
*
* Purpose: Flushes all buffers associated with an object to disk.
*
@@ -63,6 +63,8 @@ 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)
@@ -71,15 +73,57 @@ H5Oflush(hid_t 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")
+
+ /* Get the object pointer */
+ if((obj_ptr = H5I_object(obj_id)) == NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid object identifier")
+
+ /* Get the object class */
+ if((obj_class = H5O_obj_class(oloc, H5AC_dxpl_id)) == NULL)
+ 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_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) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object and object flush callback")
done:
FUNC_LEAVE_API(ret_value)
} /* H5Oflush */
+/*-------------------------------------------------------------------------
+ * Function: H5O_flush_common
+ *
+ * Purpose: Flushes the object's metadata
+ * Invokes the user-defined callback if there is one.
+ *
+ * Return: Non-negative on success, negative on failure
+ *
+ * Programmer: Vailin Choi; Dec 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_flush_common(H5O_loc_t *oloc, hid_t obj_id)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Private function */
+ if(H5O_flush_metadata(oloc, H5AC_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object metadata")
+
+ /* Check to invoke callback */
+ if(H5F_object_flush_cb(oloc->file, obj_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to do object flush callback")
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
/*-------------------------------------------------------------------------
* Function: H5O_flush_metadata
diff --git a/src/H5Opkg.h b/src/H5Opkg.h
index b9f074e..1955ec4 100644
--- a/src/H5Opkg.h
+++ b/src/H5Opkg.h
@@ -330,7 +330,7 @@ typedef struct H5O_obj_class_t {
void *(*create)(H5F_t *, void *, H5G_loc_t *, hid_t ); /*create an object of this class */
H5O_loc_t *(*get_oloc)(hid_t ); /*get the object header location for an object */
herr_t (*bh_info)(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5_ih_info_t *bh_info); /*get the index & heap info for an object */
- herr_t (*flush)(H5G_loc_t *loc, hid_t dxpl_id); /*flush an opened object of this class */
+ herr_t (*flush)(void *obj_ptr, hid_t dxpl_id); /*flush an opened object of this class */
} H5O_obj_class_t;
/* Node in skip list to map addresses from one file to another during object header copy */
diff --git a/src/H5Oprivate.h b/src/H5Oprivate.h
index 1a0f76c..0c9e779 100644
--- a/src/H5Oprivate.h
+++ b/src/H5Oprivate.h
@@ -832,6 +832,8 @@ H5_DLL herr_t H5O_msg_unlock(const H5O_loc_t *loc, unsigned type_id, hid_t dxpl_
/* 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);
+H5_DLL herr_t H5O_flush_common(H5O_loc_t *oloc, hid_t obj_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/H5Pdapl.c b/src/H5Pdapl.c
index 5239fba..17b91a9 100644
--- a/src/H5Pdapl.c
+++ b/src/H5Pdapl.c
@@ -61,6 +61,11 @@
#define H5D_ACS_PREEMPT_READ_CHUNKS_DEF H5D_CHUNK_CACHE_W0_DEFAULT
#define H5D_ACS_PREEMPT_READ_CHUNKS_ENC H5P__encode_double
#define H5D_ACS_PREEMPT_READ_CHUNKS_DEC H5P__decode_double
+/* Definition for append flush */
+#define H5D_ACS_APPEND_FLUSH_SIZE sizeof(H5D_append_flush_t)
+#define H5D_ACS_APPEND_FLUSH_DEF {0,{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},NULL,NULL}
+
+
/******************/
/* Local Typedefs */
@@ -109,7 +114,7 @@ const H5P_libclass_t H5P_CLS_DACC[1] = {{
/*******************/
/* Local Variables */
/*******************/
-
+static const H5D_append_flush_t H5D_def_append_flush_g = H5D_ACS_APPEND_FLUSH_DEF; /* Default setting for append flush */
/*-------------------------------------------------------------------------
@@ -149,6 +154,10 @@ H5P__dacc_reg_prop(H5P_genclass_t *pclass)
NULL, NULL, NULL, H5D_ACS_PREEMPT_READ_CHUNKS_ENC, H5D_ACS_PREEMPT_READ_CHUNKS_DEC, NULL, NULL, NULL, NULL) < 0)
HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+ /* Register info for append flush */
+ if(H5P_register_real(pclass, H5D_ACS_APPEND_FLUSH_NAME, H5D_ACS_APPEND_FLUSH_SIZE, &H5D_def_append_flush_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5P__dacc_reg_prop() */
@@ -281,3 +290,122 @@ done:
FUNC_LEAVE_API(ret_value)
}
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_append_flush
+ *
+ * Purpose: Sets the boundary, callback function, and user data in the
+ * property list.
+ * "ndims": number of array elements for boundary
+ * "boundary": used to determine whether the current dimension hits
+ * a boundary; if so, invoke the callback function and
+ * flush the dataset.
+ * "func": the callback function to invoke when the boundary is hit
+ * "udata": the user data to pass as parameter with the callback function
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Dec 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_append_flush(hid_t plist_id, int ndims, const hsize_t *boundary, H5D_append_cb_t func, void *udata)
+{
+ H5P_genplist_t *plist; /* property list pointer */
+ H5D_append_flush_t info;
+ unsigned u; /* local index variable */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "iIs*hx*x", plist_id, ndims, boundary, func, udata);
+
+ /* Check arguments */
+ if(ndims <= 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dimensionality cannot be negative or zero")
+ if(ndims > H5S_MAX_RANK)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dimensionality is too large")
+ if(!boundary)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no boundary dimensions specified")
+
+ /* Check if the callback function is NULL and the user data is non-NULL.
+ * This is almost certainly an error as the user data will not be used. */
+ if(!func && udata)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "callback is NULL while user data is not")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set up values */
+ info.ndims = ndims;
+ info.func = func;
+ info.udata = udata;
+
+ HDmemset(info.boundary, 0, sizeof(info.boundary));
+ /* boundary can be 0 to indicate no boundary is set */
+ for(u = 0; u < (unsigned)ndims; u++) {
+ if(boundary[u] != (boundary[u] & 0xffffffff)) /* negative value (including H5S_UNLIMITED) */
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "all boundary dimensions must be less than 2^32")
+ info.boundary[u] = boundary[u]; /* Store user's boundary dimensions */
+ }
+
+ /* Set values */
+ if(H5P_set(plist, H5D_ACS_APPEND_FLUSH_NAME, &info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set append flush")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pset_append_flush() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_append_flush()
+ *
+ * Purpose: Retrieves the boundary, callback function and user data set in
+ * property list.
+ * Note that the # of boundary sizes to retrieve will not exceed
+ * the parameter "ndims" and the ndims set previously via
+ * H5Pset_append_flush().
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Dec 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_append_flush(hid_t plist_id, int ndims, hsize_t boundary[], H5D_append_cb_t *func, void **udata)
+{
+ H5P_genplist_t *plist; /* property list pointer */
+ H5D_append_flush_t info;
+ int i; /* local index variable */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE5("e", "iIs*h*x**x", plist_id, ndims, boundary, func, udata);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Retrieve info for append flush */
+ if(H5P_get(plist, H5D_ACS_APPEND_FLUSH_NAME, &info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get object flush callback")
+
+ /* Assign return values */
+ if(boundary) {
+ HDmemset(boundary, 0, ndims * sizeof(hsize_t));
+ if(info.ndims > 0) {
+ for(i = 0; i < info.ndims && i < ndims; i++)
+ boundary[i] = info.boundary[i];
+ }
+ }
+ if(func)
+ *func = info.func;
+ if(udata)
+ *udata = info.udata;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pget_append_flush() */
diff --git a/src/H5Pfapl.c b/src/H5Pfapl.c
index 8a09ed9..dd63457 100644
--- a/src/H5Pfapl.c
+++ b/src/H5Pfapl.c
@@ -162,9 +162,16 @@
#define H5F_ACS_FILE_IMAGE_INFO_CLOSE H5P_file_image_info_close
/* Definition for # of metadata read attempts */
#define H5F_ACS_METADATA_READ_ATTEMPTS_SIZE sizeof(unsigned)
-#define H5F_ACS_METADATA_READ_ATTEMPTS_DEF 0
-#define H5F_ACS_METADATA_READ_ATTEMPTS_ENC H5P__encode_unsigned
-#define H5F_ACS_METADATA_READ_ATTEMPTS_DEC H5P__decode_unsigned
+#define H5F_ACS_METADATA_READ_ATTEMPTS_DEF 0
+#define H5F_ACS_METADATA_READ_ATTEMPTS_ENC H5P__encode_unsigned
+#define H5F_ACS_METADATA_READ_ATTEMPTS_DEC H5P__decode_unsigned
+/* Definition for object flush callback */
+#define H5F_ACS_OBJECT_FLUSH_CB_SIZE sizeof(H5F_object_flush_t)
+#define H5F_ACS_OBJECT_FLUSH_CB_DEF {NULL, NULL}
+/* Definition for status_flags in the superblock */
+#define H5F_ACS_CLEAR_STATUS_FLAGS_SIZE sizeof(hbool_t)
+#define H5F_ACS_CLEAR_STATUS_FLAGS_DEF FALSE
+
/******************/
/* Local Typedefs */
@@ -252,6 +259,8 @@ static const hbool_t H5F_def_want_posix_fd_g = H5F_ACS_WANT_POSIX_FD_DEF;
static const unsigned H5F_def_efc_size_g = H5F_ACS_EFC_SIZE_DEF; /* Default external file cache size */
static const H5FD_file_image_info_t H5F_def_file_image_info_g = H5F_ACS_FILE_IMAGE_INFO_DEF; /* Default file image info and callbacks */
static const unsigned H5F_def_metadata_read_attempts_g = H5F_ACS_METADATA_READ_ATTEMPTS_DEF; /* Default setting for the # of metadata read attempts */
+static const H5F_object_flush_t H5F_def_object_flush_cb_g = H5F_ACS_OBJECT_FLUSH_CB_DEF; /* Default setting for object flush callback */
+static const hbool_t H5F_def_clear_status_flags_g = H5F_ACS_CLEAR_STATUS_FLAGS_DEF; /* Default to clear the superblock status_flags */
/*-------------------------------------------------------------------------
@@ -407,6 +416,17 @@ H5P_facc_reg_prop(H5P_genclass_t *pclass)
NULL, NULL, NULL, NULL) < 0)
HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+ /* Register object flush callback */
+ if(H5P_register_real(pclass, H5F_ACS_OBJECT_FLUSH_CB_NAME, H5F_ACS_OBJECT_FLUSH_CB_SIZE, &H5F_def_object_flush_cb_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register the private property of whether to clear the superblock status_flags. It's used by h5clear only. */
+ if(H5P_register_real(pclass, H5F_ACS_CLEAR_STATUS_FLAGS_NAME, H5F_ACS_CLEAR_STATUS_FLAGS_SIZE, &H5F_def_clear_status_flags_g,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5P_facc_reg_prop() */
@@ -2608,7 +2628,7 @@ H5P__facc_cache_config_enc(const void *value, void **_pp, size_t *size)
H5_ENCODE_UNSIGNED(*pp, config->close_trace_file);
- HDmemcpy(*pp, (const uint8_t *)(config->trace_file_name), H5AC__MAX_TRACE_FILE_NAME_LEN + 1);
+ HDmemcpy(*pp, (const uint8_t *)(config->trace_file_name), (size_t)(H5AC__MAX_TRACE_FILE_NAME_LEN + 1));
*pp += H5AC__MAX_TRACE_FILE_NAME_LEN + 1;
H5_ENCODE_UNSIGNED(*pp, config->evictions_enabled);
@@ -3074,3 +3094,86 @@ done:
FUNC_LEAVE_API(ret_value)
} /* end H5Pget_metadata_read_attempts() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_obj_flush_cb
+ *
+ * Purpose: Sets the callback function to invoke and the user data when an
+ * object flush occurs in the file.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Dec 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_object_flush_cb(hid_t plist_id, H5F_flush_cb_t func, void *udata)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5F_object_flush_t flush_info;
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "ix*x", plist_id, func, udata);
+
+ /* Check if the callback function is NULL and the user data is non-NULL.
+ * This is almost certainly an error as the user data will not be used. */
+ if(!func && udata)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "callback is NULL while user data is not")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Update property list */
+ flush_info.func = func;
+ flush_info.udata = udata;
+
+ /* Set values */
+ if(H5P_set(plist, H5F_ACS_OBJECT_FLUSH_CB_NAME, &flush_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set object flush callback")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pset_obj_flush_cb() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_obj_flush_cb
+ *
+ * Purpose: Retrieves the callback function and user data set in the
+ * property list for an object flush.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Vailin Choi; Dec 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_object_flush_cb(hid_t plist_id, H5F_flush_cb_t *func, void **udata)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5F_object_flush_t flush_info;
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE3("e", "i*x**x", plist_id, func, udata);
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Retrieve the callback function and user data */
+ if(H5P_get(plist, H5F_ACS_OBJECT_FLUSH_CB_NAME, &flush_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get object flush callback")
+
+ /* Assign return value */
+ if(func)
+ *func = flush_info.func;
+ if(udata)
+ *udata = flush_info.udata;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5Pget_obj_flush_cb() */
diff --git a/src/H5Ppublic.h b/src/H5Ppublic.h
index cbb6f6a..3979c82 100644
--- a/src/H5Ppublic.h
+++ b/src/H5Ppublic.h
@@ -346,6 +346,9 @@ H5_DLL herr_t H5Pget_file_image_callbacks(hid_t fapl_id,
H5FD_file_image_callbacks_t *callbacks_ptr);
H5_DLL herr_t H5Pset_metadata_read_attempts(hid_t plist_id, unsigned attempts);
H5_DLL herr_t H5Pget_metadata_read_attempts(hid_t plist_id, unsigned *attempts);
+H5_DLL herr_t H5Pset_object_flush_cb(hid_t plist_id, H5F_flush_cb_t func, void *udata);
+H5_DLL herr_t H5Pget_object_flush_cb(hid_t plist_id, H5F_flush_cb_t *func, void **udata);
+
/* Dataset creation property list (DCPL) routines */
H5_DLL herr_t H5Pset_layout(hid_t plist_id, H5D_layout_t layout);
@@ -384,6 +387,10 @@ H5_DLL herr_t H5Pget_chunk_cache(hid_t dapl_id,
size_t *rdcc_nslots/*out*/,
size_t *rdcc_nbytes/*out*/,
double *rdcc_w0/*out*/);
+H5_DLL herr_t H5Pset_append_flush(hid_t plist_id,
+ int ndims, const hsize_t boundary[], H5D_append_cb_t func, void *udata);
+H5_DLL herr_t H5Pget_append_flush(hid_t plist_id,
+ int dims, hsize_t boundary[], H5D_append_cb_t *func, void **udata);
/* Dataset xfer property list (DXPL) routines */
H5_DLL herr_t H5Pset_data_transform(hid_t plist_id, const char* expression);
diff --git a/src/H5T.c b/src/H5T.c
index d545c4e..71873fe 100644
--- a/src/H5T.c
+++ b/src/H5T.c
@@ -5419,9 +5419,9 @@ H5Tflush(hid_t type_id)
if(!H5T_is_named(dt))
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a committed 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")
+ /* To flush metadata and invoke flush callback if there is */
+ if(H5O_flush_common(&dt->oloc, type_id) < 0)
+ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTFLUSH, FAIL, "unable to flush datatype and object flush callback")
done:
FUNC_LEAVE_API(ret_value)
diff --git a/src/H5config.h.in b/src/H5config.h.in
index 02bafd8..7a73f1e 100644
--- a/src/H5config.h.in
+++ b/src/H5config.h.in
@@ -346,6 +346,9 @@
/* Define to 1 if you have the `system' function. */
#undef HAVE_SYSTEM
+/* Define to 1 if you have the <sys/file.h> header file. */
+#undef HAVE_SYS_FILE_H
+
/* Define to 1 if you have the <sys/fpu.h> header file. */
#undef HAVE_SYS_FPU_H
diff --git a/src/H5private.h b/src/H5private.h
index f54bd9d..9b89d23 100644
--- a/src/H5private.h
+++ b/src/H5private.h
@@ -119,6 +119,13 @@
#endif
/*
+ * flock() in sys/file.h is used for the implemention of file locking.
+ */
+#ifdef H5_HAVE_SYS_FILE_H
+# include <sys/file.h>
+#endif
+
+/*
* Resource usage is not Posix.1 but HDF5 uses it anyway for some performance
* and debugging code if available.
*/
@@ -704,6 +711,9 @@ typedef struct {
#ifndef HDfileno
#define HDfileno(F) fileno(F)
#endif /* HDfileno */
+#ifndef HDflock
+ #define HDflock(F,L) flock(F,L)
+#endif /* HDflock */
#ifndef HDfloor
#define HDfloor(X) floor(X)
#endif /* HDfloor */