summaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorJacob Smith <jake.smith@hdfgroup.org>2020-03-13 22:13:17 (GMT)
committerJacob Smith <jake.smith@hdfgroup.org>2020-03-13 22:13:17 (GMT)
commitb65405439d88be6c09fe94360e7fea9856697926 (patch)
treef81fc8aa14e58a3b500cdf64a6a53b7150d8ac3e /test
parent7613f7e1aa89210bb625d59d79a6220c49a1f22c (diff)
downloadhdf5-b65405439d88be6c09fe94360e7fea9856697926.zip
hdf5-b65405439d88be6c09fe94360e7fea9856697926.tar.gz
hdf5-b65405439d88be6c09fe94360e7fea9856697926.tar.bz2
Add Splitter VFD to library.
* "Simultaneous and equivalent" Read-Write and Write-Only channels for file I/O. * Only supports drivers with the H5FD_FEAT_DEFAULT_VFD_COMPATIBLE flag for now, preventing issues with multi-file drivers. Add Mirror VFD to library. * Write-only operations over a network. * Uses TCP/IP sockets. * Server and auxiliary server-shutdown programs provided in a new directory, `utils/mirror_vfd`. * Automated testing via loopback ("remote" of localhost).
Diffstat (limited to 'test')
-rw-r--r--test/CMakeLists.txt19
-rw-r--r--test/CMakeTests.cmake4
-rw-r--r--test/Makefile.am19
-rw-r--r--test/h5test.c75
-rw-r--r--test/h5test.h1
-rw-r--r--test/mirror_vfd.c2736
-rw-r--r--test/test_mirror.sh.in100
-rw-r--r--test/use.h52
-rw-r--r--test/use_append_chunk.c237
-rw-r--r--test/use_append_chunk_mirror.c403
-rw-r--r--test/use_append_mchunks.c180
-rw-r--r--test/use_common.c645
-rw-r--r--test/vfd.c1097
13 files changed, 5011 insertions, 557 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 2594477..cba1d3a 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -211,6 +211,11 @@ set (cache_image_SOURCES
${HDF5_TEST_SOURCE_DIR}/genall5.c
)
+set(mirror_vfd_SOURCES
+ ${HDF5_TEST_SOURCE_DIR}/mirror_vfd.c
+ ${HDF5_TEST_SOURCE_DIR}/genall5.c
+)
+
set (ttsafe_SOURCES
${HDF5_TEST_SOURCE_DIR}/ttsafe.c
${HDF5_TEST_SOURCE_DIR}/ttsafe_dcreate.c
@@ -273,6 +278,7 @@ set (H5_TESTS
ros3
s3comms
hdfs
+ mirror_vfd
ntypes
dangle
dtransform
@@ -310,6 +316,7 @@ set (H5_TESTS_MULTIPLE
testhdf5
cache_image
ttsafe
+ mirror_vfd
)
# Only build single source tests here
foreach (h5_test ${H5_TESTS})
@@ -389,6 +396,18 @@ else ()
endif ()
set_target_properties (ttsafe PROPERTIES FOLDER test)
+#-- Adding test for mirror_vfd
+add_executable (mirror_vfd ${mirror_vfd_SOURCES})
+target_include_directories (mirror_vfd PRIVATE "${HDF5_SRC_DIR};${HDF5_BINARY_DIR};$<$<BOOL:${HDF5_ENABLE_PARALLEL}>:${MPI_C_INCLUDE_DIRS}>")
+if (NOT BUILD_SHARED_LIBS)
+ TARGET_C_PROPERTIES (mirror_vfd STATIC)
+ target_link_libraries (mirror_vfd PRIVATE ${HDF5_TEST_LIB_TARGET})
+else ()
+ TARGET_C_PROPERTIES (mirror_vfd SHARED)
+ target_link_libraries (mirror_vfd PRIVATE ${HDF5_TEST_LIBSH_TARGET})
+endif ()
+set_target_properties (mirror_vfd PROPERTIES FOLDER test)
+
##############################################################################
### A D D I T I O N A L T E S T S ###
##############################################################################
diff --git a/test/CMakeTests.cmake b/test/CMakeTests.cmake
index b7eaa56..c73aeda 100644
--- a/test/CMakeTests.cmake
+++ b/test/CMakeTests.cmake
@@ -446,6 +446,10 @@ set (test_CLEANFILES
vds_swmr_src_*.h5
tmp_vds_env/vds_src_2.h5
direct_chunk.h5
+ splitter*.h5
+ splitter.log
+ mirror_rw/*
+ mirror_wo/*
native_vol_test.h5
)
diff --git a/test/Makefile.am b/test/Makefile.am
index dd0a579..6bea16a 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -33,9 +33,11 @@ AM_CPPFLAGS+=-I$(top_srcdir)/src -I$(top_builddir)/src
# testvdsswmr.sh: vds_swmr*
# testabort_fail.sh: filenotclosed.c and del_many_dense_attrs.c
# test_filter_plugin.sh: filter_plugin.c
+# test_mirror.sh: mirror_vfd ../utils/mirror_vfd/*
# test_usecases.sh: use_append_chunk, use_append_mchunks, use_disable_mdc_flushes
TEST_SCRIPT = testerror.sh testlibinfo.sh testcheck_version.sh testlinks_env.sh testexternal_env.sh \
- testswmr.sh testvds_env.sh testvdsswmr.sh testflushrefresh.sh test_usecases.sh testabort_fail.sh
+ testswmr.sh testvds_env.sh testvdsswmr.sh testflushrefresh.sh test_usecases.sh testabort_fail.sh \
+ test_mirror.sh
SCRIPT_DEPEND = error_test$(EXEEXT) err_compat$(EXEEXT) links_env$(EXEEXT) \
external_env$(EXEEXT) filenotclosed$(EXEEXT) del_many_dense_attrs$(EXEEXT) \
flushrefresh$(EXEEXT) use_append_chunk$(EXEEXT) use_append_mchunks$(EXEEXT) use_disable_mdc_flushes$(EXEEXT) \
@@ -78,16 +80,18 @@ TEST_PROG= testhdf5 \
# swmr_* files (besides swmr.c) are used by testswmr.sh.
# vds_swmr_* files are used by testvdsswmr.sh
# vds_env is used by testvds_env.sh
+# mirror_vfd is used by test_mirror.sh
# 'make check' doesn't run them directly, so they are not included in TEST_PROG.
# Also build testmeta, which is used for timings test. It builds quickly,
# and this lets automake keep all its test programs in one place.
check_PROGRAMS=$(TEST_PROG) error_test err_compat tcheck_version \
testmeta accum_swmr_reader atomic_writer atomic_reader external_env \
links_env filenotclosed del_many_dense_attrs flushrefresh \
- use_append_chunk use_append_mchunks use_disable_mdc_flushes \
+ use_append_chunk use_append_chunk_mirror use_append_mchunks use_disable_mdc_flushes \
swmr_generator swmr_start_write swmr_reader swmr_writer swmr_remove_reader \
swmr_remove_writer swmr_addrem_writer swmr_sparse_reader swmr_sparse_writer \
- swmr_check_compat_vfd vds_env vds_swmr_gen vds_swmr_reader vds_swmr_writer
+ swmr_check_compat_vfd vds_env vds_swmr_gen vds_swmr_reader vds_swmr_writer \
+ mirror_vfd
if HAVE_SHARED_CONDITIONAL
check_PROGRAMS+= filter_plugin vol_plugin
endif
@@ -144,6 +148,7 @@ LDADD=libh5test.la $(LIBHDF5)
ttsafe_SOURCES=ttsafe.c ttsafe_dcreate.c ttsafe_error.c ttsafe_cancel.c \
ttsafe_acreate.c
cache_image_SOURCES=cache_image.c genall5.c
+mirror_vfd_SOURCES=mirror_vfd.c genall5.c
VFD_LIST = sec2 stdio core core_paged split multi family
if DIRECT_VFD_CONDITIONAL
@@ -213,7 +218,8 @@ CHECK_CLEANFILES+=accum.h5 cmpd_dset.h5 compact_dataset.h5 dataset.h5 dset_offse
flushrefresh_VERIFICATION_DONE atomic_data accum_swmr_big.h5 ohdr_swmr.h5 \
test_swmr*.h5 cache_logging.h5 cache_logging.out vds_swmr.h5 vds_swmr_src_*.h5 \
swmr[0-2].h5 swmr_writer.out swmr_writer.log.* swmr_reader.out.* swmr_reader.log.* \
- tbogus.h5.copy cache_image_test.h5 direct_chunk.h5 native_vol_test.h5
+ tbogus.h5.copy cache_image_test.h5 direct_chunk.h5 native_vol_test.h5 \
+ splitter*.h5 splitter.log
# Sources for testhdf5 executable
testhdf5_SOURCES=testhdf5.c tarray.c tattr.c tchecksum.c tconfig.c tfile.c \
@@ -223,12 +229,13 @@ testhdf5_SOURCES=testhdf5.c tarray.c tattr.c tchecksum.c tconfig.c tfile.c \
# Sources for Use Cases
use_append_chunk_SOURCES=use_append_chunk.c use_common.c
+use_append_chunk_mirror_SOURCES=use_append_chunk_mirror.c use_common.c
use_append_mchunks_SOURCES=use_append_mchunks.c use_common.c
use_disable_mdc_flushes_SOURCES=use_disable_mdc_flushes.c
# Temporary files.
DISTCLEANFILES=testerror.sh testlibinfo.sh testcheck_version.sh testlinks_env.sh test_filter_plugin.sh \
- testexternal_env.sh testswmr.sh testvds_env.sh testvdsswmr.sh test_usecases.sh testflushrefresh.sh testabort_fail.sh \
- test_vol_plugin.sh
+ testexternal_env.sh testswmr.sh testvds_env.sh testvdsswmr.sh test_usecases.sh testflushrefresh.sh \
+ testabort_fail.sh test_vol_plugin.sh test_mirror.sh
include $(top_srcdir)/config/conclude.am
diff --git a/test/h5test.c b/test/h5test.c
index 03731c6..e7d91b6 100644
--- a/test/h5test.c
+++ b/test/h5test.c
@@ -2043,6 +2043,80 @@ h5_get_version_string(H5F_libver_t libver)
} /* end of h5_get_version_string */
/*-------------------------------------------------------------------------
+ * Function: h5_compare_file_bytes()
+ *
+ * Purpose: Helper function to compare two files byte-for-byte.
+ *
+ * Return: Success: 0, if files are identical
+ * Failure: -1, if files differ
+ *
+ * Programmer: Binh-Minh Ribler
+ * October, 2018
+ *-------------------------------------------------------------------------
+ */
+int
+h5_compare_file_bytes(char *f1name, char *f2name)
+{
+ FILE *f1ptr = NULL; /* two file pointers */
+ FILE *f2ptr = NULL;
+ hsize_t f1size = 0; /* size of the files */
+ hsize_t f2size = 0;
+ char f1char = 0; /* one char from each file */
+ char f2char = 0;
+ hsize_t ii = 0;
+ int ret_value = 0; /* for error handling */
+
+ /* Open files for reading */
+ f1ptr = fopen(f1name, "r");
+ if (f1ptr == NULL) {
+ HDfprintf(stderr, "Unable to fopen() %s\n", f1name);
+ ret_value = -1;
+ goto done;
+ }
+ f2ptr = fopen(f2name, "r");
+ if (f2ptr == NULL) {
+ HDfprintf(stderr, "Unable to fopen() %s\n", f2name);
+ ret_value = -1;
+ goto done;
+ }
+
+ /* Get the file sizes and verify that they equal */
+ fseek(f1ptr , 0 , SEEK_END);
+ f1size = ftell(f1ptr);
+
+ fseek(f2ptr , 0 , SEEK_END);
+ f2size = ftell(f2ptr);
+
+ if (f1size != f2size) {
+ HDfprintf(stderr, "Files differ in size, %llu vs. %llu\n", f1size, f2size);
+ ret_value = -1;
+ goto done;
+ }
+
+ /* Compare each byte and fail if a difference is found */
+ rewind(f1ptr);
+ rewind(f2ptr);
+ for (ii = 0; ii < f1size; ii++) {
+ fread(&f1char, 1, 1, f1ptr);
+ fread(&f2char, 1, 1, f2ptr);
+ if (f1char != f2char) {
+ HDfprintf(stderr, "Mismatch @ 0x%llX: 0x%X != 0x%X\n", ii, f1char, f2char);
+ ret_value = -1;
+ goto done;
+ }
+ }
+
+done:
+ if (f1ptr) {
+ fclose(f1ptr);
+ }
+ if (f2ptr) {
+ fclose(f2ptr);
+ }
+ return(ret_value);
+} /* end h5_compare_file_bytes() */
+
+/*-------------------------------------------------------------------------
* Function: H5_get_srcdir_filename
*
* Purpose: Append the test file name to the srcdir path and return the whole string
@@ -2094,3 +2168,4 @@ const char *H5_get_srcdir(void)
else
return(NULL);
} /* end H5_get_srcdir() */
+
diff --git a/test/h5test.h b/test/h5test.h
index e67e559..39ec9d7 100644
--- a/test/h5test.h
+++ b/test/h5test.h
@@ -150,6 +150,7 @@ H5TEST_DLL herr_t h5_verify_cached_stabs(const char *base_name[], hid_t fapl);
H5TEST_DLL H5FD_class_t *h5_get_dummy_vfd_class(void);
H5TEST_DLL H5VL_class_t *h5_get_dummy_vol_class(void);
H5TEST_DLL const char *h5_get_version_string(H5F_libver_t libver);
+H5TEST_DLL int h5_compare_file_bytes(char *fname1, char *fname2);
/* Functions that will replace components of a FAPL */
H5TEST_DLL herr_t h5_get_vfd_fapl(hid_t fapl_id);
diff --git a/test/mirror_vfd.c b/test/mirror_vfd.c
new file mode 100644
index 0000000..00902dd
--- /dev/null
+++ b/test/mirror_vfd.c
@@ -0,0 +1,2736 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * 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: Test the Mirror VFD functionality.
+ */
+
+/* WARNING: The use of realpath() is probably system-dependent, as are
+ * other things here such as the socket calls.
+ * Notable to realpath() in particular is the use of "PATH_MAX", which
+ * apparently has some major potential issues if paths are abused.
+ * http://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html
+ * so BE CAREFUL about the paths we throw around?
+ */
+
+#include "h5test.h"
+#include "cache_common.h"
+#include "genall5.h"
+
+#ifdef H5_HAVE_MIRROR_VFD
+
+/* For future consideration, IP address and port number might be
+ * environment variables?
+ */
+#define SERVER_IP_ADDRESS "127.0.0.1"
+
+/* Primary listening port on server. */
+#define SERVER_HANDSHAKE_PORT 3000
+
+#define DATABUFFER_SIZE 128
+#define DSET_NAME_LEN 16
+
+/* Parameters for the "large chunked dataset" writing */
+#define MAX_DSET_COUNT 255
+#define DSET_DIM 32
+#define CHUNK_DIM 8
+
+#define CONCURRENT_COUNT 3 /* Number of files in concurrent test */
+
+/* Macro: LOGPRINT()
+ * Prints logging and debugging messages to the output stream based
+ * on the level of verbosity.
+ * 0 : no logging
+ * 1 : errors only
+ * 2 : details
+ * 3 : all
+ */
+#define DEFAULT_VERBOSITY 1
+static unsigned int g_verbosity = DEFAULT_VERBOSITY;
+
+/* Macro for selective debug printing / logging */
+#define LOGPRINT(lvl, ...) \
+do { \
+ if ((lvl) <= g_verbosity) { \
+ fprintf(g_log_stream, __VA_ARGS__); \
+ fflush(g_log_stream); \
+ } \
+} while (0)
+
+#define MIRROR_RW_DIR "mirror_rw/"
+#define MIRROR_WO_DIR "mirror_wo/"
+
+/* String buffer for error messages */
+#define MIRR_MESG_SIZE 128
+static char mesg[MIRR_MESG_SIZE + 1];
+
+/* Convenience structure for passing file names via helper functions.
+ */
+struct mirrortest_filenames {
+ char rw[H5FD_SPLITTER_PATH_MAX+1];
+ char wo[H5FD_SPLITTER_PATH_MAX+1];
+ char log[H5FD_SPLITTER_PATH_MAX+1];
+};
+
+static FILE *g_log_stream = NULL; /* initialized at runtime */
+
+static herr_t _verify_datasets(unsigned min_dset, unsigned max_dset,
+ hid_t *filespace_id, hid_t *dataset_id, hid_t memspace_id);
+
+static herr_t _create_chunking_ids(hid_t file_id, unsigned min_dset,
+ unsigned max_dset, hsize_t *chunk_dims, hsize_t *dset_dims,
+ hid_t *dataspace_ids, hid_t *filespace_ids, hid_t *dataset_ids,
+ hid_t *memspace_id);
+
+static herr_t _close_chunking_ids(unsigned min_dset, unsigned max_dset,
+ hid_t *dataspace_ids, hid_t *filespace_ids, hid_t *dataset_ids,
+ hid_t *memspace_id);
+
+static herr_t _populate_filepath(const char *dirname, const char *_basename,
+ hid_t fapl_id, char *path_out, hbool_t h5suffix);
+
+static hid_t create_mirroring_split_fapl(const char *_basename,
+ struct mirrortest_filenames *names);
+
+
+/* ----------------------------------------------------------------------------
+ * Function: _populate_filepath
+ *
+ * Purpose: Given a directory name and a base name, concatenate the two and
+ * run h5fixname() to get the "actual" path to the intented target.
+ * `h5suffix' should be FALSE to keep the base name unaltered;
+ * TRUE will append the '.h5' h5suffix to the basename...
+ * FALSE -> h5fixname_no_suffix(), TRUE -> h5fixname()
+ * <h5fixname_prefix> / <dirname> / <_basename> <h5prefix?>
+ *
+ * Programmer: Jacob Smith
+ * 2019-08-16
+ * ----------------------------------------------------------------------------
+ */
+static herr_t
+_populate_filepath(const char *dirname, const char *_basename, hid_t fapl_id,
+ char *path_out, hbool_t h5suffix)
+{
+ char _path[H5FD_SPLITTER_PATH_MAX];
+
+ if ((_basename == NULL) ||
+ (*_basename == 0) ||
+ (dirname == NULL) ||
+ (*dirname == 0) ||
+ (path_out == NULL))
+ {
+ TEST_ERROR;
+ }
+
+ if (HDsnprintf(_path, H5FD_SPLITTER_PATH_MAX, "%s%s%s", dirname,
+ (dirname[strlen(dirname)] == '/') ? "" : "/", /* slash iff needed */
+ _basename)
+ > H5FD_SPLITTER_PATH_MAX)
+ {
+ TEST_ERROR;
+ }
+
+ if (h5suffix == TRUE) {
+ if (h5_fixname(_path, fapl_id, path_out,
+ H5FD_SPLITTER_PATH_MAX)
+ == NULL)
+ {
+ TEST_ERROR;
+ }
+ }
+ else {
+ if (h5_fixname_no_suffix(_path, fapl_id, path_out,
+ H5FD_SPLITTER_PATH_MAX)
+ == NULL)
+ {
+ TEST_ERROR;
+ }
+ }
+
+ return SUCCEED;
+
+error:
+ return FAIL;
+} /* end _populate_filepath() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: build_paths
+ *
+ * Purpose: Convenience function to create the three file paths used in
+ * most mirror tests.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Jacob Smith
+ * 2019-08-16
+ * ---------------------------------------------------------------------------
+ */
+static herr_t
+build_paths(
+ const char *_basename,
+ H5FD_splitter_vfd_config_t *splitter_config,
+ struct mirrortest_filenames *names)
+{
+ char baselogname[H5FD_SPLITTER_PATH_MAX];
+
+ if (_populate_filepath(MIRROR_RW_DIR, _basename,
+ splitter_config->rw_fapl_id, names->rw, TRUE)
+ == FAIL)
+ {
+ TEST_ERROR;
+ }
+
+ if (_populate_filepath(MIRROR_WO_DIR, _basename,
+ splitter_config->wo_fapl_id, names->wo, TRUE)
+ == FAIL)
+ {
+ TEST_ERROR;
+ }
+
+ if (_basename == NULL || *_basename == 0)
+ return FAIL;
+ if (HDsnprintf(baselogname, H5FD_SPLITTER_PATH_MAX, "%s_err.log",
+ _basename)
+ > H5FD_SPLITTER_PATH_MAX)
+ {
+ TEST_ERROR;
+ }
+
+ if (_populate_filepath(MIRROR_WO_DIR, baselogname,
+ splitter_config->wo_fapl_id, names->log, FALSE)
+ == FAIL)
+ {
+ TEST_ERROR;
+ }
+
+ return SUCCEED;
+
+error:
+ return FAIL;
+} /* end build_paths() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: test_fapl_configuration
+ *
+ * Purpose: Test FAPL configuration and examination.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Jacob Smith
+ * 2019-03-12
+ * ---------------------------------------------------------------------------
+ */
+static int
+test_fapl_configuration(void)
+{
+ hid_t fapl_id;
+ H5FD_mirror_fapl_t mirror_conf = {
+ H5FD_MIRROR_FAPL_MAGIC, /* magic */
+ H5FD_MIRROR_CURR_FAPL_T_VERSION, /* version */
+ SERVER_HANDSHAKE_PORT, /* handhake_port */
+ SERVER_IP_ADDRESS, /* remote_ip "IP address" */
+ };
+ H5FD_mirror_fapl_t fa_out = {0, 0, 0, ""};
+
+ TESTING("Mirror fapl configuration (set/get)");
+
+ fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ if (H5I_INVALID_HID == fapl_id) {
+ TEST_ERROR;
+ }
+
+ if (H5Pset_fapl_mirror(fapl_id, &mirror_conf) == FAIL) {
+ TEST_ERROR;
+ }
+
+ if (H5Pget_fapl_mirror(fapl_id, &fa_out) == FAIL) {
+ TEST_ERROR;
+ }
+ if (H5FD_MIRROR_FAPL_MAGIC != fa_out.magic) {
+ TEST_ERROR;
+ }
+ if (H5FD_MIRROR_CURR_FAPL_T_VERSION != fa_out.version) {
+ TEST_ERROR;
+ }
+ if (SERVER_HANDSHAKE_PORT != fa_out.handshake_port) {
+ TEST_ERROR;
+ }
+ if (HDstrncmp(SERVER_IP_ADDRESS, (const char *)fa_out.remote_ip,
+ H5FD_MIRROR_MAX_IP_LEN))
+ {
+ TEST_ERROR;
+ }
+
+ if (H5Pclose(fapl_id) == FAIL) {
+ TEST_ERROR;
+ }
+
+ PASSED();
+ return 0;
+
+error:
+ if (H5I_INVALID_HID != fapl_id) {
+ (void)H5Pclose(fapl_id);
+ }
+ return -1;
+} /* end test_fapl_configuration() */
+
+
+
+#define PRINT_BUFFER_DIFF(act, exp, len) do { \
+ size_t _x = 0; \
+ while ((act)[_x] == (exp)[_x]) { \
+ _x++; \
+ } \
+ if (_x != (len)) { \
+ size_t _y = 0; \
+ HDprintf("First bytes differ at %zu\n", _x); \
+ HDprintf("exp "); \
+ for (_y = _x; _y < (len); _y++) { \
+ HDprintf("%02X", (unsigned char)(exp)[_y]); \
+ } \
+ HDprintf("\nact "); \
+ for (_y = _x; _y < (len); _y++) { \
+ HDprintf("%02X", (unsigned char)(act)[_y]); \
+ } \
+ HDprintf("\n"); \
+ } \
+} while (0); /* end PRINT_BUFFER_DIFF */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: test_xmit_encode_decode
+ *
+ * Purpose: Test byte-encoding operations for network transport.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Jacob Smith
+ * 2020-02-02
+ * ---------------------------------------------------------------------------
+ */
+static int
+test_xmit_encode_decode(void)
+{
+ H5FD_mirror_xmit_t xmit_mock; /* re-used header in various xmit tests */
+
+ TESTING("Mirror encode/decode of xmit elements");
+
+ /* Set bogus values matching expected; encoding doesn't care
+ * Use sequential values to easily generate the expected buffer with a
+ * for loop.
+ */
+ xmit_mock.magic = 0x00010203;
+ xmit_mock.version = 0x04;
+ xmit_mock.session_token = 0x05060708;
+ xmit_mock.xmit_count = 0x090A0B0C;
+ xmit_mock.op = 0x0D;
+
+ /* Test uint8_t encode/decode
+ */
+ do {
+ unsigned char buf[8];
+ unsigned char expected[8];
+ const uint8_t v = 200;
+ unsigned char out = 0;
+
+ /* Start of buffer uint8_t
+ */
+ HDbzero(buf, 8);
+ HDbzero(expected, 8);
+ expected[0] = 200;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint8(buf, v) != 1) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint8(&out, buf) != 1) {
+ TEST_ERROR;
+ }
+ if (v != out) {
+ TEST_ERROR;
+ }
+
+ /* Middle of buffer uint8_t
+ */
+ HDbzero(buf, 8);
+ HDbzero(expected, 8);
+ expected[3] = v;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint8((buf+3), v) != 1) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint8(&out, (buf+3)) != 1) {
+ TEST_ERROR;
+ }
+ if (v != out) {
+ TEST_ERROR;
+ }
+
+ /* End of buffer uint8_t
+ */
+ HDbzero(buf, 8);
+ HDbzero(expected, 8);
+ expected[7] = v;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint8((buf+7), v) != 1) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint8(&out, (buf+7)) != 1) {
+ TEST_ERROR;
+ }
+ if (v != out) {
+ TEST_ERROR;
+ }
+
+ } while (0); /* end uint8_t en/decode */
+
+ /* Test uint16_t encode/decode
+ */
+ do {
+ unsigned char buf[8];
+ unsigned char expected[8];
+ const uint16_t v = 0x8F02;
+ uint16_t out = 0;
+
+ /* Start of buffer uint16_t
+ */
+ HDbzero(buf, 8);
+ HDbzero(expected, 8);
+ expected[0] = 0x8F;
+ expected[1] = 0x02;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint16(buf, v) != 2) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint16(&out, buf) != 2) {
+ TEST_ERROR;
+ }
+ if (out != v) {
+ TEST_ERROR;
+ }
+
+ /* Middle of buffer uint16_t
+ */
+ HDbzero(buf, 8);
+ HDbzero(expected, 8);
+ expected[3] = 0x8F;
+ expected[4] = 0x02;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint16((buf+3), v) != 2) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint16(&out, (buf+3)) != 2) {
+ TEST_ERROR;
+ }
+ if (out != v) {
+ TEST_ERROR;
+ }
+ /* slice */
+ if (H5FD__mirror_xmit_decode_uint16(&out, (buf+4)) != 2) {
+ TEST_ERROR;
+ }
+ if (out != 0x0200) {
+ TEST_ERROR;
+ }
+
+ /* End of buffer uint16_t
+ */
+ HDbzero(buf, 8);
+ HDbzero(expected, 8);
+ expected[6] = 0x8F;
+ expected[7] = 0x02;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint16((buf+6), v) != 2) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint16(&out, (buf+6)) != 2) {
+ TEST_ERROR;
+ }
+ if (out != v) {
+ TEST_ERROR;
+ }
+
+ } while (0); /* end uint16_t en/decode */
+
+ /* Test uint32_t encode/decode
+ */
+ do {
+ unsigned char buf[8];
+ unsigned char expected[8];
+ const uint32_t v = 0x8F020048;
+ uint32_t out = 0;
+
+ /* Start of buffer uint32_t
+ */
+ HDbzero(buf, 8);
+ HDbzero(expected, 8);
+ expected[0] = 0x8F;
+ expected[1] = 0x02;
+ expected[2] = 0x00;
+ expected[3] = 0x48;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint32(buf, v) != 4) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint32(&out, buf) != 4) {
+ TEST_ERROR;
+ }
+ if (out != v) {
+ TEST_ERROR;
+ }
+
+ /* Middle of buffer uint32_t
+ */
+ HDbzero(buf, 8);
+ HDbzero(expected, 8);
+ expected[3] = 0x8F;
+ expected[4] = 0x02;
+ expected[5] = 0x00;
+ expected[6] = 0x48;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint32((buf+3), v) != 4) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint32(&out, (buf+3)) != 4) {
+ TEST_ERROR;
+ }
+ if (out != v) {
+ TEST_ERROR;
+ }
+ /* slice */
+ if (H5FD__mirror_xmit_decode_uint32(&out, (buf+4)) != 4) {
+ TEST_ERROR;
+ }
+ if (out != 0x02004800) {
+ TEST_ERROR;
+ }
+
+ /* End of buffer uint32_t
+ */
+ HDbzero(buf, 8);
+ HDbzero(expected, 8);
+ expected[4] = 0x8F;
+ expected[5] = 0x02;
+ expected[6] = 0x00;
+ expected[7] = 0x48;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint32((buf+4), v) != 4) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint32(&out, (buf+4)) != 4) {
+ TEST_ERROR;
+ }
+ if (out != v) {
+ TEST_ERROR;
+ }
+
+ } while (0); /* end uint32_t en/decode */
+
+ /* Test uint64_t encode/decode
+ */
+ do {
+ unsigned char buf[16];
+ unsigned char expected[16];
+ const uint64_t v = 0x90DCBE17939CE4BB;
+ uint64_t out = 0;
+
+ /* Start of buffer uint64_t
+ */
+ HDbzero(buf, 16);
+ HDbzero(expected, 16);
+ expected[0] = 0x90;
+ expected[1] = 0xDC;
+ expected[2] = 0xBE;
+ expected[3] = 0x17;
+ expected[4] = 0x93;
+ expected[5] = 0x9C;
+ expected[6] = 0xE4;
+ expected[7] = 0xBB;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint64(buf, v) != 8) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 16) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 16);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint64(&out, buf) != 8) {
+ TEST_ERROR;
+ }
+ if (out != v) {
+ TEST_ERROR;
+ }
+
+ /* Middle of buffer uint64_t
+ */
+ HDbzero(buf, 16);
+ HDbzero(expected, 16);
+ expected[3] = 0x90;
+ expected[4] = 0xDC;
+ expected[5] = 0xBE;
+ expected[6] = 0x17;
+ expected[7] = 0x93;
+ expected[8] = 0x9C;
+ expected[9] = 0xE4;
+ expected[10] = 0xBB;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint64((buf+3), v) != 8) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 16) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 16);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint64(&out, (buf+3)) != 8) {
+ TEST_ERROR;
+ }
+ if (out != v) {
+ TEST_ERROR;
+ }
+ /* slice */
+ if (H5FD__mirror_xmit_decode_uint64(&out, (buf+6)) != 8) {
+ TEST_ERROR;
+ }
+ if (out != 0x17939CE4BB000000) {
+ TEST_ERROR;
+ }
+
+ /* End of buffer uint64_t
+ */
+ HDbzero(buf, 16);
+ HDbzero(expected, 16);
+ expected[8] = 0x90;
+ expected[9] = 0xDC;
+ expected[10] = 0xBE;
+ expected[11] = 0x17;
+ expected[12] = 0x93;
+ expected[13] = 0x9C;
+ expected[14] = 0xE4;
+ expected[15] = 0xBB;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint64((buf+8), v) != 8) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 16) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 16);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint64(&out, (buf+8)) != 8) {
+ TEST_ERROR;
+ }
+ if (out != v) {
+ TEST_ERROR;
+ }
+
+ } while (0); /* end uint64_t en/decode */
+
+ /* Test xmit header structure encode/decode
+ * Write bogus but easily verifiable data to inside a buffer, and compare.
+ * Then decode the buffer and compare the structure contents.
+ * Then repeat from a different offset in the buffer and compare.
+ */
+ do {
+ unsigned char buf[H5FD_MIRROR_XMIT_HEADER_SIZE+8];
+ unsigned char expected[H5FD_MIRROR_XMIT_HEADER_SIZE+8];
+ H5FD_mirror_xmit_t xmit_out;
+ size_t i = 0;
+
+ /* sanity check */
+ if (14 != H5FD_MIRROR_XMIT_HEADER_SIZE) {
+ FAIL_PUTS_ERROR("Header size definition does not match test\n");
+ }
+
+ /* Populate the expected buffer; expect end padding of 0xFF
+ */
+ HDmemset(expected, 0xFF, H5FD_MIRROR_XMIT_HEADER_SIZE+8);
+ for (i=0; i < H5FD_MIRROR_XMIT_HEADER_SIZE; i++) {
+ expected[i+2] = (unsigned char)i;
+ }
+
+ /* Encode, and compare buffer contents
+ * Initial buffer is filled with 0xFF to match expected padding
+ */
+ HDmemset(buf, 0xFF, H5FD_MIRROR_XMIT_HEADER_SIZE+8);
+ if (H5FD_mirror_xmit_encode_header((buf+2), &xmit_mock)
+ != H5FD_MIRROR_XMIT_HEADER_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, H5FD_MIRROR_XMIT_HEADER_SIZE+8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, H5FD_MIRROR_XMIT_HEADER_SIZE+8);
+ TEST_ERROR;
+ }
+
+ /* Decode from buffer
+ */
+ if (H5FD_mirror_xmit_decode_header(&xmit_out, (buf+2))
+ != H5FD_MIRROR_XMIT_HEADER_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.magic != xmit_mock.magic) TEST_ERROR;
+ if (xmit_out.version != xmit_mock.version) TEST_ERROR;
+ if (xmit_out.session_token != xmit_mock.session_token) TEST_ERROR;
+ if (xmit_out.xmit_count != xmit_mock.xmit_count) TEST_ERROR;
+ if (xmit_out.op != xmit_mock.op) TEST_ERROR;
+
+ /* Decode from different offset in buffer
+ * Observe changes when ingesting the padding
+ */
+ if (H5FD_mirror_xmit_decode_header(&xmit_out, (buf))
+ != H5FD_MIRROR_XMIT_HEADER_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.magic != 0xFFFF0001) TEST_ERROR;
+ if (xmit_out.version != 0x02) TEST_ERROR;
+ if (xmit_out.session_token != 0x03040506) TEST_ERROR;
+ if (xmit_out.xmit_count != 0x0708090A) TEST_ERROR;
+ if (xmit_out.op != 0x0B) TEST_ERROR;
+
+ } while (0); /* end xmit header en/decode */
+
+ /* Test xmit set-eoa structure encode/decode
+ * Write bogus but easily verifiable data to inside a buffer, and compare.
+ * Then decode the buffer and compare the structure contents.
+ * Then repeat from a different offset in the buffer and compare.
+ */
+ do {
+ unsigned char buf[H5FD_MIRROR_XMIT_EOA_SIZE+8];
+ unsigned char expected[H5FD_MIRROR_XMIT_EOA_SIZE+8];
+ H5FD_mirror_xmit_eoa_t xmit_in;
+ H5FD_mirror_xmit_eoa_t xmit_out;
+ size_t i = 0;
+
+ /* sanity check */
+ if ((14+9) != H5FD_MIRROR_XMIT_EOA_SIZE) {
+ FAIL_PUTS_ERROR("Header size definition does not match test\n");
+ }
+ if (xmit_mock.op != 0x0D) {
+ FAIL_PUTS_ERROR("shared header structure is not in expected state");
+ }
+
+ /* Populate the expected buffer; expect end padding of 0xFF
+ */
+ HDmemset(expected, 0xFF, H5FD_MIRROR_XMIT_EOA_SIZE+8);
+ for (i=0; i < H5FD_MIRROR_XMIT_EOA_SIZE; i++) {
+ expected[i+2] = (unsigned char)i;
+ }
+
+ /* Set xmit_in
+ */
+ xmit_in.pub = xmit_mock; /* shared/common */
+ xmit_in.type = 0x0E;
+ xmit_in.eoa_addr = 0x0F10111213141516;
+
+ /* Encode, and compare buffer contents
+ * Initial buffer is filled with 0xFF to match expected padding
+ */
+ HDmemset(buf, 0xFF, H5FD_MIRROR_XMIT_EOA_SIZE+8);
+ if (H5FD_mirror_xmit_encode_set_eoa((buf+2), &xmit_in)
+ != H5FD_MIRROR_XMIT_EOA_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, H5FD_MIRROR_XMIT_EOA_SIZE+8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, H5FD_MIRROR_XMIT_EOA_SIZE+8);
+ TEST_ERROR;
+ }
+
+ /* Decode from buffer
+ */
+ if (H5FD_mirror_xmit_decode_set_eoa(&xmit_out, (buf+2))
+ != H5FD_MIRROR_XMIT_EOA_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.pub.magic != xmit_mock.magic) TEST_ERROR;
+ if (xmit_out.pub.version != xmit_mock.version) TEST_ERROR;
+ if (xmit_out.pub.session_token != xmit_mock.session_token) TEST_ERROR;
+ if (xmit_out.pub.xmit_count != xmit_mock.xmit_count) TEST_ERROR;
+ if (xmit_out.pub.op != xmit_mock.op) TEST_ERROR;
+ if (xmit_out.type != 0x0E) TEST_ERROR;
+ if (xmit_out.eoa_addr != 0x0F10111213141516) TEST_ERROR;
+
+ /* Decode from different offset in buffer
+ * Observe changes when ingesting the padding
+ */
+ if (H5FD_mirror_xmit_decode_set_eoa(&xmit_out, (buf))
+ != H5FD_MIRROR_XMIT_EOA_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.pub.magic != 0xFFFF0001) TEST_ERROR;
+ if (xmit_out.pub.version != 0x02) TEST_ERROR;
+ if (xmit_out.pub.session_token != 0x03040506) TEST_ERROR;
+ if (xmit_out.pub.xmit_count != 0x0708090A) TEST_ERROR;
+ if (xmit_out.pub.op != 0x0B) TEST_ERROR;
+ if (xmit_out.type != 0x0C) TEST_ERROR;
+ if (xmit_out.eoa_addr != 0x0D0E0F1011121314) TEST_ERROR;
+
+ } while (0); /* end xmit set-eoa en/decode */
+
+ /* Test xmit lock structure encode/decode
+ * Write bogus but easily verifiable data to inside a buffer, and compare.
+ * Then decode the buffer and compare the structure contents.
+ * Then repeat from a different offset in the buffer and compare.
+ */
+ do {
+ unsigned char buf[H5FD_MIRROR_XMIT_LOCK_SIZE+8];
+ unsigned char expected[H5FD_MIRROR_XMIT_LOCK_SIZE+8];
+ H5FD_mirror_xmit_lock_t xmit_in;
+ H5FD_mirror_xmit_lock_t xmit_out;
+ size_t i = 0;
+
+ /* sanity check */
+ if ((14+8) != H5FD_MIRROR_XMIT_LOCK_SIZE) {
+ FAIL_PUTS_ERROR("Header size definition does not match test\n");
+ }
+ if (xmit_mock.op != 0x0D) {
+ FAIL_PUTS_ERROR("shared header structure is not in expected state");
+ }
+
+ /* Populate the expected buffer; expect end padding of 0xFF
+ */
+ HDmemset(expected, 0xFF, H5FD_MIRROR_XMIT_LOCK_SIZE+8);
+ for (i=0; i < H5FD_MIRROR_XMIT_LOCK_SIZE; i++) {
+ expected[i+2] = (unsigned char)i;
+ }
+
+ /* Set xmit_in
+ */
+ xmit_in.pub = xmit_mock; /* shared/common */
+ xmit_in.rw = 0x0E0F101112131415;
+
+ /* Encode, and compare buffer contents
+ * Initial buffer is filled with 0xFF to match expected padding
+ */
+ HDmemset(buf, 0xFF, H5FD_MIRROR_XMIT_LOCK_SIZE+8);
+ if (H5FD_mirror_xmit_encode_lock((buf+2), &xmit_in)
+ != H5FD_MIRROR_XMIT_LOCK_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, H5FD_MIRROR_XMIT_LOCK_SIZE+8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, H5FD_MIRROR_XMIT_LOCK_SIZE+8);
+ TEST_ERROR;
+ }
+
+ /* Decode from buffer
+ */
+ if (H5FD_mirror_xmit_decode_lock(&xmit_out, (buf+2))
+ != H5FD_MIRROR_XMIT_LOCK_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.pub.magic != xmit_mock.magic) TEST_ERROR;
+ if (xmit_out.pub.version != xmit_mock.version) TEST_ERROR;
+ if (xmit_out.pub.session_token != xmit_mock.session_token) TEST_ERROR;
+ if (xmit_out.pub.xmit_count != xmit_mock.xmit_count) TEST_ERROR;
+ if (xmit_out.pub.op != xmit_mock.op) TEST_ERROR;
+ if (xmit_out.rw != 0x0E0F101112131415) TEST_ERROR;
+
+ /* Decode from different offset in buffer
+ * Observe changes when ingesting the padding
+ */
+ if (H5FD_mirror_xmit_decode_lock(&xmit_out, (buf))
+ != H5FD_MIRROR_XMIT_LOCK_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.pub.magic != 0xFFFF0001) TEST_ERROR;
+ if (xmit_out.pub.version != 0x02) TEST_ERROR;
+ if (xmit_out.pub.session_token != 0x03040506) TEST_ERROR;
+ if (xmit_out.pub.xmit_count != 0x0708090A) TEST_ERROR;
+ if (xmit_out.pub.op != 0x0B) TEST_ERROR;
+ if (xmit_out.rw != 0x0C0D0E0F10111213) TEST_ERROR;
+
+ } while (0); /* end xmit lock en/decode */
+
+ /* Test xmit open structure encode/decode
+ * Write bogus but easily verifiable data to inside a buffer, and compare.
+ * Then decode the buffer and compare the structure contents.
+ * Then repeat from a different offset in the buffer and compare.
+ *
+ * Verifies that the first zero character in the filepath will end the
+ * string, with all following bytes in the encoded buffer being zeroed.
+ */
+ do {
+ unsigned char buf[H5FD_MIRROR_XMIT_OPEN_SIZE+8];
+ unsigned char expected[H5FD_MIRROR_XMIT_OPEN_SIZE+8];
+ H5FD_mirror_xmit_open_t xmit_in;
+ H5FD_mirror_xmit_open_t xmit_out;
+ size_t i = 0;
+
+ /* sanity check */
+ if ((14+20+4097) != H5FD_MIRROR_XMIT_OPEN_SIZE) {
+ FAIL_PUTS_ERROR("Header size definition does not match test\n");
+ }
+ if (xmit_mock.op != 0x0D) {
+ FAIL_PUTS_ERROR("shared header structure is not in expected state");
+ }
+
+ /* Populate the expected buffer; expect end padding of 0xFF
+ */
+ HDmemset(expected, 0xFF, H5FD_MIRROR_XMIT_OPEN_SIZE+8);
+ for (i=0; i < H5FD_MIRROR_XMIT_OPEN_SIZE; i++) {
+ /* 0x100 is "zero" in a byte, so encode will treat it as a NULL-
+ * terminator in the filepath string. Expect all zeroes following.
+ */
+ expected[i+2] = (i > 0xFF) ? 0 : (unsigned char)i;
+ }
+
+ /* Set xmit_in
+ */
+ xmit_in.pub = xmit_mock; /* shared/common */
+ xmit_in.flags = 0x0E0F1011;
+ xmit_in.maxaddr = 0x1213141516171819;
+ xmit_in.size_t_blob = 0x1A1B1C1D1E1F2021;
+ for (i=0x22; i < H5FD_MIRROR_XMIT_FILEPATH_MAX+0x22; i++) {
+ /* nonzero values repeat after 0x100, but will not be encoded */
+ xmit_in.filename[i-0x22] = (char)(i % 0x100);
+ }
+ xmit_in.filename[H5FD_MIRROR_XMIT_FILEPATH_MAX-1] = 0;
+
+ /* Encode, and compare buffer contents
+ * Initial buffer is filled with 0xFF to match expected padding
+ */
+ HDmemset(buf, 0xFF, H5FD_MIRROR_XMIT_OPEN_SIZE+8);
+ if (H5FD_mirror_xmit_encode_open((buf+2), &xmit_in)
+ != H5FD_MIRROR_XMIT_OPEN_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, H5FD_MIRROR_XMIT_OPEN_SIZE+8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, H5FD_MIRROR_XMIT_OPEN_SIZE+8);
+ TEST_ERROR;
+ }
+
+ /* Decode from buffer
+ */
+ if (H5FD_mirror_xmit_decode_open(&xmit_out, (buf+2))
+ != H5FD_MIRROR_XMIT_OPEN_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.pub.magic != xmit_mock.magic) TEST_ERROR;
+ if (xmit_out.pub.version != xmit_mock.version) TEST_ERROR;
+ if (xmit_out.pub.session_token != xmit_mock.session_token) TEST_ERROR;
+ if (xmit_out.pub.xmit_count != xmit_mock.xmit_count) TEST_ERROR;
+ if (xmit_out.pub.op != xmit_mock.op) TEST_ERROR;
+ if (xmit_out.flags != xmit_in.flags) TEST_ERROR;
+ if (xmit_out.maxaddr != xmit_in.maxaddr) TEST_ERROR;
+ if (xmit_out.size_t_blob != xmit_in.size_t_blob) TEST_ERROR;
+ if (HDstrncmp(xmit_out.filename, xmit_in.filename,
+ H5FD_MIRROR_XMIT_FILEPATH_MAX)
+ != 0)
+ {
+ PRINT_BUFFER_DIFF(xmit_out.filename, xmit_in.filename,
+ H5FD_MIRROR_XMIT_FILEPATH_MAX);
+ TEST_ERROR;
+ }
+
+ /* Decode from different offset in buffer
+ * Observe changes when ingesting the padding
+ */
+ if (H5FD_mirror_xmit_decode_open(&xmit_out, (buf))
+ != H5FD_MIRROR_XMIT_OPEN_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.pub.magic != 0xFFFF0001) TEST_ERROR;
+ if (xmit_out.pub.version != 0x02) TEST_ERROR;
+ if (xmit_out.pub.session_token != 0x03040506) TEST_ERROR;
+ if (xmit_out.pub.xmit_count != 0x0708090A) TEST_ERROR;
+ if (xmit_out.pub.op != 0x0B) TEST_ERROR;
+ if (xmit_out.flags != 0x0C0D0E0F) TEST_ERROR;
+ if (xmit_out.maxaddr != 0x1011121314151617) TEST_ERROR;
+ if (xmit_out.size_t_blob != 0x18191A1B1C1D1E1F) TEST_ERROR;
+ /* update expected "filepath" in structure */
+ for (i=0x20; i < H5FD_MIRROR_XMIT_FILEPATH_MAX+0x20; i++) {
+ xmit_in.filename[i-0x20] = (i > 0xFF) ? 0 : (char)i;
+ }
+ if (HDstrncmp(xmit_out.filename, xmit_in.filename,
+ H5FD_MIRROR_XMIT_FILEPATH_MAX)
+ != 0)
+ {
+ PRINT_BUFFER_DIFF(xmit_out.filename, xmit_in.filename,
+ H5FD_MIRROR_XMIT_FILEPATH_MAX);
+ TEST_ERROR;
+ }
+
+ } while (0); /* end xmit open en/decode */
+
+ /* Test xmit reply structure encode/decode
+ * Write bogus but easily verifiable data to inside a buffer, and compare.
+ * Then decode the buffer and compare the structure contents.
+ * Then repeat from a different offset in the buffer and compare.
+ *
+ * Verifies that the first zero character in the filepath will end the
+ * string, with all following bytes in the encoded buffer being zeroed.
+ */
+ do {
+ unsigned char buf[H5FD_MIRROR_XMIT_REPLY_SIZE+8];
+ unsigned char expected[H5FD_MIRROR_XMIT_REPLY_SIZE+8];
+ H5FD_mirror_xmit_reply_t xmit_in;
+ H5FD_mirror_xmit_reply_t xmit_out;
+ size_t i = 0;
+
+ /* sanity check */
+ if ((14+4+256) != H5FD_MIRROR_XMIT_REPLY_SIZE) {
+ FAIL_PUTS_ERROR("Header size definition does not match test\n");
+ }
+ if (xmit_mock.op != 0x0D) {
+ FAIL_PUTS_ERROR("shared header structure is not in expected state");
+ }
+
+ /* Populate the expected buffer; expect end padding of 0xFF
+ */
+ HDmemset(expected, 0xFF, H5FD_MIRROR_XMIT_REPLY_SIZE+8);
+ for (i=0; i < H5FD_MIRROR_XMIT_REPLY_SIZE; i++) {
+ /* 0x100 is "zero" in a byte, so encode will treat it as a NULL-
+ * terminator in the filepath string. Expect all zeroes following.
+ */
+ expected[i+2] = (i > 0xFF) ? 0 : (unsigned char)i;
+ }
+
+ /* Set xmit_in
+ */
+ xmit_in.pub = xmit_mock; /* shared/common */
+ xmit_in.status = 0x0E0F1011;
+ for (i=0x12; i < H5FD_MIRROR_STATUS_MESSAGE_MAX+0x12; i++) {
+ /* nonzero values repeat after 0x100, but will not be encoded */
+ xmit_in.message[i-0x12] = (char)(i % 0x100);
+ }
+ xmit_in.message[H5FD_MIRROR_STATUS_MESSAGE_MAX-1] = 0;
+
+ /* Encode, and compare buffer contents
+ * Initial buffer is filled with 0xFF to match expected padding
+ */
+ HDmemset(buf, 0xFF, H5FD_MIRROR_XMIT_REPLY_SIZE+8);
+ if (H5FD_mirror_xmit_encode_reply((buf+2), &xmit_in)
+ != H5FD_MIRROR_XMIT_REPLY_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, H5FD_MIRROR_XMIT_REPLY_SIZE+8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, H5FD_MIRROR_XMIT_REPLY_SIZE+8);
+ TEST_ERROR;
+ }
+
+ /* Decode from buffer
+ */
+ if (H5FD_mirror_xmit_decode_reply(&xmit_out, (buf+2))
+ != H5FD_MIRROR_XMIT_REPLY_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.pub.magic != xmit_mock.magic) TEST_ERROR;
+ if (xmit_out.pub.version != xmit_mock.version) TEST_ERROR;
+ if (xmit_out.pub.session_token != xmit_mock.session_token) TEST_ERROR;
+ if (xmit_out.pub.xmit_count != xmit_mock.xmit_count) TEST_ERROR;
+ if (xmit_out.pub.op != xmit_mock.op) TEST_ERROR;
+ if (xmit_out.status != xmit_in.status) TEST_ERROR;
+ if (HDstrncmp(xmit_out.message, xmit_in.message,
+ H5FD_MIRROR_STATUS_MESSAGE_MAX)
+ != 0)
+ {
+ PRINT_BUFFER_DIFF(xmit_out.message, xmit_in.message,
+ H5FD_MIRROR_STATUS_MESSAGE_MAX);
+ TEST_ERROR;
+ }
+
+ /* Decode from different offset in buffer
+ * Observe changes when ingesting the padding
+ */
+ if (H5FD_mirror_xmit_decode_reply(&xmit_out, (buf))
+ != H5FD_MIRROR_XMIT_REPLY_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.pub.magic != 0xFFFF0001) TEST_ERROR;
+ if (xmit_out.pub.version != 0x02) TEST_ERROR;
+ if (xmit_out.pub.session_token != 0x03040506) TEST_ERROR;
+ if (xmit_out.pub.xmit_count != 0x0708090A) TEST_ERROR;
+ if (xmit_out.pub.op != 0x0B) TEST_ERROR;
+ if (xmit_out.status != 0x0C0D0E0F) TEST_ERROR;
+ /* update expected "message" in structure */
+ for (i=0x10; i < H5FD_MIRROR_STATUS_MESSAGE_MAX+0x10; i++) {
+ xmit_in.message[i-0x10] = (i > 0xFF) ? 0 : (char)i;
+ }
+ if (HDstrncmp(xmit_out.message, xmit_in.message,
+ H5FD_MIRROR_STATUS_MESSAGE_MAX)
+ != 0)
+ {
+ PRINT_BUFFER_DIFF(xmit_out.message, xmit_in.message,
+ H5FD_MIRROR_STATUS_MESSAGE_MAX);
+ TEST_ERROR;
+ }
+
+ } while (0); /* end xmit reply en/decode */
+
+ /* Test xmit write structure encode/decode
+ * Write bogus but easily verifiable data to inside a buffer, and compare.
+ * Then decode the buffer and compare the structure contents.
+ * Then repeat from a different offset in the buffer and compare.
+ */
+ do {
+ unsigned char buf[H5FD_MIRROR_XMIT_WRITE_SIZE+8];
+ unsigned char expected[H5FD_MIRROR_XMIT_WRITE_SIZE+8];
+ H5FD_mirror_xmit_write_t xmit_in;
+ H5FD_mirror_xmit_write_t xmit_out;
+ size_t i = 0;
+
+ /* sanity check */
+ if ((14+17) != H5FD_MIRROR_XMIT_WRITE_SIZE) {
+ FAIL_PUTS_ERROR("Header size definition does not match test\n");
+ }
+ if (xmit_mock.op != 0x0D) {
+ FAIL_PUTS_ERROR("shared header structure is not in expected state");
+ }
+
+ /* Populate the expected buffer; expect end padding of 0xFF
+ */
+ HDmemset(expected, 0xFF, H5FD_MIRROR_XMIT_WRITE_SIZE+8);
+ for (i=0; i < H5FD_MIRROR_XMIT_WRITE_SIZE; i++) {
+ expected[i+2] = (unsigned char)i;
+ }
+
+ /* Set xmit_in
+ */
+ xmit_in.pub = xmit_mock; /* shared/common */
+ xmit_in.type = 0x0E;
+ xmit_in.offset = 0x0F10111213141516;
+ xmit_in.size = 0x1718191A1B1C1D1E;
+
+ /* Encode, and compare buffer contents
+ * Initial buffer is filled with 0xFF to match expected padding
+ */
+ HDmemset(buf, 0xFF, H5FD_MIRROR_XMIT_WRITE_SIZE+8);
+ if (H5FD_mirror_xmit_encode_write((buf+2), &xmit_in)
+ != H5FD_MIRROR_XMIT_WRITE_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, H5FD_MIRROR_XMIT_WRITE_SIZE+8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, H5FD_MIRROR_XMIT_WRITE_SIZE+8);
+ TEST_ERROR;
+ }
+
+ /* Decode from buffer
+ */
+ if (H5FD_mirror_xmit_decode_write(&xmit_out, (buf+2))
+ != H5FD_MIRROR_XMIT_WRITE_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.pub.magic != xmit_mock.magic) TEST_ERROR;
+ if (xmit_out.pub.version != xmit_mock.version) TEST_ERROR;
+ if (xmit_out.pub.session_token != xmit_mock.session_token) TEST_ERROR;
+ if (xmit_out.pub.xmit_count != xmit_mock.xmit_count) TEST_ERROR;
+ if (xmit_out.pub.op != xmit_mock.op) TEST_ERROR;
+ if (xmit_out.type != 0x0E) TEST_ERROR;
+ if (xmit_out.offset != 0x0F10111213141516) TEST_ERROR;
+ if (xmit_out.size != 0x1718191A1B1C1D1E) TEST_ERROR;
+
+ /* Decode from different offset in buffer
+ * Observe changes when ingesting the padding
+ */
+ if (H5FD_mirror_xmit_decode_write(&xmit_out, (buf))
+ != H5FD_MIRROR_XMIT_WRITE_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.pub.magic != 0xFFFF0001) TEST_ERROR;
+ if (xmit_out.pub.version != 0x02) TEST_ERROR;
+ if (xmit_out.pub.session_token != 0x03040506) TEST_ERROR;
+ if (xmit_out.pub.xmit_count != 0x0708090A) TEST_ERROR;
+ if (xmit_out.pub.op != 0x0B) TEST_ERROR;
+ if (xmit_out.type != 0x0C) TEST_ERROR;
+ if (xmit_out.offset != 0x0D0E0F1011121314) TEST_ERROR;
+ if (xmit_out.size != 0x15161718191A1B1C) TEST_ERROR;
+
+ } while (0); /* end xmit write en/decode */
+
+ PASSED();
+ return 0;
+
+error:
+ return -1;
+} /* end test_xmit_encode_decode */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: create_mirroring_split_fapl
+ *
+ * Purpose: Create and populate a mirroring FAPL ID.
+ * Creates target files with the given base name -- ideally the
+ * test name -- and creates mirroring/split FAPL set to use the
+ * global mirroring info and a sec2 R/W channel driver.
+ *
+ * TODO: receive target IP from caller?
+ *
+ * Return: Success: HID of the top-level (splitter) FAPL, a non-negative
+ * value.
+ * Failure: H5I_INVALID_HID, a negative value.
+ *
+ * Programmer: Jacob Smith
+ * 2019
+ * ---------------------------------------------------------------------------
+ */
+static hid_t
+create_mirroring_split_fapl(const char *_basename,
+ struct mirrortest_filenames *names)
+{
+ H5FD_splitter_vfd_config_t splitter_config;
+ H5FD_mirror_fapl_t mirror_conf;
+ hid_t ret_value = H5I_INVALID_HID;
+
+ if (_basename == NULL || *_basename == '\0') {
+ TEST_ERROR;
+ }
+
+ splitter_config.magic = H5FD_SPLITTER_MAGIC;
+ splitter_config.version = H5FD_CURR_SPLITTER_VFD_CONFIG_VERSION;
+ splitter_config.ignore_wo_errs = FALSE;
+
+ /* Create Splitter R/W channel driver (sec2)
+ */
+ splitter_config.rw_fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ if (H5I_INVALID_HID == splitter_config.rw_fapl_id) {
+ TEST_ERROR;
+ }
+ if (H5Pset_fapl_sec2(splitter_config.rw_fapl_id) == FAIL) {
+ TEST_ERROR;
+ }
+
+ /* Create Splitter W/O channel driver (mirror)
+ */
+ mirror_conf.magic = H5FD_MIRROR_FAPL_MAGIC;
+ mirror_conf.version = H5FD_MIRROR_CURR_FAPL_T_VERSION;
+ mirror_conf.handshake_port = SERVER_HANDSHAKE_PORT;
+ if (HDstrncpy(mirror_conf.remote_ip, SERVER_IP_ADDRESS,
+ H5FD_MIRROR_MAX_IP_LEN)
+ == NULL)
+ {
+ TEST_ERROR;
+ }
+ splitter_config.wo_fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ if (H5I_INVALID_HID == splitter_config.wo_fapl_id) {
+ TEST_ERROR;
+ }
+ if (H5Pset_fapl_mirror(splitter_config.wo_fapl_id, &mirror_conf) == FAIL) {
+ TEST_ERROR;
+ }
+
+ /* Build r/w, w/o, and log file paths
+ */
+ if (build_paths(_basename, &splitter_config, names) < 0) {
+ TEST_ERROR;
+ }
+
+ /* Set file paths for w/o and logfile
+ */
+ if (HDstrncpy(splitter_config.wo_path, (const char *)names->wo,
+ H5FD_SPLITTER_PATH_MAX)
+ == NULL)
+ {
+ TEST_ERROR;
+ }
+ if (HDstrncpy(splitter_config.log_file_path, (const char *)names->log,
+ H5FD_SPLITTER_PATH_MAX)
+ == NULL)
+ {
+ TEST_ERROR;
+ }
+
+ /* Create Splitter FAPL
+ */
+ ret_value = H5Pcreate(H5P_FILE_ACCESS);
+ if (H5I_INVALID_HID == ret_value) {
+ TEST_ERROR;
+ }
+ if (H5Pset_fapl_splitter(ret_value, &splitter_config) == FAIL) {
+ TEST_ERROR;
+ }
+
+ /* Close FAPLs created for child channels
+ */
+ if (H5Pclose(splitter_config.rw_fapl_id) < 0) {
+ TEST_ERROR;
+ }
+ splitter_config.rw_fapl_id = H5I_INVALID_HID;
+ if (H5Pclose(splitter_config.wo_fapl_id) < 0) {
+ TEST_ERROR;
+ }
+ splitter_config.wo_fapl_id = H5I_INVALID_HID;
+
+ return ret_value;
+
+error:
+ if (splitter_config.wo_fapl_id >= 0) {
+ (void)H5Pclose(splitter_config.wo_fapl_id);
+ }
+ if (splitter_config.rw_fapl_id >= 0) {
+ (void)H5Pclose(splitter_config.rw_fapl_id);
+ }
+ if (ret_value >= 0) {
+ (void)H5Pclose(ret_value);
+ }
+ return H5I_INVALID_HID;
+} /* end create_mirroring_split_fapl() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: test_create_and_close
+ *
+ * Purpose: Test/demonstrate a do-nothing file open and close.
+ *
+ * Verifying file existence and contents is part of other tests.
+ *
+ * TODO: receive target IP from caller?
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Jacob Smith
+ * 2019-12-17
+ * ---------------------------------------------------------------------------
+ */
+static int
+test_create_and_close(void)
+{
+ struct mirrortest_filenames names;
+ hid_t file_id = H5I_INVALID_HID;
+ hid_t fapl_id = H5P_DEFAULT;
+
+ TESTING("File creation and immediate close");
+
+ /* Create FAPL for Splitter[sec2|mirror]
+ */
+ fapl_id = create_mirroring_split_fapl("basic_create", &names);
+ if (H5I_INVALID_HID == fapl_id) {
+ TEST_ERROR;
+ }
+
+ /* -------------------- */
+ /* TEST: Create and Close */
+
+ file_id = H5Fcreate(names.rw, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
+ if (H5I_INVALID_HID == file_id) {
+ TEST_ERROR;
+ }
+
+ /* -------------------- */
+ /* Standard cleanup */
+
+ if (H5Fclose(file_id) == FAIL) {
+ TEST_ERROR;
+ }
+ if (fapl_id != H5P_DEFAULT && fapl_id >= 0) {
+ if (H5Pclose(fapl_id) == FAIL) {
+ TEST_ERROR;
+ }
+ }
+
+ PASSED();
+ return 0;
+
+error:
+ H5E_BEGIN_TRY{
+ (void)H5Fclose(file_id);
+ (void)H5Pclose(fapl_id);
+ } H5E_END_TRY;
+ return -1;
+} /* end test_create_and_close() */
+
+
+/* ----------------------------------------------------------------------------
+ * Function: create_datasets
+ *
+ * Purpose: Given a file ID and least and greateset dataset indices, create
+ * populated chunked datasets in the target file from min_dset to
+ * (and including) max_dset.
+ * Uses #defined constants to determine chunk and dataset sizes
+ * and values.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Jacob Smith
+ * 2019-08-14
+ * ----------------------------------------------------------------------------
+ */
+static herr_t
+create_datasets(hid_t file_id,
+ unsigned min_dset,
+ unsigned max_dset)
+{
+ hid_t dataspace_ids[MAX_DSET_COUNT + 1];
+ hid_t dataset_ids[MAX_DSET_COUNT + 1];
+ hid_t filespace_ids[MAX_DSET_COUNT + 1];
+ int data_chunk[CHUNK_DIM][CHUNK_DIM];
+ unsigned int i, j, k, l, m;
+ hsize_t offset[2];
+ hid_t memspace_id = H5I_INVALID_HID;
+ hsize_t a_size[2] = {CHUNK_DIM, CHUNK_DIM};
+ hsize_t chunk_dims[2] = {CHUNK_DIM, CHUNK_DIM};
+ hsize_t dset_dims[2] = {DSET_DIM, DSET_DIM};
+
+ HDassert(file_id >= 0);
+ HDassert(min_dset <= max_dset);
+ HDassert(max_dset <= MAX_DSET_COUNT);
+
+ LOGPRINT(2, "create_dataset()\n");
+
+ /* ---------------------------------
+ * "Clear" ID arrays
+ */
+
+ for (i = 0; i < MAX_DSET_COUNT; i++) {
+ LOGPRINT(3, "clearing IDs [%d]\n", i);
+ dataspace_ids[i] = H5I_INVALID_HID;
+ dataset_ids[i] = H5I_INVALID_HID;
+ filespace_ids[i] = H5I_INVALID_HID;
+ }
+
+ /* ---------------------------------
+ * Generate dataspace, dataset, and 'filespace' IDs
+ */
+
+ if (_create_chunking_ids(file_id, min_dset, max_dset, chunk_dims,
+ dset_dims, dataspace_ids, filespace_ids, dataset_ids, &memspace_id)
+ == FAIL)
+ {
+ TEST_ERROR;
+ }
+
+ /* ---------------------------------
+ * Initialize (write) all datasets in a "round robin"...
+ * for a given chunk 'location', write chunk data to each dataset.
+ */
+
+ for (i = 0; i < DSET_DIM; i += CHUNK_DIM)
+ {
+ LOGPRINT(3, "i: %d\n", i);
+ for (j = 0; j < DSET_DIM; j += CHUNK_DIM)
+ {
+ LOGPRINT(3, " j: %d\n", j);
+ for (m = min_dset; m <= max_dset; m++)
+ {
+ LOGPRINT(3, " m: %d\n", m);
+ for (k = 0; k < CHUNK_DIM; k++)
+ {
+ for (l = 0; l < CHUNK_DIM; l++)
+ {
+ data_chunk[k][l] = (int)((DSET_DIM * DSET_DIM * m) +
+ (DSET_DIM * (i + k)) + j + l);
+ LOGPRINT(3, " data_chunk[%d][%d]: %d\n",
+ k, l, data_chunk[k][l]);
+ }
+ }
+
+ /* select on disk hyperslab */
+ offset[0] = (hsize_t)i;
+ offset[1] = (hsize_t)j;
+ LOGPRINT(3, " H5Sselect_hyperslab()\n");
+ if (H5Sselect_hyperslab(filespace_ids[m], H5S_SELECT_SET,
+ offset, NULL, a_size, NULL)
+ < 0)
+ {
+ TEST_ERROR;
+ }
+
+ LOGPRINT(3, " H5Dwrite()\n");
+ if (H5Dwrite(dataset_ids[m], H5T_NATIVE_INT, memspace_id,
+ filespace_ids[m], H5P_DEFAULT, data_chunk)
+ < 0)
+ {
+ TEST_ERROR;
+ }
+
+ }
+ }
+ }
+
+ /* ---------------------------------
+ * Read and verify data from datasets
+ */
+
+ if (_verify_datasets(min_dset, max_dset, filespace_ids, dataset_ids,
+ memspace_id)
+ == FAIL)
+ {
+ TEST_ERROR;
+ }
+
+ /* ---------------------------------
+ * Cleanup
+ */
+
+ if (_close_chunking_ids(min_dset, max_dset, dataspace_ids, filespace_ids,
+ dataset_ids, &memspace_id)
+ == FAIL)
+ {
+ TEST_ERROR;
+ }
+
+ return SUCCEED;
+
+error:
+ (void)_close_chunking_ids(min_dset, max_dset, dataspace_ids,
+ filespace_ids, dataset_ids, &memspace_id);
+ LOGPRINT(1, "create_datasets() FAILED\n");
+ return FAIL;
+} /* end create_datasets() */
+
+
+/* ----------------------------------------------------------------------------
+ * Function: _create_chunking_ids
+ *
+ * Purpose: Create new IDs to be used with the associated file.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programer: Jacob Smith
+ * 2019
+ * ----------------------------------------------------------------------------
+ */
+static herr_t
+_create_chunking_ids(hid_t file_id,
+ unsigned min_dset,
+ unsigned max_dset,
+ hsize_t *chunk_dims,
+ hsize_t *dset_dims,
+ hid_t *dataspace_ids,
+ hid_t *filespace_ids,
+ hid_t *dataset_ids,
+ hid_t *memspace_id)
+{
+ char dset_name[DSET_NAME_LEN + 1];
+ unsigned m = 0;
+ hid_t dcpl_id = H5I_INVALID_HID;
+
+ LOGPRINT(2, "_create_chunking_ids()\n");
+
+ /* --------------------
+ * Create chunking DCPL
+ */
+
+ dcpl_id = H5Pcreate(H5P_DATASET_CREATE);
+ if (dcpl_id < 0) {
+ TEST_ERROR;
+ }
+ if (H5Pset_chunk(dcpl_id, 2, chunk_dims) == FAIL) {
+ TEST_ERROR;
+ }
+
+ /* --------------------
+ * Create dataspace IDs
+ */
+
+ for (m = min_dset; m <= max_dset; m++) {
+ dataspace_ids[m] = H5Screate_simple(2, dset_dims, NULL);
+ if (dataspace_ids[m] < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE,
+ "unable to create dataspace ID %d\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+
+ /* --------------------
+ * Create dataset IDs
+ */
+
+ for (m = min_dset; m <= max_dset; m++) {
+ if (HDsnprintf(dset_name, DSET_NAME_LEN, "/dset%03d", m)
+ > DSET_NAME_LEN)
+ {
+ HDsnprintf(mesg, MIRR_MESG_SIZE,
+ "unable to compose dset name %d\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+
+ dataset_ids[m] = H5Dcreate(file_id, dset_name, H5T_STD_I32BE,
+ dataspace_ids[m], H5P_DEFAULT, dcpl_id, H5P_DEFAULT);
+ if (dataset_ids[m] < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE,
+ "unable to create dset ID %d\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+
+ /* --------------------
+ * Get file space IDs
+ */
+
+ for (m = min_dset; m <= max_dset; m++) {
+ filespace_ids[m] = H5Dget_space(dataset_ids[m]);
+ if (filespace_ids[m] < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE,
+ "unable to create filespace ID %d\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+
+ /* --------------------
+ * Create mem space to be used to read and write chunks
+ */
+
+ *memspace_id = H5Screate_simple(2, chunk_dims, NULL);
+ if (*memspace_id < 0) {
+ TEST_ERROR;
+ }
+
+ /* --------------------
+ * Clean up the DCPL, even if there were errors before
+ */
+
+ if (dcpl_id != H5P_DEFAULT && dcpl_id != H5I_INVALID_HID) {
+ if (H5Pclose(dcpl_id) == FAIL) {
+ TEST_ERROR;
+ }
+ }
+
+ return SUCCEED;
+
+error:
+ if (dcpl_id != H5P_DEFAULT && dcpl_id != H5I_INVALID_HID) {
+ (void)H5Pclose(dcpl_id);
+ }
+ LOGPRINT(1, "_create_chunking_ids() FAILED\n");
+ return FAIL;
+} /* end _create_chunking_ids() */
+
+
+/* ----------------------------------------------------------------------------
+ * Function: _open_chunking_ids
+ *
+ * Purpose: Open/access IDs from the given file.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Jacob Smith
+ * 2019
+ * ----------------------------------------------------------------------------
+ */
+static herr_t
+_open_chunking_ids(
+ hid_t file_id,
+ unsigned min_dset,
+ unsigned max_dset,
+ hsize_t *chunk_dims,
+ hid_t *filespace_ids,
+ hid_t *dataset_ids,
+ hid_t *memspace_id)
+{
+ char dset_name[DSET_NAME_LEN+1];
+ unsigned m = 0;
+
+ LOGPRINT(2, "_open_chunking_ids()\n");
+
+ /* --------------------
+ * Open dataset IDs
+ */
+
+ for (m = min_dset; m <= max_dset; m++) {
+ if (HDsnprintf(dset_name, DSET_NAME_LEN, "/dset%03d", m)
+ > DSET_NAME_LEN)
+ {
+ HDsnprintf(mesg, MIRR_MESG_SIZE,
+ "unable to compose dset name %d\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+
+ dataset_ids[m] = H5Dopen2(file_id, dset_name, H5P_DEFAULT);
+ if (dataset_ids[m] < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE, "unable to open dset ID %d\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+
+ /* --------------------
+ * Open filespace IDs
+ */
+
+ for (m = min_dset; m <= max_dset; m++) {
+ filespace_ids[m] = H5Dget_space(dataset_ids[m]);
+ if (filespace_ids[m] < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE,
+ "unable to get filespace ID %d\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+
+ /* --------------------
+ * Create mem space to be used to read and write chunks
+ */
+
+ *memspace_id = H5Screate_simple(2, chunk_dims, NULL);
+ if (*memspace_id < 0) {
+ TEST_ERROR;
+ }
+
+ return SUCCEED;
+
+error:
+ LOGPRINT(1, "_open_chunking_ids() FAILED\n");
+ return FAIL;
+} /* end _open_chunking_ids() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: _close_chunking_ids
+ *
+ * Purpose: Close IDs that were created or opened.
+ * Pass NULL into `dataspace_ids` when closing items opened with
+ * _open_chunking_ids(). (as opposed to created IDs)
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Jacob Smith
+ * 2019
+ * ---------------------------------------------------------------------------
+ */
+static herr_t
+_close_chunking_ids(unsigned min_dset,
+ unsigned max_dset,
+ hid_t *dataspace_ids,
+ hid_t *filespace_ids,
+ hid_t *dataset_ids,
+ hid_t *memspace_id)
+{
+ unsigned m;
+
+ LOGPRINT(2, "_close_chunking_ids()\n");
+
+ for (m = min_dset; m <= max_dset; m++) {
+ LOGPRINT(3, "closing ids[%d]\n", m);
+ if (dataspace_ids) {
+ if (H5Sclose(dataspace_ids[m]) < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE,
+ "unable to close dataspace_id[%d]\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+ if (H5Dclose(dataset_ids[m]) < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE,
+ "unable to close dataset_id[%d]\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ if (H5Sclose(filespace_ids[m]) < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE,
+ "unable to close filespace_id[%d]\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+
+ if ( (*memspace_id != H5I_INVALID_HID) &&
+ (H5Sclose(*memspace_id) < 0) )
+ {
+ TEST_ERROR;
+ }
+
+ return SUCCEED;
+
+error:
+ LOGPRINT(1, "_close_chunking_ids() FAILED\n");
+ return FAIL;
+} /* end _close_chunking_ids() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: _verify_datasets
+ *
+ * Purpose: Check that each chunk's contents are as expected, as pertaining
+ * to create_datasets().
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Jacob Smith
+ * 2019
+ * ---------------------------------------------------------------------------
+ */
+static herr_t
+_verify_datasets(unsigned min_dset,
+ unsigned max_dset,
+ hid_t *filespace_ids,
+ hid_t *dataset_ids,
+ hid_t memspace_id)
+{
+ unsigned i, j, k, l, m;
+ int data_chunk[CHUNK_DIM][CHUNK_DIM];
+ hsize_t offset[2];
+ hsize_t a_size[2] = {CHUNK_DIM, CHUNK_DIM};
+
+ LOGPRINT(2, "_verify_datasets()\n");
+
+ for (i = 0; i < DSET_DIM; i += CHUNK_DIM)
+ {
+ LOGPRINT(3, "i: %d\n", i);
+ for (j = 0; j < DSET_DIM; j += CHUNK_DIM)
+ {
+ LOGPRINT(3, " j: %d\n", j);
+ for (m = min_dset; m <= max_dset; m++)
+ {
+ LOGPRINT(3, " m: %d\n", m);
+
+ /* select on disk hyperslab */
+ offset[0] = (hsize_t)i;
+ offset[1] = (hsize_t)j;
+ if (H5Sselect_hyperslab(filespace_ids[m], H5S_SELECT_SET,
+ offset, NULL, a_size, NULL)
+ < 0)
+ {
+ TEST_ERROR;
+ }
+
+ if (H5Dread(dataset_ids[m], H5T_NATIVE_INT, memspace_id,
+ filespace_ids[m], H5P_DEFAULT, data_chunk)
+ < 0)
+ {
+ HDsnprintf(mesg, MIRR_MESG_SIZE,
+ " H5Dread() [%d][%d][%d]\n",
+ i, j, m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+
+ for (k = 0; k < CHUNK_DIM; k++) {
+ for (l = 0; l < CHUNK_DIM; l++) {
+ if ((unsigned)data_chunk[k][l]
+ !=
+ ((DSET_DIM * DSET_DIM * m) +
+ (DSET_DIM * (i + k)) + j + l))
+ {
+ HDsnprintf(mesg, MIRR_MESG_SIZE,
+ " MISMATCH [%d][%d][%d][%d][%d]\n",
+ i, j, m, k, l);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+ }
+
+ }
+ }
+ }
+
+ return SUCCEED;
+
+error:
+ LOGPRINT(1, "_verify_datasets() FAILED\n");
+ return FAIL;
+} /* end _verify_datasets() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: verify_datasets
+ *
+ * Purpose: Inspect the datasets in the file created by create_datasets().
+ * Wrapper for _verify_datasets() -- this function sets up and
+ * tears down accessor information.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Jacob Smith
+ * 2019
+ * ---------------------------------------------------------------------------
+ */
+static herr_t
+verify_datasets(hid_t file_id,
+ unsigned min_dset,
+ unsigned max_dset)
+{
+ hid_t dataset_ids[MAX_DSET_COUNT + 1];
+ hid_t filespace_ids[MAX_DSET_COUNT + 1];
+ unsigned i;
+ hid_t memspace_id = H5I_INVALID_HID;
+ hsize_t chunk_dims[2] = {CHUNK_DIM, CHUNK_DIM};
+
+ HDassert(file_id >= 0);
+ HDassert(min_dset <= max_dset);
+ HDassert(max_dset <= MAX_DSET_COUNT);
+
+ LOGPRINT(2, "verify_datasets()\n");
+
+ /* ---------------------------------
+ * "Clear" ID arrays
+ */
+
+ for (i = 0; i < MAX_DSET_COUNT; i++) {
+ LOGPRINT(3, "clearing IDs [%d]\n", i);
+ dataset_ids[i] = H5I_INVALID_HID;
+ filespace_ids[i] = H5I_INVALID_HID;
+ }
+
+ /* ---------------------------------
+ * Generate dataspace, dataset, and 'filespace' IDs
+ */
+
+ if (_open_chunking_ids(file_id, min_dset, max_dset, chunk_dims,
+ filespace_ids, dataset_ids, &memspace_id)
+ == FAIL)
+ {
+ TEST_ERROR;
+ }
+
+ /* ---------------------------------
+ * Read and verify data from datasets
+ */
+
+ if (_verify_datasets(min_dset, max_dset, filespace_ids, dataset_ids,
+ memspace_id)
+ == FAIL)
+ {
+ TEST_ERROR;
+ }
+
+ /* ---------------------------------
+ * Cleanup
+ */
+
+ if (_close_chunking_ids(min_dset, max_dset, NULL, filespace_ids,
+ dataset_ids, &memspace_id)
+ == FAIL)
+ {
+ TEST_ERROR;
+ }
+
+ return SUCCEED;
+
+error:
+ LOGPRINT(1, "verify_datasets() FAILED\n");
+ (void)_close_chunking_ids(min_dset, max_dset, NULL, filespace_ids,
+ dataset_ids, &memspace_id);
+ return FAIL;
+
+} /* end verify_datasets() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: test_basic_dataset_write
+ *
+ * Purpose: Create and close files; repoen files and write a dataset,
+ * close; compare files.
+ *
+ * TODO: receive target IP from caller?
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Jacob Smith
+ * 2019
+ * ---------------------------------------------------------------------------
+ */
+static int
+test_basic_dataset_write(void)
+{
+ struct mirrortest_filenames names;
+ hid_t file_id = H5I_INVALID_HID;
+ hid_t fapl_id = H5P_DEFAULT;
+ hid_t dset_id = H5I_INVALID_HID;
+ hid_t dspace_id = H5I_INVALID_HID;
+ hid_t dtype_id = H5T_NATIVE_INT;
+ hsize_t dims[2] = { DATABUFFER_SIZE, DATABUFFER_SIZE };
+ int *buf = NULL;
+ int i = 0;
+ int j = 0;
+
+ TESTING("Mirror open and dataset writing");
+
+ /* Create FAPL for Splitter[sec2|mirror]
+ */
+ fapl_id = create_mirroring_split_fapl("basic_write", &names);
+ if (H5I_INVALID_HID == fapl_id) {
+ TEST_ERROR;
+ }
+
+ /* Prepare data to be written
+ */
+ buf = (int *)HDmalloc(DATABUFFER_SIZE * DATABUFFER_SIZE * sizeof(int));
+ if (NULL == buf) {
+ TEST_ERROR;
+ }
+ for (i = 0; i < DATABUFFER_SIZE; i++) {
+ for (j = 0; j < DATABUFFER_SIZE; j++) {
+ int k = i * DATABUFFER_SIZE + j;
+ buf[k] = k;
+ }
+ }
+
+ /* -------------------- */
+ /* TEST: Create and Close */
+
+ file_id = H5Fcreate(names.rw, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
+ if (H5I_INVALID_HID == file_id) {
+ TEST_ERROR;
+ }
+ if (H5Fclose(file_id) == FAIL) {
+ TEST_ERROR;
+ }
+ file_id = H5I_INVALID_HID;
+
+
+ /* -------------------- */
+ /* TEST: Repoen and Write */
+
+ file_id = H5Fopen(names.rw, H5F_ACC_RDWR, fapl_id);
+ if (H5I_INVALID_HID == file_id) {
+ TEST_ERROR;
+ }
+
+ dspace_id = H5Screate_simple(2, dims, NULL);
+ if (H5I_INVALID_HID == dspace_id) {
+ TEST_ERROR;
+ }
+ dset_id = H5Dcreate2(file_id, "dataset", dtype_id, dspace_id, H5P_DEFAULT,
+ H5P_DEFAULT, H5P_DEFAULT);
+ if (H5I_INVALID_HID == dset_id) {
+ TEST_ERROR;
+ }
+
+ if (H5Dwrite(dset_id, dtype_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf)
+ == FAIL)
+ {
+ TEST_ERROR;
+ }
+
+ /* -------------------- */
+ /* Standard cleanup */
+
+ HDfree(buf);
+ buf = NULL;
+ if (H5Dclose(dset_id) == FAIL) {
+ TEST_ERROR;
+ }
+ if (H5Sclose(dspace_id) == FAIL) {
+ TEST_ERROR;
+ }
+ if (H5Fclose(file_id) == FAIL) {
+ TEST_ERROR;
+ }
+ if (fapl_id != H5P_DEFAULT && fapl_id > 0) {
+ if (H5Pclose(fapl_id) == FAIL) {
+ TEST_ERROR;
+ }
+ }
+
+ /* -------------------- */
+ /* TEST: Verify that the R/W and W/O files are identical */
+
+ if (h5_compare_file_bytes(names.rw, names.wo) < 0) {
+ TEST_ERROR;
+ }
+
+ PASSED();
+ return 0;
+
+error:
+ H5E_BEGIN_TRY{
+ (void)H5Fclose(file_id);
+ if (buf) {
+ HDfree(buf);
+ }
+ (void)H5Dclose(dset_id);
+ (void)H5Sclose(dspace_id);
+ if (fapl_id != H5P_DEFAULT && fapl_id > 0) {
+ (void)H5Pclose(fapl_id);
+ }
+ } H5E_END_TRY;
+ return -1;
+} /* end test_basic_dataset_write() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: test_chunked_dataset_write
+ *
+ * Purpose: Create and close files; repoen files and write a dataset,
+ * close; compare files.
+ *
+ * TODO: receive target IP from caller?
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Jacob Smith
+ * 2019
+ * ---------------------------------------------------------------------------
+ */
+static int
+test_chunked_dataset_write(void)
+{
+ struct mirrortest_filenames names;
+ hid_t file_id = H5I_INVALID_HID;
+ hid_t fapl_id = H5P_DEFAULT;
+
+ TESTING("Mirror open and dataset writing (chunked)");
+
+ /* Create FAPL for Splitter[sec2|mirror]
+ */
+ fapl_id = create_mirroring_split_fapl("chunked_write", &names);
+ if (H5I_INVALID_HID == fapl_id) {
+ TEST_ERROR;
+ }
+
+ /* -------------------- */
+ /* TEST: Create and Close */
+
+ file_id = H5Fcreate(names.rw, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
+ if (H5I_INVALID_HID == file_id) {
+ TEST_ERROR;
+ }
+ if (H5Fclose(file_id) == FAIL) {
+ TEST_ERROR;
+ }
+ file_id = H5I_INVALID_HID;
+
+ /* -------------------- */
+ /* TEST: Reopen and Write */
+
+ file_id = H5Fopen(names.rw, H5F_ACC_RDWR, fapl_id);
+ if (H5I_INVALID_HID == file_id) {
+ TEST_ERROR;
+ }
+
+ /* Write datasets to file
+ */
+ if (create_datasets(file_id, 0, MAX_DSET_COUNT) == FAIL) {
+ TEST_ERROR;
+ }
+
+ /* Close to 'flush to disk', and reopen file
+ */
+ if (H5Fclose(file_id) == FAIL) {
+ TEST_ERROR;
+ }
+ file_id = H5I_INVALID_HID;
+
+ /* Reopen file
+ */
+ file_id = H5Fopen(names.rw, H5F_ACC_RDWR, fapl_id);
+ if (H5I_INVALID_HID == file_id) {
+ TEST_ERROR;
+ }
+
+ /* Verify written data integrity
+ */
+ if (verify_datasets(file_id, 0, MAX_DSET_COUNT) == FAIL) {
+ TEST_ERROR;
+ }
+
+ /* -------------------- */
+ /* Standard cleanup */
+
+ if (H5Fclose(file_id) == FAIL) {
+ TEST_ERROR;
+ }
+ file_id = H5I_INVALID_HID;
+ if (fapl_id != H5P_DEFAULT && fapl_id > 0) {
+ if (H5Pclose(fapl_id) == FAIL) {
+ TEST_ERROR;
+ }
+ fapl_id = H5I_INVALID_HID;
+ }
+
+ /* -------------------- */
+ /* TEST: Verify that the R/W and W/O files are identical */
+
+ if (h5_compare_file_bytes(names.rw, names.wo) < 0) {
+ TEST_ERROR;
+ }
+
+ PASSED();
+ return 0;
+
+error:
+ H5E_BEGIN_TRY {
+ (void)H5Fclose(file_id);
+ if (fapl_id != H5P_DEFAULT && fapl_id > 0) {
+ (void)H5Pclose(fapl_id);
+ }
+ } H5E_END_TRY;
+ return -1;
+} /* end test_chunked_dataset_write() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: test_on_disk_zoo
+ *
+ * Purpose: Verify that the mirror can handle the passing of all the
+ * various on-disk data structures over the wire, as implemented
+ * in genall5.c:create_zoo().
+ *
+ * TODO: receive target IP from caller?
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Jacob Smith
+ * 2019
+ * ---------------------------------------------------------------------------
+ */
+static int
+test_on_disk_zoo(void)
+{
+ const char grp_name[] = "/only";
+ struct mirrortest_filenames names;
+ hid_t file_id = H5I_INVALID_HID;
+ hid_t grp_id = H5I_INVALID_HID;
+ hid_t fapl_id = H5P_DEFAULT;
+
+ TESTING("'Zoo' of on-disk structures");
+
+ /* Create FAPL for Splitter[sec2|mirror]
+ */
+ fapl_id = create_mirroring_split_fapl("zoo", &names);
+ if (H5I_INVALID_HID == fapl_id) {
+ TEST_ERROR;
+ }
+
+ /* -------------------- */
+ /* TEST: Create file */
+ file_id = H5Fcreate(names.rw, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
+ if (H5I_INVALID_HID == file_id) {
+ TEST_ERROR;
+ }
+
+ grp_id = H5Gcreate2(file_id, grp_name, H5P_DEFAULT, H5P_DEFAULT,
+ H5P_DEFAULT);
+ if (grp_id == H5I_INVALID_HID) {
+ TEST_ERROR;
+ }
+
+ /* Create datasets in file, close (flush) and reopen, validate.
+ * Use of ( pass ) a conceit required for using create_ and validate_zoo()
+ * from cache_common and/or genall5.
+ */
+
+ if ( pass ) {
+ create_zoo(file_id, grp_name, 0);
+ }
+ if ( pass ) {
+ if (H5Fclose(file_id) == FAIL) {
+ TEST_ERROR;
+ }
+ file_id = H5Fopen(names.rw, H5F_ACC_RDWR, fapl_id);
+ if (H5I_INVALID_HID == file_id) {
+ TEST_ERROR;
+ }
+ }
+ if ( pass ) {
+ validate_zoo(file_id, grp_name, 0); /* sanity-check */
+ }
+ if ( !pass ) {
+ HDprintf(failure_mssg);
+ TEST_ERROR;
+ }
+
+ /* -------------------- */
+ /* Standard cleanup */
+
+ if (fapl_id != H5P_DEFAULT && fapl_id >= 0) {
+ if (H5Pclose(fapl_id) == FAIL) {
+ TEST_ERROR;
+ }
+ }
+ if (H5Gclose(grp_id) == FAIL) {
+ TEST_ERROR;
+ }
+ if (H5Fclose(file_id) == FAIL) {
+ TEST_ERROR;
+ }
+
+ /* -------------------- */
+ /* TEST: Verify that the R/W and W/O files are identical */
+
+ if (h5_compare_file_bytes(names.rw, names.wo) < 0) {
+ TEST_ERROR;
+ }
+
+ PASSED();
+ return 0;
+
+error:
+ H5E_BEGIN_TRY {
+ (void)H5Fclose(file_id);
+ (void)H5Gclose(grp_id);
+ if (fapl_id != H5P_DEFAULT && fapl_id > 0) {
+ (void)H5Pclose(fapl_id);
+ }
+ } H5E_END_TRY;
+ return -1;
+} /* end test_on_disk_zoo() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: test_vanishing_datasets
+ *
+ * Purpose: Verify behavior when writing to a file where data is deleted.
+ *
+ * Each dataset is populated with the value of its suffix
+ * (dset5 is all fives).
+ *
+ * Opens 0..15 create one new dataset each, '/dset[i]'.
+ * Opens 3..18 delete '/dset[1-3]'
+ *
+ * Should end with no data in file.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Jacob Smith
+ * 2019
+ * ---------------------------------------------------------------------------
+ */
+static int
+test_vanishing_datasets(void)
+{
+ struct mirrortest_filenames names;
+ hid_t file_id = H5I_INVALID_HID;
+ hid_t fapl_id = H5I_INVALID_HID;
+ hid_t dset_id = H5I_INVALID_HID;
+ hid_t dspace_id = H5I_INVALID_HID;
+ hid_t mirror_fapl_id = H5I_INVALID_HID;
+ hsize_t dims[2] = {DATABUFFER_SIZE, DATABUFFER_SIZE};
+ uint32_t buf[DATABUFFER_SIZE][DATABUFFER_SIZE]; /* consider malloc? */
+ H5G_info_t group_info;
+ unsigned int i, j, k;
+ const unsigned int max_loops = 20;
+ const unsigned int max_at_one_time = 3;
+
+ TESTING("Vanishing Datasets");
+
+ /* -------------------- */
+ /* Set up recurrent data (FAPL, dataspace) */
+
+ /* Create FAPL for Splitter[sec2|mirror]
+ */
+ fapl_id = create_mirroring_split_fapl("vanishing", &names);
+ if (H5I_INVALID_HID == fapl_id) {
+ TEST_ERROR;
+ }
+
+ dspace_id = H5Screate_simple(2, dims, NULL);
+ if (dspace_id < 0) {
+ TEST_ERROR;
+ }
+
+ /* create file */
+ file_id = H5Fcreate(names.rw, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
+ if (H5I_INVALID_HID == file_id) {
+ TEST_ERROR;
+ }
+
+ for (i=0; i < max_loops; i++) {
+ char namebuf[DSET_NAME_LEN + 1];
+
+ /* deleting datasets */
+ if (i >= max_at_one_time) {
+ if (HDsnprintf(namebuf, DSET_NAME_LEN, "/dset%02d",
+ (i - max_at_one_time) )
+ > DSET_NAME_LEN)
+ {
+ TEST_ERROR;
+ }
+ if (H5Ldelete(file_id, namebuf, H5P_DEFAULT) < 0) {
+ TEST_ERROR;
+ }
+ } /* end if deleting a dataset */
+
+ /* writing datasets */
+ if (i < (max_loops - max_at_one_time)) {
+ if (HDsnprintf(namebuf, DSET_NAME_LEN, "/dset%02d", i)
+ > DSET_NAME_LEN)
+ {
+ TEST_ERROR;
+ }
+ dset_id = H5Dcreate2(file_id, namebuf, H5T_STD_U32LE, dspace_id,
+ H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+ if (H5I_INVALID_HID == dset_id) {
+ TEST_ERROR;
+ }
+
+ for (j=0; j < DATABUFFER_SIZE; j++) {
+ for (k=0; k < DATABUFFER_SIZE; k++) {
+ buf[j][k] = (uint32_t)i;
+ }
+ }
+
+ if (H5Dwrite(dset_id, H5T_STD_U32LE, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+ buf)
+ < 0)
+ {
+ TEST_ERROR;
+ }
+
+ if (H5Dclose(dset_id) < 0) {
+ TEST_ERROR;
+ }
+ dset_id = H5I_INVALID_HID;
+ } /* end if writing a dataset */
+
+ } /* end for dataset create-destroy cycles */
+
+ if (H5Fclose(file_id) < 0) {
+ TEST_ERROR;
+ }
+ file_id = H5I_INVALID_HID;
+
+ /* verify there are no datasets in file */
+ file_id = H5Fopen(names.rw, H5F_ACC_RDONLY, H5P_DEFAULT);
+ if (file_id < 0) {
+ TEST_ERROR;
+ }
+ if (H5Gget_info(file_id, &group_info) < 0) {
+ TEST_ERROR;
+ }
+ if (group_info.nlinks > 0) {
+ HDfprintf(stderr, "links in rw file: %d\n", group_info.nlinks);
+ HDfflush(stderr);
+ TEST_ERROR;
+ }
+ if (H5Fclose(file_id) < 0) {
+ TEST_ERROR;
+ }
+ file_id = H5Fopen(names.wo, H5F_ACC_RDONLY, H5P_DEFAULT);
+ if (file_id < 0) {
+ TEST_ERROR;
+ }
+ if (H5Gget_info(file_id, &group_info) < 0) {
+ TEST_ERROR;
+ }
+ if (group_info.nlinks > 0) {
+ HDfprintf(stderr, "links in wo file: %d\n", group_info.nlinks);
+ HDfflush(stderr);
+ TEST_ERROR;
+ }
+ if (H5Fclose(file_id) < 0) {
+ TEST_ERROR;
+ }
+ file_id = H5I_INVALID_HID;
+
+ if (h5_compare_file_bytes(names.rw, names.wo) < 0)
+ TEST_ERROR;
+
+ /* -------------------- */
+ /* Teardown */
+
+ if (H5Sclose(dspace_id) < 0) {
+ TEST_ERROR;
+ }
+ if (H5Pclose(fapl_id) < 0) {
+ TEST_ERROR;
+ }
+
+ PASSED();
+ return 0;
+
+error:
+ H5E_BEGIN_TRY {
+ if (mirror_fapl_id != H5I_INVALID_HID) {
+ H5Pclose(mirror_fapl_id);
+ }
+ if (fapl_id != H5I_INVALID_HID) {
+ H5Pclose(fapl_id);
+ }
+ if (file_id != H5I_INVALID_HID) {
+ H5Fclose(file_id);
+ }
+ if (dset_id != H5I_INVALID_HID) {
+ H5Dclose(dset_id);
+ }
+ if (dspace_id != H5I_INVALID_HID) {
+ H5Sclose(dspace_id);
+ }
+ } H5E_END_TRY;
+ return -1;
+} /* test_vanishing_datasets() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: test_concurrent_access
+ *
+ * Purpose: Verify that more than one file may be opened at a time.
+ *
+ * TODO: receive target IP from caller?
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Jacob Smith
+ * 2020-03-09
+ * ---------------------------------------------------------------------------
+ */
+static int
+test_concurrent_access(void)
+{
+ struct file_bundle {
+ struct mirrortest_filenames names;
+ hid_t dset_id;
+ hid_t fapl_id;
+ hid_t file_id;
+ } bundle[CONCURRENT_COUNT];
+ hid_t dspace_id = H5I_INVALID_HID;
+ hid_t dtype_id = H5T_NATIVE_INT;
+ hsize_t dims[2] = { DATABUFFER_SIZE, DATABUFFER_SIZE };
+ int *buf = NULL;
+ int i = 0;
+ int j = 0;
+
+ TESTING("Concurrent opened mirrored files");
+
+ /* blank bundle */
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ bundle[i].dset_id = H5I_INVALID_HID;
+ bundle[i].fapl_id = H5I_INVALID_HID;
+ bundle[i].file_id = H5I_INVALID_HID;
+ *bundle[i].names.rw = '\0';
+ *bundle[i].names.wo = '\0';
+ *bundle[i].names.log = '\0';
+ }
+
+ /* Create FAPL for Splitter[sec2|mirror]
+ */
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ char _name[16] = "";
+ hid_t _fapl_id = H5I_INVALID_HID;
+ HDsnprintf(_name, 15, "concurrent%d", i);
+ _fapl_id = create_mirroring_split_fapl(_name, &bundle[i].names);
+ if (H5I_INVALID_HID == _fapl_id) {
+ TEST_ERROR;
+ }
+ bundle[i].fapl_id = _fapl_id;
+ }
+
+ /* Prepare data to be written
+ */
+ buf = (int *)HDmalloc(DATABUFFER_SIZE * DATABUFFER_SIZE * sizeof(int));
+ if (NULL == buf) {
+ TEST_ERROR;
+ }
+ for (i = 0; i < DATABUFFER_SIZE; i++) {
+ for (j = 0; j < DATABUFFER_SIZE; j++) {
+ int k = i * DATABUFFER_SIZE + j;
+ buf[k] = k;
+ }
+ }
+
+ /* Prepare generic dataspace
+ */
+ dspace_id = H5Screate_simple(2, dims, NULL);
+ if (H5I_INVALID_HID == dspace_id) {
+ TEST_ERROR;
+ }
+
+ /* -------------------- */
+ /* TEST: Create file and open elements */
+
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ hid_t _file_id = H5I_INVALID_HID;
+ hid_t _dset_id = H5I_INVALID_HID;
+
+ _file_id = H5Fcreate(bundle[i].names.rw, H5F_ACC_TRUNC, H5P_DEFAULT,
+ bundle[i].fapl_id);
+ if (H5I_INVALID_HID == _file_id) {
+ TEST_ERROR;
+ }
+
+ bundle[i].file_id = _file_id;
+
+ _dset_id = H5Dcreate2(_file_id, "dataset", dtype_id, dspace_id,
+ H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+ if (H5I_INVALID_HID == _dset_id) {
+ TEST_ERROR;
+ }
+ bundle[i].dset_id = _dset_id;
+ }
+
+ /* -------------------- */
+ /* TEST: Write to files */
+
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ if (H5Dwrite(bundle[i].dset_id, dtype_id, H5S_ALL, H5S_ALL,
+ H5P_DEFAULT, buf)
+ == FAIL)
+ {
+ TEST_ERROR;
+ }
+ }
+
+ /* -------------------- */
+ /* TEST: Close elements */
+
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ if (H5Dclose(bundle[i].dset_id) == FAIL) {
+ TEST_ERROR;
+ }
+ if (H5Fclose(bundle[i].file_id) == FAIL) {
+ TEST_ERROR;
+ }
+ if (H5Pclose(bundle[i].fapl_id) == FAIL) {
+ TEST_ERROR;
+ }
+ }
+
+ /* -------------------- */
+ /* Standard cleanup */
+
+ HDfree(buf);
+ buf = NULL;
+ if (H5Sclose(dspace_id) == FAIL) {
+ TEST_ERROR;
+ }
+
+ /* -------------------- */
+ /* TEST: Verify that the R/W and W/O files are identical */
+
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ if (h5_compare_file_bytes(bundle[i].names.rw, bundle[i].names.wo) < 0) {
+ TEST_ERROR;
+ }
+ }
+
+ PASSED();
+ return 0;
+
+error:
+ H5E_BEGIN_TRY{
+ if (buf) {
+ HDfree(buf);
+ }
+ (void)H5Sclose(dspace_id);
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ (void)H5Dclose(bundle[i].dset_id);
+ (void)H5Fclose(bundle[i].file_id);
+ (void)H5Pclose(bundle[i].fapl_id);
+ }
+ } H5E_END_TRY;
+ return -1;
+} /* end test_concurrent_access() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: main
+ *
+ * Purpose: Run tests.
+ *
+ * Return: Success: 0
+ * Failure: 1
+ *
+ * Programmer: Jacob Smith
+ * 2019
+ * ---------------------------------------------------------------------------
+ */
+int
+main(void)
+{
+ int nerrors = 0;
+
+ h5_reset();
+
+ g_log_stream = stdout; /* default debug/logging output stream */
+
+ HDprintf("Testing Mirror VFD functionality.\n");
+
+ /* -------------------- */
+ /* SETUP */
+
+ /* Create directories for test-generated .h5 files
+ */
+ if (nerrors == 0) {
+ if ((HDmkdir(MIRROR_RW_DIR, (mode_t)0755) < 0) && (errno != EEXIST)) {
+ nerrors++;
+ }
+ }
+ if (nerrors == 0) {
+ if ((HDmkdir(MIRROR_WO_DIR, (mode_t)0755) < 0) && (errno != EEXIST)) {
+ nerrors++;
+ }
+ }
+
+ /* -------------------- */
+ /* TESTS */
+ /* Tests return negative values; `-=' increments nerrors count */
+
+ if (nerrors == 0) {
+ nerrors -= test_fapl_configuration();
+ nerrors -= test_xmit_encode_decode();
+ nerrors -= test_create_and_close();
+ nerrors -= test_basic_dataset_write();
+ nerrors -= test_chunked_dataset_write();
+ nerrors -= test_on_disk_zoo();
+ nerrors -= test_vanishing_datasets();
+ nerrors -= test_concurrent_access();
+ }
+
+ if (nerrors) {
+ HDprintf("***** %d Mirror VFD TEST%s FAILED! *****\n",
+ nerrors, nerrors > 1 ? "S" : "");
+ return EXIT_FAILURE;
+ }
+
+ HDprintf("All Mirror Virtual File Driver tests passed.\n");
+ return EXIT_SUCCESS;
+} /* end main() */
+
+#else /* H5_HAVE_MIRROR_VFD */
+
+int
+main(void)
+{
+ h5_reset();
+ HDprintf("Testing Mirror VFD functionality.\n");
+ HDprintf("SKIPPED - Mirror VFD not built.\n");
+ return EXIT_SUCCESS;
+}
+
+#endif /* H5_HAVE_MIRROR_VFD */
+
+
diff --git a/test/test_mirror.sh.in b/test/test_mirror.sh.in
new file mode 100644
index 0000000..3fdc673
--- /dev/null
+++ b/test/test_mirror.sh.in
@@ -0,0 +1,100 @@
+#! /bin/bash
+#
+# 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.
+#
+# Tests for the Mirror VFD feature.
+#
+# Created:
+# Jacob Smith, 2019-12-30
+
+###############################################################################
+## test parameters
+###############################################################################
+
+nerrors=0
+
+SERVER_VERBOSITY="--verbosity=1"
+SERVER_PORT="--port=3000"
+
+
+###############################################################################
+## Main
+###############################################################################
+
+## TODO: arguments for main port, port range, verbosity?
+# Parse options (none accepted at this time)
+while [ $# -gt 0 ]; do
+ case "$1" in
+ *) # unknown option
+ echo "$0: Unknown option ($1)"
+ exit 1
+ ;;
+ esac
+done
+
+
+
+RUN_DIR=mirror_vfd_test
+MIRROR_UTILS=../utils/mirror_vfd # TODO: presupposes from test/
+
+mkdir $RUN_DIR
+
+# Copy program files into dedicated test directory
+for FILE in $MIRROR_UTILS/mirror_* ; do
+ case "$FILE" in
+ *.o) continue ;; # Don't copy .o files
+ esac
+ cp $FILE $RUN_DIR
+done
+cp mirror_vfd $RUN_DIR
+
+# With the --disable-shared option, program files are built in their main
+# directories; otherwise they are built in dir/.libs with a corresponding
+# wrapper script. Copy these libs builds if appropriate.
+if [ -f $MIRROR_UTILS/.libs/mirror_server ] ; then
+ RUN_LIBS=$RUN_DIR/.libs
+ mkdir $RUN_LIBS
+ for FILE in $MIRROR_UTILS/.libs/mirror_* ; do
+ case "$FILE" in
+ *.o) continue ;; # Don't copy .o files
+ esac
+ cp $FILE $RUN_LIBS
+ done
+ cp .libs/mirror_vfd $RUN_LIBS
+fi
+
+cd $RUN_DIR
+
+echo "Launching Mirror Server"
+SERVER_ARGS="$SERVER_PORT $SERVER_VERBOSITY"
+./mirror_server $SERVER_ARGS &
+
+./mirror_vfd
+nerrors=$?
+
+echo "Stopping Mirror Server"
+./mirror_server_halten_sie $SERVER_PORT
+
+###############################################################################
+## Report and exit
+###############################################################################
+cd ..
+if test $nerrors -eq 0 ; then
+ echo "Mirror VFD tests passed."
+ if test -z "$HDF5_NOCLEANUP" ; then
+ rm -rf $RUN_DIR
+ fi
+ exit 0
+else
+ echo "Mirror VFD tests FAILED."
+ exit 1
+fi
+
diff --git a/test/use.h b/test/use.h
index 54d9b26..e5eced2 100644
--- a/test/use.h
+++ b/test/use.h
@@ -16,48 +16,46 @@
#include "h5test.h"
/* Macro definitions */
-#define Hgoto_error(val) {ret_value=val; goto done;}
-#define Hgoto_done {goto done;}
-#define Chunksize_DFT 256 /* chunksize default */
-#define ErrorReportMax 10 /* max number of errors reported */
+#define Hgoto_error(val) {ret_value=val; goto done;}
+#define Hgoto_done {goto done;}
+#define Chunksize_DFT 256 /* chunksize default */
+#define ErrorReportMax 10 /* max number of errors reported */
/* these two definitions must match each other */
-#define UC_DATATYPE H5T_NATIVE_SHORT /* use case HDF5 data type */
-#define UC_CTYPE short /* use case C data type */
-#define UC_RANK 3 /* use case dataset rank */
+#define UC_DATATYPE H5T_NATIVE_SHORT /* use case HDF5 data type */
+#define UC_CTYPE short /* use case C data type */
+#define UC_RANK 3 /* use case dataset rank */
/* Name of message file that is sent by the writer */
#define WRITER_MESSAGE "USE_WRITER_MESSAGE"
/* type declarations */
typedef enum part_t {
- UC_READWRITE =0, /* both writer and reader */
- UC_WRITER, /* writer only */
- UC_READER /* reader only */
+ UC_READWRITE = 0, /* both writer and reader */
+ UC_WRITER, /* writer only */
+ UC_READER /* reader only */
} part_t;
typedef struct options_t {
- hsize_t chunksize; /* chunks are chunksize^2 planes */
- hsize_t chunkplanes; /* number of planes per chunk, default 1 */
+ hsize_t chunksize; /* chunks are chunksize^2 planes */
+ hsize_t chunkplanes; /* number of planes per chunk, default 1 */
hsize_t chunkdims[UC_RANK]; /* chunk dims is (chunkplan, chunksize, chunksize) */
hsize_t dims[UC_RANK]; /* dataset initial dims */
hsize_t max_dims[UC_RANK]; /* dataset max dims */
- hsize_t nplanes; /* number of planes to write, default proportional to chunksize */
- char *filename; /* use case data filename */
- part_t launch; /* launch writer, reader or both */
- hbool_t use_swmr; /* use swmr open (1) or not */
- int iterations; /* iterations, default 1 */
+ hsize_t nplanes; /* number of planes to write, default proportional to chunksize */
+ char *filename; /* use case data filename */
+ part_t launch; /* launch writer, reader or both */
+ hbool_t use_swmr; /* use swmr open (1) or not */
+ int iterations; /* iterations, default 1 */
+ hid_t fapl_id; /* instance-specific FAPL ID */
+ char *progname; /* Program name (used in usage and dset name) */
} options_t;
-/* global variables declarations */
-extern options_t UC_opts; /* Use Case Options */
-extern const char *progname_g; /* Program name */
-
/* prototype declarations */
-int parse_option(int argc, char * const argv[]);
-int setup_parameters(int argc, char * const argv[]);
-void show_parameters(void);
+int parse_option(int argc, char * const argv[], options_t * opts);
+int setup_parameters(int argc, char * const argv[], options_t * opts);
+void show_parameters(options_t * opts);
void usage(const char *prog);
-int create_uc_file(void);
-int write_uc_file(hbool_t tosend, hid_t fid);
-int read_uc_file(hbool_t towait);
+int create_uc_file(options_t * opts);
+int write_uc_file(hbool_t tosend, hid_t file_id, options_t * opts);
+int read_uc_file(hbool_t towait, options_t * opts);
diff --git a/test/use_append_chunk.c b/test/use_append_chunk.c
index 6b34f1e..35594cf 100644
--- a/test/use_append_chunk.c
+++ b/test/use_append_chunk.c
@@ -11,7 +11,7 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Use Case 1.7 Appending a single chunk
+ * Use Case 1.7 Appending a single chunk
* Description:
* Appending a single chunk of raw data to a dataset along an unlimited
* dimension within a pre-created file and reading the new data back.
@@ -24,35 +24,36 @@
* Level:
* User Level
* Guarantees:
- * o Readers will see the modified dimension sizes after the Writer
- * finishes HDF5 metadata updates and issues H5Fflush or H5Oflush calls.
- * o Readers will see newly appended data after the Writer finishes
- * the flush operation.
- *
+ * o Readers will see the modified dimension sizes after the Writer
+ * finishes HDF5 metadata updates and issues H5Fflush or H5Oflush calls.
+ * o Readers will see newly appended data after the Writer finishes
+ * the flush operation.
+ *
* Preconditions:
- * o Readers are not allowed to modify the file. o All datasets
- * that are modified by the Writer exist when the Writer opens the file.
- * o All datasets that are modified by the Writer exist when a Reader
- * opens the file. o Data is written by a hyperslab contained in
- * one chunk.
- *
+ * o Readers are not allowed to modify the file.
+ * o All datasets that are modified by the Writer exist when the Writer
+ * opens the file.
+ * o All datasets that are modified by the Writer exist when a Reader
+ * opens the file.
+ * o Data is written by a hyperslab contained in one chunk.
+ *
* Main Success Scenario:
- * 1. An application creates a file with required objects (groups,
- * datasets, and attributes).
- * 2. The Writer application opens the file and datasets in the file
- * and starts adding data along the unlimited dimension using a hyperslab
- * selection that corresponds to an HDF5 chunk.
- * 3. A Reader opens the file and a dataset in a file, and queries
- * the sizes of the dataset; if the extent of the dataset has changed,
- * reads the appended data back.
- *
+ * 1. An application creates a file with required objects (groups,
+ * datasets, and attributes).
+ * 2. The Writer application opens the file and datasets in the file
+ * and starts adding data along the unlimited dimension using a hyperslab
+ * selection that corresponds to an HDF5 chunk.
+ * 3. A Reader opens the file and a dataset in a file, and queries
+ * the sizes of the dataset; if the extent of the dataset has changed,
+ * reads the appended data back.
+ *
* Discussion points:
- * 1. Since the new data is written to the file, and metadata update
- * operation of adding pointer to the newly written chunk is atomic and
- * happens after the chunk is on the disk, only two things may happen
- * to the Reader:
- * o The Reader will not see new data.
- * o The Reader will see all new data written by Writer.
+ * 1. Since the new data is written to the file, and metadata update
+ * operation of adding pointer to the newly written chunk is atomic and
+ * happens after the chunk is on the disk, only two things may happen
+ * to the Reader:
+ * o The Reader will not see new data.
+ * o The Reader will see all new data written by Writer.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Created: Albert Cheng, 2013/5/28 */
@@ -68,46 +69,43 @@
#include "use.h"
-/* Global Variable definitions */
-options_t UC_opts; /* Use Case Options */
-const char *progname_g="use_append_chunk"; /* program name */
+#define USE_APPEND_CHUNK_PROGNAME "use_append_chunk"
+
+static options_t UC_opts; /* Use Case Options */
/* Setup parameters for the use case.
* Return: 0 succeed; -1 fail.
*/
-int setup_parameters(int argc, char * const argv[])
+int
+setup_parameters(int argc, char * const argv[], options_t * opts)
{
/* use case defaults */
- HDmemset(&UC_opts, 0, sizeof(options_t));
- UC_opts.chunksize = Chunksize_DFT;
- UC_opts.use_swmr = TRUE; /* use swmr open */
- UC_opts.iterations = 1;
- UC_opts.chunkplanes = 1;
-
- /* parse options */
- if (parse_option(argc, argv) < 0)
- return(-1);
-
- /* set chunk dims */
- UC_opts.chunkdims[0] = UC_opts.chunkplanes;
- UC_opts.chunkdims[1] = UC_opts.chunkdims[2] = UC_opts.chunksize;
-
- /* set dataset initial and max dims */
- UC_opts.dims[0] = 0;
- UC_opts.max_dims[0] = H5S_UNLIMITED;
- UC_opts.dims[1] = UC_opts.dims[2] = UC_opts.max_dims[1] = UC_opts.max_dims[2] = UC_opts.chunksize;
-
- /* set nplanes */
- if (UC_opts.nplanes == 0)
- UC_opts.nplanes = (hsize_t)UC_opts.chunksize;
-
- /* show parameters and return */
- show_parameters();
+ HDmemset(opts, 0, sizeof(options_t));
+ opts->chunksize = Chunksize_DFT;
+ opts->use_swmr = TRUE; /* use swmr open */
+ opts->iterations = 1;
+ opts->chunkplanes = 1;
+ opts->progname = USE_APPEND_CHUNK_PROGNAME;
+
+ if (parse_option(argc, argv, opts) < 0)
+ return(-1);
+
+ opts->chunkdims[0] = opts->chunkplanes;
+ opts->chunkdims[1] = opts->chunkdims[2] = opts->chunksize;
+
+ opts->dims[0] = 0;
+ opts->max_dims[0] = H5S_UNLIMITED;
+ opts->dims[1] = opts->dims[2] = opts->max_dims[1] = opts->max_dims[2] = opts->chunksize;
+
+ if (opts->nplanes == 0)
+ opts->nplanes = (hsize_t)opts->chunksize;
+
+ show_parameters(opts);
return(0);
-}
+} /* setup_parameters() */
-/* Overall Algorithm:
+/* Overall Algorithm:
* Parse options from user;
* Generate/pre-created test files needed and close it;
* fork: child process becomes the reader process;
@@ -119,22 +117,20 @@ main(int argc, char *argv[])
{
pid_t childpid=0;
pid_t mypid, tmppid;
- int child_status;
+ int child_status;
int child_wait_option=0;
int ret_value = 0;
int child_ret_value;
hbool_t send_wait = FALSE;
hid_t fapl = -1; /* File access property list */
hid_t fid = -1; /* File ID */
- char *name; /* Test file name */
- /* initialization */
- if (setup_parameters(argc, argv) < 0){
+ if (setup_parameters(argc, argv, &UC_opts) < 0) {
Hgoto_error(1);
}
/* Determine the need to send/wait message file*/
- if(UC_opts.launch == UC_READWRITE) {
+ if (UC_opts.launch == UC_READWRITE) {
HDunlink(WRITER_MESSAGE);
send_wait = TRUE;
}
@@ -144,38 +140,63 @@ main(int argc, char *argv[])
/* UC_WRITER: create datafile, skip reader, launch writer. */
/* UC_READER: skip create, launch reader, exit. */
/* ==============================================================*/
- /* ============*/
+ /* =========== */
/* Create file */
- /* ============*/
- if (UC_opts.launch != UC_READER){
+ /* =========== */
+ if (UC_opts.launch != UC_READER) {
HDprintf("Creating skeleton data file for test...\n");
- if (create_uc_file() < 0){
+ if ((UC_opts.fapl_id = h5_fileaccess()) < 0) {
+ HDfprintf(stderr, "can't create creation FAPL\n");
+ Hgoto_error(1);
+ }
+ if (H5Pset_libver_bounds(UC_opts.fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) {
+ HDfprintf(stderr, "can't set creation FAPL libver bounds\n");
+ Hgoto_error(1);
+ }
+ if (create_uc_file(&UC_opts) < 0) {
HDfprintf(stderr, "***encounter error\n");
Hgoto_error(1);
- }else
+ } else {
HDprintf("File created.\n");
+ }
+ /* Close FAPL to prevent issues with forking later */
+ if (H5Pclose(UC_opts.fapl_id) < 0) {
+ HDfprintf(stderr, "can't close creation FAPL\n");
+ Hgoto_error(1);
+ }
+ UC_opts.fapl_id = H5I_INVALID_HID;
}
- if (UC_opts.launch==UC_READWRITE){
- /* fork process */
- if((childpid = HDfork()) < 0) {
+ /* ============ */
+ /* Fork process */
+ /* ============ */
+ if (UC_opts.launch == UC_READWRITE) {
+ if ((childpid = HDfork()) < 0) {
HDperror("fork");
Hgoto_error(1);
- };
- };
+ }
+ }
mypid = HDgetpid();
/* ============= */
/* launch reader */
/* ============= */
- if (UC_opts.launch != UC_WRITER){
+ if (UC_opts.launch != UC_WRITER) {
/* child process launch the reader */
- if(0 == childpid) {
+ if (0 == childpid) {
HDprintf("%d: launch reader process\n", mypid);
- if (read_uc_file(send_wait) < 0){
+ if ((UC_opts.fapl_id = h5_fileaccess()) < 0) {
+ HDfprintf(stderr, "can't create read FAPL\n");
+ HDexit(EXIT_FAILURE);
+ }
+ if (read_uc_file(send_wait, &UC_opts) < 0) {
HDfprintf(stderr, "read_uc_file encountered error\n");
HDexit(EXIT_FAILURE);
}
+ if (H5Pclose(UC_opts.fapl_id) < 0) {
+ HDfprintf(stderr, "can't close read FAPL\n");
+ HDexit(EXIT_FAILURE);
+ }
HDexit(EXIT_SUCCESS);
}
}
@@ -186,65 +207,63 @@ main(int argc, char *argv[])
/* this process continues to launch the writer */
HDprintf("%d: continue as the writer process\n", mypid);
- name = UC_opts.filename;
-
- /* Set file access proeprty list */
- if((fapl = h5_fileaccess()) < 0)
+ if ((fapl = h5_fileaccess()) < 0) {
+ HDfprintf(stderr, "can't create write FAPL\n");
Hgoto_error(1);
+ }
- if(UC_opts.use_swmr)
- if(H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0)
+ if (UC_opts.use_swmr) {
+ if (H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) {
+ HDfprintf(stderr, "can't set write FAPL libver bounds\n");
Hgoto_error(1);
+ }
+ }
- /* Open the file */
- if((fid = H5Fopen(name, H5F_ACC_RDWR | (UC_opts.use_swmr ? H5F_ACC_SWMR_WRITE : 0), fapl)) < 0) {
+ if ((fid = H5Fopen(UC_opts.filename, H5F_ACC_RDWR | (UC_opts.use_swmr ? H5F_ACC_SWMR_WRITE : 0), fapl)) < 0) {
HDfprintf(stderr, "H5Fopen failed\n");
Hgoto_error(1);
}
- if(write_uc_file(send_wait, fid) < 0) {
+ if (write_uc_file(send_wait, fid, &UC_opts) < 0) {
HDfprintf(stderr, "write_uc_file encountered error\n");
Hgoto_error(1);
}
+ if (H5Fclose(fid) < 0) {
+ HDfprintf(stderr, "Failed to close write\n");
+ Hgoto_error(1);
+ }
+
+ if (H5Pclose(fapl) < 0) {
+ HDfprintf(stderr, "can't close write FAPL\n");
+ Hgoto_error(1);
+ }
+
/* ================================================ */
/* If readwrite, collect exit code of child process */
/* ================================================ */
- if (UC_opts.launch == UC_READWRITE){
- if ((tmppid = HDwaitpid(childpid, &child_status, child_wait_option)) < 0){
+ if (UC_opts.launch == UC_READWRITE) {
+ if ((tmppid = HDwaitpid(childpid, &child_status, child_wait_option)) < 0) {
HDperror("waitpid");
Hgoto_error(1);
}
- /* Close the file */
- if(H5Fclose(fid) < 0) {
- HDfprintf(stderr, "Failed to close file id\n");
- Hgoto_error(1);
- }
-
- /* Close the property list */
- if(H5Pclose(fapl) < 0) {
- HDfprintf(stderr, "Failed to close the property list\n");
- Hgoto_error(1);
- }
-
- if (WIFEXITED(child_status)){
- if ((child_ret_value=WEXITSTATUS(child_status)) != 0){
+ if (WIFEXITED(child_status)) {
+ if ((child_ret_value = WEXITSTATUS(child_status)) != 0) {
HDprintf("%d: child process exited with non-zero code (%d)\n",
mypid, child_ret_value);
Hgoto_error(2);
}
- } else {
- HDprintf("%d: child process terminated abnormally\n", mypid);
- Hgoto_error(2);
- }
+ } else {
+ HDprintf("%d: child process terminated abnormally\n", mypid);
+ Hgoto_error(2);
+ }
}
-
+
done:
- /* Print result and exit */
- if (ret_value != 0){
+ if (ret_value != 0) {
HDprintf("Error(s) encountered\n");
- }else{
+ } else {
HDprintf("All passed\n");
}
diff --git a/test/use_append_chunk_mirror.c b/test/use_append_chunk_mirror.c
new file mode 100644
index 0000000..6ee01c0
--- /dev/null
+++ b/test/use_append_chunk_mirror.c
@@ -0,0 +1,403 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * 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. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* HACKED VERSION
+ * Demonstrate SWMR with a mirrored file.
+ *
+ * Must be built with SERVER_IP as the IP address of the target system
+ * with a running mirror server, and SERVER_PORT as the primary server port.
+ *
+ * In addition to the local file, 'shinano.h5' will be created on the remote
+ * system, mirroring the local file. The file location will be local to
+ * Server's/Writer's invocation directory.
+ *
+ * Template for demonstration purposes:
+ *
+ * # Launch mirror server on remote machine (in foreground to easily stop)
+ * REMOTE(1)$ ./mirror_server /path/to/mirror_worker
+ *
+ * # Launch chunk writer with plenty of chunks.
+ * LOCAL(1)$ ./use_append_chunk_mirror -l w -n 10000
+ *
+ * # Wait one second for files to be created.
+ *
+ * # Launch chunk readers on both files.
+ * LOCAL(2)$ ./use_append_chunk_mirror -l r -n 10000
+ * REMOTE(2)$ ./use_append_chunk_mirror -l r -n 10000 -f shinano.h5
+ *
+ * # Hard-stop the server.
+ * REMOTE(1)$ ^C
+ * # alt, softer shutdown using echo and nc
+ * echo "SHUTDOWN" | nc localhost 3000
+ */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Use Case 1.7 Appending a single chunk
+ * Description:
+ * Appending a single chunk of raw data to a dataset along an unlimited
+ * dimension within a pre-created file and reading the new data back.
+ * Goal:
+ * Read data appended by the Writer to a pre-existing dataset in a
+ * file. The dataset has one or more unlimited dimensions. The data is
+ * appended by a hyperslab that is contained in one chunk (for example,
+ * appending 2-dim planes along the slowest changing dimension in the
+ * 3-dim dataset).
+ * Level:
+ * User Level
+ * Guarantees:
+ * o Readers will see the modified dimension sizes after the Writer
+ * finishes HDF5 metadata updates and issues H5Fflush or H5Oflush calls.
+ * o Readers will see newly appended data after the Writer finishes
+ * the flush operation.
+ *
+ * Preconditions:
+ * o Readers are not allowed to modify the file.
+ * o All datasets that are modified by the Writer exist when the Writer
+ * opens the file.
+ * o All datasets that are modified by the Writer exist when a Reader
+ * opens the file.
+ * o Data is written by a hyperslab contained in one chunk.
+ *
+ * Main Success Scenario:
+ * 1. An application creates a file with required objects (groups,
+ * datasets, and attributes).
+ * 2. The Writer application opens the file and datasets in the file
+ * and starts adding data along the unlimited dimension using a hyperslab
+ * selection that corresponds to an HDF5 chunk.
+ * 3. A Reader opens the file and a dataset in a file, and queries
+ * the sizes of the dataset; if the extent of the dataset has changed,
+ * reads the appended data back.
+ *
+ * Discussion points:
+ * 1. Since the new data is written to the file, and metadata update
+ * operation of adding pointer to the newly written chunk is atomic and
+ * happens after the chunk is on the disk, only two things may happen
+ * to the Reader:
+ * o The Reader will not see new data.
+ * o The Reader will see all new data written by Writer.
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Created: Jacob Smith, 2019 */
+
+#include "use.h"
+
+/* This test uses many POSIX things that are not available on
+ * Windows. We're using a check for fork(2) here as a proxy for
+ * all POSIX/Unix/Linux things until this test can be made
+ * more platform-independent.
+ */
+#ifdef H5_HAVE_FORK
+
+#ifdef H5_HAVE_MIRROR_VFD
+
+#define THIS_PROGNAME "use_append_chunk_mirror"
+
+#define CONNECT_WITH_JELLY 0
+
+#if CONNECT_WITH_JELLY
+#define SERVER_IP "10.10.10.248" /* hard-coded IP address */
+#else
+#define SERVER_IP "127.0.0.1" /* localhost */
+#endif /* CONNECT_WITH_JELLY */
+#define SERVER_PORT 3000 /* hard-coded port number */
+#define MIRROR_FILE_NAME "shinano.h5" /* hard-coded duplicate/mirror filename */
+
+static options_t UC_opts; /* Use Case Options */
+
+/* Setup parameters for the use case.
+ * Return: 0 succeed; -1 fail.
+ */
+int
+setup_parameters(int argc, char * const argv[], options_t * opts)
+{
+ /* use case defaults */
+ HDmemset(opts, 0, sizeof(options_t));
+ opts->chunksize = Chunksize_DFT;
+ opts->use_swmr = TRUE;
+ opts->iterations = 1;
+ opts->chunkplanes = 1;
+ opts->progname = THIS_PROGNAME;
+
+ if (parse_option(argc, argv, opts) < 0)
+ return(-1);
+
+ opts->chunkdims[0] = opts->chunkplanes;
+ opts->chunkdims[1] = opts->chunkdims[2] = opts->chunksize;
+
+ opts->dims[0] = 0;
+ opts->max_dims[0] = H5S_UNLIMITED;
+ opts->dims[1] = opts->dims[2] = opts->max_dims[1] = opts->max_dims[2] = opts->chunksize;
+
+ if (opts->nplanes == 0)
+ opts->nplanes = (hsize_t)opts->chunksize;
+
+ show_parameters(opts);
+ return(0);
+} /* setup_parameters() */
+
+
+/* Overall Algorithm:
+ * Parse options from user;
+ * Generate/pre-created test files needed and close it;
+ * fork: child process becomes the reader process;
+ * while parent process continues as the writer process;
+ * both run till ending conditions are met.
+ */
+int
+main(int argc, char *argv[])
+{
+ pid_t childpid=0;
+ pid_t mypid, tmppid;
+ int child_status;
+ int child_wait_option=0;
+ int ret_value = 0;
+ int child_ret_value;
+ hbool_t send_wait = FALSE;
+ hid_t fid = -1; /* File ID */
+ H5FD_mirror_fapl_t mirr_fa;
+ H5FD_splitter_vfd_config_t split_fa;
+ hid_t mirr_fapl_id = H5I_INVALID_HID;
+
+ if (setup_parameters(argc, argv, &UC_opts) < 0) {
+ Hgoto_error(1);
+ }
+
+ mirr_fa.magic = H5FD_MIRROR_FAPL_MAGIC;
+ mirr_fa.version = H5FD_MIRROR_CURR_FAPL_T_VERSION;
+ mirr_fa.handshake_port = SERVER_PORT;
+ HDstrncpy(mirr_fa.remote_ip, SERVER_IP, H5FD_MIRROR_MAX_IP_LEN);
+
+
+ split_fa.wo_fapl_id = H5I_INVALID_HID;
+ split_fa.rw_fapl_id = H5I_INVALID_HID;
+ split_fa.magic = H5FD_SPLITTER_MAGIC;
+ split_fa.version = H5FD_CURR_SPLITTER_VFD_CONFIG_VERSION;
+ split_fa.log_file_path[0] = '\0'; /* none */
+ split_fa.ignore_wo_errs = FALSE;
+ HDstrncpy(split_fa.wo_path, MIRROR_FILE_NAME, H5FD_SPLITTER_PATH_MAX);
+
+ /* Determine the need to send/wait message file*/
+ if (UC_opts.launch == UC_READWRITE) {
+ HDunlink(WRITER_MESSAGE);
+ send_wait = TRUE;
+ }
+
+ /* ==============================================================*/
+ /* UC_READWRITE: create datafile, launch both reader and writer. */
+ /* UC_WRITER: create datafile, skip reader, launch writer. */
+ /* UC_READER: skip create, launch reader, exit. */
+ /* ==============================================================*/
+ /* =========== */
+ /* Create file */
+ /* =========== */
+ if (UC_opts.launch != UC_READER) {
+ HDprintf("Creating skeleton data file for test...\n");
+
+ /* Prepare mirror child driver */
+ mirr_fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ if (mirr_fapl_id == H5I_INVALID_HID) {
+ HDfprintf(stderr, "can't create creation mirror FAPL\n");
+ Hgoto_error(1);
+ }
+ if (H5Pset_fapl_mirror(mirr_fapl_id, &mirr_fa) < 0) {
+ HDfprintf(stderr, "can't set creation mirror FAPL\n");
+ H5Eprint2(H5E_DEFAULT, stdout);
+ Hgoto_error(1);
+ }
+
+ /* Prepare parent "splitter" driver in UC_opts */
+ split_fa.wo_fapl_id = mirr_fapl_id;
+ split_fa.rw_fapl_id = H5P_DEFAULT;
+ UC_opts.fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ if (UC_opts.fapl_id == H5I_INVALID_HID) {
+ HDfprintf(stderr, "can't create creation FAPL\n");
+ Hgoto_error(1);
+ }
+ if (H5Pset_fapl_splitter(UC_opts.fapl_id, &split_fa) < 0) {
+ HDfprintf(stderr, "can't set creation FAPL\n");
+ H5Eprint2(H5E_DEFAULT, stdout);
+ Hgoto_error(1);
+ }
+
+ if (H5Pset_libver_bounds(UC_opts.fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) {
+ HDfprintf(stderr, "can't set creation FAPL libver bounds\n");
+ Hgoto_error(1);
+ }
+
+ /* Create file */
+ if (create_uc_file(&UC_opts) < 0) {
+ HDfprintf(stderr, "***encounter error\n");
+ Hgoto_error(1);
+ } else {
+ HDprintf("File created.\n");
+ }
+
+ /* Close FAPLs to prevent issues with forking later */
+ if (H5Pclose(UC_opts.fapl_id) < 0) {
+ HDfprintf(stderr, "can't close creation FAPL\n");
+ Hgoto_error(1);
+ }
+ UC_opts.fapl_id = H5I_INVALID_HID;
+ if (H5Pclose(mirr_fapl_id) < 0) {
+ HDfprintf(stderr, "can't close creation mirror FAPL\n");
+ Hgoto_error(1);
+ }
+ mirr_fapl_id = H5I_INVALID_HID;
+ }
+
+ /* ============ */
+ /* Fork process */
+ /* ============ */
+ if (UC_opts.launch == UC_READWRITE) {
+ if ((childpid = HDfork()) < 0) {
+ HDperror("fork");
+ Hgoto_error(1);
+ }
+ }
+ mypid = HDgetpid();
+
+ /* ============= */
+ /* launch reader */
+ /* ============= */
+ if (UC_opts.launch != UC_WRITER) {
+ /* child process -- launch the reader */
+ /* reader only opens the one file -- separate reader needed for mirrored file 'shinano.h5' */
+ if (0 == childpid) {
+ HDprintf("%d: launch reader process\n", mypid);
+
+ UC_opts.fapl_id = H5P_DEFAULT;
+ if (read_uc_file(send_wait, &UC_opts) < 0) {
+ HDfprintf(stderr, "read_uc_file encountered error (%d)\n", mypid);
+ HDexit(1);
+ }
+
+ HDexit(0);
+ }
+ }
+
+ /* ============= */
+ /* launch writer */
+ /* ============= */
+ /* this process continues to launch the writer */
+ HDprintf("%d: continue as the writer process\n", mypid);
+
+ /* Prepare mirror child driver */
+ mirr_fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ if (mirr_fapl_id == H5I_INVALID_HID) {
+ HDfprintf(stderr, "can't create creation mirror FAPL\n");
+ Hgoto_error(1);
+ }
+ if (H5Pset_fapl_mirror(mirr_fapl_id, &mirr_fa) < 0) {
+ HDfprintf(stderr, "can't set creation mirror FAPL\n");
+ H5Eprint2(H5E_DEFAULT, stdout);
+ Hgoto_error(1);
+ }
+
+ /* Prepare parent "splitter" driver in UC_opts */
+ split_fa.wo_fapl_id = mirr_fapl_id;
+ split_fa.rw_fapl_id = H5P_DEFAULT;
+ UC_opts.fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ if (UC_opts.fapl_id == H5I_INVALID_HID) {
+ HDfprintf(stderr, "can't create creation FAPL\n");
+ Hgoto_error(1);
+ }
+ if (H5Pset_fapl_splitter(UC_opts.fapl_id, &split_fa) < 0) {
+ HDfprintf(stderr, "can't set creation FAPL\n");
+ H5Eprint2(H5E_DEFAULT, stdout);
+ Hgoto_error(1);
+ }
+
+ if (UC_opts.use_swmr) {
+ if (H5Pset_libver_bounds(UC_opts.fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) {
+ HDfprintf(stderr, "can't set write FAPL libver bounds\n");
+ Hgoto_error(1);
+ }
+ }
+
+ if ((fid = H5Fopen(UC_opts.filename, H5F_ACC_RDWR | (UC_opts.use_swmr ? H5F_ACC_SWMR_WRITE : 0), UC_opts.fapl_id)) < 0) {
+ HDfprintf(stderr, "H5Fopen failed\n");
+ Hgoto_error(1);
+ }
+
+ if (write_uc_file(send_wait, fid, &UC_opts) < 0) {
+ HDfprintf(stderr, "write_uc_file encountered error\n");
+ Hgoto_error(1);
+ }
+
+ if (H5Fclose(fid) < 0) {
+ HDfprintf(stderr, "Failed to close write\n");
+ Hgoto_error(1);
+ }
+
+ if (H5Pclose(UC_opts.fapl_id) < 0) {
+ HDfprintf(stderr, "can't close write FAPL\n");
+ Hgoto_error(1);
+ }
+
+ if (H5Pclose(mirr_fapl_id) < 0) {
+ HDfprintf(stderr, "can't close write mirror FAPL\n");
+ Hgoto_error(1);
+ }
+
+ /* ================================================ */
+ /* If readwrite, collect exit code of child process */
+ /* ================================================ */
+ if (UC_opts.launch == UC_READWRITE) {
+ if ((tmppid = HDwaitpid(childpid, &child_status, child_wait_option)) < 0) {
+ HDperror("waitpid");
+ Hgoto_error(1);
+ }
+
+ if (WIFEXITED(child_status)) {
+ if ((child_ret_value = WEXITSTATUS(child_status)) != 0) {
+ HDprintf("%d: child process exited with non-zero code (%d)\n",
+ mypid, child_ret_value);
+ Hgoto_error(2);
+ }
+ } else {
+ HDprintf("%d: child process terminated abnormally\n", mypid);
+ Hgoto_error(2);
+ }
+ }
+
+done:
+ if (ret_value != 0) {
+ HDprintf("Error(s) encountered\n");
+ } else {
+ HDprintf("All passed\n");
+ }
+
+ return(ret_value);
+}
+
+#else /* H5_HAVE_MIRROR_VFD */
+
+int
+main(void)
+{
+ HDfprintf(stderr, "Mirror VFD is not built. Skipping.\n");
+ return EXIT_SUCCESS;
+} /* end main() */
+
+#endif /* H5_HAVE_MIRROR_VFD */
+
+#else /* H5_HAVE_FORK */
+
+int
+main(void)
+{
+ HDfprintf(stderr, "Non-POSIX platform. Skipping.\n");
+ return EXIT_SUCCESS;
+} /* end main() */
+
+#endif /* H5_HAVE_FORK */
+
diff --git a/test/use_append_mchunks.c b/test/use_append_mchunks.c
index b7d45a4..2eb5a1d 100644
--- a/test/use_append_mchunks.c
+++ b/test/use_append_mchunks.c
@@ -29,14 +29,14 @@
* finishes HDF5 metadata updates and issues H5Fflush or H5Oflush calls.
* o Readers will see newly appended data after the Writer finishes
* the flush operation.
- *
+ *
* Preconditions:
* o Readers are not allowed to modify the file.
* o All datasets that are modified by the Writer exist when the
* Writer opens the file.
* o All datasets that are modified by the Writer exist when a Reader
* opens the file.
- *
+ *
* Main Success Scenario:
* 1. An application creates a file with required objects (groups,
* datasets, and attributes).
@@ -45,7 +45,7 @@
* spans several chunks.
* 3. A Reader opens the file and a dataset in a file; if the size of
* the unlimited dimension has changed, reads the appended data back.
- *
+ *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Created: Albert Cheng, 2013/6/1 */
@@ -61,46 +61,45 @@
#include "use.h"
-/* Global Variable definitions */
-options_t UC_opts; /* Use Case Options */
-const char *progname_g="use_append_mchunks"; /* program name */
+#define USE_APPEND_MCHUNKS_PROGNAME "use_append_mchunks"
+
+static options_t UC_opts; /* Use Case Options */
/* Setup parameters for the use case.
* Return: 0 succeed; -1 fail.
*/
-int setup_parameters(int argc, char * const argv[])
+int
+setup_parameters(int argc, char * const argv[], options_t * opts)
{
/* use case defaults */
- HDmemset(&UC_opts, 0, sizeof(options_t));
- UC_opts.chunksize = Chunksize_DFT;
- UC_opts.use_swmr = 1; /* use swmr open */
- UC_opts.iterations = 1;
- UC_opts.chunkplanes = 1;
-
- /* parse options */
- if (parse_option(argc, argv) < 0){
- return(-1);
+ HDmemset(opts, 0, sizeof(options_t));
+ opts->chunksize = Chunksize_DFT;
+ opts->use_swmr = 1; /* use swmr open */
+ opts->iterations = 1;
+ opts->chunkplanes = 1;
+ opts->progname = USE_APPEND_MCHUNKS_PROGNAME;
+ opts->fapl_id = H5I_INVALID_HID;
+
+ if (parse_option(argc, argv, opts) < 0) {
+ return(-1);
}
- /* set chunk dims */
- UC_opts.chunkdims[0] = (hsize_t)UC_opts.chunkplanes;
- UC_opts.chunkdims[1] = UC_opts.chunkdims[2] = (hsize_t)UC_opts.chunksize;
- /* set dataset initial and max dims */
- UC_opts.dims[0] = 0;
- UC_opts.max_dims[0] = H5S_UNLIMITED;
- UC_opts.dims[1] = UC_opts.dims[2] = UC_opts.max_dims[1] = UC_opts.max_dims[2] = 2 * (hsize_t)UC_opts.chunksize;
+ opts->chunkdims[0] = (hsize_t)opts->chunkplanes;
+ opts->chunkdims[1] = opts->chunkdims[2] = (hsize_t)opts->chunksize;
+
+ opts->dims[0] = 0;
+ opts->max_dims[0] = H5S_UNLIMITED;
+ opts->dims[1] = opts->dims[2] = opts->max_dims[1] = opts->max_dims[2] = 2 * (hsize_t)opts->chunksize;
- /* set nplanes */
- if (UC_opts.nplanes == 0)
- UC_opts.nplanes = 2 * (hsize_t)UC_opts.chunksize;
+ if (opts->nplanes == 0)
+ opts->nplanes = 2 * (hsize_t)opts->chunksize;
- /* show parameters and return */
- show_parameters();
+ show_parameters(opts);
return(0);
-}
+} /* end setup_parameters() */
-/* Overall Algorithm:
+/* Overall Algorithm:
* Parse options from user;
* Generate/pre-created test files needed and close it;
* fork: child process becomes the reader process;
@@ -112,22 +111,20 @@ main(int argc, char *argv[])
{
pid_t childpid=0;
pid_t mypid, tmppid;
- int child_status;
+ int child_status;
int child_wait_option=0;
int ret_value = 0;
int child_ret_value;
hbool_t send_wait = 0;
hid_t fapl = -1; /* File access property list */
hid_t fid = -1; /* File ID */
- char *name; /* Test file name */
- /* initialization */
- if (setup_parameters(argc, argv) < 0){
+ if (setup_parameters(argc, argv, &UC_opts) < 0) {
Hgoto_error(1);
}
/* Determine the need to send/wait message file*/
- if(UC_opts.launch == UC_READWRITE) {
+ if (UC_opts.launch == UC_READWRITE) {
HDunlink(WRITER_MESSAGE);
send_wait = 1;
}
@@ -137,38 +134,63 @@ main(int argc, char *argv[])
/* UC_WRITER: create datafile, skip reader, launch writer. */
/* UC_READER: skip create, launch reader, exit. */
/* ==============================================================*/
- /* ============*/
+ /* =========== */
/* Create file */
- /* ============*/
- if (UC_opts.launch != UC_READER){
+ /* =========== */
+ if (UC_opts.launch != UC_READER) {
HDprintf("Creating skeleton data file for test...\n");
- if (create_uc_file() < 0){
- HDfprintf(stderr, "***encounter error\n");
- Hgoto_error(1);
- }else
- HDprintf("File created.\n");
+ if ((UC_opts.fapl_id = h5_fileaccess()) < 0) {
+ HDfprintf(stderr, "can't create creation FAPL\n");
+ Hgoto_error(1);
+ }
+ if (H5Pset_libver_bounds(UC_opts.fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) {
+ HDfprintf(stderr, "can't set creation FAPL libver bounds\n");
+ Hgoto_error(1);
+ }
+ if (create_uc_file(&UC_opts) < 0) {
+ HDfprintf(stderr, "***encounter error\n");
+ Hgoto_error(1);
+ } else {
+ HDprintf("File created.\n");
+ }
+ /* Close FAPL to prevent issues with forking later */
+ if (H5Pclose(UC_opts.fapl_id) < 0) {
+ HDfprintf(stderr, "can't close creation FAPL\n");
+ Hgoto_error(1);
+ }
+ UC_opts.fapl_id = H5I_INVALID_HID;
}
- if (UC_opts.launch==UC_READWRITE){
- /* fork process */
- if((childpid = fork()) < 0) {
+ /* ============ */
+ /* Fork process */
+ /* ============ */
+ if (UC_opts.launch==UC_READWRITE) {
+ if ((childpid = fork()) < 0) {
perror("fork");
Hgoto_error(1);
- };
- };
+ }
+ }
mypid = getpid();
/* ============= */
/* launch reader */
/* ============= */
- if (UC_opts.launch != UC_WRITER){
+ if (UC_opts.launch != UC_WRITER) {
/* child process launch the reader */
- if(0 == childpid) {
+ if (0 == childpid) {
HDprintf("%d: launch reader process\n", mypid);
- if (read_uc_file(send_wait) < 0){
+ if ((UC_opts.fapl_id = h5_fileaccess()) < 0) {
+ HDfprintf(stderr, "can't create read FAPL\n");
+ HDexit(EXIT_FAILURE);
+ }
+ if (read_uc_file(send_wait, &UC_opts) < 0) {
HDfprintf(stderr, "read_uc_file encountered error\n");
HDexit(EXIT_FAILURE);
}
+ if (H5Pclose(UC_opts.fapl_id) < 0) {
+ HDfprintf(stderr, "can't close read FAPL\n");
+ HDexit(EXIT_FAILURE);
+ }
HDexit(EXIT_SUCCESS);
}
}
@@ -179,51 +201,50 @@ main(int argc, char *argv[])
/* this process continues to launch the writer */
HDprintf("%d: continue as the writer process\n", mypid);
- name = UC_opts.filename;
-
/* Set the file access property list */
- if((fapl = h5_fileaccess()) < 0)
+ if ((fapl = h5_fileaccess()) < 0) {
+ HDfprintf(stderr, "can't get write FAPL\n");
Hgoto_error(1);
+ }
- if(UC_opts.use_swmr)
- if(H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0)
+ if (UC_opts.use_swmr) {
+ if (H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) {
+ HDfprintf(stderr, "can't set write FAPL libver bounds\n");
Hgoto_error(1);
+ }
+ }
- /* Open the file */
- if((fid = H5Fopen(name, H5F_ACC_RDWR | (UC_opts.use_swmr ? H5F_ACC_SWMR_WRITE : 0), fapl)) < 0) {
+ if ((fid = H5Fopen(UC_opts.filename, H5F_ACC_RDWR | (UC_opts.use_swmr ? H5F_ACC_SWMR_WRITE : 0), fapl)) < 0) {
HDfprintf(stderr, "H5Fopen failed\n");
Hgoto_error(1);
}
- if(write_uc_file(send_wait, fid) < 0) {
+ if (write_uc_file(send_wait, fid, &UC_opts) < 0) {
HDfprintf(stderr, "write_uc_file encountered error\n");
Hgoto_error(1);
}
+ if (H5Fclose(fid) < 0) {
+ HDfprintf(stderr, "Failed to close file id\n");
+ Hgoto_error(1);
+ }
+
+ if (H5Pclose(fapl) < 0) {
+ HDfprintf(stderr, "can't close write FAPL\n");
+ Hgoto_error(1);
+ }
/* ================================================ */
/* If readwrite, collect exit code of child process */
/* ================================================ */
- if (UC_opts.launch == UC_READWRITE){
- if ((tmppid = waitpid(childpid, &child_status, child_wait_option)) < 0){
+ if (UC_opts.launch == UC_READWRITE) {
+ if ((tmppid = waitpid(childpid, &child_status, child_wait_option)) < 0) {
perror("waitpid");
Hgoto_error(1);
}
- /* Close the file */
- if(H5Fclose(fid) < 0) {
- HDfprintf(stderr, "Failed to close file id\n");
- Hgoto_error(1);
- }
-
- /* Close the property list */
- if(H5Pclose(fapl) < 0) {
- HDfprintf(stderr, "Failed to close the property list\n");
- Hgoto_error(1);
- }
-
- if (WIFEXITED(child_status)){
- if ((child_ret_value=WEXITSTATUS(child_status)) != 0){
+ if (WIFEXITED(child_status)) {
+ if ((child_ret_value=WEXITSTATUS(child_status)) != 0) {
HDprintf("%d: child process exited with non-zero code (%d)\n",
mypid, child_ret_value);
Hgoto_error(1);
@@ -233,17 +254,16 @@ main(int argc, char *argv[])
Hgoto_error(2);
}
}
-
+
done:
- /* Print result and exit */
- if (ret_value != 0){
+ if (ret_value != 0) {
HDprintf("Error(s) encountered\n");
- }else{
+ } else {
HDprintf("All passed\n");
}
return(ret_value);
-}
+} /* end main() */
#else /* H5_HAVE_FORK */
diff --git a/test/use_common.c b/test/use_common.c
index 4111b24..a986543 100644
--- a/test/use_common.c
+++ b/test/use_common.c
@@ -23,8 +23,13 @@
#define H5D_FRIEND /*suppress error about including H5Dpkg */
#define H5D_TESTING
-#include "H5Dpkg.h"
+#include "H5Dpkg.h" /* TODO : used to verify chunk index type (yes?) -- is there a way to do this sanity-check using the public API instead? */
+/* ----------------------------------------------------------------------------
+ * Print a common/shared usage message.
+ * Receives program name to show default test file name (<program_name>.h5).
+ * ----------------------------------------------------------------------------
+ */
void
usage(const char *prog)
{
@@ -41,10 +46,13 @@ usage(const char *prog)
HDfprintf(stderr, "\n");
} /* end usage() */
-/* Setup Use Case parameters by parsing command line options.
-* Setup default values if not set by options. */
+/* ----------------------------------------------------------------------------
+ * Setup Use Case parameters by parsing command line options.
+ * Includes default values for unspecified options.
+ * ----------------------------------------------------------------------------
+ */
int
-parse_option(int argc, char * const argv[])
+parse_option(int argc, char * const argv[], options_t * opts)
{
int ret_value=0;
int c;
@@ -56,302 +64,307 @@ parse_option(int argc, char * const argv[])
/* suppress getopt from printing error */
opterr = 0;
- while (1){
- c = getopt (argc, argv, nagg_options);
- if (-1 == c)
- break;
- switch (c) {
- case 'h':
- usage(progname_g);
- HDexit(EXIT_SUCCESS);
- break;
- case 'f': /* usecase data file name */
- UC_opts.filename = optarg;
- break;
- case 'i': /* iterations */
- if ((UC_opts.iterations = HDatoi(optarg)) <= 0) {
- HDfprintf(stderr, "bad iterations number %s, must be a positive integer\n", optarg);
- usage(progname_g);
- Hgoto_error(-1);
- };
- break;
- case 'l': /* launch reader or writer only */
- switch (*optarg) {
- case 'r': /* reader only */
- UC_opts.launch = UC_READER;
- break;
- case 'w': /* writer only */
- UC_opts.launch = UC_WRITER;
- break;
+ while (1) {
+ c = getopt(argc, argv, nagg_options);
+ if (-1 == c)
+ break;
+ switch (c) {
+ case 'h':
+ usage(opts->progname);
+ exit(EXIT_SUCCESS);
+ break;
+ case 'f': /* usecase data file name */
+ opts->filename = optarg;
+ break;
+ case 'i': /* iterations */
+ if ((opts->iterations = HDatoi(optarg)) <= 0) {
+ HDfprintf(stderr, "bad iterations number %s, must be a positive integer\n", optarg);
+ usage(opts->progname);
+ Hgoto_error(-1);
+ }
+ break;
+ case 'l': /* launch reader or writer only */
+ switch (*optarg) {
+ case 'r': /* reader only */
+ opts->launch = UC_READER;
+ break;
+ case 'w': /* writer only */
+ opts->launch = UC_WRITER;
+ break;
+ default:
+ HDfprintf(stderr, "launch value(%c) should be w or r only.\n", *optarg);
+ usage(opts->progname);
+ Hgoto_error(-1);
+ break;
+ } /* end switch (reader/writer-only mode toggle) */
+ break;
+ case 'n': /* number of planes to write/read */
+ if ((opts->nplanes = HDstrtoul(optarg, NULL, 0)) <= 0) {
+ HDfprintf(stderr, "bad number of planes %s, must be a positive integer\n", optarg);
+ usage(opts->progname);
+ Hgoto_error(-1);
+ }
+ break;
+ case 's': /* use swmr file open mode */
+ use_swmr = HDatoi(optarg);
+ if (use_swmr != 0 && use_swmr != 1) {
+ HDfprintf(stderr, "swmr value should be 0(no) or 1(yes)\n");
+ usage(opts->progname);
+ Hgoto_error(-1);
+ }
+ opts->use_swmr = (hbool_t)use_swmr;
+ break;
+ case 'y': /* Number of planes per chunk */
+ if ((opts->chunkplanes = HDstrtoul(optarg, NULL, 0)) <= 0) {
+ HDfprintf(stderr, "bad number of planes per chunk %s, must be a positive integer\n", optarg);
+ usage(opts->progname);
+ Hgoto_error(-1);
+ }
+ break;
+ case 'z': /* size of chunk=(z,z) */
+ if ((opts->chunksize = HDstrtoull(optarg, NULL, 0)) <= 0) {
+ HDfprintf(stderr, "bad chunksize %s, must be a positive integer\n", optarg);
+ usage(opts->progname);
+ Hgoto_error(-1);
+ }
+ break;
+ case '?':
+ HDfprintf(stderr, "getopt returned '%c'.\n", c);
+ Hgoto_error(-1);
default:
- HDfprintf(stderr, "launch value(%c) should be w or r only.\n", *optarg);
- usage(progname_g);
- Hgoto_error(-1);
- break;
- }
- break;
- case 'n': /* number of planes to write/read */
- if ((UC_opts.nplanes = HDstrtoul(optarg, NULL, 0)) <= 0) {
- HDfprintf(stderr, "bad number of planes %s, must be a positive integer\n", optarg);
- usage(progname_g);
- Hgoto_error(-1);
- };
- break;
- case 's': /* use swmr file open mode */
- use_swmr = HDatoi(optarg);
- if (use_swmr != 0 && use_swmr != 1) {
- HDfprintf(stderr, "swmr value should be 0(no) or 1(yes)\n");
- usage(progname_g);
+ HDfprintf(stderr, "getopt returned unexpected value.\n");
+ HDfprintf(stderr, "Unexpected value is %d\n", c);
Hgoto_error(-1);
- }
- UC_opts.use_swmr = (hbool_t)use_swmr;
- break;
- case 'y': /* Number of planes per chunk */
- if ((UC_opts.chunkplanes = HDstrtoul(optarg, NULL, 0)) <= 0) {
- HDfprintf(stderr, "bad number of planes per chunk %s, must be a positive integer\n", optarg);
- usage(progname_g);
- Hgoto_error(-1);
- };
- break;
- case 'z': /* size of chunk=(z,z) */
- if ((UC_opts.chunksize = HDstrtoull(optarg, NULL, 0)) <= 0) {
- HDfprintf(stderr, "bad chunksize %s, must be a positive integer\n", optarg);
- usage(progname_g);
- Hgoto_error(-1);
- };
- break;
- case '?':
- HDfprintf(stderr, "getopt returned '%c'.\n", c);
- Hgoto_error(-1);
- default:
- HDfprintf(stderr, "getopt returned unexpected value.\n");
- HDfprintf(stderr, "Unexpected value is %d\n", c);
- Hgoto_error(-1);
- }
- }
+ } /* end switch (argument symbol) */
+ } /* end while (there are still arguments) */
/* set test file name if not given */
- if (!UC_opts.filename){
- /* default data file name is <progname>.h5 */
- if ((UC_opts.filename=(char*)HDmalloc(HDstrlen(progname_g)+4))==NULL) {
- HDfprintf(stderr, "malloc: failed\n");
- Hgoto_error(-1);
- };
- HDstrcpy(UC_opts.filename, progname_g);
- HDstrcat(UC_opts.filename, ".h5");
+ if (!opts->filename) {
+ /* default data file name is <progname>.h5 */
+ if ((opts->filename=(char*)HDmalloc(HDstrlen(opts->progname)+4))==NULL) {
+ HDfprintf(stderr, "malloc: failed\n");
+ Hgoto_error(-1);
+ }
+ HDstrcpy(opts->filename, opts->progname);
+ HDstrcat(opts->filename, ".h5");
}
done:
- /* All done. */
return(ret_value);
-}
+} /* end parse_option() */
-/* Show parameters used for this use case */
-void show_parameters(void){
+/* ----------------------------------------------------------------------------
+ * Show parameters used for this use case.
+ * ----------------------------------------------------------------------------
+ */
+void
+show_parameters(options_t * opts)
+{
HDprintf("===Parameters used:===\n");
- printf("chunk dims=(%llu, %llu, %llu)\n", (unsigned long long)UC_opts.chunkdims[0],
- (unsigned long long)UC_opts.chunkdims[1], (unsigned long long)UC_opts.chunkdims[2]);
- printf("dataset max dims=(%llu, %llu, %llu)\n", (unsigned long long)UC_opts.max_dims[0],
- (unsigned long long)UC_opts.max_dims[1], (unsigned long long)UC_opts.max_dims[2]);
- HDprintf("number of planes to write=%llu\n", (unsigned long long)UC_opts.nplanes);
- HDprintf("using SWMR mode=%s\n", UC_opts.use_swmr ? "yes(1)" : "no(0)");
- HDprintf("data filename=%s\n", UC_opts.filename);
+ HDprintf("chunk dims=(%llu, %llu, %llu)\n", (unsigned long long)opts->chunkdims[0],
+ (unsigned long long)opts->chunkdims[1], (unsigned long long)opts->chunkdims[2]);
+ HDprintf("dataset max dims=(%llu, %llu, %llu)\n", (unsigned long long)opts->max_dims[0],
+ (unsigned long long)opts->max_dims[1], (unsigned long long)opts->max_dims[2]);
+ HDprintf("number of planes to write=%llu\n", (unsigned long long)opts->nplanes);
+ HDprintf("using SWMR mode=%s\n", opts->use_swmr ? "yes(1)" : "no(0)");
+ HDprintf("data filename=%s\n", opts->filename);
HDprintf("launch part=");
- switch (UC_opts.launch){
- case UC_READWRITE:
- printf("Reader/Writer\n");
- break;
- case UC_WRITER:
- printf("Writer\n");
- break;
- case UC_READER:
- printf("Reader\n");
- break;
- default:
- /* should not happen */
- printf("Illegal part(%d)\n", UC_opts.launch);
- };
- HDprintf("number of iterations=%d (not used yet)\n", UC_opts.iterations);
+ switch (opts->launch) {
+ case UC_READWRITE:
+ HDprintf("Reader/Writer\n");
+ break;
+ case UC_WRITER:
+ HDprintf("Writer\n");
+ break;
+ case UC_READER:
+ HDprintf("Reader\n");
+ break;
+ default:
+ /* should not happen */
+ HDprintf("Illegal part(%d)\n", opts->launch);
+ }
+ HDprintf("number of iterations=%d (not used yet)\n", opts->iterations);
HDprintf("===Parameters shown===\n");
-}
+} /* end show_parameters() */
-/* Create the skeleton use case file for testing.
+/* ----------------------------------------------------------------------------
+ * Create the skeleton use case file for testing.
* It has one 3d dataset using chunked storage.
* The dataset is (unlimited, chunksize, chunksize).
* Dataset type is 2 bytes integer.
* It starts out "empty", i.e., first dimension is 0.
*
* Return: 0 succeed; -1 fail.
+ * ----------------------------------------------------------------------------
*/
-int create_uc_file(void)
+int
+create_uc_file(options_t * opts)
{
- hsize_t dims[3]; /* Dataset starting dimensions */
- hid_t fid; /* File ID for new HDF5 file */
- hid_t dcpl; /* Dataset creation property list */
- hid_t sid; /* Dataspace ID */
- hid_t dsid; /* Dataset ID */
- hid_t fapl; /* File access property list */
+ hsize_t dims[3]; /* Dataset starting dimensions */
+ hid_t fid; /* File ID for new HDF5 file */
+ hid_t dcpl; /* Dataset creation property list */
+ hid_t sid; /* Dataspace ID */
+ hid_t dsid; /* Dataset ID */
H5D_chunk_index_t idx_type; /* Chunk index type */
- /* Create the file */
- if((fapl = h5_fileaccess()) < 0)
- return -1;
- if(H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0)
- return -1;
- if((fid = H5Fcreate(UC_opts.filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0)
+ if ((fid = H5Fcreate(opts->filename, H5F_ACC_TRUNC, H5P_DEFAULT, opts->fapl_id)) < 0)
return -1;
/* Set up dimension sizes */
dims[0] = 0;
- dims[1] = dims[2] = UC_opts.max_dims[1];
+ dims[1] = dims[2] = opts->max_dims[1];
/* Create dataspace for creating datasets */
- if((sid = H5Screate_simple(3, dims, UC_opts.max_dims)) < 0)
+ if ((sid = H5Screate_simple(3, dims, opts->max_dims)) < 0)
return -1;
/* Create dataset creation property list */
- if((dcpl = H5Pcreate(H5P_DATASET_CREATE)) < 0)
+ if ((dcpl = H5Pcreate(H5P_DATASET_CREATE)) < 0)
return -1;
- if(H5Pset_chunk(dcpl, 3, UC_opts.chunkdims) < 0)
+ if (H5Pset_chunk(dcpl, 3, opts->chunkdims) < 0)
return -1;
/* create dataset of progname */
- if((dsid = H5Dcreate2(fid, progname_g, UC_DATATYPE, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT)) < 0)
- return -1;
+ if ((dsid = H5Dcreate2(fid, opts->progname, UC_DATATYPE, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT)) < 0)
+ return -1;
/* Check that the chunk index type is not version 1 B-tree.
* Version 1 B-trees are not supported under SWMR.
*/
- if(H5D__layout_idx_type_test(dsid, &idx_type) < 0)
+ if (H5D__layout_idx_type_test(dsid, &idx_type) < 0)
return -1;
- if(idx_type == H5D_CHUNK_IDX_BTREE) {
+ if (idx_type == H5D_CHUNK_IDX_BTREE) {
HDfprintf(stderr, "ERROR: Chunk index is version 1 B-tree: aborting.\n");
return -1;
}
/* Close everything */
- if(H5Dclose(dsid) < 0)
- return -1;
- if(H5Pclose(fapl) < 0)
+ if (H5Dclose(dsid) < 0)
return -1;
- if(H5Pclose(dcpl) < 0)
+ if (H5Pclose(dcpl) < 0)
return -1;
- if(H5Sclose(sid) < 0)
+ if (H5Sclose(sid) < 0)
return -1;
- if(H5Fclose(fid) < 0)
+ if (H5Fclose(fid) < 0)
return -1;
return 0;
-}
+} /* end create_uc_file() */
-/* Append planes, each of (1,2*chunksize,2*chunksize) to the dataset.
+/* ----------------------------------------------------------------------------
+ * Append planes, each of (1,2*chunksize,2*chunksize) to the dataset.
* In other words, 4 chunks are appended to the dataset at a time.
* Fill each plan with the plane number and then write it at the nth plane.
* Increase the plane number and repeat till the end of dataset, when it
* reaches chunksize long. End product is a (2*chunksize)^3 cube.
*
* Return: 0 succeed; -1 fail.
+ * ----------------------------------------------------------------------------
*/
-int write_uc_file(hbool_t tosend, hid_t fid)
+int
+write_uc_file(hbool_t tosend, hid_t file_id, options_t * opts)
{
- hid_t dsid; /* dataset ID */
- hid_t dcpl; /* Dataset creation property list */
- UC_CTYPE *buffer, *bufptr; /* data buffer */
- hsize_t cz=UC_opts.chunksize; /* Chunk size */
- hid_t f_sid; /* dataset file space id */
- hid_t m_sid; /* memory space id */
- int rank; /* rank */
- hsize_t chunk_dims[3]; /* Chunk dimensions */
- hsize_t dims[3]; /* Dataspace dimensions */
- hsize_t memdims[3]; /* Memory space dimensions */
- hsize_t start[3] = {0,0,0}, count[3]; /* Hyperslab selection values */
- hsize_t i, j, k;
-
- if(tosend)
+ hid_t dsid; /* dataset ID */
+ hid_t dcpl; /* Dataset creation property list */
+ UC_CTYPE *buffer, *bufptr; /* data buffer */
+ hsize_t cz=opts->chunksize; /* Chunk size */
+ hid_t f_sid; /* dataset file space id */
+ hid_t m_sid; /* memory space id */
+ int rank; /* rank */
+ hsize_t chunk_dims[3]; /* Chunk dimensions */
+ hsize_t dims[3]; /* Dataspace dimensions */
+ hsize_t memdims[3]; /* Memory space dimensions */
+ hsize_t start[3] = {0,0,0}, count[3]; /* Hyperslab selection values */
+ hsize_t i, j, k;
+
+ if (TRUE == tosend) {
/* Send a message that H5Fopen is complete--releasing the file lock */
h5_send_message(WRITER_MESSAGE, NULL, NULL);
+ }
/* Open the dataset of the program name */
- if((dsid = H5Dopen2(fid, progname_g, H5P_DEFAULT)) < 0){
+ if ((dsid = H5Dopen2(file_id, opts->progname, H5P_DEFAULT)) < 0) {
HDfprintf(stderr, "H5Dopen2 failed\n");
return -1;
}
/* Find chunksize used */
- if ((dcpl = H5Dget_create_plist(dsid)) < 0){
+ if ((dcpl = H5Dget_create_plist(dsid)) < 0) {
HDfprintf(stderr, "H5Dget_create_plist failed\n");
return -1;
}
- if (H5D_CHUNKED != H5Pget_layout(dcpl)){
+ if (H5D_CHUNKED != H5Pget_layout(dcpl)) {
HDfprintf(stderr, "storage layout is not chunked\n");
return -1;
}
- if ((rank = H5Pget_chunk(dcpl, 3, chunk_dims)) != 3){
+ if ((rank = H5Pget_chunk(dcpl, 3, chunk_dims)) != 3) {
HDfprintf(stderr, "storage rank is not 3\n");
return -1;
}
/* verify chunk_dims against set paramenters */
- if (chunk_dims[0]!=UC_opts.chunkdims[0] || chunk_dims[1] != cz || chunk_dims[2] != cz){
+ if (chunk_dims[0]!=opts->chunkdims[0] || chunk_dims[1] != cz || chunk_dims[2] != cz) {
HDfprintf(stderr, "chunk size is not as expected. Got dims=(%llu,%llu,%llu)\n",
- (unsigned long long)chunk_dims[0], (unsigned long long)chunk_dims[1],
+ (unsigned long long)chunk_dims[0], (unsigned long long)chunk_dims[1],
(unsigned long long)chunk_dims[2]);
return -1;
}
/* allocate space for data buffer 1 X dims[1] X dims[2] of UC_CTYPE */
memdims[0]=1;
- memdims[1] = UC_opts.dims[1];
- memdims[2] = UC_opts.dims[2];
+ memdims[1] = opts->dims[1];
+ memdims[2] = opts->dims[2];
if ((buffer=(UC_CTYPE*)HDmalloc((size_t)memdims[1]*(size_t)memdims[2]*sizeof(UC_CTYPE)))==NULL) {
HDfprintf(stderr, "malloc: failed\n");
return -1;
- };
+ }
/*
* Get dataset rank and dimension.
*/
f_sid = H5Dget_space(dsid); /* Get filespace handle first. */
rank = H5Sget_simple_extent_ndims(f_sid);
- if (rank != UC_RANK){
+ if (rank != UC_RANK) {
HDfprintf(stderr, "rank(%d) of dataset does not match\n", rank);
return -1;
}
- if (H5Sget_simple_extent_dims(f_sid, dims, NULL) < 0){
+ if (H5Sget_simple_extent_dims(f_sid, dims, NULL) < 0) {
HDfprintf(stderr, "H5Sget_simple_extent_dims got error\n");
return -1;
}
HDprintf("dataset rank %d, dimensions %llu x %llu x %llu\n",
- rank, (unsigned long long)(dims[0]), (unsigned long long)(dims[1]),
+ rank, (unsigned long long)(dims[0]), (unsigned long long)(dims[1]),
(unsigned long long)(dims[2]));
/* verify that file space dims are as expected and are consistent with memory space dims */
- if (dims[0] != 0 || dims[1] != memdims[1] || dims[2] != memdims[2]){
+ if (dims[0] != 0 || dims[1] != memdims[1] || dims[2] != memdims[2]) {
HDfprintf(stderr, "dataset is not empty. Got dims=(%llu,%llu,%llu)\n",
- (unsigned long long)dims[0], (unsigned long long)dims[1],
+ (unsigned long long)dims[0], (unsigned long long)dims[1],
(unsigned long long)dims[2]);
return -1;
}
/* setup mem-space for buffer */
- if ((m_sid=H5Screate_simple(rank, memdims, NULL))<0){
+ if ((m_sid=H5Screate_simple(rank, memdims, NULL))<0) {
HDfprintf(stderr, "H5Screate_simple for memory failed\n");
return -1;
- };
+ }
/* write planes */
count[0]=1;
count[1]=dims[1];
count[2]=dims[2];
- for (i=0; i<UC_opts.nplanes; i++){
+ for (i=0; i < opts->nplanes; i++) {
/* fill buffer with value i+1 */
bufptr = buffer;
- for (j=0; j<dims[1]; j++)
- for (k=0; k<dims[2]; k++)
+ for (j=0; j < dims[1]; j++) {
+ for (k=0; k < dims[2]; k++) {
*bufptr++ = (UC_CTYPE)i;
+ }
+ }
/* Cork the dataset's metadata in the cache, if SWMR is enabled */
- if(UC_opts.use_swmr) {
- if(H5Odisable_mdc_flushes(dsid) < 0) {
+ if (opts->use_swmr) {
+ if (H5Odisable_mdc_flushes(dsid) < 0) {
HDfprintf(stderr, "H5Odisable_mdc_flushes failed\n");
return -1;
}
@@ -359,64 +372,65 @@ int write_uc_file(hbool_t tosend, hid_t fid)
/* extend the dataset by one for new plane */
dims[0]=i+1;
- if(H5Dset_extent(dsid, dims) < 0){
+ if (H5Dset_extent(dsid, dims) < 0) {
HDfprintf(stderr, "H5Dset_extent failed\n");
return -1;
}
/* Get the dataset's dataspace */
- if((f_sid = H5Dget_space(dsid)) < 0){
+ if ((f_sid = H5Dget_space(dsid)) < 0) {
HDfprintf(stderr, "H5Dset_extent failed\n");
return -1;
}
start[0]=i;
/* Choose the next plane to write */
- if(H5Sselect_hyperslab(f_sid, H5S_SELECT_SET, start, NULL, count, NULL) < 0){
+ if (H5Sselect_hyperslab(f_sid, H5S_SELECT_SET, start, NULL, count, NULL) < 0) {
HDfprintf(stderr, "Failed H5Sselect_hyperslab\n");
return -1;
}
/* Write plane to the dataset */
- if(H5Dwrite(dsid, UC_DATATYPE, m_sid, f_sid, H5P_DEFAULT, buffer) < 0){
+ if (H5Dwrite(dsid, UC_DATATYPE, m_sid, f_sid, H5P_DEFAULT, buffer) < 0) {
HDfprintf(stderr, "Failed H5Dwrite\n");
return -1;
}
/* Uncork the dataset's metadata from the cache, if SWMR is enabled */
- if(UC_opts.use_swmr)
- if(H5Oenable_mdc_flushes(dsid) < 0) {
+ if (opts->use_swmr) {
+ if (H5Oenable_mdc_flushes(dsid) < 0) {
HDfprintf(stderr, "H5Oenable_mdc_flushes failed\n");
return -1;
}
+ }
/* flush file to make the just written plane available. */
- if(H5Dflush(dsid) < 0) {
+ if (H5Dflush(dsid) < 0) {
HDfprintf(stderr, "Failed to H5Fflush file\n");
return -1;
}
- }
+ } /* end for each plane to write */
/* Done writing. Free/Close all resources including data file */
HDfree(buffer);
- if (H5Dclose(dsid) < 0){
+ if (H5Dclose(dsid) < 0) {
HDfprintf(stderr, "Failed to close datasete\n");
return -1;
}
- if (H5Sclose(m_sid) < 0){
+ if (H5Sclose(m_sid) < 0) {
HDfprintf(stderr, "Failed to close memory space\n");
return -1;
}
- if (H5Sclose(f_sid) < 0){
+ if (H5Sclose(f_sid) < 0) {
HDfprintf(stderr, "Failed to close file space\n");
return -1;
}
return 0;
-}
-
+} /* end write_uc_file() */
-/* Read planes from the dataset.
+/* ----------------------------------------------------------------------------
+ * Read planes from the dataset.
* It expects the dataset is being changed (growing).
* It checks the unlimited dimension (1st one). When it increases,
* it will read in the new planes, one by one, and verify the data correctness.
@@ -425,61 +439,51 @@ int write_uc_file(hbool_t tosend, hid_t fid)
* that is the expected end of data, the reader exits.
*
* Return: 0 succeed; -1 fail.
+ * ----------------------------------------------------------------------------
*/
-int read_uc_file(hbool_t towait)
+int
+read_uc_file(hbool_t towait, options_t * opts)
{
- hid_t fapl; /* file access property list ID */
- hid_t fid; /* File ID for new HDF5 file */
- hid_t dsid; /* dataset ID */
- char *name;
- UC_CTYPE *buffer, *bufptr; /* read data buffer */
- hid_t f_sid; /* dataset file space id */
- hid_t m_sid; /* memory space id */
- int rank; /* rank */
- hsize_t dims[3]; /* Dataspace dimensions */
- hsize_t memdims[3]; /* Memory space dimensions */
- hsize_t nplane=0, nplane_old=0; /* nth plane, last nth plane */
- hsize_t start[3] = {0,0,0}, count[3]; /* Hyperslab selection values */
- hsize_t j, k;
- int nreadererr=0;
- int nerrs;
- int nonewplane;
+ hid_t fid; /* File ID for new HDF5 file */
+ hid_t dsid; /* dataset ID */
+ UC_CTYPE *buffer, *bufptr; /* read data buffer */
+ hid_t f_sid; /* dataset file space id */
+ hid_t m_sid; /* memory space id */
+ int rank; /* rank */
+ hsize_t dims[3]; /* Dataspace dimensions */
+ hsize_t memdims[3]; /* Memory space dimensions */
+ hsize_t nplane=0, nplanes_seen=0; /* nth plane, last nth plane */
+ hsize_t start[3] = {0,0,0}, count[3]; /* Hyperslab selection values */
+ hsize_t j, k;
+ int nreadererr=0;
+ int nerrs;
+ int loops_waiting_for_plane;
/* Before reading, wait for the message that H5Fopen is complete--file lock is released */
- if(towait && h5_wait_message(WRITER_MESSAGE) < 0) {
+ if (towait && h5_wait_message(WRITER_MESSAGE) < 0) {
HDfprintf(stderr, "Cannot find writer message file...failed\n");
return -1;
}
- name = UC_opts.filename;
-
- /* Open the file */
- if((fapl = h5_fileaccess()) < 0)
- return -1;
- if((fid = H5Fopen(name, H5F_ACC_RDONLY | (UC_opts.use_swmr ? H5F_ACC_SWMR_READ : 0), fapl)) < 0){
+ HDfprintf(stderr, "Opening to read %s\n", opts->filename);
+ if ((fid = H5Fopen(opts->filename, H5F_ACC_RDONLY | (opts->use_swmr ? H5F_ACC_SWMR_READ : 0), opts->fapl_id)) < 0) {
HDfprintf(stderr, "H5Fopen failed\n");
return -1;
}
- if (H5Pclose(fapl) < 0){
- HDfprintf(stderr, "Failed to property list\n");
- return -1;
- }
-
- /* Open the dataset of the program name */
- if((dsid = H5Dopen2(fid, progname_g, H5P_DEFAULT)) < 0){
+ if ((dsid = H5Dopen2(fid, opts->progname, H5P_DEFAULT)) < 0) {
HDfprintf(stderr, "H5Dopen2 failed\n");
return -1;
}
- /* allocate space for data buffer 1 X dims[1] X dims[2] of UC_CTYPE */
- memdims[0]=1;
- memdims[1] = UC_opts.dims[1];
- memdims[2] = UC_opts.dims[2];
+ /* Allocate space for data buffer 1 X dims[1] X dims[2] of UC_CTYPE */
+ memdims[0] = 1;
+ memdims[1] = opts->dims[1];
+ memdims[2] = opts->dims[2];
if ((buffer=(UC_CTYPE*)HDmalloc((size_t)memdims[1]*(size_t)memdims[2]*sizeof(UC_CTYPE)))==NULL) {
HDfprintf(stderr, "malloc: failed\n");
return -1;
- };
+ }
/*
* Get dataset rank and dimension.
@@ -487,11 +491,11 @@ int read_uc_file(hbool_t towait)
*/
f_sid = H5Dget_space(dsid); /* Get filespace handle first. */
rank = H5Sget_simple_extent_ndims(f_sid);
- if (rank != UC_RANK){
+ if (rank != UC_RANK) {
HDfprintf(stderr, "rank(%d) of dataset does not match\n", rank);
return -1;
}
- if (H5Sget_simple_extent_dims(f_sid, dims, NULL) < 0){
+ if (H5Sget_simple_extent_dims(f_sid, dims, NULL) < 0) {
HDfprintf(stderr, "H5Sget_simple_extent_dims got error\n");
return -1;
}
@@ -499,7 +503,7 @@ int read_uc_file(hbool_t towait)
rank, (unsigned long long)(dims[0]), (unsigned long long)(dims[1]),
(unsigned long long)(dims[2]));
/* verify that file space dims are as expected and are consistent with memory space dims */
- if (dims[1] != memdims[1] || dims[2] != memdims[2]){
+ if (dims[1] != memdims[1] || dims[2] != memdims[2]) {
HDfprintf(stderr, "dataset dimension is not as expected. Got dims=(%llu,%llu,%llu)\n",
(unsigned long long)dims[0], (unsigned long long)dims[1],
(unsigned long long)dims[2]);
@@ -509,120 +513,101 @@ int read_uc_file(hbool_t towait)
return -1;
}
- /* setup mem-space for buffer */
- if ((m_sid=H5Screate_simple(rank, memdims, NULL))<0){
+ /* Setup mem-space for buffer */
+ if ((m_sid=H5Screate_simple(rank, memdims, NULL)) < 0) {
HDfprintf(stderr, "H5Screate_simple for memory failed\n");
return -1;
- };
+ }
- /* Read 1 plane at a time whenever the dataset grows larger
- * (along dim[0]) */
- count[0]=1;
- count[1]=dims[1];
- count[2]=dims[2];
+ /* Read 1 plane at a time whenever the dataset grows larger (along dim[0]) */
+ count[0] = 1;
+ count[1] = dims[1];
+ count[2] = dims[2];
/* quit when all nplanes have been read */
- nonewplane=0;
- while (nplane_old < UC_opts.nplanes ){
- /* print progress message according to if new planes are availalbe */
- if (nplane_old < dims[0]) {
- if (nonewplane){
- /* end the previous message */
- HDprintf("\n");
- nonewplane=0;
- }
- HDprintf("reading planes %llu to %llu\n", (unsigned long long)nplane_old,
+ loops_waiting_for_plane=0;
+ while (nplanes_seen < opts->nplanes) {
+ /* print progress message according to if new planes are availalbe */
+ if (nplanes_seen < dims[0]) {
+ if (loops_waiting_for_plane) {
+ /* end the previous message */
+ HDprintf("\n");
+ loops_waiting_for_plane=0;
+ }
+ HDprintf("reading planes %llu to %llu\n", (unsigned long long)nplanes_seen,
(unsigned long long)dims[0]);
- }else{
- if (nonewplane){
- HDprintf(".");
- if (nonewplane>=30){
- HDfprintf(stderr, "waited too long for new plane, quit.\n");
- return -1;
- }
- }else{
- /* print mesg only the first time; dots still no new plane */
- HDprintf("no new planes to read ");
}
- nonewplane++;
- /* pause for a second */
- HDsleep(1);
- }
- for (nplane=nplane_old; nplane < dims[0]; nplane++){
- /* read planes between last old nplanes and current extent */
- /* Get the dataset's dataspace */
- if((f_sid = H5Dget_space(dsid)) < 0){
- HDfprintf(stderr, "H5Dget_space failed\n");
- return -1;
+ else {
+ if (loops_waiting_for_plane) {
+ HDprintf(".");
+ if (loops_waiting_for_plane>=30) {
+ HDfprintf(stderr, "waited too long for new plane, quit.\n");
+ return -1;
+ }
+ }
+ else {
+ /* print mesg only the first time; dots still no new plane */
+ HDprintf("waiting for new planes to read ");
+ }
+ loops_waiting_for_plane++;
+ /* pause for a second */
+ HDsleep(1);
}
- start[0]=nplane;
- /* Choose the next plane to read */
- if(H5Sselect_hyperslab(f_sid, H5S_SELECT_SET, start, NULL, count, NULL) < 0){
- HDfprintf(stderr, "H5Sselect_hyperslab failed\n");
- return -1;
- }
+ for (nplane=nplanes_seen; nplane < dims[0]; nplane++) {
+ /* read planes between last old nplanes and current extent */
+ /* Get the dataset's dataspace */
+ if ((f_sid = H5Dget_space(dsid)) < 0) {
+ HDfprintf(stderr, "H5Dget_space failed\n");
+ return -1;
+ }
- /* Read the plane from the dataset */
- if(H5Dread(dsid, UC_DATATYPE, m_sid, f_sid, H5P_DEFAULT, buffer) < 0){
- HDfprintf(stderr, "H5Dread failed\n");
- return -1;
- }
+ start[0]=nplane;
+ /* Choose the next plane to read */
+ if (H5Sselect_hyperslab(f_sid, H5S_SELECT_SET, start, NULL, count, NULL) < 0) {
+ HDfprintf(stderr, "H5Sselect_hyperslab failed\n");
+ return -1;
+ }
- /* compare read data with expected data value which is nplane */
- bufptr = buffer;
- nerrs=0;
- for (j=0; j<dims[1]; j++){
- for (k=0; k<dims[2]; k++){
- if ((hsize_t)*bufptr++ != nplane){
- if (++nerrs < ErrorReportMax){
- HDfprintf(stderr,
- "found error %llu plane(%llu,%llu), expected %llu, got %d\n",
- (unsigned long long)nplane, (unsigned long long)j,
- (unsigned long long)k, (unsigned long long)nplane, (int)*(bufptr-1));
- }
- }
+ /* Read the plane from the dataset */
+ if (H5Dread(dsid, UC_DATATYPE, m_sid, f_sid, H5P_DEFAULT, buffer) < 0) {
+ HDfprintf(stderr, "H5Dread failed\n");
+ return -1;
}
- }
- if (nerrs){
- nreadererr++;
- HDfprintf(stderr, "found %d unexpected values in plane %llu\n", nerrs,
+
+ /* compare read data with expected data value which is nplane */
+ bufptr = buffer;
+ nerrs=0;
+ for (j=0; j < dims[1]; j++) {
+ for (k=0; k < dims[2]; k++) {
+ if ((hsize_t)*bufptr++ != nplane) {
+ if (++nerrs < ErrorReportMax) {
+ HDfprintf(stderr,
+ "found error %llu plane(%llu,%llu), expected %llu, got %d\n",
+ (unsigned long long)nplane, (unsigned long long)j,
+ (unsigned long long)k, (unsigned long long)nplane, (int)*(bufptr-1));
+ } /* end if should print error */
+ } /* end if value mismatch */
+ } /* end for plane second dimension */
+ } /* end for plane first dimension */
+ if (nerrs) {
+ nreadererr++;
+ HDfprintf(stderr, "found %d unexpected values in plane %llu\n", nerrs,
(unsigned long long)nplane);
- }
- }
- /* Have read all current planes */
- nplane_old=dims[0];
+ }
+ } /* end for each plane added since last read */
- /* check if dataset has grown since last time */
-#if 0
- /* close dsid and file, then reopen them */
- if (H5Dclose(dsid) < 0){
- HDfprintf(stderr, "H5Dclose failed\n");
- return -1;
- }
- if (H5Fclose(fid) < 0){
- HDfprintf(stderr, "H5Fclose failed\n");
- return -1;
- }
- if((fid = H5Fopen(name, H5F_ACC_RDONLY | (UC_opts.use_swmr ? H5F_ACC_SWMR_READ : 0), H5P_DEFAULT)) < 0){
- HDfprintf(stderr, "H5Fopen failed\n");
- return -1;
- }
- if((dsid = H5Dopen2(fid, progname_g, H5P_DEFAULT)) < 0){
- HDfprintf(stderr, "H5Dopen2 failed\n");
- return -1;
- }
-#else
- H5Drefresh(dsid);
-#endif
- f_sid = H5Dget_space(dsid); /* Get filespace handle first. */
- if (H5Sget_simple_extent_dims(f_sid, dims, NULL) < 0){
- HDfprintf(stderr, "H5Sget_simple_extent_dims got error\n");
- return -1;
- }
- }
+ nplanes_seen=dims[0];
+
+ /* check if dataset has grown since last time (update dims) */
+ H5Drefresh(dsid);
+ f_sid = H5Dget_space(dsid); /* Get filespace handle first. */
+ if (H5Sget_simple_extent_dims(f_sid, dims, NULL) < 0) {
+ HDfprintf(stderr, "H5Sget_simple_extent_dims got error\n");
+ return -1;
+ }
+ } /* end while (expecting more planes to read) */
- /* Close the file */
- if(H5Fclose(fid) < 0) {
+ if (H5Fclose(fid) < 0) {
HDfprintf(stderr, "H5Fclose failed\n");
return -1;
}
@@ -631,7 +616,7 @@ int read_uc_file(hbool_t towait)
return -1;
else
return 0;
-} /* read_uc_file() */
+} /* end read_uc_file() */
#endif /* H5_HAVE_FORK */
diff --git a/test/vfd.c b/test/vfd.c
index e88d9bb..97995d2 100644
--- a/test/vfd.c
+++ b/test/vfd.c
@@ -25,6 +25,7 @@
#define FAMILY_SIZE (1*KB)
#define FAMILY_SIZE2 (5*KB)
#define MULTI_SIZE 128
+#define SPLITTER_SIZE 8 /* dimensions of a dataset */
#define CORE_INCREMENT (4*KB)
#define CORE_PAGE_SIZE (1024*KB)
@@ -59,6 +60,9 @@ const char *FILENAME[] = {
"windows_file", /*8*/
"new_multi_file_v16",/*9*/
"ro_s3_file", /*10*/
+ "splitter_rw_file", /*11*/
+ "splitter_wo_file", /*12*/
+ "splitter.log", /*13*/
NULL
};
@@ -66,8 +70,47 @@ const char *FILENAME[] = {
#define COMPAT_BASENAME "family_v16_"
#define MULTI_COMPAT_BASENAME "multi_file_v16"
+#define SPLITTER_DATASET_NAME "dataset"
+
+/* Macro: HEXPRINT()
+ * Helper macro to pretty-print hexadecimal output of a buffer of known size.
+ * Each line has the address of the first printed byte, and four columns of
+ * four-byte data.
+ */
+static int __k;
+#define HEXPRINT(size, buf) \
+for (__k = 0; __k < (size); __k++) { \
+ if (__k % 16 == 0) { \
+ HDprintf("\n%04x", __k); \
+ } \
+ HDprintf((__k%4 == 0) ? " %02X" : " %02X", (unsigned char)(buf)[__k]); \
+} /* end #define HEXPRINT() */
+/* Helper structure to pass around dataset information.
+ */
+struct splitter_dataset_def {
+ void *buf; /* contents of dataset */
+ const char *dset_name; /* dataset name, always added to root group */
+ hid_t mem_type_id; /* datatype */
+ const hsize_t *dims; /* dimensions */
+ int n_dims; /* rank */
+};
+
+static int splitter_prepare_file_paths(H5FD_splitter_vfd_config_t *vfd_config,
+ char *filename_rw_out);
+static int splitter_create_single_file_at(const char *filename, hid_t fapl_id,
+ const struct splitter_dataset_def *data);
+static int splitter_compare_expected_data(hid_t file_id,
+ const struct splitter_dataset_def *data);
+static int run_splitter_test(const struct splitter_dataset_def *data,
+ hbool_t ignore_wo_errors, hbool_t provide_logfile_path,
+ hid_t sub_fapl_ids[2]);
+static int splitter_RO_test(const struct splitter_dataset_def *data,
+ hid_t child_fapl_id);
+static int splitter_tentative_open_test(hid_t child_fapl_id);
+static int file_exists(const char *filename, hid_t fapl_id);
+
/*-------------------------------------------------------------------------
* Function: test_sec2
*
@@ -859,7 +902,7 @@ test_family(void)
hid_t driver_id = -1; /* ID for this VFD */
unsigned long driver_flags = 0; /* VFD feature flags */
char filename[1024];
- char dname[]="dataset";
+ char dname[] = "dataset";
unsigned int i, j;
int *fhandle=NULL, *fhandle2=NULL;
int **buf = NULL;
@@ -1263,7 +1306,7 @@ error:
return FAIL;
} /* end test_family_member_fapl() */
-
+
/*-------------------------------------------------------------------------
* Function: test_multi_opens
*
@@ -2179,6 +2222,1052 @@ error:
#endif /* H5_HAVE_ROS3_VFD */
} /* end test_ros3() */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * Macro: SPLITTER_TEST_FAULT()
+ *
+ * utility macro, helps create stack-like backtrace on error.
+ * requires defined in the calling function:
+ * * variable `int ret_value` (return -1 on error)`
+ * * label `done` for exit on fault
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+#define SPLITTER_TEST_FAULT(mesg) { \
+ H5_FAILED(); \
+ AT(); \
+ HDfprintf(stderr, mesg); \
+ H5Eprint2(H5E_DEFAULT, stderr); \
+ fflush(stderr); \
+ ret_value = -1; \
+ goto done; \
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: compare_splitter_config_info
+ *
+ * Purpose: Helper function to compare configuration info found in a
+ * FAPL against a canonical structure.
+ *
+ * Return: Success: 0, if config info in FAPL matches info structure.
+ * Failure: -1, if difference detected.
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+compare_splitter_config_info(hid_t fapl_id, H5FD_splitter_vfd_config_t *info)
+{
+ int ret_value = 0;
+ H5FD_splitter_vfd_config_t fetched_info;
+
+ fetched_info.magic = H5FD_SPLITTER_MAGIC;
+ fetched_info.version = H5FD_CURR_SPLITTER_VFD_CONFIG_VERSION;
+ fetched_info.rw_fapl_id = H5I_INVALID_HID;
+ fetched_info.wo_fapl_id = H5I_INVALID_HID;
+
+ if (H5Pget_fapl_splitter(fapl_id, &fetched_info) < 0) {
+ SPLITTER_TEST_FAULT("can't get splitter info\n");
+ }
+ if (info->rw_fapl_id == H5P_DEFAULT) {
+ if (H5Pget_driver(fetched_info.rw_fapl_id) != H5Pget_driver(H5P_FILE_ACCESS_DEFAULT)) {
+ SPLITTER_TEST_FAULT("Read-Write driver mismatch (default)\n");
+ }
+ }
+ else {
+ if (H5Pget_driver(fetched_info.rw_fapl_id) != H5Pget_driver(info->rw_fapl_id)) {
+ SPLITTER_TEST_FAULT("Read-Write driver mismatch\n");
+ }
+ }
+ if (info->wo_fapl_id == H5P_DEFAULT) {
+ if (H5Pget_driver(fetched_info.wo_fapl_id) != H5Pget_driver(H5P_FILE_ACCESS_DEFAULT)) {
+ SPLITTER_TEST_FAULT("Write-Only driver mismatch (default)\n");
+ }
+ }
+ else {
+ if (H5Pget_driver(fetched_info.wo_fapl_id) != H5Pget_driver(info->wo_fapl_id)) {
+ SPLITTER_TEST_FAULT("Write-Only driver mismatch\n");
+ }
+ }
+ if ( (HDstrlen(info->wo_path) != HDstrlen(fetched_info.wo_path)) ||
+ HDstrncmp(info->wo_path, fetched_info.wo_path, H5FD_SPLITTER_PATH_MAX))
+ {
+ HDfprintf(stderr, "MISMATCH: '%s' :: '%s'\n", info->wo_path, fetched_info.wo_path);
+ HEXPRINT(H5FD_SPLITTER_PATH_MAX, info->wo_path);
+ HEXPRINT(H5FD_SPLITTER_PATH_MAX, fetched_info.wo_path);
+ SPLITTER_TEST_FAULT("Write-Only file path mismatch\n");
+ }
+
+done:
+ return ret_value;
+} /* end compare_splitter_config_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: run_splitter_test
+ *
+ * Purpose: Auxiliary function for test_splitter().
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Description:
+ * Perform basic open-write-close with the Splitter VFD.
+ * Prior to operations, removes files from a previous run,
+ * if they exist.
+ * After writing, compares read-write and write-only files.
+ * Includes FAPL sanity testing.
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+run_splitter_test(const struct splitter_dataset_def *data,
+ hbool_t ignore_wo_errors,
+ hbool_t provide_logfile_path,
+ hid_t sub_fapl_ids[2])
+{
+ hid_t file_id = H5I_INVALID_HID;
+ hid_t fapl_id = H5I_INVALID_HID;
+ hid_t dset_id = H5I_INVALID_HID;
+ hid_t space_id = H5I_INVALID_HID;
+ hid_t fapl_id_out = H5I_INVALID_HID;
+ hid_t fapl_id_cpy = H5I_INVALID_HID;
+ H5FD_splitter_vfd_config_t vfd_config;
+ char filename_rw[H5FD_SPLITTER_PATH_MAX + 1];
+ FILE *logfile = NULL;
+ int ret_value = 0;
+
+ vfd_config.magic = H5FD_SPLITTER_MAGIC;
+ vfd_config.version = H5FD_CURR_SPLITTER_VFD_CONFIG_VERSION;
+ vfd_config.ignore_wo_errs = ignore_wo_errors;
+ vfd_config.rw_fapl_id = sub_fapl_ids[0];
+ vfd_config.wo_fapl_id = sub_fapl_ids[1];
+
+ if (splitter_prepare_file_paths(&vfd_config, filename_rw) < 0) {
+ SPLITTER_TEST_FAULT("can't prepare file paths\n");
+ }
+
+ if (provide_logfile_path == FALSE) {
+ *vfd_config.log_file_path = '\0'; /* reset as empty string */
+ }
+
+ /* Create a new fapl to use the SPLITTER file driver */
+ if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) == H5I_INVALID_HID) {
+ SPLITTER_TEST_FAULT("can't create FAPL ID\n");
+ }
+ if (H5Pset_fapl_splitter(fapl_id, &vfd_config) < 0) {
+ SPLITTER_TEST_FAULT("can't set splitter FAPL\n");
+ }
+ if (H5Pget_driver(fapl_id) != H5FD_SPLITTER) {
+ SPLITTER_TEST_FAULT("set FAPL not SPLITTER\n");
+ }
+
+ if (compare_splitter_config_info(fapl_id, &vfd_config) < 0) {
+ SPLITTER_TEST_FAULT("information mismatch\n");
+ }
+
+ /*
+ * Copy property list, light compare, and close the copy.
+ * Helps test driver-implemented FAPL-copying and library ID management.
+ */
+
+ fapl_id_cpy = H5Pcopy(fapl_id);
+ if (H5I_INVALID_HID == fapl_id_cpy) {
+ SPLITTER_TEST_FAULT("can't copy FAPL\n");
+ }
+ if (compare_splitter_config_info(fapl_id_cpy, &vfd_config) < 0) {
+ SPLITTER_TEST_FAULT("information mismatch\n");
+ }
+ if (H5Pclose(fapl_id_cpy) < 0) {
+ SPLITTER_TEST_FAULT("can't close fapl copy\n");
+ }
+
+ /*
+ * Proceed with test. Create file.
+ */
+ file_id = H5Fcreate(filename_rw, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
+ if (file_id < 0) {
+ SPLITTER_TEST_FAULT("can't create file\n");
+ }
+
+ /*
+ * Check driver from file
+ */
+
+ fapl_id_out = H5Fget_access_plist(file_id);
+ if (H5I_INVALID_HID == fapl_id_out) {
+ SPLITTER_TEST_FAULT("can't get file's FAPL\n");
+
+ }
+ if (H5Pget_driver(fapl_id_out) != H5FD_SPLITTER) {
+ SPLITTER_TEST_FAULT("wrong file FAPL driver\n");
+ }
+ if (compare_splitter_config_info(fapl_id_out, &vfd_config) < 0) {
+ SPLITTER_TEST_FAULT("information mismatch\n");
+ }
+ if (H5Pclose(fapl_id_out) < 0) {
+ SPLITTER_TEST_FAULT("can't close file's FAPL\n");
+ }
+
+ /*
+ * Create and write the dataset
+ */
+
+ space_id = H5Screate_simple(data->n_dims, data->dims, NULL);
+ if (space_id < 0) {
+ SPLITTER_TEST_FAULT("can't create dataspace\n");
+ }
+ dset_id = H5Dcreate2(file_id, data->dset_name, data->mem_type_id, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+ if (dset_id < 0) {
+ SPLITTER_TEST_FAULT("can't create dataset\n");
+ }
+ if (H5Dwrite(dset_id, data->mem_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, data->buf) < 0) {
+ SPLITTER_TEST_FAULT("can't write data to dataset\n");
+ }
+
+ /* Close everything */
+ if (H5Dclose(dset_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close dset\n");
+ }
+ if (H5Sclose(space_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close space\n");
+ }
+ if (H5Pclose(fapl_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close fapl\n");
+ }
+ if (H5Fclose(file_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close file\n");
+ }
+
+ /* Verify that the R/W and W/O files are identical */
+ if (h5_compare_file_bytes(filename_rw, vfd_config.wo_path) < 0) {
+ SPLITTER_TEST_FAULT("files are not byte-for-byte equivalent\n");
+ }
+
+ /* Verify existence of logfile iff appropriate */
+ logfile = fopen(vfd_config.log_file_path, "r");
+ if ( (TRUE == provide_logfile_path && NULL == logfile) ||
+ (FALSE == provide_logfile_path && NULL != logfile) )
+ {
+ SPLITTER_TEST_FAULT("no logfile when one was expected\n");
+ }
+
+done:
+ if (ret_value < 0) {
+ H5E_BEGIN_TRY {
+ (void)H5Dclose(dset_id);
+ (void)H5Sclose(space_id);
+ (void)H5Pclose(fapl_id_out);
+ (void)H5Pclose(fapl_id_cpy);
+ (void)H5Pclose(fapl_id);
+ (void)H5Fclose(file_id);
+ } H5E_END_TRY;
+ }
+ if (logfile != NULL) {
+ fclose(logfile);
+ }
+ return ret_value;
+
+} /* end run_splitter_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: driver_is_splitter_compatible
+ *
+ * Purpose: Determine whether the driver set in the FAPL ID is compatible
+ * with the Splitter VFD -- specificially, Write-Only channel.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Description: Attempts to put the given FAPL ID as the W/O channel.
+ * Uses driver's own mechanisms to generate error, and catches
+ * error.
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+driver_is_splitter_compatible(hid_t fapl_id)
+{
+ H5FD_splitter_vfd_config_t vfd_config;
+ hid_t split_fapl_id = H5I_INVALID_HID;
+ herr_t ret;
+ int ret_value = 0;
+
+ split_fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ if (H5I_INVALID_HID == split_fapl_id) {
+ FAIL_PUTS_ERROR("Can't create contained FAPL");
+ }
+ vfd_config.magic = H5FD_SPLITTER_MAGIC;
+ vfd_config.version = H5FD_CURR_SPLITTER_VFD_CONFIG_VERSION;
+ vfd_config.ignore_wo_errs = FALSE;
+ vfd_config.rw_fapl_id = H5P_DEFAULT;
+ vfd_config.wo_fapl_id = fapl_id;
+ HDstrncpy(vfd_config.wo_path, "nonesuch", H5FD_SPLITTER_PATH_MAX);
+
+ H5E_BEGIN_TRY {
+ ret = H5Pset_fapl_splitter(split_fapl_id, &vfd_config);
+ } H5E_END_TRY;
+ if (SUCCEED == ret) {
+ ret_value = -1;
+ }
+
+ if (H5Pclose(split_fapl_id) < 0) {
+ FAIL_PUTS_ERROR("Can't close contained FAPL")
+ }
+ split_fapl_id = H5I_INVALID_HID;
+
+ return ret_value;
+
+error:
+ H5E_BEGIN_TRY {
+ (void)H5Pclose(split_fapl_id);
+ } H5E_END_TRY;
+ return -1;
+} /* end driver_is_splitter_compatible() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: splitter_RO_test
+ *
+ * Purpose: Verify Splitter VFD with the Read-Only access flag.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Description: Attempt read-only opening of files with different
+ * permutations of files already existing on-disk.
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+splitter_RO_test(
+ const struct splitter_dataset_def *data,
+ hid_t child_fapl_id)
+{
+ char filename_rw[H5FD_SPLITTER_PATH_MAX + 1];
+ H5FD_splitter_vfd_config_t vfd_config;
+ hid_t fapl_id = H5I_INVALID_HID;
+ int ret_value = 0;
+ hid_t file_id = H5I_INVALID_HID;
+
+ vfd_config.magic = H5FD_SPLITTER_MAGIC;
+ vfd_config.version = H5FD_CURR_SPLITTER_VFD_CONFIG_VERSION;
+ vfd_config.ignore_wo_errs = FALSE;
+ vfd_config.rw_fapl_id = child_fapl_id;
+ vfd_config.wo_fapl_id = child_fapl_id;
+
+ if (splitter_prepare_file_paths(&vfd_config, filename_rw) < 0) {
+ SPLITTER_TEST_FAULT("can't prepare splitter file paths\n");
+ }
+
+ /* Create a new fapl to use the SPLITTER file driver */
+ fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ if (H5I_INVALID_HID == fapl_id) {
+ SPLITTER_TEST_FAULT("can't create FAPL ID\n");
+ }
+ if (H5Pset_fapl_splitter(fapl_id, &vfd_config) < 0) {
+ SPLITTER_TEST_FAULT("can't set splitter FAPL\n");
+ }
+ if (H5Pget_driver(fapl_id) != H5FD_SPLITTER) {
+ SPLITTER_TEST_FAULT("set FAPL not SPLITTER\n");
+ }
+
+ /* Attempt R/O open when both files are nonexistent
+ * Should fail.
+ */
+
+ H5E_BEGIN_TRY {
+ file_id = H5Fopen(filename_rw, H5F_ACC_RDONLY, fapl_id);
+ } H5E_END_TRY;
+ if (file_id >= 0) {
+ SPLITTER_TEST_FAULT("R/O open on nonexistent files unexpectedly successful\n");
+ }
+
+ /* Attempt R/O open when only W/O file exists
+ * Should fail.
+ */
+
+ if (splitter_create_single_file_at(vfd_config.wo_path, vfd_config.wo_fapl_id, data) < 0) {
+ SPLITTER_TEST_FAULT("can't write W/O file\n");
+ }
+ H5E_BEGIN_TRY {
+ file_id = H5Fopen(filename_rw, H5F_ACC_RDONLY, fapl_id);
+ } H5E_END_TRY;
+ if (file_id >= 0) {
+ SPLITTER_TEST_FAULT("R/O open with extant W/O file unexpectedly successful\n");
+ }
+ HDremove(vfd_config.wo_path);
+
+ /* Attempt R/O open when only R/W file exists
+ * Should fail.
+ */
+
+ if (splitter_create_single_file_at(filename_rw, vfd_config.rw_fapl_id, data) < 0) {
+ SPLITTER_TEST_FAULT("can't create R/W file\n");
+ }
+ H5E_BEGIN_TRY {
+ file_id = H5Fopen(filename_rw, H5F_ACC_RDONLY, fapl_id);
+ } H5E_END_TRY;
+ if (file_id >= 0) {
+ SPLITTER_TEST_FAULT("R/O open with extant R/W file unexpectedly successful\n");
+ }
+
+ /* Attempt R/O open when both R/W and W/O files exist
+ */
+
+ if (splitter_create_single_file_at(vfd_config.wo_path, vfd_config.wo_fapl_id, data) < 0) {
+ SPLITTER_TEST_FAULT("can't create W/O file\n");
+ }
+ file_id = H5Fopen(filename_rw, H5F_ACC_RDONLY, fapl_id);
+ if (file_id < 0) {
+ SPLITTER_TEST_FAULT("R/O open on two extant files failed\n");
+ }
+ if (splitter_compare_expected_data(file_id, data) < 0) {
+ SPLITTER_TEST_FAULT("data mismatch in R/W file\n");
+ }
+ if (H5Fclose(file_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close file(s)\n");
+ }
+ file_id = H5I_INVALID_HID;
+
+ /* Cleanup
+ */
+
+ if (H5Pclose(fapl_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close FAPL ID\n");
+ }
+ fapl_id = H5I_INVALID_HID;
+
+done:
+ if (ret_value < 0) {
+ H5E_BEGIN_TRY {
+ (void)H5Pclose(fapl_id);
+ (void)H5Fclose(file_id);
+ } H5E_END_TRY;
+ } /* end if error */
+ return ret_value;
+} /* end splitter_RO_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: splitter_prepare_file_paths
+ *
+ * Purpose: Get file paths ready for use by the Splitter VFD tests.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Description:
+ * Use h5_fixname to adjust the splitter-relevant file paths
+ * from those given in FILENAMES.
+ *
+ * REMOVES EXISTING FILES AT THE PATH LOCATIONS PRIOR TO RETURN.
+ *
+ * The relevant file paths will be set in filename_rw_out and
+ * inside the config structure (wo_path, log_file_path).
+ *
+ * `filename_rw_out` must be at least H5FD_SPLITTER_PATH_MAX+1
+ * characters long.
+ *
+ * `vfd_config` must have its child FAPL IDs preset.
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+splitter_prepare_file_paths(H5FD_splitter_vfd_config_t *vfd_config, char *filename_rw_out)
+{
+ int ret_value = 0;
+
+ if (vfd_config == NULL || vfd_config->magic != H5FD_SPLITTER_MAGIC) {
+ SPLITTER_TEST_FAULT("invalid splitter config pointer\n");
+ }
+ if (filename_rw_out == NULL) {
+ SPLITTER_TEST_FAULT("NULL filename_rw pointer\n");
+ }
+
+ /* TODO: sanity-check fapl IDs? */
+
+ /* Build the r/w file, w/o file, and the log file paths.
+ * Output is stored in the associated string pointers.
+ */
+ h5_fixname(FILENAME[11], vfd_config->rw_fapl_id, filename_rw_out, H5FD_SPLITTER_PATH_MAX);
+ h5_fixname(FILENAME[12], vfd_config->wo_fapl_id, vfd_config->wo_path, H5FD_SPLITTER_PATH_MAX);
+ h5_fixname_no_suffix(FILENAME[13], vfd_config->wo_fapl_id, vfd_config->log_file_path, H5FD_SPLITTER_PATH_MAX);
+
+ /* Delete any existing files on disk.
+ */
+ HDremove(filename_rw_out);
+ HDremove(vfd_config->wo_path);
+ HDremove(vfd_config->log_file_path);
+
+done:
+ return ret_value;
+} /* end splitter_prepare_file_paths() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: splitter_crate_single_file_at
+ *
+ * Purpose: Create a file, optionally w/ dataset.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Description:
+ * Create a file at the given location with the given FAPL,
+ * and write data as defined in `data` in a pre-determined location in the file.
+ *
+ * If the dataset definition pointer is NULL, no data is written
+ * to the file.
+ *
+ * Will always overwrite an existing file with the given name/path.
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+splitter_create_single_file_at(
+ const char *filename,
+ hid_t fapl_id,
+ const struct splitter_dataset_def *data)
+{
+ hid_t file_id = H5I_INVALID_HID;
+ hid_t space_id = H5I_INVALID_HID;
+ hid_t dset_id = H5I_INVALID_HID;
+ int ret_value = 0;
+
+ if (filename == NULL || *filename == '\0') {
+ SPLITTER_TEST_FAULT("filename is invalid\n");
+ }
+ /* TODO: sanity-check fapl id? */
+
+ file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
+ if (file_id < 0) {
+ SPLITTER_TEST_FAULT("can't create file\n");
+ }
+
+ if (data) {
+ /* TODO: sanity-check data, if it exists? */
+ space_id = H5Screate_simple(data->n_dims, data->dims, NULL);
+ if (space_id < 0) {
+ SPLITTER_TEST_FAULT("can't create dataspace\n");
+ }
+
+ dset_id = H5Dcreate2(
+ file_id,
+ data->dset_name,
+ data->mem_type_id,
+ space_id,
+ H5P_DEFAULT,
+ H5P_DEFAULT,
+ H5P_DEFAULT);
+ if (dset_id < 0) {
+ SPLITTER_TEST_FAULT("can't create dataset\n");
+ }
+
+ if (H5Dwrite(dset_id, data->mem_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, data->buf) < 0) {
+ SPLITTER_TEST_FAULT("can't write data to dataset\n");
+ }
+
+ if (H5Dclose(dset_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close dset\n");
+ }
+ if (H5Sclose(space_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close space\n");
+ }
+ } /* end if data definition is provided */
+
+ if (H5Fclose(file_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close file\n");
+ }
+
+done:
+ if (ret_value < 0) {
+ H5E_BEGIN_TRY {
+ (void)H5Dclose(dset_id);
+ (void)H5Sclose(space_id);
+ (void)H5Fclose(file_id);
+ } H5E_END_TRY;
+ } /* end if error */
+ return ret_value;
+} /* end splitter_create_single_file_at() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: splitter_compare_expected_data
+ *
+ * Purpose: Compare data within a predermined dataset.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Description: Read data from the file at a predetermined location, and
+ * compare its contents byte-for-byte with that expected in
+ * the `data` definition structure.
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+splitter_compare_expected_data(hid_t file_id,
+ const struct splitter_dataset_def *data)
+{
+ hid_t dset_id = H5I_INVALID_HID;
+ int buf[SPLITTER_SIZE][SPLITTER_SIZE];
+ int expected[SPLITTER_SIZE][SPLITTER_SIZE];
+ size_t i = 0;
+ size_t j = 0;
+ int ret_value = 0;
+
+ if (sizeof((void *)buf) != sizeof(data->buf)) {
+ SPLITTER_TEST_FAULT("invariant size of expected data does not match that received!\n");
+ }
+ HDmemcpy(expected, data->buf, sizeof(expected));
+
+ dset_id = H5Dopen2(file_id, data->dset_name, H5P_DEFAULT);
+ if (dset_id < 0) {
+ SPLITTER_TEST_FAULT("can't open dataset\n");
+ }
+
+ if (H5Dread(dset_id, data->mem_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, (void *)buf) < 0) {
+ SPLITTER_TEST_FAULT("can't read dataset\n");
+ }
+
+ for (i=0; i < SPLITTER_SIZE; i++) {
+ for (j=0; j < SPLITTER_SIZE; j++) {
+ if (buf[i][j] != expected[i][j]) {
+ SPLITTER_TEST_FAULT("mismatch in expected data\n");
+ }
+ }
+ }
+
+ if (H5Dclose(dset_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close dataset\n");
+ }
+
+done:
+ if (ret_value < 0) {
+ H5E_BEGIN_TRY {
+ (void)H5Dclose(dset_id);
+ } H5E_END_TRY;
+ }
+ return ret_value;
+} /* end splitter_compare_expected_data() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: splitter_tentative_open_test()
+ *
+ * Purpose: Verifies Splitter behavior with "tentative" H5F_open.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Description:
+ * H5F_open() has a two-stage opening process when given a
+ * Read/Write access flag -- first it performs a "tentative
+ * open", where it checks to see whether files already exist
+ * on the system, done in such a way as to not "alter its state"
+ * (i.e., truncate).
+ * This can cause problems with the Splitter VFD, as the
+ * file on the R/W channel might exist already, but that on the
+ * W/O channel will not, and vice-versa.
+ *
+ * This test exists to verify that in any event, files will be
+ * created as required.
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+splitter_tentative_open_test(hid_t child_fapl_id)
+{
+ char filename_rw[H5FD_SPLITTER_PATH_MAX + 1];
+ H5FD_splitter_vfd_config_t vfd_config;
+ hid_t fapl_id = H5I_INVALID_HID;
+ hid_t file_id = H5I_INVALID_HID;
+ int buf[SPLITTER_SIZE][SPLITTER_SIZE]; /* for comparison */
+ hsize_t dims[2] = { SPLITTER_SIZE, SPLITTER_SIZE }; /* for comparison */
+ int i = 0; /* for comparison */
+ int j = 0; /* for comparison */
+ struct splitter_dataset_def data; /* for comparison */
+ int ret_value = 0;
+
+ /* pre-fill data buffer to write */
+ for (i=0; i < SPLITTER_SIZE; i++) {
+ for (j=0; j < SPLITTER_SIZE; j++) {
+ buf[i][j] = i*100+j;
+ }
+ }
+
+ /* Dataset info */
+ data.buf = (void *)buf;
+ data.mem_type_id = H5T_NATIVE_INT;
+ data.dims = dims;
+ data.n_dims = 2;
+ data.dset_name = SPLITTER_DATASET_NAME;
+
+ vfd_config.magic = H5FD_SPLITTER_MAGIC;
+ vfd_config.version = H5FD_CURR_SPLITTER_VFD_CONFIG_VERSION;
+ vfd_config.ignore_wo_errs = FALSE;
+ vfd_config.rw_fapl_id = child_fapl_id;
+ vfd_config.wo_fapl_id = child_fapl_id;
+
+ if (splitter_prepare_file_paths(&vfd_config, filename_rw) < 0) {
+ SPLITTER_TEST_FAULT("can't prepare splitter file paths\n");
+ }
+
+ /* Create a new fapl to use the SPLITTER file driver */
+ if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) == H5I_INVALID_HID) {
+ SPLITTER_TEST_FAULT("can't create FAPL ID\n");
+ }
+ if (H5Pset_fapl_splitter(fapl_id, &vfd_config) < 0) {
+ SPLITTER_TEST_FAULT("can't set splitter FAPL\n");
+ }
+ if (H5Pget_driver(fapl_id) != H5FD_SPLITTER) {
+ SPLITTER_TEST_FAULT("set FAPL not SPLITTER\n");
+ }
+
+ /* H5Fopen() with RDWR access.
+ * Neither file exist already
+ * Should fail.
+ */
+
+ H5E_BEGIN_TRY {
+ file_id = H5Fopen(filename_rw, H5F_ACC_RDWR, fapl_id);
+ } H5E_END_TRY;
+ if (file_id != H5I_INVALID_HID) {
+ SPLITTER_TEST_FAULT("open with both nonexistent files unexpectedly succeeded\n");
+ }
+ if (file_exists(filename_rw, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("R/W file unexpectedly created\n");
+ }
+ if (file_exists(vfd_config.wo_path, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("W/O file unexpectedly created\n");
+ }
+
+ /* H5Fopen() with RDWR access.
+ * W/O file exists already.
+ * Should fail.
+ */
+
+ if (splitter_create_single_file_at(vfd_config.wo_path, child_fapl_id, &data) < 0) {
+ SPLITTER_TEST_FAULT("can't write W/O file\n");
+ }
+ H5E_BEGIN_TRY {
+ file_id = H5Fopen(filename_rw, H5F_ACC_RDWR, fapl_id);
+ } H5E_END_TRY;
+ if (file_id != H5I_INVALID_HID) {
+ SPLITTER_TEST_FAULT("open with nonexistent R/W file unexpectedly succeeded\n");
+ }
+ if (file_exists(filename_rw, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("R/W file unexpectedly created\n");
+ }
+ if (!file_exists(vfd_config.wo_path, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("W/O file mysteriously disappeared\n");
+ }
+ HDremove(vfd_config.wo_path);
+ if (file_exists(vfd_config.wo_path, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("failed to remove W/O file\n");
+ }
+
+ /* H5Fopen() with RDWR access.
+ * R/W file exists already.
+ * Should fail.
+ */
+
+ if (splitter_create_single_file_at(filename_rw, child_fapl_id, &data) < 0) {
+ SPLITTER_TEST_FAULT("can't write R/W file\n");
+ }
+ H5E_BEGIN_TRY {
+ file_id = H5Fopen(filename_rw, H5F_ACC_RDWR, fapl_id);
+ } H5E_END_TRY;
+ if (file_id != H5I_INVALID_HID) {
+ SPLITTER_TEST_FAULT("open with nonexistent W/O unexpectedly succeeded\n");
+ }
+ if (!file_exists(filename_rw, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("R/W file mysteriously disappeared\n");
+ }
+ if (file_exists(vfd_config.wo_path, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("W/O file unexpectedly created\n");
+ }
+
+ /* H5Fopen() with RDWR access.
+ * Both files already exist.
+ */
+
+ if (splitter_create_single_file_at(vfd_config.wo_path, child_fapl_id, &data) < 0) {
+ SPLITTER_TEST_FAULT("can't write W/O file\n");
+ }
+ file_id = H5Fopen(filename_rw, H5F_ACC_RDWR, fapl_id);
+ if (file_id == H5I_INVALID_HID) {
+ SPLITTER_TEST_FAULT("file-open failed with both present\n");
+ }
+ /* Open successful; close file then inspect presence again */
+ if (H5Fclose(file_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close file ID\n");
+ }
+ if (!file_exists(filename_rw, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("R/W file mysteriously disappared\n");
+ }
+ if (!file_exists(vfd_config.wo_path, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("W/O file mysteriously disappeared\n");
+ }
+ if (h5_compare_file_bytes(filename_rw, vfd_config.wo_path) < 0) {
+ SPLITTER_TEST_FAULT("files are not byte-for-byte equivalent\n");
+ }
+
+ /* H5Fcreate() with TRUNC access.
+ * Both files already exist.
+ */
+
+ file_id = H5Fcreate(filename_rw, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
+ if (file_id == H5I_INVALID_HID) {
+ SPLITTER_TEST_FAULT("file-open failed with both present\n");
+ }
+ /* Open successful; close file then inspect presence again */
+ if (H5Fclose(file_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close file ID\n");
+ }
+ if (!file_exists(filename_rw, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("R/W file mysteriously disappared\n");
+ }
+ if (!file_exists(vfd_config.wo_path, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("W/O file mysteriously disappeared\n");
+ }
+ if (h5_compare_file_bytes(filename_rw, vfd_config.wo_path) < 0) {
+ SPLITTER_TEST_FAULT("files are not byte-for-byte equivalent\n");
+ }
+
+ /* H5Fcreate() with TRUNC access.
+ * R/W already exists.
+ */
+
+ HDremove(filename_rw);
+ HDremove(vfd_config.wo_path);
+ if (splitter_create_single_file_at(filename_rw, child_fapl_id, &data) < 0) {
+ SPLITTER_TEST_FAULT("can't write R/W file\n");
+ }
+
+ if (file_exists(vfd_config.wo_path, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("failed to remove W/O file\n");
+ }
+ file_id = H5Fcreate(filename_rw, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
+ if (file_id == H5I_INVALID_HID) {
+ SPLITTER_TEST_FAULT("file-open failed with both present\n");
+ }
+ /* Open successful; close file then inspect presence again */
+ if (H5Fclose(file_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close file ID\n");
+ }
+ if (!file_exists(filename_rw, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("R/W file mysteriously disappared\n");
+ }
+ if (!file_exists(vfd_config.wo_path, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("W/O file mysteriously disappeared\n");
+ }
+ if (h5_compare_file_bytes(filename_rw, vfd_config.wo_path) < 0) {
+ SPLITTER_TEST_FAULT("files are not byte-for-byte equivalent\n");
+ }
+
+ /* H5Fcreate() with TRUNC access.
+ * W/O already exists.
+ */
+
+ HDremove(filename_rw);
+ HDremove(vfd_config.wo_path);
+ if (splitter_create_single_file_at(vfd_config.wo_path, child_fapl_id, &data) < 0) {
+ SPLITTER_TEST_FAULT("can't write R/W file\n");
+ }
+
+ if (file_exists(filename_rw, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("failed to remove R/W file\n");
+ }
+ file_id = H5Fcreate(filename_rw, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
+ if (file_id == H5I_INVALID_HID) {
+ SPLITTER_TEST_FAULT("file-open failed with both present\n");
+ }
+ /* Open successful; close file then inspect presence again */
+ if (H5Fclose(file_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close file ID\n");
+ }
+ if (!file_exists(filename_rw, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("R/W file mysteriously disappared\n");
+ }
+ if (!file_exists(vfd_config.wo_path, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("W/O file mysteriously disappeared\n");
+ }
+ if (h5_compare_file_bytes(filename_rw, vfd_config.wo_path) < 0) {
+ SPLITTER_TEST_FAULT("files are not byte-for-byte equivalent\n");
+ }
+
+ /* H5Fcreate with both files absent is tested elsewhere */
+
+ /* Cleanup
+ */
+
+ if (H5Pclose(fapl_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close splitter FAPL ID\n");
+ }
+
+done:
+ if (ret_value < 0) {
+ H5E_BEGIN_TRY {
+ (void)H5Pclose(fapl_id);
+ (void)H5Fclose(file_id);
+ } H5E_END_TRY;
+ } /* end if error */
+ return ret_value;
+} /* end splitter_tentative_open_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: file_exists()
+ *
+ * Purpose: Determine whether a file exists on-system
+ *
+ * Return: Non-zero (1) if it exists (H5Fopen successful),
+ * zero (0) if absent (cannot be opened).
+ *
+ * Description: Attempt H5Fopen with the given FAPL ID and RDONLY access flag.
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+file_exists(const char *filename, hid_t fapl_id)
+{
+ hid_t file_id = H5I_INVALID_HID;
+ int ret_value = 0;
+
+ H5E_BEGIN_TRY {
+ file_id = H5Fopen(filename, H5F_ACC_RDONLY, fapl_id);
+ } H5E_END_TRY;
+ if (file_id != H5I_INVALID_HID) {
+ ret_value = 1;
+ if (H5Fclose(file_id) < 0) {
+ FAIL_PUTS_ERROR("can't close file ID\n");
+ }
+ }
+
+ return ret_value;
+
+error:
+ H5E_BEGIN_TRY {
+ (void)H5Fclose(file_id);
+ } H5E_END_TRY;
+ return ret_value;
+} /* end file_exists() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: test_splitter
+ *
+ * Purpose: Tests the Splitter VFD
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Description:
+ * This test function uses the Splitter VFD to produce a r/w
+ * file and a w/o file. It will verify that the two files
+ * are identical.
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+test_splitter(void)
+{
+ int buf[SPLITTER_SIZE][SPLITTER_SIZE];
+ hsize_t dims[2] = { SPLITTER_SIZE, SPLITTER_SIZE };
+ hid_t child_fapl_id = H5I_INVALID_HID;
+ int i = 0;
+ int j = 0;
+ struct splitter_dataset_def data;
+
+ TESTING("SPLITTER file driver");
+
+ /* pre-fill data buffer to write */
+ for (i=0; i < SPLITTER_SIZE; i++) {
+ for (j=0; j < SPLITTER_SIZE; j++) {
+ buf[i][j] = i*100+j;
+ }
+ }
+
+ /* Dataset info */
+ data.buf = (void *)buf;
+ data.mem_type_id = H5T_NATIVE_INT;
+ data.dims = dims;
+ data.n_dims = 2;
+ data.dset_name = SPLITTER_DATASET_NAME;
+
+ /* Stand-in for manual FAPL creation
+ * Enables verification with arbitrary VFDs via `make check-vfd`
+ */
+ child_fapl_id = h5_fileaccess();
+ if (child_fapl_id < 0) {
+ TEST_ERROR;
+ }
+
+ if (!driver_is_splitter_compatible(child_fapl_id)) {
+ SKIPPED();
+ HDprintf(" given driver is not Splitter W/O compatible.\n");
+ return 0;
+ }
+
+ /* Test Read-Only access, including when a file on the W/O channel
+ * does not exist.
+ */
+ if (splitter_RO_test(&data, child_fapl_id) < 0) {
+ TEST_ERROR;
+ }
+
+ /* Test opening of files when the W/O channel does not exist.
+ */
+ if (splitter_tentative_open_test(child_fapl_id) < 0) {
+ TEST_ERROR;
+ }
+
+
+ /* Test file creation, utilizing different child FAPLs (default vs.
+ * specified), logfile, and Write Channel error ignoring behavior.
+ */
+ for (i=0; i < 4; i++) {
+ hbool_t ignore_wo_errors = (i & 1) ? TRUE : FALSE;
+ hbool_t provide_logfile_path = (i & 2) ? TRUE : FALSE;
+ hid_t child_fapl_ids[2] = { H5P_DEFAULT, H5P_DEFAULT };
+
+ /* Test child driver definition/default combination */
+ for (j=0; j < 4; j++) {
+
+ child_fapl_ids[0] = (j & 1) ? child_fapl_id : H5P_DEFAULT;
+ child_fapl_ids[1] = (j & 2) ? child_fapl_id : H5P_DEFAULT;
+
+ if (run_splitter_test(&data, ignore_wo_errors, provide_logfile_path, child_fapl_ids) < 0) {
+ TEST_ERROR;
+ }
+
+ } /* end for child fapl definition/pairing */
+
+ } /* end for behavior-flag loops */
+
+/* TODO: SWMR open? */
+/* Concurrent opens with both drivers using the Splitter */
+
+
+ if (H5Pclose(child_fapl_id) == FAIL) {
+ TEST_ERROR;
+ }
+
+ PASSED();
+ return 0;
+
+error:
+ if (child_fapl_id != H5I_INVALID_HID) {
+ (void)H5Pclose(child_fapl_id);
+ }
+ return -1;
+} /* end test_splitter() */
+
+#undef SPLITTER_TEST_FAULT
+
+
/*-------------------------------------------------------------------------
* Function: main
*
@@ -2187,9 +3276,6 @@ error:
* Return: Success: 0
* Failure: 1
*
- * Programmer: Raymond Lu
- * Tuesday, Sept 24, 2002
- *
*-------------------------------------------------------------------------
*/
int
@@ -2213,6 +3299,7 @@ main(void)
nerrors += test_stdio() < 0 ? 1 : 0;
nerrors += test_windows() < 0 ? 1 : 0;
nerrors += test_ros3() < 0 ? 1 : 0;
+ nerrors += test_splitter() < 0 ? 1 : 0;
if(nerrors) {
HDprintf("***** %d Virtual File Driver TEST%s FAILED! *****\n",