diff options
-rwxr-xr-x | bin/trace | 1 | ||||
-rw-r--r-- | src/H5.c | 6 | ||||
-rw-r--r-- | src/H5AC.c | 4 | ||||
-rw-r--r-- | src/H5ACprivate.h | 2 | ||||
-rw-r--r-- | src/H5Cprivate.h | 2 | ||||
-rw-r--r-- | src/H5Ctag.c | 6 | ||||
-rw-r--r-- | src/H5Dint.c | 2 | ||||
-rw-r--r-- | src/H5F.c | 31 | ||||
-rw-r--r-- | src/H5FDint.c | 1 | ||||
-rw-r--r-- | src/H5FDprivate.h | 122 | ||||
-rw-r--r-- | src/H5FDvfd_swmr.c | 1139 | ||||
-rw-r--r-- | src/H5FDvfd_swmr.h | 36 | ||||
-rw-r--r-- | src/H5Fint.c | 257 | ||||
-rw-r--r-- | src/H5Fpkg.h | 9 | ||||
-rw-r--r-- | src/H5Fprivate.h | 22 | ||||
-rw-r--r-- | src/H5Fpublic.h | 16 | ||||
-rw-r--r-- | src/H5Fquery.c | 23 | ||||
-rw-r--r-- | src/H5Pfapl.c | 227 | ||||
-rw-r--r-- | src/H5Ppublic.h | 4 | ||||
-rw-r--r-- | src/H5private.h | 30 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/hdf5.h | 1 | ||||
-rw-r--r-- | test/Makefile.am | 2 | ||||
-rw-r--r-- | test/vfd_swmr.c | 691 |
24 files changed, 2622 insertions, 16 deletions
@@ -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", @@ -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 */ @@ -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 0e8620d..a7e8493 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 0f08ede..e4235a8 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 9af391e..9d15ca6 100644 --- a/src/H5Dint.c +++ b/src/H5Dint.c @@ -2927,7 +2927,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 */ @@ -1989,3 +1989,34 @@ 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 ea8c4d8..b423490 100644 --- a/src/H5FDint.c +++ b/src/H5FDint.c @@ -394,4 +394,3 @@ H5FD_driver_query(const H5FD_class_t *driver, unsigned long *flags/*out*/) FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD_driver_query() */ - diff --git a/src/H5FDprivate.h b/src/H5FDprivate.h index c79d676..57be23a 100644 --- a/src/H5FDprivate.h +++ b/src/H5FDprivate.h @@ -36,7 +36,121 @@ /**************************/ /* Length of filename buffer */ -#define H5FD_MAX_FILENAME_LEN 1024 +#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 */ \ + + H5FD_SIZEOF_CHKSUM /* Index entry checksum */ \ + ) + +/* 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 */ \ + ) + +#define H5FD_MD_EMPTY_INDEX_SIZE \ + ( \ + H5_SIZEOF_MAGIC /* Signature */ \ + + 8 /* Tick num */ \ + + 4 /* Number of entries */ \ + + H5FD_SIZEOF_CHKSUM /* Metadata header checksum */ \ + ) + +/* Retries for metadata file */ +#define H5FD_VFD_SWMR_MD_FILE_RETRY_MAX 50 /* Maximum retries when opening the MD file */ +#define H5FD_VFD_SWMR_MD_LOAD_RETRY_MAX 20 /* Maximum retries when trying to load the MD file header and index */ +#define H5FD_VFD_SWMR_MD_HEADER_RETRY_MAX 40 /* Maximum retries when deserializing the MD file header */ +#define H5FD_VFD_SWMR_MD_INDEX_RETRY_MAX 5 /* Maximum retries when deserializing the MD file index */ + + +/* + * fs_page_size: Size of pages in both the HDF5 file and the metadata file IN BYTES + * tick_num: Sequence number of the current tick. + * Initialized to zero on file creation/open, and incremented by the + * VFD SWMR writer at the end of each tick. + * index_offset: The offset of the current metadata file index in the metadata file + * IN BYTES. + * index_length: The length of the current metadata file index IN BYTES. + */ +typedef struct H5FD_vfd_swmr_md_header { + uint32_t fs_page_size; + uint64_t tick_num; + uint64_t index_offset; + uint64_t index_length; +} H5FD_vfd_swmr_md_header; + +/* Internal representation of metadata file index entry */ +/* + * hdf5_page_offset: Unsigned 64-bit value containing the base address of the + * metadata page, or multi page metadata entry in the HDF5 + * file IN PAGES. + * To obtain byte offset, multiply this value by the page size. + * md_file_page_offset: Unsigned 64-bit value containing the base address of the + * metadata page, or multi page metadata entry in the metadata + * file IN PAGES. + * To obtain byte offset, multiply this value by the page size. + * length: The length of the metadata page or multi page metadata entry + * in BYTES. + * chksum: Checksum for the metadata page or multi page metadata entry + * tick_of_last_change: Number of the last tick in which this index entry was changed. + * This field is only used by the VFD SWMR writer. + * For readers, it will always be set to 0. + * is_moved_to_hdf5_file: Set to TRUE iff the entry referenced is in the HDF5 file and + * is therefore about to be removed from the metadata file + */ +typedef struct H5FD_vfd_swmr_idx_entry_t { + uint64_t hdf5_page_offset; + uint64_t md_file_page_offset; + uint32_t length; + uint32_t chksum; + uint64_t tick_of_last_change; + hbool_t is_moved_to_hdf5_file; +} H5FD_vfd_swmr_idx_entry_t; + +/* + * tick_num: Sequence number of the current tick. + * Initialized to zero on file creation/open, and incremented by the + * VFD SWMR writer at the end of each tick. + * num_entries: The number of entires in the index. + * entries: The array of index entries + */ +typedef struct H5FD_vfd_swmr_md_index { + uint64_t tick_num; + uint32_t num_entries; + H5FD_vfd_swmr_idx_entry_t *entries; +} H5FD_vfd_swmr_md_index; + + #ifdef H5_HAVE_PARALLEL /* ======== Temporary data transfer properties ======== */ @@ -155,6 +269,12 @@ 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_vfd_swmr_writer_end_of_tick(); +H5_DLL herr_t H5FD_vfd_swmr_reader_end_of_tick(); +H5_DLL herr_t H5FD_vfd_swmr_get_tick_and_idx(H5FD_t *_file, hbool_t read_index, + uint64_t *tick_ptr, uint32_t *num_entries_ptr, H5FD_vfd_swmr_idx_entry_t index[]); + /* Function prototypes for MPI based VFDs*/ #ifdef H5_HAVE_PARALLEL /* General routines */ diff --git a/src/H5FDvfd_swmr.c b/src/H5FDvfd_swmr.c new file mode 100644 index 0000000..e4df4f1 --- /dev/null +++ b/src/H5FDvfd_swmr.c @@ -0,0 +1,1139 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + + * 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. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Purpose: + */ + +#include "H5FDdrvr_module.h" /* This source code file is part of the H5FD driver module */ + + +#include "H5Eprivate.h" /* Error handling */ +#include "H5Fprivate.h" /* File access */ +#include "H5FDprivate.h" /* File drivers */ +#include "H5FDvfd_swmr.h" /* VFD SWMR file driver */ +#include "H5FLprivate.h" /* Free Lists */ +#include "H5Iprivate.h" /* IDs */ +#include "H5MMprivate.h" /* Memory management */ +#include "H5Pprivate.h" /* Property lists */ + +/* The driver identification number, initialized at runtime */ +static hid_t H5FD_VFD_SWMR_g = 0; + +typedef struct H5FD_vfd_swmr_t { + H5FD_t pub; /* public stuff, must be first */ + + /* HDF5 file */ + char hdf5_filename[H5FD_MAX_FILENAME_LEN]; /* Name of the HDF5 file from open */ + H5FD_t *hdf5_file_lf; /* Driver info for the HDF5 file */ + + /* Metadata file */ + int md_fd; /* File descriptor the metadata file */ + int32_t md_pages_reserved; /* # of pages reserved at the head of the metadata file */ + char md_file_path[H5FD_MAX_FILENAME_LEN]; /* Name of the metadate file */ + H5FD_vfd_swmr_md_header md_header; /* Metadata file header */ + H5FD_vfd_swmr_md_index md_index; /* Metadata file index */ +} H5FD_vfd_swmr_t; + +#define MAXADDR (((haddr_t)1<<(8*sizeof(HDoff_t)-1))-1) + +/* Prototypes */ +static herr_t H5FD_vfd_swmr_term(void); +static H5FD_t *H5FD_vfd_swmr_open(const char *name, unsigned flags, hid_t fapl_id, + haddr_t maxaddr); +static herr_t H5FD_vfd_swmr_close(H5FD_t *_file); +static int H5FD_vfd_swmr_cmp(const H5FD_t *_f1, const H5FD_t *_f2); +static herr_t H5FD_vfd_swmr_query(const H5FD_t *_f1, unsigned long *flags); +static haddr_t H5FD_vfd_swmr_get_eoa(const H5FD_t *_file, H5FD_mem_t type); +static herr_t H5FD_vfd_swmr_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr); +static haddr_t H5FD_vfd_swmr_get_eof(const H5FD_t *_file, H5FD_mem_t type); +static herr_t H5FD_vfd_swmr_get_handle(H5FD_t *_file, hid_t fapl, void** file_handle); +static herr_t H5FD_vfd_swmr_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr, + size_t size, void *buf); +static herr_t H5FD_vfd_swmr_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_vfd_swmr_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing); +static herr_t H5FD_vfd_swmr_lock(H5FD_t *_file, hbool_t rw); +static herr_t H5FD_vfd_swmr_unlock(H5FD_t *_file); + +/* VFD SWMR */ +static herr_t H5FD_vfd_swmr_header_deserialize(H5FD_t *_file, H5FD_vfd_swmr_md_header *md_header); +static herr_t H5FD_vfd_swmr_index_deserialize(H5FD_t *_file, H5FD_vfd_swmr_md_index *md_index, H5FD_vfd_swmr_md_header *md_header); +static herr_t H5FD_vfd_swmr_load_hdr_and_idx(H5FD_t *_file, hbool_t open); + +static const H5FD_class_t H5FD_vfd_swmr_g = { + "swmr", /* name */ + MAXADDR, /* maxaddr */ + H5F_CLOSE_WEAK, /* fc_degree */ + H5FD_vfd_swmr_term, /* terminate */ + NULL, /* sb_size */ + NULL, /* sb_encode */ + NULL, /* sb_decode */ + 0, /* fapl_size */ + NULL, /* fapl_get */ + NULL, /* fapl_copy */ + NULL, /* fapl_free */ + 0, /* dxpl_size */ + NULL, /* dxpl_copy */ + NULL, /* dxpl_free */ + H5FD_vfd_swmr_open, /* open */ + H5FD_vfd_swmr_close, /* close */ + H5FD_vfd_swmr_cmp, /* cmp */ + H5FD_vfd_swmr_query, /* query */ + NULL, /* get_type_map */ + NULL, /* alloc */ + NULL, /* free */ + H5FD_vfd_swmr_get_eoa, /* get_eoa */ + H5FD_vfd_swmr_set_eoa, /* set_eoa */ + H5FD_vfd_swmr_get_eof, /* get_eof */ + H5FD_vfd_swmr_get_handle, /* get_handle */ + H5FD_vfd_swmr_read, /* read */ + H5FD_vfd_swmr_write, /* write */ + NULL, /* flush */ + H5FD_vfd_swmr_truncate, /* truncate */ + H5FD_vfd_swmr_lock, /* lock */ + H5FD_vfd_swmr_unlock, /* unlock */ + H5FD_FLMAP_DICHOTOMY /* fl_map */ +}; + +/* Declare a free list to manage the H5FD_vfd_swmr_t struct */ +H5FL_DEFINE_STATIC(H5FD_vfd_swmr_t); + +/* Declare a free list to manage the H5FD_vfd_swmr_idx_entry_t sequence information */ +H5FL_SEQ_DEFINE(H5FD_vfd_swmr_idx_entry_t); + + +/*------------------------------------------------------------------------- + * Function: H5FD__init_package + * + * Purpose: Initializes any interface-specific data or routines. + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD__init_package(void) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_STATIC + + if(H5FD_vfd_swmr_init() < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "unable to initialize swmr VFD") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5FD__init_package() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_vfd_swmr_init + * + * Purpose: Initialize this driver by registering the driver with the + * library. + * + * Return: Success: The driver ID for the VFD SWMR driver. + * Failure: Negative + * + * Programmer: Robb Matzke + * Thursday, July 29, 1999 + * + *------------------------------------------------------------------------- + */ +hid_t +H5FD_vfd_swmr_init(void) +{ + hid_t ret_value = H5I_INVALID_HID; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + if(H5I_VFL != H5I_get_type(H5FD_VFD_SWMR_g)) + H5FD_VFD_SWMR_g = H5FD_register(&H5FD_vfd_swmr_g, sizeof(H5FD_class_t), FALSE); + + /* Set return value */ + ret_value = H5FD_VFD_SWMR_g; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_vfd_swmr_init() */ + + +/*--------------------------------------------------------------------------- + * Function: H5FD_vfd_swmr_term + * + * Purpose: Shut down the VFD + * + * Returns: SUCCEED (Can't fail) + * + * Programmer: Quincey Koziol + * Friday, Jan 30, 2004 + * + *--------------------------------------------------------------------------- + */ +static herr_t +H5FD_vfd_swmr_term(void) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Reset VFL ID */ + H5FD_VFD_SWMR_g = 0; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5FD_vfd_swmr_term() */ + + +/*------------------------------------------------------------------------- + * Function: H5Pset_fapl_vfd_swmr (Not yet) + * + * Purpose: Modify the file access property list to use the H5FD_SWMR + * driver + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5Pset_fapl_vfd_swmr(hid_t fapl_id) +{ + H5P_genplist_t *plist; /* Property list pointer */ + herr_t ret_value; + + FUNC_ENTER_API(FAIL) + H5TRACE1("e", "i", fapl_id); + + if(NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list") + + ret_value = H5P_set_driver(plist, H5FD_VFD_SWMR, NULL); + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Pset_fapl_vfd_swmr() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_vfd_swmr_open + * + * Purpose: Open the metadata file and the underlying HDF5 file + * + * Return: Success: A pointer to a new file data structure. The + * public fields will be initialized by the + * caller, which is always H5FD_open(). + * Failure: NULL + * + *------------------------------------------------------------------------- + */ +static H5FD_t * +H5FD_vfd_swmr_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr) +{ + H5FD_vfd_swmr_t *file = NULL; /* VFD SWMR driver info */ + H5P_genplist_t *plist; /* Property list pointer */ + H5F_vfd_swmr_config_t *vfd_swmr_config = NULL; /* Points to VFD SWMR configuration */ + unsigned file_retries = H5FD_VFD_SWMR_MD_FILE_RETRY_MAX; /* Maximum retries for opening md file */ + uint64_t nanosec = 1; /* # of nanoseconds to sleep between retries */ + H5FD_t *ret_value = NULL; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* Get file access property list */ + if(NULL == (plist = (H5P_genplist_t *)H5I_object(fapl_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a file access property list") + + /* Allocate buffer for reading the VFD SWMR configuration */ + if(NULL == (vfd_swmr_config = (uint8_t *)H5MM_malloc(sizeof(H5F_vfd_swmr_config_t)))) + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "memory allocation failed for H5F_vfd_swmr_config_t") + + /* Get VFD SWMR configuration */ + if(H5P_get(plist, H5F_ACS_VFD_SWMR_CONFIG_NAME, vfd_swmr_config) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get VFD SWMR config info") + + /* Ensure that this is the reader */ + HDassert(!vfd_swmr_config->vfd_swmr_writer); + + /* Create the new driver struct */ + if(NULL == (file = H5FL_CALLOC(H5FD_vfd_swmr_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate file struct") + + file->hdf5_file_lf = NULL; + file->md_pages_reserved = vfd_swmr_config->md_pages_reserved; + + /* Retain a copy of the name used to open the HDF5 file */ + HDstrncpy(file->hdf5_filename, name, sizeof(file->hdf5_filename)); + file->hdf5_filename[sizeof(file->hdf5_filename) - 1] = '\0'; + + /* Retain a copy of the metadata file name */ + HDstrncpy(file->md_file_path, vfd_swmr_config->md_file_path, sizeof(file->md_file_path)); + file->md_file_path[sizeof(file->md_file_path) - 1] = '\0'; + + /* Retry on opening the metadata file */ + do { + if((file->md_fd = HDopen(file->md_file_path, O_RDONLY)) >= 0) + break; + /* Sleep and double the sleep time on next retry */ + H5_nanosleep(nanosec); + nanosec *= 2; + } while (--file_retries); + + /* Exhaust all retries for opening the md file */ + if(file_retries == 0) + HGOTO_ERROR(H5E_VFL, H5E_OPENERROR, NULL, "unable to open the metadata file after all retry attempts") + + /* Retry on loading and decoding the header and index in the metadata file */ + if(H5FD_vfd_swmr_load_hdr_and_idx(file, TRUE) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTGET, NULL, "unable to load/decode the md file header/index") + + /* Hard-wired to open the underlying HDF5 file with SEC2 */ + if((file->hdf5_file_lf = H5FD_open(name, flags, H5P_FILE_ACCESS_DEFAULT, maxaddr)) == NULL) + HGOTO_ERROR(H5E_VFL, H5E_CANTOPENFILE, NULL, "can't set driver info") + + /* Set return value */ + ret_value = (H5FD_t*)file; + +done: + /* Free the buffer */ + if(vfd_swmr_config) + vfd_swmr_config = (uint8_t *)H5MM_xfree(vfd_swmr_config); + + /* Handle closing if error */ + if(NULL == ret_value && file) { + if(H5FD_vfd_swmr_close(file) < 0) + HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "error from closing") + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_vfd_swmr_open() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_vfd_swmr_close + * + * Purpose: Handle closing for VFD SWMR driver + * --close the underlying HDF5 file + * --close the metadata file if open + * --free the index entries if available + * + * Return: Success: SUCCEED + * Failure: FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_vfd_swmr_close(H5FD_t *_file) +{ + H5FD_vfd_swmr_t *file = (H5FD_vfd_swmr_t *)_file; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* Sanity check */ + HDassert(file); + + /* Close the underlying file */ + if(file->hdf5_file_lf && H5FD_close(file->hdf5_file_lf) < 0) + /* Push error, but keep going */ + HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "unable to close the HDF5 file") + + /* Close the metadata file */ + if(file->md_fd >= 0 && HDclose(file->md_fd) < 0) + /* Push error, but keep going */ + HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "unable to close the metadata file") + + /* Free the index entries */ + if(file->md_index.num_entries && file->md_index.entries) + file->md_index.entries = H5FL_SEQ_FREE(H5FD_vfd_swmr_idx_entry_t, file->md_index.entries); + + /* Release the driver info */ + file = H5FL_FREE(H5FD_vfd_swmr_t, file); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_vfd_swmr_close() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_vfd_swmr_cmp + * + * Purpose: Compares two files belonging to this driver using an + * arbitrary (but consistent) ordering. + * + * Return: Success: A value like strcmp() + * Failure: never fails (arguments were checked by the + * caller). + * + * Programmer: Robb Matzke + * Thursday, July 29, 1999 + * + *------------------------------------------------------------------------- + */ +static int +H5FD_vfd_swmr_cmp(const H5FD_t *_f1, const H5FD_t *_f2) +{ + const H5FD_vfd_swmr_t *f1 = (const H5FD_vfd_swmr_t *)_f1; + const H5FD_vfd_swmr_t *f2 = (const H5FD_vfd_swmr_t *)_f2; + int ret_value = 0; + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + ret_value = H5FD_cmp(f1->hdf5_file_lf, f2->hdf5_file_lf); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_vfd_swmr_cmp() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_vfd_swmr_query + * + * Purpose: Set the flags that this VFL driver is capable of supporting. + * (listed in H5FDpublic.h) + * + * Return: SUCCEED (Can't fail) + * + * Programmer: Quincey Koziol + * Friday, August 25, 2000 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_vfd_swmr_query(const H5FD_t *_file, unsigned long *flags /* out */) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Set the VFL feature flags that this driver supports */ + if(flags) { + *flags = 0; + *flags |= H5FD_FEAT_AGGREGATE_METADATA; /* OK to aggregate metadata allocations */ + *flags |= H5FD_FEAT_ACCUMULATE_METADATA; /* OK to accumulate metadata for faster writes */ + *flags |= H5FD_FEAT_DATA_SIEVE; /* OK to perform data sieving for faster raw data reads & writes */ + *flags |= H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */ + *flags |= H5FD_FEAT_POSIX_COMPAT_HANDLE; /* get_handle callback returns a POSIX file descriptor */ + *flags |= H5FD_FEAT_SUPPORTS_SWMR_IO; /* VFD supports the single-writer/multiple-readers (SWMR) pattern */ + *flags |= H5FD_FEAT_DEFAULT_VFD_COMPATIBLE; /* VFD creates a file which can be opened with the default VFD */ + + } /* end if */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5FD_vfd_swmr_query() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_vfd_swmr_get_eoa + * + * Purpose: Gets the end-of-address marker for the file for the underlying + * HDF5 file. The EOA marker is the first address past the last byte + * allocated in the format address space. + * + * Return: The end-of-address marker. + * + * Programmer: Robb Matzke + * Monday, August 2, 1999 + * + *------------------------------------------------------------------------- + */ +static haddr_t +H5FD_vfd_swmr_get_eoa(const H5FD_t *_file, H5FD_mem_t type) +{ + const H5FD_vfd_swmr_t *file = (const H5FD_vfd_swmr_t *)_file; + haddr_t ret_value = HADDR_UNDEF; + + FUNC_ENTER_NOAPI_NOINIT + + if((ret_value = H5FD_get_eoa(file->hdf5_file_lf, type)) == HADDR_UNDEF) + HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to get HDF5 file eoa") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_vfd_swmr_get_eoa() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_vfd_swmr_set_eoa + * + * Purpose: Set the end-of-address marker for the underlying HDF5 file. + * This function is called shortly after an existing HDF5 file is opened + * in order to tell the driver where the end of the HDF5 data is located. + * + * Return: SUCCEED (Can't fail) + * + * Programmer: Robb Matzke + * Thursday, July 29, 1999 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_vfd_swmr_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr) +{ + H5FD_vfd_swmr_t *file = (H5FD_vfd_swmr_t *)_file; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT + + if(H5FD_set_eoa(file->hdf5_file_lf, type, addr) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to set HDF5 file eoa") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_vfd_swmr_set_eoa() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_vfd_swmr_get_eof + * + * Purpose: Returns the end-of-file marker, which is the greater of + * either the filesystem end-of-file or the HDF5 end-of-address + * markers for the underlying HDF5 file + * + * Return: End of file address, the first address past the end of the + * "file", either the filesystem file or the HDF5 file. + * + *------------------------------------------------------------------------- + */ +static haddr_t +H5FD_vfd_swmr_get_eof(const H5FD_t *_file, H5FD_mem_t type) +{ + const H5FD_vfd_swmr_t *file = (const H5FD_vfd_swmr_t *)_file; + haddr_t ret_value = HADDR_UNDEF; + + FUNC_ENTER_NOAPI_NOINIT + + /* LATER: need to determine the metadata file or underlying HDF5 file ? */ + if((ret_value = H5FD_get_eof(file->hdf5_file_lf, type)) == HADDR_UNDEF) + HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to set file eoa") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_vfd_swmr_get_eof() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_vfd_swmr_get_handle + * + * Purpose: Returns the file handle for the underling HDF5 file + * + * Returns: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_vfd_swmr_get_handle(H5FD_t *_file, hid_t fapl, void **file_handle) +{ + H5FD_vfd_swmr_t *file = (H5FD_vfd_swmr_t *)_file; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT + + if(!file_handle) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file handle not valid") + + /* LATER? H5P_get(plist, H5F_ACS_SWMR_FILE_NAME, &type) */ + + if((ret_value = H5FD_get_vfd_handle(file->hdf5_file_lf, fapl, file_handle)) < 0) + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "unable to get handle for HDF5 file") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_vfd_swmr_get_handle() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_vfd_swmr_read + * + * Purpose: TBD + * + * Return: Success: SUCCEED. Result is stored in caller-supplied + * buffer BUF. + * Failure: FAIL, Contents of buffer BUF are undefined. + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_vfd_swmr_read(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, + haddr_t addr, size_t size, void *buf /*out*/) +{ + H5FD_vfd_swmr_t *file = (H5FD_vfd_swmr_t *)_file; +H5FD_vfd_swmr_idx_entry_t *index; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(file && file->pub.cls); + HDassert(buf); + +#ifdef TEMP +tick_num +num_entries +H5FD_vfd_swmr_idx_entry_t *index; + if(H5FD_vfd_swmr_get_tick_and_idx(file, TRUE, &tick_num, &num_entries, NULL) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FALSE, "unable to retrieve tick and entries from the md file") + + if(num_entries) { + + /* Allocate memory for index entries */ + if(NULL == (index = H5FL_SEQ_MALLOC(H5FD_vfd_swmr_idx_entry_t, num_entries))) + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FALSE, "memory allocation failed for index entries") + + /* Get the entries for the index */ + if(H5FD_vfd_swmr_get_tick_and_idx(file, FALSE, FALSE, &tick_num, &num_entries, index) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTGET, NULL, "unable to load/decode the md file header/index") + } + +search for addr from the index +if found, read the page into buf based on the offset/size found in the index and return +otherwise read from the underlying HDF5 file +#endif + + if(H5FD_read(file->hdf5_file_lf, type, addr, size, buf) < 0) + HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "file read request failed") + +done: + if(ret_value < 0) { + /* What needs to be cleaned up */ + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_vfd_swmr_read() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_vfd_swmr_write + * + * Purpose: Writes SIZE bytes of data to FILE beginning at address ADDR + * from buffer BUF according to data transfer properties in + * DXPL_ID. + * + * Return: SUCCEED/FAIL + * + * Programmer: Robb Matzke + * Thursday, July 29, 1999 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_vfd_swmr_write(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, + haddr_t addr, size_t size, const void *buf) +{ + H5FD_vfd_swmr_t *file = (H5FD_vfd_swmr_t *)_file; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(file && file->pub.cls); + HDassert(buf); + + if(H5FD_write(file->hdf5_file_lf, type, addr, size, buf) < 0) + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "file write request failed") + +done: + if(ret_value < 0) { + /* Reset last file I/O information */ + /* What needs to be cleaned up */ + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_vfd_swmr_write() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_vfd_swmr_truncate + * + * Purpose: Makes sure that the true file size is the same (or larger) + * than the end-of-address for the underlying HDF5 file + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_vfd_swmr_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing) +{ + H5FD_vfd_swmr_t *file = (H5FD_vfd_swmr_t *)_file; /* VFD SWMR file struct */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(file); + + if(H5FD_truncate(file->hdf5_file_lf, closing) < 0) + HGOTO_ERROR(H5E_IO, H5E_BADVALUE, FAIL, "unable to truncate the HDF5 file") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_vfd_swmr_truncate() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_vfd_swmr_lock + * + * Purpose: To place an advisory lock on the underlying HDF5 file. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_vfd_swmr_lock(H5FD_t *_file, hbool_t rw) +{ + H5FD_vfd_swmr_t *file = (H5FD_vfd_swmr_t *)_file; /* VFD SWMR file struct */ + int lock_flags; /* file locking flags */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(file); + + if(H5FD_lock(file->hdf5_file_lf, rw) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTLOCK, FAIL, "unable to lock the HDF5 file") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_vfd_swmr_lock() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_vfd_swmr_unlock + * + * Purpose: To remove the existing lock on the underlying HDF5 file + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_vfd_swmr_unlock(H5FD_t *_file) +{ + H5FD_vfd_swmr_t *file = (H5FD_vfd_swmr_t *)_file; /* VFD SWMR file struct */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(file); + + if(H5FD_unlock(file->hdf5_file_lf) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTUNLOCK, FAIL, "unable to unlock the HDF5 file") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_vfd_swmr_unlock() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_vfd_swmr_get_tick_and_idx() + * + * Purpose: Retrieve tick_num, num_entries and index from the metadata file + * --If the parameter "reload_hdr_and_index" is true, load and decode the header + * and index via H5FD_vfd_swmr_load_hdr_and_idx(), which may replace the VFD's + * local copies of header and index with the latest info read. + * --Return tick_num, num_entries and index from the VFD's local copies. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5FD_vfd_swmr_get_tick_and_idx(H5FD_t *_file, hbool_t reload_hdr_and_index, + uint64_t *tick_ptr, uint32_t *num_entries_ptr, H5FD_vfd_swmr_idx_entry_t index[]) +{ + H5FD_vfd_swmr_t *file = (H5FD_vfd_swmr_t *)_file; /* VFD SWMR file struct */ + H5FD_t *ret_value = FALSE; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + if(reload_hdr_and_index) { + if(H5FD_vfd_swmr_load_hdr_and_idx(file, FALSE) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTLOAD, FAIL, "unable to load/decode md header and index") + } + + /* Return tick_num */ + if(tick_ptr != NULL) + *tick_ptr = file->md_header.tick_num; + + if(num_entries_ptr != NULL) { + if(*num_entries_ptr >= file->md_index.num_entries && index != NULL) + HDmemcpy(index, file->md_index.entries, (file->md_index.num_entries * sizeof(H5FD_vfd_swmr_idx_entry_t))); + + *num_entries_ptr = file->md_index.num_entries; + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5FD_vfd_swmr_get_tick_and_idx() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_vfd_swmr_load_hdr_and_idx() + * + * Purpose: Load and decode the header and index in the metadata file + * Try to load and decode the header: + * --If fail, RETRY + * --If succeed: + * --If the size of header and index does not fit within md_pages_reserved, return error + * --If NOT an initial open call: + * --If tick_num just read is the same as the VFD's local copy, just return + * --If tick_num just read is less than the VFD's local copy, return error + * --If tick_num just read is greater than the VFD's local copy or an initial open call: + * --Try to load and decode the index: + * --If fail, RETRY + * --If succeed: + * --If tick_num in header matches that in index, replace the VFD's + * local copy with the header and index just read + * --If tick_num in header is 1 greater than that in index, RETRY + * --Otherwise, return error + * + * Return: Success: SUCCEED + * Failure: FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_vfd_swmr_load_hdr_and_idx(H5FD_t *_file, hbool_t open) +{ + H5FD_vfd_swmr_t *file = (H5FD_vfd_swmr_t *)_file; /* VFD SWMR file struct */ + unsigned load_retries = H5FD_VFD_SWMR_MD_LOAD_RETRY_MAX; /* Retries for loading header and index */ + uint64_t nanosec = 1; /* # of nanoseconds to sleep between retries */ + H5FD_vfd_swmr_md_header md_header; /* Metadata file header */ + H5FD_vfd_swmr_md_index md_index; /* Metadata file index */ + H5FD_t *ret_value = FALSE; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + do { + HDmemset(&md_header, 0, sizeof(H5FD_vfd_swmr_md_header)); + HDmemset(&md_index, 0, sizeof(H5FD_vfd_swmr_md_index)); + + /* Load and decode the header */ + if(H5FD_vfd_swmr_header_deserialize(file, &md_header) >= 0) { + + /* Error if header + index fit does not within md_pages_reserved */ + if((H5FD_MD_HEADER_SIZE + md_header.index_length) > + (file->md_pages_reserved * md_header.fs_page_size)) + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "header + index does not fit within md_pages_reserved") + + if(!open) { + if(md_header.tick_num == file->md_header.tick_num) + break; + else if(md_header.tick_num < file->md_header.tick_num) + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "tick number read is less than local copy") + } + + HDassert(md_header.tick_num > file->md_header.tick_num || open); + + /* Load and decode the index */ + if(H5FD_vfd_swmr_index_deserialize(file, &md_index, &md_header) >= 0) { + + /* tick_num is the same in both header and index */ + if(md_header.tick_num == md_index.tick_num) { + HDmemcpy(&file->md_header, &md_header, sizeof(H5FD_vfd_swmr_md_header)); + HDmemcpy(&file->md_index, &md_index, sizeof(H5FD_vfd_swmr_md_index)); + break; + } + /* Error when tick_num in header is more than one greater that in the index */ + else if(md_header.tick_num > (md_index.tick_num + 1)) + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "tick number mis-match in header and index") + + } /* end if index ok */ + } /* end if header ok */ + + /* Sleep and double the sleep time next time */ + H5_nanosleep(nanosec); + nanosec *= 2; + + } while(--load_retries); + + /* Exhaust all retries for loading and decoding the md file header and index */ + if(load_retries == 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTLOAD, FAIL, "error in loading/decoding the metadata file header and index") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5FD_vfd_swmr_load_hdr_and_idx() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_vfd_swmr_header_deserialize() + * + * Purpose: To load and decode the header in the metadata file + * --Retry to get a file with size at least the size of the header + * --Retry on loading the valid magic and checksum for the header + * --Decode the header + * + * Return: Success: SUCCEED + * Failure: FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_vfd_swmr_header_deserialize(H5FD_t *_file, H5FD_vfd_swmr_md_header *md_header) +{ + H5FD_vfd_swmr_t *file = (H5FD_vfd_swmr_t *)_file; /* VFD SWMR file struct */ + struct stat stat_buf; /* Buffer for stat info */ + uint8_t image[H5FD_MD_HEADER_SIZE]; /* Buffer for element data */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + uint64_t nanosec = 1; /* # of nanoseconds to sleep between retries */ + unsigned file_retries = H5FD_VFD_SWMR_MD_FILE_RETRY_MAX; /* Retries for 'stat' the file */ + unsigned header_retries = H5FD_VFD_SWMR_MD_HEADER_RETRY_MAX; /* Retries for loading header */ + uint8_t *p = NULL; /* Pointer to buffer */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* Try to stat the metadata file till md header size */ + do { + /* Retrieve the metadata file size */ + if(HDfstat(file->md_fd, &stat_buf)) + HGOTO_ERROR(H5E_VFL, H5E_CANTGET, NULL, "unable to fstat the md file") + + /* Verify file size is at least header size */ + if(stat_buf.st_size >= H5FD_MD_HEADER_SIZE) + break; + + /* Sleep and double the sleep time next time */ + H5_nanosleep(nanosec); + nanosec *= 2; + } while (--file_retries); + + /* Exhaust all retries for "stat" the md file */ + if(file_retries == 0) + HGOTO_ERROR(H5E_VFL, H5E_OPENERROR, NULL, "unable to the metadata file after all retry attempts") + + /* Try to get valid magic and checksum for header */ + p = image; + do { + /* Set file pointer to the beginning the file */ + if(HDlseek(file->md_fd, (HDoff_t)0, SEEK_SET) < 0) + HGOTO_ERROR(H5E_VFL, H5E_SEEKERROR, FAIL, "unable to seek in metadata file") + /* Read the header */ + if(HDread(file->md_fd, image, H5FD_MD_HEADER_SIZE) < H5FD_MD_HEADER_SIZE) + HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "error in reading the header in metadata file") + + /* Verify magic number */ + if(HDmemcmp(p, H5FD_MD_HEADER_MAGIC, (size_t)H5_SIZEOF_MAGIC) == 0) { + + /* Verify stored and computed checksums are equal */ + H5F_get_checksums(image, H5FD_MD_HEADER_SIZE, &stored_chksum, &computed_chksum); + if(stored_chksum == computed_chksum) + break; + } + /* Sleep and double the sleep time next time */ + H5_nanosleep(nanosec); + nanosec *= 2; + } while(--header_retries); + + /* Exhaust all retries for loading the header */ + if(header_retries == 0) + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "incorrect checksum after after all read attempts") + + /* Header magic is already valid */ + p += H5_SIZEOF_MAGIC; + + /* Deserialize page size, tick number, index offset, index length */ + UINT32DECODE(p, md_header->fs_page_size); + UINT64DECODE(p, md_header->tick_num); + UINT64DECODE(p, md_header->index_offset); + UINT64DECODE(p, md_header->index_length); + + /* Checksum is already valid */ + UINT32DECODE(p, stored_chksum); + + /* Sanity check */ + HDassert((size_t)(p - (const uint8_t *)&image[0]) <= H5FD_MD_HEADER_SIZE); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5FD_vfd_swmr_header_deserialize() */ + + + +/*------------------------------------------------------------------------- + * Function: H5FD_vfd_swmr_index_deserialize() + * + * Purpose: Load and decode the index in the metadata file + * --Retry to get a file with size at least the size of the + * (header+index) + * --Retry on loading the valid magic and checksum for the index + * --Decode the index + * --Decode the index entries if the tick number in the header and + * the index match + * + * Return: Success: SUCCEED + * Failure: FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_vfd_swmr_index_deserialize(H5FD_t *_file, H5FD_vfd_swmr_md_index *md_index, H5FD_vfd_swmr_md_header *md_header) +{ + H5FD_vfd_swmr_t *file = (H5FD_vfd_swmr_t *)_file; /* VFD SWMR file struct */ + uint8_t *image; /* Buffer */ + uint8_t *p = NULL; /* Pointer to buffer */ + struct stat stat_buf; /* Buffer for stat info */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + uint64_t nanosec = 1; /* # of nanoseconds to sleep between retries */ + unsigned i; /* Local index variable */ + unsigned file_retries = H5FD_VFD_SWMR_MD_FILE_RETRY_MAX; /* Retries for 'stat' the file */ + unsigned index_retries = H5FD_VFD_SWMR_MD_INDEX_RETRY_MAX; /* Retries for loading the index */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* Try to stat the metadata file till at least md (header+index) size */ + do { + /* Retrieve the metadata file size */ + if(HDfstat(file->md_fd, &stat_buf)) + HGOTO_ERROR(H5E_VFL, H5E_CANTGET, NULL, "unable to fstat the md file") + + /* Verify file size is at least header size */ + if(stat_buf.st_size >= (H5FD_MD_HEADER_SIZE + md_header->index_length)) + break; + + /* Sleep and double the sleep time next time */ + H5_nanosleep(nanosec); + nanosec *= 2; + } while (--file_retries); + + /* Allocate buffer for reading index */ + if(NULL == (image = (uint8_t *)H5MM_malloc(md_header->index_length))) + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "memory allocation failed for index's on disk image buffer") + + /* Verify magic and checksum for index */ + p = image; + do { + if(HDlseek(file->md_fd, (HDoff_t)md_header->index_offset, SEEK_SET) < 0) + HGOTO_ERROR(H5E_VFL, H5E_SEEKERROR, FAIL, "unable to seek in metadata file") + if(HDread(file->md_fd, image, md_header->index_length) < md_header->index_length) + HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "error in reading the header in metadata file") + + /* Verify valid magic for index */ + if(HDmemcmp(p, H5FD_MD_INDEX_MAGIC, (size_t)H5_SIZEOF_MAGIC) == 0) { + + /* Verify stored and computed checksums are equal */ + H5F_get_checksums(image, md_header->index_length, &stored_chksum, &computed_chksum); + if(stored_chksum == computed_chksum) + break; + } + H5_nanosleep(nanosec); + nanosec *= 2; /* Double the sleep time next time */ + } while(--index_retries); + + /* Exhaust all retries for loading the index */ + if(index_retries == 0) + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "incorrect checksum after after all read attempts") + + /* Magic is already valid */ + p += H5_SIZEOF_MAGIC; + + /* Deserialize the index info: tick number, number of entries, entries, checksum */ + UINT64DECODE(p, md_index->tick_num); + UINT32DECODE(p, md_index->num_entries); + + /* Read index entries */ + if(md_index->num_entries) { + /* Allocate memory for index entries */ + if(NULL == (md_index->entries = H5FL_SEQ_MALLOC(H5FD_vfd_swmr_idx_entry_t, md_index->num_entries))) + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, NULL, "memory allocation failed for index entries") + + /* Decode index entries */ + for(i = 0; i < md_index->num_entries; i++) { + UINT32DECODE(p, md_index->entries[i].hdf5_page_offset); + UINT32DECODE(p, md_index->entries[i].md_file_page_offset); + UINT32DECODE(p, md_index->entries[i].length); + UINT32DECODE(p, md_index->entries[i].chksum); + } /* end for */ + + /* MAY BE SORTED ALREADY: Sort entries in increasing hdf5_page_offset */ + //HDqsort(file->md_index.entries, num_entries, sizeof(H5FD_vfd_swmr_idx_entry_t), H5FD__idx_entry_cmp); + } /* end if */ + + /* Checksum is already valid */ + UINT32DECODE(p, stored_chksum); + + /* Sanity check */ + HDassert((size_t)(p - image) <= md_header->index_length); + +done: + if(image) + image = (uint8_t *)H5MM_xfree(image); + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5FD_vfd_swmr_index_deserialize() */ + + +/*------------------------------------------------------------------------- +* Function: H5FD_vfd_swmr_writer_end_of_tick +* +* Purpose: TBD +* +* Return: SUCCEED/FAIL +* +* Programmer: +* +*------------------------------------------------------------------------- +*/ +herr_t +H5FD_vfd_swmr_writer_end_of_tick(void) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_vfd_swmr_writer_end_of_tick() */ + + +/*------------------------------------------------------------------------- +* Function: H5FD_vfd_swmr_reader_end_of_tick +* +* Purpose: TBD +* +* Return: SUCCEED/FAIL +* +*------------------------------------------------------------------------- +*/ +herr_t +H5FD_vfd_swmr_reader_end_of_tick(void) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_vfd_swmr_reader_end_of_tick() */ + + +/* Used by HDqsort: keep this for now */ +#ifdef TEMP +static int +H5FD__idx_entry_cmp(const void *_entry1, const void *_entry2) +{ + const H5FD_vfd_swmr_idx_entry_t *entry1 = (const H5FD_vfd_swmr_idx_entry_t *)_entry1; + const H5FD_vfd_swmr_idx_entry_t *entry2 = (const H5FD_vfd_swmr_idx_entry_t *)_entry2; + + int ret_value = 0; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Sanity checks */ + HDassert(entry1); + HDassert(entry2); + + if(entry1->hdf5_page_offset < entry2->hdf5_page_offset) + ret_value = -1; + else if(entry1->hdf5_page_offset > entry2->hdf5_page_offset) + ret_value = 1; + else + ret_value = 0; + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5FD__idx_entry_cmp() */ +#endif diff --git a/src/H5FDvfd_swmr.h b/src/H5FDvfd_swmr.h new file mode 100644 index 0000000..d317a18 --- /dev/null +++ b/src/H5FDvfd_swmr.h @@ -0,0 +1,36 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Programmer: Robb Matzke <matzke@llnl.gov> + * Monday, August 2, 1999 + * + * Purpose: The public header file for the VFD SWMR driver. + */ +#ifndef H5FDswmr_H +#define H5FDswmr_H + +#define H5FD_VFD_SWMR (H5FD_vfd_swmr_init()) + +#ifdef __cplusplus +extern "C" { +#endif + +H5_DLL hid_t H5FD_vfd_swmr_init(void); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/H5Fint.c b/src/H5Fint.c index 39934d6..17c494f 100644 --- a/src/H5Fint.c +++ b/src/H5Fint.c @@ -81,6 +81,11 @@ static herr_t H5F__build_actual_name(const H5F_t *f, const H5P_genplist_t *fapl, static herr_t H5F__flush_phase1(H5F_t *f); static herr_t H5F__flush_phase2(H5F_t *f, hbool_t closing); +/* VFD SWMR */ +static herr_t H5F__vfd_swmr_init_info(H5F_t *f); +static herr_t H5F__vfd_swmr_init_md(H5F_t *f); +static herr_t H5F__vfd_swmr_close_md(H5F_t *f); + /*********************/ /* Package Variables */ @@ -185,6 +190,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, H5I_INVALID_HID, "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, H5I_INVALID_HID, "can't set collective metadata read flag") @@ -1034,6 +1043,11 @@ 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") + f->shared->vfd_swmr_md_fd = -1; + /* 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. @@ -1294,6 +1308,12 @@ H5F__dest(H5F_t *f, hbool_t flush) /* Push error, but keep going*/ HDONE_ERROR(H5E_FILE, H5E_CANTDEC, FAIL, "can't close property list") + /* Handle closing for the metadata file (VFD SWMR writer) */ + if(H5F_ACC_RDWR & H5F_INTENT(f) && f->shared->vfd_swmr_md_fd >= 0) { + if(H5F__vfd_swmr_close_md(f) < 0) + HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "unable to close the metadata file") + } + /* Close the file */ if(H5FD_close(f->shared->lf) < 0) /* Push error, but keep going*/ @@ -1426,7 +1446,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) @@ -1596,6 +1617,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. @@ -1622,6 +1644,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. */ @@ -1636,8 +1661,36 @@ 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) { + + /* Initialize globals for VFD SWMR writer and reader */ + if(H5F__vfd_swmr_init_info(file) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTSET, NULL, "file open fail with initialization for VFD SWMR") + + /* For VFD SWMR writer */ + if(H5F_INTENT(file) & H5F_ACC_RDWR) { + HDassert(file->shared->vfd_swmr_config.vfd_swmr_writer); + + /* Create the metadata file */ + if(((file->shared->vfd_swmr_md_fd = HDopen(file->shared->vfd_swmr_config.md_file_path, O_CREAT|O_RDWR, H5_POSIX_CREATE_MODE_RW))) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to create the metadata file") + + /* Create header and empty index in the metadata file */ + if(!file_create) { + if(H5F__vfd_swmr_init_md(file) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTSET, NULL, "fail to initialize md 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 @@ -1741,9 +1794,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() */ @@ -3465,3 +3524,197 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* H5F__format_convert() */ + +/*------------------------------------------------------------------------- + * Function: H5F__vfd_swmr_init_info + * + * Purpose: Initialize globals and the corresponding fields in file pointer. + * 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 + * For VFD SWMR reader: + * --set vfd_swmr_g to TRUE + * --set vfd_swmr_writer_g to FALSE + * --set tick_num_g to the current tick read from the metadata file + * --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__vfd_swmr_init_info(H5F_t *f) +{ + struct timespec tmp_end_of_tick; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + if(f->shared->vfd_swmr_config.vfd_swmr_writer) { + vfd_swmr_writer_g = f->shared->vfd_swmr_writer = TRUE; + tick_num_g = f->shared->tick_num = 0; + } else { + HDassert(!f->shared->vfd_swmr_config.vfd_swmr_writer); + vfd_swmr_writer_g = f->shared->vfd_swmr_writer = FALSE; + + /* Set tick_num_g to the current tick read from the metadata file */ + if(H5FD_vfd_swmr_get_tick_and_idx(f->shared->lf, FALSE, &tick_num_g, NULL, NULL) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTLOAD, FAIL, "unable to load/decode metadata file") + f->shared->tick_num = tick_num_g; + } + + /* 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_g = f->shared->vfd_swmr = TRUE; + vfd_swmr_file_g = f->shared; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5F__vfd_swmr_init_info() */ + + +/*------------------------------------------------------------------------- + * Function: H5F__vfd_swmr_init_md + * + * Purpose: Encode the header and an empty index to the metadata file. + * This is used by the VFD SWMR writer when: + * --opening an existing HDF5 file + * --the HDF5 file is flushed and about to close + * + * Return: Success: SUCCEED + * Failure: FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5F__vfd_swmr_init_md(H5F_t *f) +{ + uint8_t *p = NULL; /* Pointer to buffer */ + uint8_t *pp = NULL; /* Pointer to buffer for index */ + uint32_t metadata_chksum; /* Computed metadata checksum value */ + uint8_t image[H5FD_MD_HEADER_SIZE + H5FD_MD_EMPTY_INDEX_SIZE]; /* Buffer for header and empty index */ + unsigned hdr_idx_size = H5FD_MD_HEADER_SIZE + H5FD_MD_EMPTY_INDEX_SIZE; /* Size of header and index */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* + * Encode metadata file header + */ + p = image; + + /* Encode magic for header */ + HDmemcpy(p, H5FD_MD_HEADER_MAGIC, (size_t)H5_SIZEOF_MAGIC); + p += H5_SIZEOF_MAGIC; + + /* Encode page size, tick number, index offset, index length */ + 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)); + + /* Calculate checksum for header */ + metadata_chksum = H5_checksum_metadata(image, (size_t)(p - image), 0); + + /* Encode checksum for header */ + UINT32ENCODE(p, metadata_chksum); + + /* Sanity checks on header */ + HDassert((size_t)(p - image == H5FD_MD_HEADER_SIZE)); + + /* + * Encode metadata file index + */ + pp = p; + + /* Encode magic for index */ + HDmemcpy(p, H5FD_MD_INDEX_MAGIC, (size_t)H5_SIZEOF_MAGIC); + p += H5_SIZEOF_MAGIC; + + /* Encode tick number */ + UINT64ENCODE(p, f->shared->tick_num); + + /* Encode zero number of entries in index */ + UINT32ENCODE(p, 0); + + /* Calculate checksum for index */ + metadata_chksum = H5_checksum_metadata(pp, (size_t)(p - pp), 0); + + /* Encode checksum for index */ + UINT32ENCODE(p, metadata_chksum); + + /* Sanity checks on index */ + HDassert((size_t)(p - pp == H5FD_MD_EMPTY_INDEX_SIZE)); + + /* Verify the md file descriptor exists */ + HDassert(f->shared->vfd_swmr_md_fd >= 0); + + /* Set to beginning of the file */ + if(HDlseek(f->shared->vfd_swmr_md_fd, (HDoff_t)0, SEEK_SET) < 0) + HGOTO_ERROR(H5E_VFL, H5E_SEEKERROR, FAIL, "unable to seek in metadata file") + + /* Write header and empty index to the metadata file */ + if(HDwrite(f->shared->vfd_swmr_md_fd, image, hdr_idx_size) != hdr_idx_size) + HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "error in writing header and index to metadata file") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5F__vfd_swmr_init_md() */ + + +/*------------------------------------------------------------------------- + * Function: H5F__vfd_swmr_close_md + * + * Purpose: This is used by the VFD SWMR writer when the HDF5 file is + * flushed and about to close: + * --increment the tick + * --write header and an empty index to the metadata file + * --close and unlink the metadata file + * + * Return: Success: SUCCEED + * Failure: FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +H5F__vfd_swmr_close_md(H5F_t *f) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + HDassert(f->shared->vfd_swmr_md_fd >= 0); + + /* Increment tick_num */ + tick_num_g = ++f->shared->tick_num; + + /* Write an empty header and index to the md file */ + if(H5F__vfd_swmr_init_md(f) < 0) + HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "unable to encode and write to the metadata file") + + /* Close the md file */ + if(HDclose(f->shared->vfd_swmr_md_fd) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "unable to close the metadata file") + f->shared->vfd_swmr_md_fd = -1; + + /* Unlink the md file */ + if(HDunlink(f->shared->vfd_swmr_config.md_file_path) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTREMOVE, FAIL, "unable to unlink the metadata file") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5F__vfd_swmr_close_md() */ diff --git a/src/H5Fpkg.h b/src/H5Fpkg.h index 44344f0..7e04f35 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 1ce9374..356a606 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; @@ -740,6 +761,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..9c47098 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 2500ea8..93b50d7 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 5320da1..f2e9a75 100644 --- a/src/H5Pfapl.c +++ b/src/H5Pfapl.c @@ -41,11 +41,12 @@ #include "H5Ppkg.h" /* Property lists */ /* Includes needed to set as default file driver */ -#include "H5FDsec2.h" /* Posix unbuffered I/O file driver */ +#include "H5FDsec2.h" /* Posix unbuffered I/O file driver */ #include "H5FDstdio.h" /* Standard C buffered I/O */ #ifdef H5_HAVE_WINDOWS #include "H5FDwindows.h" /* Win32 I/O */ #endif +#include "H5FDvfd_swmr.h" /* Posix unbuffered I/O file driver */ /****************/ @@ -259,6 +260,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 +312,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,7 +406,9 @@ 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 +654,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 +3659,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 +3944,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 +5055,110 @@ 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. + * Note: Hard-wired to set the driver in the fapl + * to use the SWMR VFD driver; this will be changed + * later + * + * 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") + + /* Hard-wired to use SWMR VFD */ + if(!config_ptr->vfd_swmr_writer) { + if(H5P_set_driver(plist, H5FD_VFD_SWMR, NULL) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set VFD SWMR driver info") + } + +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 2dff0f0..45b0340 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 @@ -2057,12 +2066,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_vfd_swmr_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_vfd_swmr_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); \ { /* @@ -2263,6 +2292,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/src/Makefile.am b/src/Makefile.am index 472dfc6..bc89990 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -63,7 +63,7 @@ libhdf5_la_SOURCES= H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \ H5FA.c H5FAcache.c H5FAdbg.c H5FAdblock.c H5FAdblkpage.c H5FAhdr.c \ H5FAint.c H5FAstat.c H5FAtest.c \ H5FD.c H5FDcore.c \ - H5FDfamily.c H5FDint.c H5FDlog.c \ + H5FDfamily.c H5FDint.c H5FDlog.c H5FDvfd_swmr.c \ H5FDmulti.c H5FDsec2.c H5FDspace.c H5FDstdio.c H5FDtest.c \ H5FL.c H5FO.c H5FS.c H5FScache.c H5FSdbg.c H5FSint.c H5FSsection.c \ H5FSstat.c H5FStest.c \ @@ -135,7 +135,7 @@ include_HEADERS = hdf5.h H5api_adpt.h H5overflow.h H5pubconf.h H5public.h H5vers H5Epubgen.h H5Epublic.h H5Fpublic.h \ H5FDpublic.h H5FDcore.h H5FDdirect.h \ H5FDfamily.h H5FDlog.h H5FDmpi.h H5FDmpio.h \ - H5FDmulti.h H5FDsec2.h H5FDstdio.h \ + H5FDmulti.h H5FDsec2.h H5FDstdio.h H5FDvfd_swmr.h \ H5Gpublic.h H5Ipublic.h H5Lpublic.h \ H5MMpublic.h H5Opublic.h H5Ppublic.h \ H5PLextern.h H5PLpublic.h \ @@ -47,6 +47,7 @@ #include "H5FDmulti.h" /* Usage-partitioned file family */ #include "H5FDsec2.h" /* POSIX unbuffered file I/O */ #include "H5FDstdio.h" /* Standard C buffered I/O */ +#include "H5FDvfd_swmr.h" /* VFD SWMR reader VFD */ #ifdef H5_HAVE_WINDOWS #include "H5FDwindows.h" /* Win32 I/O */ #endif diff --git a/test/Makefile.am b/test/Makefile.am index d4db6d0..bcb50ec 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..4d1695a --- /dev/null +++ b/test/vfd_swmr.c @@ -0,0 +1,691 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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"); + my_config->vfd_swmr_writer = TRUE; + + /* 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; + + /* 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; + + /* 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; + + /* + * VDF SWMR READER + */ + /* 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 = FALSE; + 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; + + + /* Open the file for reading only */ + H5E_BEGIN_TRY { + fid_read = H5Fopen("myfile", H5F_ACC_RDONLY, fapl2); + } H5E_END_TRY; + if(fid_read >= 0) + TEST_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() */ + |