From 45be06a387c1294fa3c95cc71106afcc023ddb91 Mon Sep 17 00:00:00 2001 From: Vailin Choi Date: Tue, 14 Aug 2018 13:21:00 -0500 Subject: Preliminary checkins for implementation done so far: 1) Public routines: H5Pget/set_vfd_swmr_config 2) Public routine: H5Fvfd_swmr_end_tick 3) Initialization when opening a file with VFD SWMR writer 4) Tests in test/vfd_swmr.c for VFD SWMR 5) Fix a bug in src/H5Fint.c: when error is encountered after the root group is created Note the following: --This is WORK IN PROGRESS and will subject to change as implementation goes. --There is test failure form enc_dec_plist.c: I will fix this when changes to the property list are settled. --The branch is updated with the latest from develop as of 8/14/2018 --- bin/trace | 1 + src/H5.c | 6 + src/H5AC.c | 4 +- src/H5ACprivate.h | 2 +- src/H5Cprivate.h | 2 +- src/H5Ctag.c | 6 +- src/H5Dint.c | 2 +- src/H5F.c | 32 +++ src/H5FDint.c | 108 +++++++++ src/H5FDprivate.h | 43 ++++ src/H5Fint.c | 207 +++++++++++++++- src/H5Fpkg.h | 9 + src/H5Fprivate.h | 22 ++ src/H5Fpublic.h | 16 ++ src/H5Fquery.c | 23 ++ src/H5Pfapl.c | 213 +++++++++++++++++ src/H5Ppublic.h | 4 + src/H5private.h | 30 +++ test/Makefile.am | 2 +- test/vfd_swmr.c | 695 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 20 files changed, 1417 insertions(+), 10 deletions(-) create mode 100644 test/vfd_swmr.c diff --git a/bin/trace b/bin/trace index cf41238..9712b59 100755 --- a/bin/trace +++ b/bin/trace @@ -117,6 +117,7 @@ $Source = ""; "H5F_info1_t" => "x", "H5F_info2_t" => "x", "H5F_retry_info_t" => "x", + "H5F_vfd_swmr_config_t" => "x", "H5FD_t" => "x", "H5FD_class_t" => "x", "H5FD_stream_fapl_t" => "x", diff --git a/src/H5.c b/src/H5.c index 1b13fea..8ff8bdc 100644 --- a/src/H5.c +++ b/src/H5.c @@ -85,6 +85,12 @@ char H5_lib_vers_info_g[] = H5_VERS_INFO; static hbool_t H5_dont_atexit_g = FALSE; H5_debug_t H5_debug_g; /* debugging info */ +hbool_t vfd_swmr_g = FALSE; +hbool_t vfd_swmr_writer_g = FALSE; +uint64_t tick_num_g = 0; +struct timespec end_of_tick_g; +H5F_file_t *vfd_swmr_file_g; + /*******************/ /* Local Variables */ diff --git a/src/H5AC.c b/src/H5AC.c index 989ee10..e6b1928 100644 --- a/src/H5AC.c +++ b/src/H5AC.c @@ -2760,7 +2760,7 @@ done: *------------------------------------------------------------------------------ */ herr_t -H5AC_expunge_tag_type_metadata(H5F_t *f, haddr_t tag, int type_id, unsigned flags) +H5AC_expunge_tag_type_metadata(H5F_t *f, haddr_t tag, int type_id, unsigned flags, hbool_t type_match) { /* Variable Declarations */ herr_t ret_value = SUCCEED; @@ -2773,7 +2773,7 @@ H5AC_expunge_tag_type_metadata(H5F_t *f, haddr_t tag, int type_id, unsigned flag HDassert(f->shared); /* Call cache level function to expunge entries with specified tag and type id */ - if(H5C_expunge_tag_type_metadata(f, tag, type_id, flags)<0) + if(H5C_expunge_tag_type_metadata(f, tag, type_id, flags, type_match)<0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Cannot expunge tagged type entries") done: diff --git a/src/H5ACprivate.h b/src/H5ACprivate.h index 99cc0e9..36872c4 100644 --- a/src/H5ACprivate.h +++ b/src/H5ACprivate.h @@ -444,7 +444,7 @@ H5_DLL void H5AC_set_ring(H5AC_ring_t ring, H5AC_ring_t *orig_ring); H5_DLL herr_t H5AC_unsettle_entry_ring(void *entry); H5_DLL herr_t H5AC_unsettle_ring(H5F_t * f, H5AC_ring_t ring); H5_DLL herr_t H5AC_expunge_tag_type_metadata(H5F_t *f, haddr_t tag, int type_id, - unsigned flags); + unsigned flags, hbool_t type_match); H5_DLL herr_t H5AC_get_tag(const void *thing, /*OUT*/ haddr_t *tag); /* Virtual entry routines */ diff --git a/src/H5Cprivate.h b/src/H5Cprivate.h index 38a86ee..a3e46db 100644 --- a/src/H5Cprivate.h +++ b/src/H5Cprivate.h @@ -2246,7 +2246,7 @@ H5_DLL herr_t H5C_flush_cache(H5F_t *f, unsigned flags); H5_DLL herr_t H5C_flush_tagged_entries(H5F_t *f, haddr_t tag); H5_DLL herr_t H5C_force_cache_image_load(H5F_t * f); H5_DLL herr_t H5C_evict_tagged_entries(H5F_t *f, haddr_t tag, hbool_t match_global); -H5_DLL herr_t H5C_expunge_tag_type_metadata(H5F_t *f, haddr_t tag, int type_id, unsigned flags); +H5_DLL herr_t H5C_expunge_tag_type_metadata(H5F_t *f, haddr_t tag, int type_id, unsigned flags, hbool_t type_match); H5_DLL herr_t H5C_get_tag(const void *thing, /*OUT*/ haddr_t *tag); #if H5C_DO_TAGGING_SANITY_CHECKS herr_t H5C_verify_tag(int id, haddr_t tag); diff --git a/src/H5Ctag.c b/src/H5Ctag.c index 66aedd9..16baac3 100644 --- a/src/H5Ctag.c +++ b/src/H5Ctag.c @@ -75,6 +75,7 @@ typedef struct { H5F_t *f; /* File pointer for evicting entry */ int type_id; /* Cache entry type to expunge */ unsigned flags; /* Flags for expunging entry */ + hbool_t type_match; } H5C_tag_iter_ettm_ctx_t; /* Typedef for tagged entry iterator callback context - mark corked */ @@ -811,7 +812,7 @@ H5C__expunge_tag_type_metadata_cb(H5C_cache_entry_t *entry, void *_ctx) HDassert(ctx); /* Found one with the same tag and type id */ - if(entry->type->id == ctx->type_id) + if(entry->type->id == ctx->type_id || !ctx->type_match) if(H5C_expunge_entry(ctx->f, entry->type, entry->addr, ctx->flags) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTEXPUNGE, H5_ITER_ERROR, "can't expunge entry") @@ -835,7 +836,7 @@ done: *------------------------------------------------------------------------- */ herr_t -H5C_expunge_tag_type_metadata(H5F_t *f, haddr_t tag, int type_id, unsigned flags) +H5C_expunge_tag_type_metadata(H5F_t *f, haddr_t tag, int type_id, unsigned flags, hbool_t type_match) { H5C_t *cache; /* Pointer to cache structure */ H5C_tag_iter_ettm_ctx_t ctx; /* Context for iterator callback */ @@ -855,6 +856,7 @@ H5C_expunge_tag_type_metadata(H5F_t *f, haddr_t tag, int type_id, unsigned flags ctx.f = f; ctx.type_id = type_id; ctx.flags = flags; + ctx.type_match = type_match; /* Iterate through hash table entries, expunge those with specified tag and type id */ if(H5C__iter_tagged_entries(cache, tag, FALSE, H5C__expunge_tag_type_metadata_cb, &ctx) < 0) diff --git a/src/H5Dint.c b/src/H5Dint.c index e8874a2..21594c6 100644 --- a/src/H5Dint.c +++ b/src/H5Dint.c @@ -2986,7 +2986,7 @@ done: HDONE_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "address undefined") /* Expunge from cache all v1 B-tree type entries associated with tag */ - if(H5AC_expunge_tag_type_metadata(dataset->oloc.file, dataset->oloc.addr, H5AC_BT_ID, H5AC__NO_FLAGS_SET)) + if(H5AC_expunge_tag_type_metadata(dataset->oloc.file, dataset->oloc.addr, H5AC_BT_ID, H5AC__NO_FLAGS_SET, TRUE)) HDONE_ERROR(H5E_DATASET, H5E_CANTEXPUNGE, FAIL, "unable to expunge index metadata") } /* end if */ diff --git a/src/H5F.c b/src/H5F.c index 01fd7db..079af75 100644 --- a/src/H5F.c +++ b/src/H5F.c @@ -1713,3 +1713,35 @@ H5Fincrement_filesize(hid_t file_id, hsize_t increment) done: FUNC_LEAVE_API(ret_value) } /* H5Fincrement_filesize() */ + + +/*------------------------------------------------------------------------- + * Function: H5Fvfd_swmr_end_tick() + * + * Purpose: To allow user to trigger end of tick processing + * + * Return: Non-negative on success/Negative on errors + *------------------------------------------------------------------------- + */ +herr_t +H5Fvfd_swmr_end_tick(hid_t file_id) +{ + H5F_t *file; /* File object for file ID */ + 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, "hid_t identifier is not a file ID") + + /* This will work only if the file is opened with VFD SWMR configured.*/ + if(!(H5F_USE_VFD_SWMR(file))) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "must have VFD SWMR configured for this public routine") + + /* ??Trigger end of tick processing later */ + +done: + FUNC_LEAVE_API(ret_value) +} /* H5Fvfd_swmr_end_tick() */ diff --git a/src/H5FDint.c b/src/H5FDint.c index 023ff57..a26815e 100644 --- a/src/H5FDint.c +++ b/src/H5FDint.c @@ -418,3 +418,111 @@ H5FD_driver_query(const H5FD_class_t *driver, unsigned long *flags/*out*/) FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD_driver_query() */ + +/*------------------------------------------------------------------------- +* Function: H5FD_writer_end_of_tick +* +* Purpose: +* +* Return: SUCCEED/FAIL +* +* Programmer: +* +*------------------------------------------------------------------------- +*/ +herr_t +H5FD_writer_end_of_tick(void) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_writer_end_of_tick() */ + + +/*------------------------------------------------------------------------- +* Function: H5FD_reader_end_of_tick +* +* Purpose: +* +* Return: SUCCEED/FAIL +* +* Programmer: +* +*------------------------------------------------------------------------- +*/ +herr_t +H5FD_reader_end_of_tick(void) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_reader_end_of_tick() */ + +#ifdef OUT + +/*------------------------------------------------------------------------- + * Function: H5FD_vfd_swmr_md_read + * + * Purpose: ?? + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: + * + *------------------------------------------------------------------------- + */ +herr_t +H5FD_vfd_swmr_md_read(int md_fd, haddr_t addr, size_t size, const void *buf) +{ + + HDlseek(fd, (HDoff_t)addr, SEEK_SET); + bytes_read = HDread(md_fd, buf, size); + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5FD_vfd_swmr_read() */ + +herr_t +H5FD_vfd_swmr_hdr_deserialize(int md_fd, size_t len) +{ + uint8_t image[H5FD_MD_HEADER_SIZE]; /* Buffer for element data */ + uint8_t *p = NULL; + uint32_t fs_page_size; + uint64_t tick_num; + uint64_t index_offset; + uint64_t index_length; + uint32_t stored_chksum; /* Stored metadata checksum value */ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(FAIL) + + p = &image[0]; + + HDlseek(md_fd, (HDoff_t)0, SEEK_SET); + HDread(md_fd, image, H5FD_MD_HEADER_SIZE); + + /* Magic number */ + if(HDmemcmp(p, H5FD_MD_HEADER_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + HGOTO_ERROR(H5E_VFL, H5E_CANTLOAD, NULL, "wrong metadata file header signature") + p += H5_SIZEOF_MAGIC; + + UINT32DECODE(p, fs_page_size); + UINT64DECODE(p, tick_num); + UINT64DECODE(p, index_offset); + UINT64DECODE(p, index_length); + + /* NEED to verify checksum/retry ?? */ + /* Metadata checksum */ + UINT32DECODE(p, stored_chksum); + + /* Sanity check */ + HDassert((size_t)(p - (const uint8_t *)&image[0]) <= len); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5FD_vfd_swmr_hdr_deserialize() */ +#endif diff --git a/src/H5FDprivate.h b/src/H5FDprivate.h index 0430064..1698d96 100644 --- a/src/H5FDprivate.h +++ b/src/H5FDprivate.h @@ -38,6 +38,45 @@ /* Length of filename buffer */ #define H5FD_MAX_FILENAME_LEN 1024 +/* + * VFD SWMR + */ +/* Metadata file header */ +#define H5FD_MD_HEADER_MAGIC "VHDR" /* Header magic */ +#define H5FD_SIZEOF_CHKSUM 4 /* Size of checksum */ + +/* Size of the header in the metadata file */ +#define H5FD_MD_HEADER_SIZE \ + ( \ + H5_SIZEOF_MAGIC /* Signature */ \ + + 4 /* Page size */ \ + + 8 /* Tick number */ \ + + 8 /* Index offset */ \ + + 8 /* Index length number */ \ + + H5FD_SIZEOF_CHKSUM /* Metadata header checksum */ \ + ) + +/* Size of an index entry in the metadata file */ +#define H5FD_MD_INDEX_ENTRY_SIZE \ + ( \ + 4 /* HDF5 file page offset */ \ + + 4 /* Metadata file page offset */ \ + + 4 /* Length */ \ + ) + +/* Metadata file index magic */ +#define H5FD_MD_INDEX_MAGIC "VIDX" /* Index magic */ + +/* Size of the metadata file index */ +#define H5FD_MD_INDEX_SIZE(N) /* N is number of entries in index */ \ + ( \ + H5_SIZEOF_MAGIC /* Signature */ \ + + 8 /* Tick num */ \ + + 4 /* Number of entries */ \ + + (N * H5FD_MD_INDEX_ENTRY_SIZE) /* Index entries */ \ + + H5FD_SIZEOF_CHKSUM /* Metadata header checksum */ \ + ) + #ifdef H5_HAVE_PARALLEL /* ======== Temporary data transfer properties ======== */ /* Definitions for memory MPI type property */ @@ -157,6 +196,10 @@ H5_DLL herr_t H5FD_set_base_addr(H5FD_t *file, haddr_t base_addr); H5_DLL haddr_t H5FD_get_base_addr(const H5FD_t *file); H5_DLL herr_t H5FD_set_paged_aggr(H5FD_t *file, hbool_t paged); +/* Function prototypes for VFD SWMR */ +H5_DLL herr_t H5FD_writer_end_of_tick(); +H5_DLL herr_t H5FD_reader_end_of_tick(); + /* Function prototypes for MPI based VFDs*/ #ifdef H5_HAVE_PARALLEL /* General routines */ diff --git a/src/H5Fint.c b/src/H5Fint.c index abc638a..6448027 100644 --- a/src/H5Fint.c +++ b/src/H5Fint.c @@ -79,6 +79,9 @@ static char *H5F__getenv_prefix_name(char **env_prefix/*in,out*/); 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__flush_phase1(H5F_t *f); static herr_t H5F__flush_phase2(H5F_t *f, hbool_t closing); +static herr_t H5F__init_vfd_swmr(H5F_t *f, hbool_t file_create); +static herr_t H5F__init_vfd_swmr_info(H5F_t *f); +static herr_t H5F__init_vfd_swmr_md(H5F_t *f, hbool_t file_create); /*********************/ @@ -184,6 +187,10 @@ H5F_get_access_plist(H5F_t *f, hbool_t app_ref) if(H5P_set(new_plist, H5F_ACS_PAGE_BUFFER_MIN_RAW_PERC_NAME, &(f->shared->page_buf->min_raw_perc)) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't set minimum raw data fraction of page buffer") } /* end if */ + + if(H5P_set(new_plist, H5F_ACS_VFD_SWMR_CONFIG_NAME, &(f->shared->vfd_swmr_config)) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set initial metadata cache resize config.") + #ifdef H5_HAVE_PARALLEL if(H5P_set(new_plist, H5_COLL_MD_READ_FLAG_NAME, &(f->coll_md_read)) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't set collective metadata read flag") @@ -1033,6 +1040,10 @@ H5F__new(H5F_file_t *shared, unsigned flags, hid_t fcpl_id, hid_t fapl_id, H5FD_ 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 object flush cb info") + /* Get VFD SWMR configuration */ + if(H5P_get(plist, H5F_ACS_VFD_SWMR_CONFIG_NAME, &(f->shared->vfd_swmr_config)) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get VFD SWMR config info") + /* Create a metadata cache with the specified number of elements. * The cache might be created with a different number of elements and * the access property list should be updated to reflect that. @@ -1497,7 +1508,8 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id) hbool_t use_file_locking; /*read from env var */ hbool_t ci_load = FALSE; /* whether MDC ci load requested */ hbool_t ci_write = FALSE; /* whether MDC CI write requested */ - H5F_t *ret_value = NULL; /*actual return value */ + hbool_t file_create = FALSE; /* creating a new file or not */ + H5F_t *ret_value = NULL; /*actual return value */ FUNC_ENTER_NOAPI(NULL) @@ -1667,6 +1679,7 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id) HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "can't get minimum raw data fraction of page buffer") } /* end if */ + /* * Read or write the file superblock, depending on whether the file is * empty or not. @@ -1693,6 +1706,9 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id) */ if(H5G_mkroot(file, TRUE) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to create/open root group") + + file_create = TRUE; + } /* end if */ else if (1 == shared->nrefs) { /* Read the superblock if it hasn't been read before. */ @@ -1707,8 +1723,19 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id) /* Open the root group */ if(H5G_mkroot(file, FALSE) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to read root group") + } /* end if */ + if(H5F_VFD_SWMR_CONFIG(file)) { + /* Page buffering and page allocation strategy have to be enabled */ + if(!page_buf_size || !H5F_PAGED_AGGR(file)) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "file open fail with VFD SWMR writer") + if(1 == shared->nrefs && H5F_INTENT(file) & H5F_ACC_RDWR) { + if(H5F__init_vfd_swmr(file, file_create) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTSET, NULL, "file open fail with initialization for VFD SWMR writer") + } + } + /* * Decide the file close degree. If it's the first time to open the * file, set the degree to access property list value; if it's the @@ -1812,9 +1839,15 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id) ret_value = file; done: - if((NULL == ret_value) && file) + if((NULL == ret_value) && file) { + if(file->shared->root_grp && file->shared->nrefs == 1) { + if(H5AC_expunge_tag_type_metadata(file, H5G_oloc(file->shared->root_grp)->addr, H5AC_OHDR_ID, H5AC__NO_FLAGS_SET, FALSE) < 0) + HDONE_ERROR(H5E_FILE, H5E_CANTEXPUNGE, NULL, "unable to expunge root group tagged entries") + } + if(H5F__dest(file, FALSE) < 0) HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, NULL, "problems closing file") + } FUNC_LEAVE_NOAPI(ret_value) } /* end H5F_open() */ @@ -3685,3 +3718,173 @@ done: FUNC_LEAVE_NOAPI_VOL(ret_value) } /* H5F__format_convert() */ + +/*------------------------------------------------------------------------- + * Function: H5F__init_vfd_swmr + * + * Purpose: Intitialize info and the metadata file for VFD SWMR writer. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5F__init_vfd_swmr(H5F_t *f, hbool_t file_create) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Initialize info */ + if(H5F__init_vfd_swmr_info(f) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "error in initializing info for VFD SWMR writer") + + /* Initialize the metadata file */ + if(H5F__init_vfd_swmr_md(f, file_create) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "error in creating metadata file for VFD SWMR writer") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5F__init_vfd_swmr() */ + + +/*------------------------------------------------------------------------- + * Function: H5F__init_vfd_swmr_info + * + * Purpose: Initialize globals and the corresponding fields in f + * for VFD SWMR writer: + * --set vfd_swmr_g to TRUE + * --set vfd_swmr_writer_g to TRUE + * --set tick_num_g to 0 + * --set end_of_tick_g to the current time + tick length + * --set vfd_swmr_file_g to f->shared + * + * Return: Success: SUCCEED + * Failure: FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5F__init_vfd_swmr_info(H5F_t *f) +{ + struct timespec tmp_end_of_tick; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + HDassert(f->shared->vfd_swmr_config.vfd_swmr_writer); + + vfd_swmr_g = f->shared->vfd_swmr = TRUE; + vfd_swmr_writer_g = f->shared->vfd_swmr_writer = TRUE; + tick_num_g = f->shared->tick_num = 0; + + /* Get current time */ + if(HDclock_gettime(CLOCK_MONOTONIC, &tmp_end_of_tick) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get time via clock_gettime") + + /* Increment by tick length */ + tmp_end_of_tick.tv_nsec += f->shared->vfd_swmr_config.tick_len * 100000000; + tmp_end_of_tick.tv_sec += tmp_end_of_tick.tv_nsec / 1000000000; + tmp_end_of_tick.tv_nsec = tmp_end_of_tick.tv_nsec % 1000000000; + HDmemcpy(&end_of_tick_g, &tmp_end_of_tick, sizeof(struct timespec)); + HDmemcpy(&f->shared->end_of_tick, &tmp_end_of_tick, sizeof(struct timespec)); + + vfd_swmr_file_g = f->shared; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5F__init_vfd_swmr_info() */ + + +/*------------------------------------------------------------------------- + * Function: H5F__init_vfd_swmr_md + * + * Purpose: Open the metadata file for VFD SMWR and allocate md_pages_reserved + * in the file. + * If not creating a new file, write header and an empty index + * to the file. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5F__init_vfd_swmr_md(H5F_t *f, hbool_t file_create) +{ + uint8_t image[H5FD_MD_HEADER_SIZE]; /* Buffer for element data */ + uint8_t image_empty_idx[H5FD_MD_INDEX_SIZE(0)]; /* Buffer for element data */ + uint8_t *p = NULL; /* Pointer to buffer */ + uint32_t metadata_chksum; /* Computed metadata checksum value */ + int fd; /* File descriptor */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Open the metadata file */ + if((fd = HDopen(f->shared->vfd_swmr_config.md_file_path, O_CREAT|O_RDWR, H5_POSIX_CREATE_MODE_RW)) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "unable to open metadata file") + + /* Set the file to md_pages_reserved */ + if(HDftruncate(fd, (HDoff_t)f->shared->vfd_swmr_config.md_pages_reserved * f->shared->fs_page_size) < 0) + HGOTO_ERROR(H5E_FILE, H5E_SEEKERROR, FAIL, "unable to extend file properly") + + if(!file_create) { + /* + * Encode metadata file header + */ + p = &image[0]; + + /* Magic for header */ + HDmemcpy(p, H5FD_MD_HEADER_MAGIC, (size_t)H5_SIZEOF_MAGIC); + p += H5_SIZEOF_MAGIC; + + UINT32ENCODE(p, f->shared->fs_page_size); + UINT64ENCODE(p, f->shared->tick_num); + UINT64ENCODE(p, H5FD_MD_HEADER_SIZE); + UINT64ENCODE(p, H5FD_MD_INDEX_SIZE(0)); + + metadata_chksum = H5_checksum_metadata((uint8_t *)p, (size_t)(p - &image[0]), 0); + + /* Checksum for header */ + UINT32ENCODE(p, metadata_chksum); + + /* Sanity checks */ + HDassert((size_t)(p - &image[0] == H5FD_MD_HEADER_SIZE)); + + /* Write header to the metadata file */ + if(HDwrite(fd, &image[0], H5FD_MD_HEADER_SIZE) != H5FD_MD_HEADER_SIZE) + HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "error in writing header to metadata file") + + /* + * Encode metadata file index + */ + p = &image_empty_idx[0]; + + /* Magic for index */ + HDmemcpy(p, H5FD_MD_INDEX_MAGIC, (size_t)H5_SIZEOF_MAGIC); + p += H5_SIZEOF_MAGIC; + + UINT64ENCODE(p, f->shared->tick_num); + + /* No entry in index */ + UINT32ENCODE(p, 0); + + metadata_chksum = H5_checksum_metadata((uint8_t *)p, (size_t)(p - &image_empty_idx[0]), 0); + + /* Checksum for index */ + UINT32ENCODE(p, metadata_chksum); + + /* sanity checks */ + HDassert((size_t)(p - &image_empty_idx[0] == H5FD_MD_INDEX_SIZE(0))); + + /* Write index to the metadata file */ + if(HDwrite(fd, &image_empty_idx[0], H5FD_MD_INDEX_SIZE(0)) != H5FD_MD_INDEX_SIZE(0)) + HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "error in writing index to metadata file") + } + f->shared->vfd_swmr_md_fd = fd; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5F__init_vfd_swmr_md() */ diff --git a/src/H5Fpkg.h b/src/H5Fpkg.h index 2ab41de..19c49fb 100644 --- a/src/H5Fpkg.h +++ b/src/H5Fpkg.h @@ -353,6 +353,15 @@ struct H5F_file_t { /* Object flush info */ H5F_object_flush_t object_flush; /* Information for object flush callback */ + + /* VFD SWMR configuration info */ + H5F_vfd_swmr_config_t vfd_swmr_config; /* Copy of the VFD SWMR configuration from the + FAPL used to open the file */ + hbool_t vfd_swmr; /* The file is opened with VFD SWMR configured or not*/ + hbool_t vfd_swmr_writer; /* This is the VFD SWMR writer or not */ + uint64_t tick_num; /* Number of the current tick */ + struct timespec end_of_tick; /* End time of the current tick */ + int vfd_swmr_md_fd; /* POSIX: file descriptor of the metadata file */ }; /* diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h index 979ba7d..9c7ea9e 100644 --- a/src/H5Fprivate.h +++ b/src/H5Fprivate.h @@ -331,6 +331,7 @@ typedef struct H5F_t H5F_t; #define H5F_POINT_OF_NO_RETURN(F) ((F)->shared->fs.point_of_no_return) #define H5F_FIRST_ALLOC_DEALLOC(F) ((F)->shared->first_alloc_dealloc) #define H5F_EOA_PRE_FSM_FSALLOC(F) ((F)->shared->eoa_pre_fsm_fsalloc) +#define H5F_USE_VFD_SWMR(F) ((F)->shared->vfd_swmr) #else /* H5F_MODULE */ #define H5F_LOW_BOUND(F) (H5F_get_low_bound(F)) #define H5F_HIGH_BOUND(F) (H5F_get_high_bound(F)) @@ -388,6 +389,7 @@ typedef struct H5F_t H5F_t; #define H5F_POINT_OF_NO_RETURN(F) (H5F_get_point_of_no_return(F)) #define H5F_FIRST_ALLOC_DEALLOC(F) (H5F_get_first_alloc_dealloc(F)) #define H5F_EOA_PRE_FSM_FSALLOC(F) (H5F_get_eoa_pre_fsm_fsalloc(F)) +#define H5F_USE_VFD_SWMR(F) (H5F_use_vfd_swmr(F)) #endif /* H5F_MODULE */ @@ -508,6 +510,20 @@ typedef struct H5F_t H5F_t; #define H5F_ACS_PAGE_BUFFER_MIN_META_PERC_NAME "page_buffer_min_meta_perc" /* the min metadata percentage for the page buffer cache */ #define H5F_ACS_PAGE_BUFFER_MIN_RAW_PERC_NAME "page_buffer_min_raw_perc" /* the min raw data percentage for the page buffer cache */ +/* Default configuration for VFD SWMR: not configured */ +#define H5F_ACS_VFD_SWMR_CONFIG_NAME "vfd_swmr_config" /* VFD SWMR configuration */ +#define H5F__DEFAULT_VFD_SWMR_CONFIG \ +{ \ + /* int32_t version = */ 0, \ + /* int32_t tick_len = */ 0, \ + /* int32_t max_lag = */ 0, \ + /* hbool_t vfd_swmr_writer = */ FALSE, \ + /* hbool_t flush_raw_data = */ FALSE, \ + /* int32_t md_pages_reserved = */ 0, \ + /* char md_file_path[] = */ "", \ + /* char log_file_path[] = */ "" \ +} + /* ======================== File Mount properties ====================*/ #define H5F_MNT_SYM_LOCAL_NAME "local" /* Whether absolute symlinks local to file. */ @@ -575,6 +591,9 @@ typedef struct H5F_t H5F_t; /* Check for file using paged aggregation */ #define H5F_PAGED_AGGR(F) (F->shared->fs_strategy == H5F_FSPACE_STRATEGY_PAGE && F->shared->fs_page_size) +/* Check for file configured with VFD SWMR */ +#define H5F_VFD_SWMR_CONFIG(F) (F->shared->vfd_swmr_config.version >= H5F__CURR_VFD_SWMR_CONFIG_VERSION) + /* Metadata read attempt values */ #define H5F_METADATA_READ_ATTEMPTS 1 /* Default # of read attempts for non-SWMR access */ #define H5F_SWMR_METADATA_READ_ATTEMPTS 100 /* Default # of read attempts for SWMR access */ @@ -651,6 +670,8 @@ struct H5P_genplist_t; /* Main file structures */ typedef struct H5F_file_t H5F_file_t; +extern H5F_file_t *vfd_swmr_file_g; + /* Block aggregation structure */ typedef struct H5F_blk_aggr_t H5F_blk_aggr_t; @@ -741,6 +762,7 @@ H5_DLL hsize_t H5F_get_pgend_meta_thres(const H5F_t *f); H5_DLL hbool_t H5F_get_point_of_no_return(const H5F_t *f); H5_DLL hbool_t H5F_get_first_alloc_dealloc(const H5F_t *f); H5_DLL haddr_t H5F_get_eoa_pre_fsm_fsalloc(const H5F_t *f); +H5_DLL hbool_t H5F_use_vfd_swmr(const H5F_t *f); /* Functions than retrieve values set/cached from the superblock/FCPL */ H5_DLL haddr_t H5F_get_base_addr(const H5F_t *f); diff --git a/src/H5Fpublic.h b/src/H5Fpublic.h index 73c59f5..a685d25 100644 --- a/src/H5Fpublic.h +++ b/src/H5Fpublic.h @@ -217,6 +217,19 @@ typedef struct 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); +/* VFD SWMR configuration data used by H5Pset/get_vfd_swmr_config */ +#define H5F__CURR_VFD_SWMR_CONFIG_VERSION 1 +#define H5F__MAX_VFD_SWMR_FILE_NAME_LEN 1024 +typedef struct H5F_vfd_swmr_config_t { + int32_t version; + int32_t tick_len; + int32_t max_lag; + hbool_t vfd_swmr_writer; + hbool_t flush_raw_data; + int32_t md_pages_reserved; + char md_file_path[H5F__MAX_VFD_SWMR_FILE_NAME_LEN + 1]; + char log_file_path[H5F__MAX_VFD_SWMR_FILE_NAME_LEN + 1]; +} H5F_vfd_swmr_config_t; #ifdef __cplusplus extern "C" { @@ -274,6 +287,9 @@ H5_DLL herr_t H5Fget_page_buffering_stats(hid_t file_id, unsigned accesses[2], unsigned hits[2], unsigned misses[2], unsigned evictions[2], unsigned bypasses[2]); H5_DLL herr_t H5Fget_mdc_image_info(hid_t file_id, haddr_t *image_addr, hsize_t *image_size); +/* VFD SWMR */ +H5_DLL herr_t H5Fvfd_swmr_end_tick(hid_t file_id); + #ifdef H5_HAVE_PARALLEL H5_DLL herr_t H5Fset_mpi_atomicity(hid_t file_id, hbool_t flag); H5_DLL herr_t H5Fget_mpi_atomicity(hid_t file_id, hbool_t *flag); diff --git a/src/H5Fquery.c b/src/H5Fquery.c index be24072..41d885a 100644 --- a/src/H5Fquery.c +++ b/src/H5Fquery.c @@ -1215,3 +1215,26 @@ H5F_get_eoa_pre_fsm_fsalloc(const H5F_t *f) FUNC_LEAVE_NOAPI(f->shared->eoa_pre_fsm_fsalloc) } /* end H5F_get_eoa_pre_fsm_fsalloc() */ + +/*------------------------------------------------------------------------- + * Function: H5F_use_vfd_swmr + * + * Purpose: Quick and dirty routine to determine if VFD SWMR is + * enabled for this file. + * (Mainly added to stop non-file routines from poking about in the + * H5F_t data structure) + * + * Return: TRUE/FALSE on success/abort on failure (shouldn't fail) + *------------------------------------------------------------------------- + */ +hbool_t +H5F_use_vfd_swmr(const H5F_t *f) +{ + /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + HDassert(f); + HDassert(f->shared); + + FUNC_LEAVE_NOAPI(f->shared->vfd_swmr) +} /* end H5F_use_vfd_swmr() */ diff --git a/src/H5Pfapl.c b/src/H5Pfapl.c index 7ba9c11..a0291e6 100644 --- a/src/H5Pfapl.c +++ b/src/H5Pfapl.c @@ -259,6 +259,11 @@ #define H5F_ACS_PAGE_BUFFER_MIN_RAW_PERC_ENC H5P__encode_unsigned #define H5F_ACS_PAGE_BUFFER_MIN_RAW_PERC_DEC H5P__decode_unsigned +/* Definitions for the VFD SWMR configuration */ +#define H5F_ACS_VFD_SWMR_CONFIG_SIZE sizeof(H5F_vfd_swmr_config_t) +#define H5F_ACS_VFD_SWMR_CONFIG_DEF H5F__DEFAULT_VFD_SWMR_CONFIG +#define H5F_ACS_VFD_SWMR_CONFIG_ENC H5P__facc_vfd_swmr_config_enc +#define H5F_ACS_VFD_SWMR_CONFIG_DEC H5P__facc_vfd_swmr_config_dec /******************/ /* Local Typedefs */ @@ -306,6 +311,8 @@ static herr_t H5P__facc_multi_type_enc(const void *value, void **_pp, size_t *si static herr_t H5P__facc_multi_type_dec(const void **_pp, void *value); static herr_t H5P__facc_libver_type_enc(const void *value, void **_pp, size_t *size); static herr_t H5P__facc_libver_type_dec(const void **_pp, void *value); +static herr_t H5P__facc_vfd_swmr_config_enc(const void *value, void **_pp, size_t *size); +static herr_t H5P__facc_vfd_swmr_config_dec(const void **_pp, void *value); /* Metadata cache log location property callbacks */ static herr_t H5P_facc_mdc_log_location_enc(const void *value, void **_pp, size_t *size); @@ -398,6 +405,8 @@ static const size_t H5F_def_page_buf_size_g = H5F_ACS_PAGE_BUFFER_SIZE_DEF; static const unsigned H5F_def_page_buf_min_meta_perc_g = H5F_ACS_PAGE_BUFFER_MIN_META_PERC_DEF; /* Default page buffer minimum metadata size */ static const unsigned H5F_def_page_buf_min_raw_perc_g = H5F_ACS_PAGE_BUFFER_MIN_RAW_PERC_DEF; /* Default page buffer mininum raw data size */ +static const H5F_vfd_swmr_config_t *H5F_def_vfd_swmr_config_g = H5F_ACS_VFD_SWMR_CONFIG_DEF; /* Default vfd swmr configuration */ + /*------------------------------------------------------------------------- * Function: H5P__facc_reg_prop @@ -644,6 +653,12 @@ 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 the default VFD SWMR configuration */ + if(H5P_register_real(pclass, H5F_ACS_VFD_SWMR_CONFIG_NAME, H5F_ACS_VFD_SWMR_CONFIG_SIZE, &H5F_def_vfd_swmr_config_g, + NULL, NULL, NULL, H5F_ACS_VFD_SWMR_CONFIG_ENC, H5F_ACS_VFD_SWMR_CONFIG_DEC, + 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() */ @@ -3643,6 +3658,7 @@ H5P__facc_cache_config_dec(const void **_pp, void *_value) enc_size = *(*pp)++; HDassert(enc_size < 256); UINT64DECODE_VAR(*pp, enc_value, enc_size); + config->max_size = (size_t)enc_value; enc_size = *(*pp)++; @@ -3927,6 +3943,105 @@ H5P__facc_libver_type_dec(const void **_pp, void *_value) /*------------------------------------------------------------------------- + * Function: H5P__facc_vfd_swmr_config_enc + * + * Purpose: Callback routine which is called whenever the VFD SWMR config + * property in the file access property list is encoded. + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Vailin Choi; July 2018 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5P__facc_vfd_swmr_config_enc(const void *value, void **_pp, size_t *size) +{ + const H5F_vfd_swmr_config_t *config = (const H5F_vfd_swmr_config_t *)value; /* Create local aliases for values */ + uint8_t **pp = (uint8_t **)_pp; + + FUNC_ENTER_STATIC_NOERR + + /* Sanity check */ + HDassert(value); + HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t)); + + if(NULL != *pp) { + + /* int */ + INT32ENCODE(*pp, (int32_t)config->version); + INT32ENCODE(*pp, (int32_t)config->tick_len); + INT32ENCODE(*pp, (int32_t)config->max_lag); + H5_ENCODE_UNSIGNED(*pp, config->vfd_swmr_writer); + H5_ENCODE_UNSIGNED(*pp, config->flush_raw_data); + INT32ENCODE(*pp, (int32_t)config->md_pages_reserved); + HDmemcpy(*pp, (const uint8_t *)(config->md_file_path), (size_t)(H5F__MAX_VFD_SWMR_FILE_NAME_LEN + 1)); + *pp += H5F__MAX_VFD_SWMR_FILE_NAME_LEN + 1; + HDmemcpy(*pp, (const uint8_t *)(config->log_file_path), (size_t)(H5F__MAX_VFD_SWMR_FILE_NAME_LEN + 1)); + *pp += H5F__MAX_VFD_SWMR_FILE_NAME_LEN + 1; + + } /* end if */ + + /* Compute encoded size */ + *size += ( (4 * sizeof(int32_t)) + sizeof(unsigned) + + (2 * (H5F__MAX_VFD_SWMR_FILE_NAME_LEN + 1)) ); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5P__facc_vfd_swmr_config_enc() */ + + +/*------------------------------------------------------------------------- + * Function: H5P__facc_vfd_swmr_config_dec + * + * Purpose: Callback routine which is called whenever the VFD SWMR + * config property in the file access property list is decoded. + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Vailin Choi; July 2018 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5P__facc_vfd_swmr_config_dec(const void **_pp, void *_value) +{ + H5F_vfd_swmr_config_t *config = (H5F_vfd_swmr_config_t *)_value; + const uint8_t **pp = (const uint8_t **)_pp; + + FUNC_ENTER_STATIC_NOERR + + /* Sanity checks */ + HDassert(pp); + HDassert(*pp); + HDassert(config); + HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t)); + + /* Set property to default value */ + HDmemcpy(config, &H5F_def_vfd_swmr_config_g, sizeof(H5F_vfd_swmr_config_t)); + + /* int */ + INT32DECODE(*pp, config->version); + INT32DECODE(*pp, config->tick_len); + INT32DECODE(*pp, config->max_lag); + + H5_DECODE_UNSIGNED(*pp, config->vfd_swmr_writer); + H5_DECODE_UNSIGNED(*pp, config->flush_raw_data); + + /* int */ + INT32DECODE(*pp, config->md_pages_reserved); + + HDstrcpy(config->md_file_path, (const char *)(*pp)); + *pp += H5F__MAX_VFD_SWMR_FILE_NAME_LEN + 1; + + HDstrcpy(config->log_file_path, (const char *)(*pp)); + *pp += H5F__MAX_VFD_SWMR_FILE_NAME_LEN + 1; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5P__facc_vfd_swmr_config_dec() */ + +/*------------------------------------------------------------------------- * Function: H5Pset_core_write_tracking * * Purpose: Enables/disables core VFD write tracking and page @@ -4939,3 +5054,101 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Pget_page_buffer_size() */ +/*------------------------------------------------------------------------- + * Function: H5Pset_vfd_swmr_config + * + * Purpose: Set VFD SWMR configuration in the target FAPL. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Vailin Choi; July 2018 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Pset_vfd_swmr_config(hid_t plist_id, H5F_vfd_swmr_config_t *config_ptr) +{ + H5P_genplist_t *plist; /* Property list pointer */ + size_t name_len; + herr_t ret_value = SUCCEED; /* return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE2("e", "i*x", plist_id, config_ptr); + + /* 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") + + /* Validate the input configuration */ + + /* Check args */ + if(config_ptr == NULL) + HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "NULL config_ptr on entry") + + /* This field must always be set to a known version */ + if(config_ptr->version != H5F__CURR_VFD_SWMR_CONFIG_VERSION) + HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "Unknown config version") + + /* This field must be >= 0 */ + if(config_ptr->tick_len < 0) + HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "tick_len must be greater than 0") + + /* This field must be at least 3 */ + if(config_ptr->max_lag < 3 ) + HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "max_lag must be at least 3") + + /* This field must be >= 1 */ + if(config_ptr->md_pages_reserved < 1 ) + HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "md_pages_reserved must be at least 1") + + /* Must provide the path for the metadata file */ + name_len = HDstrlen(config_ptr->md_file_path); + if(name_len == 0) + HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "md_file_path is empty") + else if(name_len > H5F__MAX_VFD_SWMR_FILE_NAME_LEN) + HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "md_file_path is too long") + + /* Set the modified config */ + if(H5P_set(plist, H5F_ACS_VFD_SWMR_CONFIG_NAME, config_ptr) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set metadata cache initial config") + +done: + FUNC_LEAVE_API(ret_value) +} /* H5Pset_vfd_swmr_config() */ + + +/*------------------------------------------------------------------------- + * Function: H5Pget_vfd_swmr_config + * + * Purpose: Retrieve the VFD SWMR configuration from the target FAPL. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Vailin Choi; July 2018 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Pget_vfd_swmr_config(hid_t plist_id, H5F_vfd_swmr_config_t *config_ptr) +{ + H5P_genplist_t *plist; /* Property list pointer */ + herr_t ret_value = SUCCEED; /* return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE2("e", "i*x", plist_id, config_ptr); + + /* 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") + + /* Validate the config_ptr */ + if(config_ptr == NULL) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL config_ptr on entry.") + + /* Get the current VFD SWMR configuration */ + if(H5P_get(plist, H5F_ACS_VFD_SWMR_CONFIG_NAME, config_ptr) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get VFD SWMR config") + +done: + FUNC_LEAVE_API(ret_value) +} /* H5Pget_vfd_swmr_config() */ diff --git a/src/H5Ppublic.h b/src/H5Ppublic.h index c5596e5..3abb3fd 100644 --- a/src/H5Ppublic.h +++ b/src/H5Ppublic.h @@ -370,6 +370,10 @@ H5_DLL herr_t H5Pset_mdc_image_config(hid_t plist_id, H5AC_cache_image_config_t H5_DLL herr_t H5Pget_mdc_image_config(hid_t plist_id, H5AC_cache_image_config_t *config_ptr /*out*/); H5_DLL herr_t H5Pset_page_buffer_size(hid_t plist_id, size_t buf_size, unsigned min_meta_per, unsigned min_raw_per); H5_DLL herr_t H5Pget_page_buffer_size(hid_t plist_id, size_t *buf_size, unsigned *min_meta_per, unsigned *min_raw_per); +/* VFD SWMR configuration */ +H5_DLL herr_t H5Pset_vfd_swmr_config(hid_t plist_id, H5F_vfd_swmr_config_t *config_ptr); +H5_DLL herr_t H5Pget_vfd_swmr_config(hid_t plist_id, H5F_vfd_swmr_config_t *config_ptr); + /* Dataset creation property list (DCPL) routines */ H5_DLL herr_t H5Pset_layout(hid_t plist_id, H5D_layout_t layout); diff --git a/src/H5private.h b/src/H5private.h index 8974e46..6fa81a0 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -982,6 +982,9 @@ typedef off_t h5_stat_size_t; #ifndef HDgettimeofday #define HDgettimeofday(S,P) gettimeofday(S,P) #endif /* HDgettimeofday */ +#ifndef HDclock_gettime + #define HDclock_gettime(C,T) clock_gettime(C,T) +#endif /* HDclock_gettime */ #ifndef HDgetuid #define HDgetuid() getuid() #endif /* HDgetuid */ @@ -1942,6 +1945,12 @@ extern hbool_t H5_libterm_g; /* Is the library being shutdown? */ #define H5_INIT_GLOBAL (H5_libinit_g) #define H5_TERM_GLOBAL (H5_libterm_g) +/* Temporary Gobals for VFD SWMR */ +extern hbool_t vfd_swmr_g; +extern hbool_t vfd_swmr_writer_g; +extern uint64_t tick_num_g; +extern struct timespec end_of_tick_g; + #endif /* H5_HAVE_THREADSAFE */ #ifdef H5_HAVE_CODESTACK @@ -2058,12 +2067,32 @@ H5_DLL herr_t H5CX_pop(void); \ BEGIN_MPE_LOG +#define VFD_SWMR_TEST_FOR_END_OF_TICK(swmr_reader_exit, err) \ + /* Initialize the library */ \ + if(vfd_swmr_g) { \ + struct timespec curr_time; \ + if(HDclock_gettime(CLOCK_MONOTONIC, &curr_time) < 0) \ + HGOTO_ERROR(H5E_FUNC, H5E_CANTGET, err, "can't get time via clock_gettime") \ + if( (curr_time.tv_sec >= end_of_tick_g.tv_sec) && \ + (curr_time.tv_nsec >= end_of_tick_g.tv_nsec) ) { \ + if(vfd_swmr_writer_g) { \ + if(H5FD_writer_end_of_tick() < 0) \ + HGOTO_ERROR(H5E_FUNC, H5E_CANTSET, err, "end of tick error for VFD SWMR writer") \ + } \ + else if(!swmr_reader_exit) { \ + if(H5FD_reader_end_of_tick() < 0) \ + HGOTO_ERROR(H5E_FUNC, H5E_CANTSET, err, "end of tick error for VFD SWMR reader") \ + } \ + } \ + } + /* Use this macro for all "normal" API functions */ #define FUNC_ENTER_API(err) {{ \ FUNC_ENTER_API_COMMON \ FUNC_ENTER_API_INIT(err); \ /* Clear thread error stack entering public functions */ \ H5E_clear_stack(NULL); \ + VFD_SWMR_TEST_FOR_END_OF_TICK(FALSE, err); \ { /* @@ -2298,6 +2327,7 @@ H5_DLL herr_t H5CX_pop(void); H5TRACE_RETURN(ret_value); #define FUNC_LEAVE_API(ret_value) \ + VFD_SWMR_TEST_FOR_END_OF_TICK(!vfd_swmr_writer_g, ret_value); \ FUNC_LEAVE_API_COMMON(ret_value); \ (void)H5CX_pop(); \ H5_POP_FUNC \ diff --git a/test/Makefile.am b/test/Makefile.am index b9aa3fb..0a4823f 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -54,7 +54,7 @@ check_SCRIPTS = $(TEST_SCRIPT) TEST_PROG= testhdf5 \ cache cache_api cache_image cache_tagging lheap ohdr stab gheap \ evict_on_close farray earray btree2 fheap \ - pool accum hyperslab istore bittests dt_arith page_buffer \ + pool accum hyperslab istore bittests dt_arith page_buffer vfd_swmr\ dtypes dsets cmpd_dset filter_fail extend direct_chunk external efc \ objcopy links unlink twriteorder big mtime fillval mount \ flush1 flush2 app_ref enum set_extent ttsafe enc_dec_plist \ diff --git a/test/vfd_swmr.c b/test/vfd_swmr.c new file mode 100644 index 0000000..8b6e356 --- /dev/null +++ b/test/vfd_swmr.c @@ -0,0 +1,695 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*********************************************************** +* +* Test program: +* +* Tests the VFD SWMR Feature. +* +*************************************************************/ + +#include "h5test.h" + +/* + * This file needs to access private information from the H5F package. + */ +#define H5MF_FRIEND /*suppress error about including H5MFpkg */ +#include "H5MFpkg.h" + +#define H5F_FRIEND /*suppress error about including H5Fpkg */ +#define H5F_TESTING +#include "H5Fpkg.h" + +#include "H5CXprivate.h" /* API Contexts */ +#include "H5Iprivate.h" +#include "H5PBprivate.h" + + +#define FILENAME_LEN 1024 +#define NUM_DSETS 5 +#define NX 100 +#define NY 50 + +static unsigned open_file(char *filename, hid_t fapl, hsize_t page_size, size_t page_buffer_size); + +/* test routines for VFD SWMR */ +static unsigned test_fapl(); +static unsigned test_file_end_tick(); +static unsigned test_file_fapl(); + +const char *FILENAME[] = { + "filepaged", + NULL +}; + + +/*********************/ +/*********************/ + + +/*------------------------------------------------------------------------- + * Function: test_fapl() + * + * Purpose: A) Verify that invalid info set in the fapl fails + * as expected (see the RFC for VFD SWMR): + * --version: should be a known version + * --tick_len: should be >= 0 + * --max_lag: should be >= 3 + * --md_pages_reserved: should be >= 1 + * --md_file_path: should contain the metadata file path (POSIX) + * B) Verify that info set in the fapl is retrieved correctly. + * + * Return: 0 if test is sucessful + * 1 if test fails + * + * Programmer: Vailin Choi; July 2018 + * + *------------------------------------------------------------------------- + */ +static unsigned +test_fapl() +{ + hid_t fapl = -1; /* File access property list */ + H5F_vfd_swmr_config_t *my_config = NULL; /* Configuration for VFD SWMR */ + herr_t ret; /* Return value */ + + TESTING("Configure VFD SWMR with fapl"); + + /* Allocate memory for the configuration structure */ + if((my_config = (H5F_vfd_swmr_config_t *)HDmalloc(sizeof(H5F_vfd_swmr_config_t))) == NULL) + FAIL_STACK_ERROR; + HDmemset(my_config, 0, sizeof(H5F_vfd_swmr_config_t)); + + /* Get a copy of the file access property list */ + if((fapl = H5Pcreate(H5P_FILE_ACCESS)) < 0) + TEST_ERROR; + + /* Should get invalid VFD SWMR config info */ + if(H5Pget_vfd_swmr_config(fapl, my_config) < 0) + TEST_ERROR; + + /* Verify that the version is incorrect */ + if(my_config->version >= H5F__CURR_VFD_SWMR_CONFIG_VERSION) + TEST_ERROR; + + /* Should fail: version is 0 */ + H5E_BEGIN_TRY { + ret = H5Pset_vfd_swmr_config(fapl, my_config); + } H5E_END_TRY; + if(ret >= 0) + TEST_ERROR; + + /* Set valid version */ + my_config->version = H5F__CURR_VFD_SWMR_CONFIG_VERSION; + /* Should fail: tick_len is -1 */ + my_config->tick_len = -1; + H5E_BEGIN_TRY { + ret = H5Pset_vfd_swmr_config(fapl, my_config); + } H5E_END_TRY; + if(ret >= 0) + TEST_ERROR; + + /* Set valid tick_len */ + my_config->tick_len = 3; + /* Should fail: max_lag is 2 */ + my_config->max_lag = 2; + H5E_BEGIN_TRY { + ret = H5Pset_vfd_swmr_config(fapl, my_config); + } H5E_END_TRY; + if(ret >= 0) + TEST_ERROR; + + /* Set valid max_lag */ + my_config->max_lag = 3; + /* Should fail: md_pages_reserved is 0 */ + H5E_BEGIN_TRY { + ret = H5Pset_vfd_swmr_config(fapl, my_config); + } H5E_END_TRY; + if(ret >= 0) + TEST_ERROR; + + /* Set valid md_pages_reserved */ + my_config->md_pages_reserved = 2; + /* Should fail: empty md_file_path */ + H5E_BEGIN_TRY { + ret = H5Pset_vfd_swmr_config(fapl, my_config); + } H5E_END_TRY; + if(ret >= 0) + TEST_ERROR; + + /* Set md_file_path */ + HDstrcpy(my_config->md_file_path, "my_md_file"); + + /* Should succeed in setting the configuration info */ + if(H5Pset_vfd_swmr_config(fapl, my_config) < 0) + TEST_ERROR; + + /* Clear the configuration structure */ + HDmemset(my_config, 0, sizeof(H5F_vfd_swmr_config_t)); + + /* Retrieve the configuration info just set */ + if(H5Pget_vfd_swmr_config(fapl, my_config) < 0) + TEST_ERROR; + + /* Verify the configuration info */ + if(my_config->version < H5F__CURR_VFD_SWMR_CONFIG_VERSION) + TEST_ERROR; + if(my_config->md_pages_reserved != 2) + TEST_ERROR; + if(HDstrcmp(my_config->md_file_path, "my_md_file") != 0) + TEST_ERROR; + + /* Close the file access property list */ + if(H5Pclose(fapl) < 0) + FAIL_STACK_ERROR; + + if(my_config) + HDfree(my_config); + + PASSED() + return 0; + +error: + H5E_BEGIN_TRY { + H5Pclose(fapl); + } H5E_END_TRY; + if(my_config) + HDfree(my_config); + return 1; +} /* test_fapl() */ + + +/*------------------------------------------------------------------------- + * Function: test_file_fapl() + * + * Purpose: A) Verify that page buffering and paged aggregation + * have to be enabled for a file to be configured + * with VFD SWMR. + * B) Verify the VFD SWMR configuration set in fapl + * used to create/open the file is the same as the + * configuration retrieved from the file's fapl. + * + * Return: 0 if test is sucessful + * 1 if test fails + * + * Programmer: Vailin Choi; July 2018 + * + *------------------------------------------------------------------------- + */ +static unsigned +test_file_fapl() +{ + hid_t fid = -1; /* File ID */ + hid_t fcpl = -1; /* File creation property list ID */ + hid_t fapl1 = -1; /* File access property list ID */ + hid_t fapl2 = -1; /* File access property list ID */ + hid_t file_fapl = -1; /* File access property list ID associated with the file */ + H5F_vfd_swmr_config_t *config1 = NULL; /* Configuration for VFD SWMR */ + H5F_vfd_swmr_config_t *config2 = NULL; /* Configuration for VFD SWMR */ + H5F_vfd_swmr_config_t *config3 = NULL; /* Configuration for VFD SWMR */ + herr_t ret; /* Return value */ +hid_t fid_read = -1; /* File ID for VFD SWMR reader */ +hid_t sid = -1; +hid_t did = -1; + + TESTING("VFD SWMR configuration for the file and fapl"); + + /* Should succeed without VFD SWMR configured */ + if((fid = H5Fcreate("myfile", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR; + + /* Close the file */ + if(H5Fclose(fid) < 0) + FAIL_STACK_ERROR; + + /* Allocate memory for the configuration structure */ + if((config1 = (H5F_vfd_swmr_config_t *)HDmalloc(sizeof(H5F_vfd_swmr_config_t))) == NULL) + FAIL_STACK_ERROR; + if((config2 = (H5F_vfd_swmr_config_t *)HDmalloc(sizeof(H5F_vfd_swmr_config_t))) == NULL) + FAIL_STACK_ERROR; + if((config3 = (H5F_vfd_swmr_config_t *)HDmalloc(sizeof(H5F_vfd_swmr_config_t))) == NULL) + FAIL_STACK_ERROR; + HDmemset(config1, 0, sizeof(H5F_vfd_swmr_config_t)); + HDmemset(config2, 0, sizeof(H5F_vfd_swmr_config_t)); + HDmemset(config3, 0, sizeof(H5F_vfd_swmr_config_t)); + + /* Create a copy of the file access property list */ + if((fapl1 = H5Pcreate(H5P_FILE_ACCESS)) < 0) + TEST_ERROR; + + config1->version = H5F__CURR_VFD_SWMR_CONFIG_VERSION; + config1->tick_len = 4; + config1->max_lag = 6; + config1->vfd_swmr_writer = TRUE; + config1->md_pages_reserved = 2; + HDstrcpy(config1->md_file_path, "my_md_file"); + + /* Should succeed in setting the VFD SWMR configuration */ + if(H5Pset_vfd_swmr_config(fapl1, config1) < 0) + TEST_ERROR; + + /* Should fail to configure VFD SWMR: page buffering and paged aggregation not enabled */ + H5E_BEGIN_TRY { + fid = H5Fcreate("myfile", H5F_ACC_TRUNC, H5P_DEFAULT, fapl1); + } H5E_END_TRY; + if(fid >= 0) + TEST_ERROR; + + /* Create a copy of file creation property list */ + if((fcpl = H5Pcreate(H5P_FILE_CREATE)) < 0) + FAIL_STACK_ERROR + + /* Set file space strategy */ + if(H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_PAGE, FALSE, (hsize_t)1) < 0) + FAIL_STACK_ERROR; + + /* Should fail to configure VFD SWMR: no page buffering */ + H5E_BEGIN_TRY { + fid = H5Fcreate("myfile", H5F_ACC_TRUNC, fcpl, fapl1); + } H5E_END_TRY; + if(fid >= 0) + TEST_ERROR; + + /* Enable page buffering */ + if(H5Pset_page_buffer_size(fapl1, 4096, 0, 0) < 0) + FAIL_STACK_ERROR; + + /* Should succeed to configure VFD SWMR: paged aggregation and page buffering enabled */ + if((fid = H5Fcreate("myfile", H5F_ACC_TRUNC, fcpl, fapl1)) < 0) + TEST_ERROR; + + /* Get the file's file access property list */ + if((file_fapl = H5Fget_access_plist(fid)) < 0) + FAIL_STACK_ERROR; + + /* Retrieve the VFD SWMR configuration from file_fapl */ + if(H5Pget_vfd_swmr_config(file_fapl, config2) < 0) + TEST_ERROR; + + /* Verify the retrieved info is the same as config1 */ + if(HDmemcmp(config1, config2, sizeof(H5F_vfd_swmr_config_t)) != 0) + TEST_ERROR; + + if((fid_read = H5Fopen("myfile", H5F_ACC_RDONLY, fapl1)) < 0) + TEST_ERROR; + if((sid = H5Screate(H5S_SCALAR)) < 0) + TEST_ERROR; + if((did = H5Dcreate2(fid_read, "dset", H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR; + if(H5Dclose(did) < 0) + FAIL_STACK_ERROR; + if(H5Fclose(fid_read) < 0) + FAIL_STACK_ERROR; + + /* Closing */ + if(H5Fclose(fid) < 0) + FAIL_STACK_ERROR; + if(H5Pclose(file_fapl) < 0) + FAIL_STACK_ERROR; + + /* Should succeed: VFD SWMR writer */ + if((fid = H5Fopen("myfile", H5F_ACC_RDWR, fapl1)) < 0) + TEST_ERROR; + + /* Get the file's file access property list */ + if((file_fapl = H5Fget_access_plist(fid)) < 0) + FAIL_STACK_ERROR; + + /* Clear info in config2 */ + HDmemset(config2, 0, sizeof(H5F_vfd_swmr_config_t)); + + /* Retrieve the VFD SWMR configuration from file_fapl */ + if(H5Pget_vfd_swmr_config(file_fapl, config2) < 0) + TEST_ERROR; + + /* Verify the retrieved info is the same as config1 */ + if(HDmemcmp(config1, config2, sizeof(H5F_vfd_swmr_config_t)) != 0) + TEST_ERROR; + + /* Closing */ + if(H5Fclose(fid) < 0) + FAIL_STACK_ERROR; + if(H5Pclose(file_fapl) < 0) + FAIL_STACK_ERROR; + + /* Should succeed: VFD SWMR reader */ + if((fid = H5Fopen("myfile", H5F_ACC_RDONLY, fapl1)) < 0) + TEST_ERROR; + + /* Get the file's file access property list */ + if((file_fapl = H5Fget_access_plist(fid)) < 0) + FAIL_STACK_ERROR; + + /* Clear info in config2 */ + HDmemset(config2, 0, sizeof(H5F_vfd_swmr_config_t)); + + /* Retrieve the VFD SWMR configuration from file_fapl */ + if(H5Pget_vfd_swmr_config(file_fapl, config2) < 0) + TEST_ERROR; + + /* Verify the retrieved info is the same as config1 */ + if(HDmemcmp(config1, config2, sizeof(H5F_vfd_swmr_config_t)) != 0) + TEST_ERROR; + + /* Closing */ + if(H5Fclose(fid) < 0) + FAIL_STACK_ERROR; + if(H5Pclose(file_fapl) < 0) + FAIL_STACK_ERROR; + + /* Set a different VFD SWMR configuration */ + /* Create a copy of the file access property list */ + if((fapl2 = H5Pcreate(H5P_FILE_ACCESS)) < 0) + TEST_ERROR; + + config3->version = H5F__CURR_VFD_SWMR_CONFIG_VERSION; + config3->tick_len = 4; + config3->max_lag = 10; + config3->vfd_swmr_writer = TRUE; + config3->md_pages_reserved = 2; + HDstrcpy(config3->md_file_path, "my_md_file"); + + /* Should succeed in setting the VFD SWMR configuration */ + if(H5Pset_vfd_swmr_config(fapl2, config3) < 0) + TEST_ERROR; + + /* Enable page buffering */ + if(H5Pset_page_buffer_size(fapl2, 4096, 0, 0) < 0) + FAIL_STACK_ERROR; + + /* Should succeed: VFD SWMR writer */ + if((fid = H5Fopen("myfile", H5F_ACC_RDWR, fapl2)) < 0) + TEST_ERROR; + + /* Get the file's file access property list */ + if((file_fapl = H5Fget_access_plist(fid)) < 0) + FAIL_STACK_ERROR; + + /* Clear info in config2 */ + HDmemset(config2, 0, sizeof(H5F_vfd_swmr_config_t)); + + /* Retrieve the VFD SWMR configuration from file_fapl */ + if(H5Pget_vfd_swmr_config(file_fapl, config2) < 0) + TEST_ERROR; + + /* Verify the retrieved info is NOT the same as config1 */ + if(HDmemcmp(config1, config2, sizeof(H5F_vfd_swmr_config_t)) == 0) + TEST_ERROR; + + /* Verify the retrieved info is the same as config3 */ + if(HDmemcmp(config2, config3, sizeof(H5F_vfd_swmr_config_t)) != 0) + TEST_ERROR; + + /* Closing */ + if(H5Fclose(fid) < 0) + FAIL_STACK_ERROR; + if(H5Pclose(file_fapl) < 0) + FAIL_STACK_ERROR; + + if(H5Pclose(fapl1) < 0) + FAIL_STACK_ERROR; + if(H5Pclose(fapl2) < 0) + FAIL_STACK_ERROR; + if(H5Pclose(fcpl) < 0) + FAIL_STACK_ERROR; + if(config1) + HDfree(config1); + if(config2) + HDfree(config2); + if(config3) + HDfree(config3); + + PASSED() + return 0; + +error: + H5E_BEGIN_TRY { + H5Pclose(fapl1); + H5Pclose(fapl2); + H5Pclose(fcpl); + H5Fclose(fid); + } H5E_END_TRY; + if(config1) + HDfree(config1); + if(config2) + HDfree(config2); + if(config3) + HDfree(config3); + return 1; +} /* test_file_fapl() */ + + +/*------------------------------------------------------------------------- + * Function: test_file_end_tick() + * + * Purpose: Verify the public routine H5Fvfd_swmr_end_tick() works + * as described in the RFC for VFD SWMR. + * --routine will fail if the file is not opened with VFD SWMR + * ?? Will add more tests when end of tick processing + * is activated in this routine + * + * Return: 0 if test is sucessful + * 1 if test fails + * + * Programmer: Vailin Choi; July 2018 + * + *------------------------------------------------------------------------- + */ +static unsigned +test_file_end_tick() +{ + hid_t fid = -1; /* File ID */ + hid_t fapl = -1; /* File access property list */ + hid_t fcpl = -1; /* File creation property list */ + H5F_vfd_swmr_config_t *my_config = NULL; /* Configuration for VFD SWMR */ + herr_t ret; /* Return value */ + + TESTING("H5Fvfd_swmr_end_tick() for VFD SWMR"); + + /* Should succeed without VFD SWMR configured */ + if((fid = H5Fcreate("myfile", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR; + + /* Should fail */ + H5E_BEGIN_TRY { + ret = H5Fvfd_swmr_end_tick(fid); + } H5E_END_TRY; + if(ret >= 0) + TEST_ERROR; + + /* Close the file */ + if(H5Fclose(fid) < 0) + FAIL_STACK_ERROR; + + /* Allocate memory for the configuration structure */ + if((my_config = (H5F_vfd_swmr_config_t *)HDmalloc(sizeof(H5F_vfd_swmr_config_t))) == NULL) + FAIL_STACK_ERROR; + HDmemset(my_config, 0, sizeof(H5F_vfd_swmr_config_t)); + + /* Create a copy of the file access property list */ + if((fapl = H5Pcreate(H5P_FILE_ACCESS)) < 0) + FAIL_STACK_ERROR; + + /* Set the configuration */ + my_config->version = H5F__CURR_VFD_SWMR_CONFIG_VERSION; + my_config->tick_len = 3; + my_config->max_lag = 3; + my_config->vfd_swmr_writer = TRUE; + my_config->md_pages_reserved = 2; + HDstrcpy(my_config->md_file_path, "my_md_file"); + + /* Should succeed in setting the VFD SWMR configuration */ + if(H5Pset_vfd_swmr_config(fapl, my_config) < 0) + TEST_ERROR; + + /* Enable page buffering */ + if(H5Pset_page_buffer_size(fapl, 4096, 0, 0) < 0) + FAIL_STACK_ERROR; + + /* Create a copy of file creation property list */ + if((fcpl = H5Pcreate(H5P_FILE_CREATE)) < 0) + FAIL_STACK_ERROR + + /* Set file space strategy */ + if(H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_PAGE, FALSE, (hsize_t)1) < 0) + FAIL_STACK_ERROR; + + /* Create the file with VFD SWMR configured */ + if((fid = H5Fcreate("myfile", H5F_ACC_TRUNC, fcpl, fapl)) < 0) + FAIL_STACK_ERROR; + + /* Should succeed */ + if(H5Fvfd_swmr_end_tick(fid) < 0) + TEST_ERROR; + + /* Close the file */ + if(H5Fclose(fid) < 0) + FAIL_STACK_ERROR; + + /* Open the file as VFD SWMR writer */ + if((fid = H5Fopen("myfile", H5F_ACC_RDWR, fapl)) < 0) + TEST_ERROR; + + /* Should succeed */ + if(H5Fvfd_swmr_end_tick(fid) < 0) + TEST_ERROR; + + /* Close the file */ + if(H5Fclose(fid) < 0) + FAIL_STACK_ERROR; + +#ifdef NOTYET + /* Open the file as VFD SWMR reader */ + if((fid = H5Fopen("myfile", H5F_ACC_RDONLY, fapl)) < 0) + FAIL_STACK_ERROR; + + /* Should succeed */ + if(H5Fvfd_swmr_end_tick(fid) < 0) + TEST_ERROR; + + /* Close the file */ + if(H5Fclose(fid) < 0) + FAIL_STACK_ERROR; +#endif + + /* Open the file as writer without VFD SWMR configured */ + if((fid = H5Fopen("myfile", H5F_ACC_RDWR, H5P_DEFAULT)) < 0) + FAIL_STACK_ERROR; + + /* Should fail */ + H5E_BEGIN_TRY { + ret = H5Fvfd_swmr_end_tick(fid); + } H5E_END_TRY; + if(ret >= 0) + TEST_ERROR; + + /* Close the file */ + if(H5Fclose(fid) < 0) + FAIL_STACK_ERROR; + + /* Open the file as reader without VFD SWMR configured */ + if((fid = H5Fopen("myfile", H5F_ACC_RDONLY, H5P_DEFAULT)) < 0) + FAIL_STACK_ERROR; + + /* Should fail */ + H5E_BEGIN_TRY { + ret = H5Fvfd_swmr_end_tick(fid); + } H5E_END_TRY; + if(ret >= 0) + TEST_ERROR; + + /* Close the file */ + if(H5Fclose(fid) < 0) + FAIL_STACK_ERROR; + + if(H5Pclose(fapl) < 0) + FAIL_STACK_ERROR; + if(H5Pclose(fcpl) < 0) + FAIL_STACK_ERROR; + if(my_config) + HDfree(my_config); + + PASSED() + return 0; + +error: + H5E_BEGIN_TRY { + H5Pclose(fapl); + H5Pclose(fcpl); + H5Fclose(fid); + } H5E_END_TRY; + + if(my_config) + HDfree(my_config); + + return 1; +} /* test_file_end_tick() */ + + +/*------------------------------------------------------------------------- + * Function: main() + * + * Purpose: Main function for VFD SWMR tests. + * + * Return: 0 if test is sucessful + * 1 if test fails + * + *------------------------------------------------------------------------- + */ +int +main(void) +{ + hid_t fapl = -1; /* File access property list for data files */ + unsigned nerrors = 0; /* Cumulative error count */ + const char *env_h5_drvr = NULL; /* File Driver value from environment */ + hbool_t api_ctx_pushed = FALSE; /* Whether API context pushed */ + + h5_reset(); + + /* Get the VFD to use */ + env_h5_drvr = HDgetenv("HDF5_DRIVER"); + if(env_h5_drvr == NULL) + env_h5_drvr = "nomatch"; + + /* Temporary skip testing with multi/split drivers: + * Page buffering depends on paged aggregation which is + * currently disabled for multi/split drivers. + */ + if((0 == HDstrcmp(env_h5_drvr, "multi")) || + (0 == HDstrcmp(env_h5_drvr, "split"))) { + + SKIPPED() + HDputs("Skip VFD SWMR test because paged aggregation is disabled for multi/split drivers"); + HDexit(EXIT_SUCCESS); + } /* end if */ + + if((fapl = h5_fileaccess()) < 0) { + nerrors++; + PUTS_ERROR("Can't get VFD-dependent fapl") + } /* end if */ + + /* Push API context */ + if(H5CX_push() < 0) FAIL_STACK_ERROR + api_ctx_pushed = TRUE; + + nerrors += test_fapl(); + nerrors += test_file_fapl(); + nerrors += test_file_end_tick(); + + h5_clean_files(FILENAME, fapl); + + if(nerrors) + goto error; + + /* Pop API context */ + if(api_ctx_pushed && H5CX_pop() < 0) FAIL_STACK_ERROR + api_ctx_pushed = FALSE; + + HDputs("All VFD SWMR tests passed."); + + HDexit(EXIT_SUCCESS); + +error: + HDprintf("***** %d VFD SWMR TEST%s FAILED! *****\n", + nerrors, nerrors > 1 ? "S" : ""); + + H5E_BEGIN_TRY { + H5Pclose(fapl); + } H5E_END_TRY; + + if(api_ctx_pushed) H5CX_pop(); + + HDexit(EXIT_FAILURE); +} /* main() */ + -- cgit v0.12