summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xbin/trace1
-rw-r--r--src/H5.c6
-rw-r--r--src/H5AC.c4
-rw-r--r--src/H5ACprivate.h2
-rw-r--r--src/H5Cprivate.h2
-rw-r--r--src/H5Ctag.c6
-rw-r--r--src/H5Dint.c2
-rw-r--r--src/H5F.c31
-rw-r--r--src/H5FDint.c1
-rw-r--r--src/H5FDprivate.h122
-rw-r--r--src/H5FDvfd_swmr.c1139
-rw-r--r--src/H5FDvfd_swmr.h36
-rw-r--r--src/H5Fint.c257
-rw-r--r--src/H5Fpkg.h9
-rw-r--r--src/H5Fprivate.h22
-rw-r--r--src/H5Fpublic.h16
-rw-r--r--src/H5Fquery.c23
-rw-r--r--src/H5Pfapl.c227
-rw-r--r--src/H5Ppublic.h4
-rw-r--r--src/H5private.h30
-rw-r--r--src/Makefile.am4
-rw-r--r--src/hdf5.h1
-rw-r--r--test/Makefile.am2
-rw-r--r--test/vfd_swmr.c691
24 files changed, 2622 insertions, 16 deletions
diff --git a/bin/trace b/bin/trace
index cf41238..9712b59 100755
--- a/bin/trace
+++ b/bin/trace
@@ -117,6 +117,7 @@ $Source = "";
"H5F_info1_t" => "x",
"H5F_info2_t" => "x",
"H5F_retry_info_t" => "x",
+ "H5F_vfd_swmr_config_t" => "x",
"H5FD_t" => "x",
"H5FD_class_t" => "x",
"H5FD_stream_fapl_t" => "x",
diff --git a/src/H5.c b/src/H5.c
index 32af55b..20038fe 100644
--- a/src/H5.c
+++ b/src/H5.c
@@ -85,6 +85,12 @@ char H5_lib_vers_info_g[] = H5_VERS_INFO;
static hbool_t H5_dont_atexit_g = FALSE;
H5_debug_t H5_debug_g; /* debugging info */
+hbool_t vfd_swmr_g = FALSE;
+hbool_t vfd_swmr_writer_g = FALSE;
+uint64_t tick_num_g = 0;
+struct timespec end_of_tick_g;
+H5F_file_t *vfd_swmr_file_g;
+
/*******************/
/* Local Variables */
diff --git a/src/H5AC.c b/src/H5AC.c
index 9894e39..16bd30a 100644
--- a/src/H5AC.c
+++ b/src/H5AC.c
@@ -2760,7 +2760,7 @@ done:
*------------------------------------------------------------------------------
*/
herr_t
-H5AC_expunge_tag_type_metadata(H5F_t *f, haddr_t tag, int type_id, unsigned flags)
+H5AC_expunge_tag_type_metadata(H5F_t *f, haddr_t tag, int type_id, unsigned flags, hbool_t type_match)
{
/* Variable Declarations */
herr_t ret_value = SUCCEED;
@@ -2773,7 +2773,7 @@ H5AC_expunge_tag_type_metadata(H5F_t *f, haddr_t tag, int type_id, unsigned flag
HDassert(f->shared);
/* Call cache level function to expunge entries with specified tag and type id */
- if(H5C_expunge_tag_type_metadata(f, tag, type_id, flags) < 0)
+ if(H5C_expunge_tag_type_metadata(f, tag, type_id, flags, type_match)<0)
HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Cannot expunge tagged type entries")
done:
diff --git a/src/H5ACprivate.h b/src/H5ACprivate.h
index 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 */
diff --git a/src/H5F.c b/src/H5F.c
index 97330e5..c6db168 100644
--- a/src/H5F.c
+++ b/src/H5F.c
@@ -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 \
diff --git a/src/hdf5.h b/src/hdf5.h
index 1709375..7fb3895 100644
--- a/src/hdf5.h
+++ b/src/hdf5.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() */
+