diff options
author | Vailin Choi <vchoi@hdfgroup.org> | 2014-01-08 17:09:23 (GMT) |
---|---|---|
committer | Vailin Choi <vchoi@hdfgroup.org> | 2014-01-08 17:09:23 (GMT) |
commit | a196a4f351abed0670c10bc50887bd4e56dd4775 (patch) | |
tree | cc56e2d57884eae938e6606624d0c619d6dfe541 /src | |
parent | 955c0736022947649441634f7ee3dc5c973085d4 (diff) | |
download | hdf5-a196a4f351abed0670c10bc50887bd4e56dd4775.zip hdf5-a196a4f351abed0670c10bc50887bd4e56dd4775.tar.gz hdf5-a196a4f351abed0670c10bc50887bd4e56dd4775.tar.bz2 |
[svn-r24622] Implementation (pending code review) for:
(A) SWMR related public routines: H5Fstart_swmr_write, H5Pget/set_append_flush, H5Pget/set_object_flush_cb.
(B) File locking.
Tested on jam, koala, ostrich, platypus.
Diffstat (limited to 'src')
-rw-r--r-- | src/H5AC.c | 33 | ||||
-rw-r--r-- | src/H5ACprivate.h | 2 | ||||
-rw-r--r-- | src/H5C.c | 39 | ||||
-rw-r--r-- | src/H5Cprivate.h | 4 | ||||
-rw-r--r-- | src/H5D.c | 14 | ||||
-rw-r--r-- | src/H5Dint.c | 97 | ||||
-rw-r--r-- | src/H5Doh.c | 25 | ||||
-rw-r--r-- | src/H5Dpkg.h | 1 | ||||
-rw-r--r-- | src/H5Dprivate.h | 9 | ||||
-rw-r--r-- | src/H5Dpublic.h | 3 | ||||
-rw-r--r-- | src/H5F.c | 382 | ||||
-rw-r--r-- | src/H5FD.c | 58 | ||||
-rw-r--r-- | src/H5FDcore.c | 79 | ||||
-rw-r--r-- | src/H5FDdirect.c | 78 | ||||
-rw-r--r-- | src/H5FDprivate.h | 2 | ||||
-rw-r--r-- | src/H5FDpublic.h | 4 | ||||
-rw-r--r-- | src/H5FDsec2.c | 72 | ||||
-rw-r--r-- | src/H5Fio.c | 49 | ||||
-rw-r--r-- | src/H5Fpkg.h | 21 | ||||
-rw-r--r-- | src/H5Fprivate.h | 13 | ||||
-rw-r--r-- | src/H5Fpublic.h | 5 | ||||
-rw-r--r-- | src/H5Fsuper.c | 2 | ||||
-rw-r--r-- | src/H5G.c | 5 | ||||
-rw-r--r-- | src/H5Ocopy.c | 29 | ||||
-rw-r--r-- | src/H5Oflush.c | 54 | ||||
-rw-r--r-- | src/H5Opkg.h | 2 | ||||
-rw-r--r-- | src/H5Oprivate.h | 2 | ||||
-rw-r--r-- | src/H5Pdapl.c | 130 | ||||
-rw-r--r-- | src/H5Pfapl.c | 111 | ||||
-rw-r--r-- | src/H5Ppublic.h | 7 | ||||
-rw-r--r-- | src/H5T.c | 6 | ||||
-rw-r--r-- | src/H5config.h.in | 3 | ||||
-rw-r--r-- | src/H5private.h | 10 |
33 files changed, 1256 insertions, 95 deletions
@@ -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, @@ -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, @@ -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 */ /********************/ @@ -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() */ @@ -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 */ @@ -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); @@ -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 */ |