diff options
author | vchoi-hdfgroup <55293060+vchoi-hdfgroup@users.noreply.github.com> | 2021-04-13 19:05:00 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-13 19:05:00 (GMT) |
commit | 791b9893e48c0e1d77314a816babe635d54cfef9 (patch) | |
tree | c664c8e2d92de51db3ec39f016cbc3dfbc0f866c | |
parent | d6227619a91ad361ff0fb2f1b3b9a9494ee66892 (diff) | |
parent | 62198a3ee104e897d057a96471e6444ffff4eaa3 (diff) | |
download | hdf5-791b9893e48c0e1d77314a816babe635d54cfef9.zip hdf5-791b9893e48c0e1d77314a816babe635d54cfef9.tar.gz hdf5-791b9893e48c0e1d77314a816babe635d54cfef9.tar.bz2 |
Merge pull request #6 from vchoi-hdfgroup/feature/vfd_swmr
Feature/vfd swmr
-rw-r--r-- | test/genall5.c | 17 | ||||
-rw-r--r-- | test/testvfdswmr.sh.in | 14 | ||||
-rw-r--r-- | test/vfd_swmr.c | 9 | ||||
-rw-r--r-- | test/vfd_swmr_common.c | 9 | ||||
-rw-r--r-- | test/vfd_swmr_common.h | 3 | ||||
-rw-r--r-- | test/vfd_swmr_group_writer.c | 59 | ||||
-rw-r--r-- | test/vfd_swmr_zoo_writer.c | 731 |
7 files changed, 543 insertions, 299 deletions
diff --git a/test/genall5.c b/test/genall5.c index 39e25ac..70190c6 100644 --- a/test/genall5.c +++ b/test/genall5.c @@ -19,6 +19,7 @@ * of the same name. */ +#include <err.h> #include "cache_common.h" #include "vfd_swmr_common.h" /* for below_speed_limit() */ #include "genall5.h" @@ -412,7 +413,7 @@ vrfy_ns_grp_c(hid_t fid, const char *group_name, unsigned nlinks) gid = H5Gopen2(fid, group_name, H5P_DEFAULT); if (gid <= 0) { - failure_mssg = "vrfy_ns_grp_c: H5Gopen2() failed"; + failure_mssg = "vrfy_ns_grp_c: H5Gopen2 failed"; return false; } @@ -2753,12 +2754,14 @@ tend_zoo(hid_t fid, const char *base_path, struct timespec *lastmsgtime, zoo_con } out: if (!ok) { - if (HDstrcmp(failure_mssg, last_failure_mssg) != 0) - *lastmsgtime = (struct timespec){.tv_sec = 0, .tv_nsec = 0}; - - if (below_speed_limit(lastmsgtime, &config.msgival)) { - last_failure_mssg = failure_mssg; - HDfprintf(stderr, "%s: %s", __func__, failure_mssg); + /* Currently not used: this step makes sure the operation doesn't take too long. + * Any test that sets config.msgival or lastmsgtime to 0 will skip this step */ + if (strcmp(failure_mssg, last_failure_mssg) != 0 && ((config.msgival.tv_sec || config.msgival.tv_nsec)) + && (lastmsgtime->tv_sec || lastmsgtime->tv_nsec)) { + if (below_speed_limit(lastmsgtime, &config.msgival)) { + last_failure_mssg = failure_mssg; + warnx("%s: %s", __func__, failure_mssg); + } } } return ok; diff --git a/test/testvfdswmr.sh.in b/test/testvfdswmr.sh.in index 42932b0..c64f9de 100644 --- a/test/testvfdswmr.sh.in +++ b/test/testvfdswmr.sh.in @@ -582,16 +582,16 @@ done # read and written by VFD SWMR. # if [ ${do_zoo:-no} = yes ]; then - [ -e ./fifo ] && rm -f ./fifo - mkfifo -m 0600 ./fifo rm -f ./shared_tick_num echo launch vfd_swmr_zoo_writer - STDIN_PATH="./fifo" catch_out_err_and_rc vfd_swmr_zoo_writer \ - ../vfd_swmr_zoo_writer -m 1000 -q & + catch_out_err_and_rc vfd_swmr_zoo_writer \ + ../vfd_swmr_zoo_writer -q & pid_writer=$! - STDOUT_PATH="./fifo" catch_out_err_and_rc vfd_swmr_zoo_reader \ - ../vfd_swmr_zoo_reader -q -W & + # -l is the expected maximal number of ticks from the writer's finishing zoo creation or deletion + # to the reader's finishing validation of zoo creation or deletion + catch_out_err_and_rc vfd_swmr_zoo_reader \ + ../vfd_swmr_zoo_reader -l 4 -q & pid_reader=$! # Wait for the reader to finish before signalling the @@ -599,7 +599,6 @@ if [ ${do_zoo:-no} = yes ]; then # reader will find the shadow file when it opens # the .h5 file. wait $pid_reader - kill -USR1 $(cat vfd_swmr_zoo_writer.pid) wait $pid_writer # Collect exit code of the reader @@ -615,7 +614,6 @@ if [ ${do_zoo:-no} = yes ]; then fi # Clean up output files - rm -f ./fifo rm -f vfd_swmr_zoo_writer.{out,rc} rm -f vfd_swmr_zoo_reader.*.{out,rc} fi diff --git a/test/vfd_swmr.c b/test/vfd_swmr.c index 9c5899e..2d34ebd 100644 --- a/test/vfd_swmr.c +++ b/test/vfd_swmr.c @@ -848,15 +848,6 @@ error: return 1; } /* test_writer_create_open_flush() */ -/* Sleep for `tenths` tenths of a second */ -static void -decisleep(uint32_t tenths) -{ - uint64_t nsec = tenths * 100 * 1000 * 1000; - - H5_nanosleep(nsec); -} - /*------------------------------------------------------------------------- * Function: test_writer_md() * diff --git a/test/vfd_swmr_common.c b/test/vfd_swmr_common.c index dad9e3d..68e0b9c 100644 --- a/test/vfd_swmr_common.c +++ b/test/vfd_swmr_common.c @@ -72,6 +72,15 @@ below_speed_limit(struct timespec *last, const struct timespec *ival) return result; } +/* Sleep for `tenths` tenths of a second. */ +void +decisleep(uint32_t tenths) +{ + uint64_t nsec = tenths * 100 * 1000 * 1000; + + H5_nanosleep(nsec); +} + /* Like vsnprintf(3), but abort the program with an error message on * `stderr` if the buffer is too small or some other error occurs. */ diff --git a/test/vfd_swmr_common.h b/test/vfd_swmr_common.h index e70c316..fee0725 100644 --- a/test/vfd_swmr_common.h +++ b/test/vfd_swmr_common.h @@ -57,7 +57,8 @@ H5TEST_DLLVAR int verbosity; extern "C" { #endif -H5TEST_DLL hbool_t below_speed_limit(struct timespec *, const struct timespec *); +H5TEST_DLL bool below_speed_limit(struct timespec *, const struct timespec *); +H5TEST_DLL void decisleep(uint32_t tenths); H5TEST_DLL estack_state_t estack_get_state(void); H5TEST_DLL estack_state_t disable_estack(void); diff --git a/test/vfd_swmr_group_writer.c b/test/vfd_swmr_group_writer.c index b9dbb42..25ee8c5 100644 --- a/test/vfd_swmr_group_writer.c +++ b/test/vfd_swmr_group_writer.c @@ -34,6 +34,7 @@ typedef struct { unsigned int nsteps; unsigned int update_interval; bool use_vfd_swmr; + bool use_named_pipes; } state_t; #define ALL_HID_INITIALIZER \ @@ -41,21 +42,24 @@ typedef struct { { \ .file = H5I_INVALID_HID, .one_by_one_sid = H5I_INVALID_HID, .filename = "", \ .filetype = H5T_NATIVE_UINT32, .asteps = 10, .csteps = 10, .nsteps = 100, .update_interval = READER_WAIT_TICKS, \ - .use_vfd_swmr = true \ + .use_vfd_swmr = true, \ + .use_named_pipes = true \ } static void usage(const char *progname) { fprintf(stderr, "usage: %s [-S] [-a steps] [-b] [-c]\n" - " [-n iterations] [-u numb_ticks]\n" + " [-n iterations] [-N] [-q] [-u numb_ticks]\n" "\n" "-S: do not use VFD SWMR\n" "-a steps: `steps` between adding attributes\n" "-b: write data in big-endian byte order\n" "-c steps: `steps` between communication between the writer and reader\n" "-n ngroups: the number of groups\n" + "-N: do not use named pipes, mainly for running the writer and reader seperately\n" "-u numb_tcks: `numb_ticks` for the reader to wait before verification\n" + "-q: silence printouts, few messages\n" "\n", progname); exit(EXIT_FAILURE); @@ -83,7 +87,7 @@ state_init(state_t *s, int argc, char **argv) if (tfile) HDfree(tfile); - while ((ch = getopt(argc, argv, "SWa:bc:n:qu:")) != -1) { + while ((ch = getopt(argc, argv, "Sa:bc:n:Nqu:")) != -1) { switch (ch) { case 'S': s->use_vfd_swmr = false; @@ -120,6 +124,9 @@ state_init(state_t *s, int argc, char **argv) case 'b': s->filetype = H5T_STD_U32BE; break; + case 'N': + s->use_named_pipes = false; + break; case 'q': verbosity = 0; break; @@ -334,15 +341,6 @@ error: return false; } -/* Sleep for `tenths` tenths of a second */ -static void -decisleep(uint32_t tenths) -{ - uint64_t nsec = tenths * 100 * 1000 * 1000; - - H5_nanosleep(nsec); -} - int main(int argc, char **argv) { @@ -413,7 +411,7 @@ main(int argc, char **argv) * two-way communication so that the two sides can move forward together. * One is for the writer to write to the reader. * The other one is for the reader to signal the writer. */ - if (writer) { + if (s.use_named_pipes && writer) { /* Writer creates two named pipes(FIFO) */ if (HDmkfifo(fifo_writer_to_reader, 0600) < 0) { H5_FAILED(); AT(); @@ -430,13 +428,13 @@ main(int argc, char **argv) } /* Both the writer and reader open the pipes */ - if ((fd_writer_to_reader = HDopen(fifo_writer_to_reader, O_RDWR)) < 0) { + if (s.use_named_pipes && (fd_writer_to_reader = HDopen(fifo_writer_to_reader, O_RDWR)) < 0) { H5_FAILED(); AT(); printf("HDopen failed\n"); goto error; } - if ((fd_reader_to_writer = HDopen(fifo_reader_to_writer, O_RDWR)) < 0) { + if (s.use_named_pipes && (fd_reader_to_writer = HDopen(fifo_reader_to_writer, O_RDWR)) < 0) { H5_FAILED(); AT(); printf("HDopen failed\n"); goto error; @@ -451,14 +449,15 @@ main(int argc, char **argv) printf("write_group failed\n"); /* At communication interval, notifies the reader about the failture and quit */ - if (step % s.csteps == 0) { + if (s.use_named_pipes && (step % s.csteps == 0)) { notify = -1; HDwrite(fd_writer_to_reader, ¬ify, sizeof(int)); - goto error; } + + goto error; } else { /* At communication interval, notifies the reader and waits for its response */ - if (step % s.csteps == 0) { + if (s.use_named_pipes && (step % s.csteps == 0)) { /* Bump up the value of notify to notice the reader to start to read */ notify++; if (HDwrite(fd_writer_to_reader, ¬ify, sizeof(int)) < 0) { @@ -506,7 +505,7 @@ main(int argc, char **argv) /* At communication interval, waits for the writer to finish creation before starting verification */ - if (step % s.csteps == 0) { + if (s.use_named_pipes && (step % s.csteps == 0)) { /* The writer should have bumped up the value of notify. * Do the same with verify and confirm it */ verify++; @@ -532,7 +531,8 @@ main(int argc, char **argv) } /* Wait for a few ticks for the update to happen */ - decisleep(config.tick_len * s.update_interval); + if (s.use_named_pipes) + decisleep(config.tick_len * s.update_interval); /* Start to verify group */ if (!verify_group(&s, step)) { @@ -540,13 +540,14 @@ main(int argc, char **argv) printf("verify_group failed\n"); /* At communication interval, tell the writer about the failure and exit */ - if (step % s.csteps == 0) { + if (s.use_named_pipes && (step % s.csteps == 0)) { notify = -1; HDwrite(fd_reader_to_writer, ¬ify, sizeof(int)); - goto error; } + + goto error; } else { - if (step % s.csteps == 0) { + if (s.use_named_pipes && (step % s.csteps == 0)) { /* Send back the same nofity value for acknowledgement to tell the writer * move to the next step */ if (HDwrite(fd_reader_to_writer, ¬ify, sizeof(int)) < 0) { @@ -578,20 +579,20 @@ main(int argc, char **argv) } /* Both the writer and reader close the named pipes */ - if (HDclose(fd_writer_to_reader) < 0) { + if (s.use_named_pipes && HDclose(fd_writer_to_reader) < 0) { H5_FAILED(); AT(); printf("HDclose failed\n"); goto error; } - if (HDclose(fd_reader_to_writer) < 0) { + if (s.use_named_pipes && HDclose(fd_reader_to_writer) < 0) { H5_FAILED(); AT(); printf("HDclose failed\n"); goto error; } /* Reader finishes last and deletes the named pipes */ - if(!writer) { + if(s.use_named_pipes && !writer) { if(HDremove(fifo_writer_to_reader) != 0) { H5_FAILED(); AT(); printf("HDremove failed\n"); @@ -614,13 +615,13 @@ error: H5Fclose(s.file); } H5E_END_TRY; - if (fd_writer_to_reader >= 0) + if (s.use_named_pipes && fd_writer_to_reader >= 0) HDclose(fd_writer_to_reader); - if (fd_reader_to_writer >= 0) + if (s.use_named_pipes && fd_reader_to_writer >= 0) HDclose(fd_reader_to_writer); - if(!writer) { + if(s.use_named_pipes && !writer) { HDremove(fifo_writer_to_reader); HDremove(fifo_reader_to_writer); } diff --git a/test/vfd_swmr_zoo_writer.c b/test/vfd_swmr_zoo_writer.c index 75f3338..00dcd9e 100644 --- a/test/vfd_swmr_zoo_writer.c +++ b/test/vfd_swmr_zoo_writer.c @@ -11,7 +11,6 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include <err.h> -#include <libgen.h> #define H5C_FRIEND /* suppress error about including H5Cpkg */ #define H5F_FRIEND /* suppress error about including H5Fpkg */ @@ -29,31 +28,30 @@ #include "genall5.h" #include "vfd_swmr_common.h" -#ifndef _arraycount -#define _arraycount(_a) (sizeof(_a) / sizeof(_a[0])) -#endif +#define MAX_READ_LEN_IN_SECONDS 2 +#define TICK_LEN 4 typedef struct _shared_ticks { uint64_t reader_tick; } shared_ticks_t; -typedef struct _tick_stats { - uint64_t writer_tried_increase; - uint64_t writer_aborted_increase; - uint64_t writer_read_shared_file; - uint64_t reader_tick_was_zero; // writer read reader tick equal to 0 - uint64_t reader_tick_lead_writer; // writer read reader tick greater than - // proposed writer tick - uint64_t writer_lead_reader_by[1]; // proposed writer tick lead reader - // tick by `lead` ticks - // `writer_lead_reader_by[lead]` - // times, for `0 <= lead <= max_lag - 1` -} tick_stats_t; - +int fd_writer_to_reader = -1, fd_reader_to_writer = -1; +const char *fifo_writer_to_reader = "./fifo_writer_to_reader"; +const char *fifo_reader_to_writer = "./fifo_reader_to_writer"; +bool use_vfd_swmr = true; +bool use_named_pipe = true; +bool print_estack = false; static H5F_vfd_swmr_config_t swmr_config; -static tick_stats_t * tick_stats = NULL; -static const hid_t badhid = H5I_INVALID_HID; static bool writer; +struct timespec ival = {MAX_READ_LEN_IN_SECONDS, 0}; /* Expected maximal time for reader's validation */ + +zoo_config_t config = { + .proc_num = 0 + , .skip_compact = false + , .skip_varlen = true + , .max_pause_msecs = 0 + , .msgival = {.tv_sec = 0, .tv_nsec = 0} +}; static void #ifndef H5C_COLLECT_CACHE_STATS @@ -74,335 +72,578 @@ print_cache_hits(H5C_t H5_ATTR_UNUSED *cache) #endif void -zoo_create_hook(hid_t fid) +zoo_create_hook(hid_t H5_ATTR_UNUSED fid) { dbgf(3, "%s: enter\n", __func__); if (writer) - H5Fvfd_swmr_end_tick(fid); + decisleep(1); } +/* Print out the menu for the command-line options */ static void usage(const char *progname) { - fprintf(stderr, "usage: %s [-C] [-S] [-W] [-a] [-e] [-m] [-q] [-v]\n", progname); + fprintf(stderr, "usage: %s [-C] [-S] [-a] [-e] [-p] [-q] [-v]\n", progname); fprintf(stderr, "\n -C: skip compact dataset tests\n"); - fprintf(stderr, " -S: do not use VFD SWMR\n"); - fprintf(stderr, " -W: do not wait for SIGINT or SIGUSR1\n"); - fprintf(stderr, " -a: run all tests, including variable-length data\n"); - fprintf(stderr, " -e: print error stacks\n"); - fprintf(stderr, " -m ms: maximum `ms` milliseconds pause between\n"); - fprintf(stderr, " each create/delete step\n"); - fprintf(stderr, " -q: be quiet: few/no progress messages\n"); - fprintf(stderr, " -v: be verbose: most progress messages\n"); + fprintf(stderr, " -S: do not use VFD SWMR\n"); + fprintf(stderr, " -a: run all tests, including variable-length data\n"); + fprintf(stderr, " -e: print error stacks\n"); + fprintf(stderr, " -l tick_num: expected maximal number of ticks from \n"); + fprintf(stderr, " the writer's finishing zoo creation or deletion to the reader's finishing validation\n"); + fprintf(stderr, " -N: do not use named pipes\n"); + fprintf(stderr, " -q: be quiet: few/no progress messages\n"); + fprintf(stderr, " -v: be verbose: most progress messages\n"); exit(EXIT_FAILURE); } -bool -vfd_swmr_writer_may_increase_tick_to(uint64_t new_tick, bool wait_for_reader) +/* Private function to help parsing command-line options */ +static int +parse_command_line_options(int argc, char **argv) { - static int fd = -1; - shared_ticks_t shared; - ssize_t nread; - h5_retry_t retry; - bool do_try; + int ch; + unsigned long tmpl; + char *end; + + while ((ch = getopt(argc, argv, "CSael:Nqv")) != -1) { + switch(ch) { + case 'C': + config.skip_compact = true; + break; + case 'S': + use_vfd_swmr = false; + break; + case 'a': + config.skip_varlen = false; + break; + case 'e': + print_estack = true; + break; + case 'l': + /* Expected maximal number of ticks from the writer's finishing zoo creation or deletion + * to the reader's finishing validation of zoo creation or deletion */ + errno = 0; + tmpl = HDstrtoul(optarg, &end, 0); + + if (end == optarg || *end != '\0') { + printf("couldn't parse `-l` argument `%s`", optarg); + goto error; + } else if (errno != 0) { + printf("couldn't parse `-l` argument `%s`", optarg); + goto error; + } else if (tmpl > UINT_MAX) { + printf("`-l` argument `%lu` too large", tmpl); + goto error; + } + + { + /* Translate the tick number to time represented by the timespec struct */ + float time = (float)(((unsigned)tmpl * TICK_LEN) / 10.0); + unsigned sec = (unsigned)time; + unsigned nsec = (unsigned)((time - sec) * 10 * 1000 * 1000); + + ival.tv_sec = sec; + ival.tv_nsec = nsec; + } + break; + case 'N': + /* Disable named pipes, mainly for running the writer and reader seperately */ + use_named_pipe = false; + break; + case 'q': + verbosity = 1; + break; + case 'v': + verbosity = 3; + break; + default: + usage(argv[0]); + break; + } + } + argv += optind; + argc -= optind; - dbgf(3, "%s: enter\n", __func__); + if (argc > 0) { + H5_FAILED(); AT(); + printf("unexpected command-line arguments"); + goto error; + } + + return 0; + +error: + return -1; +} - if (fd == -1) { - fd = open("./shared_tick_num", O_RDONLY); - if (fd == -1) { - warn("%s: open", __func__); // TBD ratelimit/silence this warning - return true; +/* Writer creates two named pipes(FIFO) to coordinate two-way communication + * between the writer and the reader. Both the writer and reader open the named pipes */ +static int +create_open_named_pipes(void) +{ + /* Writer creates two named pipes(FIFO) to coordinate two-way communication */ + if (writer) { + if (HDmkfifo(fifo_writer_to_reader, 0600) < 0) { + H5_FAILED(); AT(); + printf("HDmkfifo failed"); + goto error; } - assert(tick_stats == NULL); - tick_stats = calloc(1, sizeof(*tick_stats) + - (swmr_config.max_lag - 1) * sizeof(tick_stats->writer_lead_reader_by[0])); - if (tick_stats == NULL) - err(EXIT_FAILURE, "%s: calloc", __func__); + + if (HDmkfifo(fifo_reader_to_writer, 0600) < 0) { + H5_FAILED(); AT(); + printf("HDmkfifo failed"); + goto error; + } + } + + /* Both the writer and reader open the pipes */ + if ((fd_writer_to_reader = HDopen(fifo_writer_to_reader, O_RDWR)) < 0) { + H5_FAILED(); AT(); + printf("fifo_writer_to_reader open failed"); + goto error; } - tick_stats->writer_tried_increase++; + if ((fd_reader_to_writer = HDopen(fifo_reader_to_writer, O_RDWR)) < 0) { + H5_FAILED(); AT(); + printf("fifo_reader_to_writer open failed"); + goto error; + } - for (do_try = h5_retry_init(&retry, 14, 10 * 1000 * 1000, 100 * 1000 * 1000); do_try; - do_try = wait_for_reader && h5_retry_next(&retry)) { + return 0; - tick_stats->writer_read_shared_file++; +error: + return -1; +} + +/* Notify the reader of finishing zoo creation by sending the timestamp + * and wait for the reader to finish validation before proceeding */ +static int +notify_and_wait_for_reader(hid_t fid, int verify) +{ + int notify; + unsigned int i; + struct timespec last = {0, 0}; + + /* Get the time when finishing zoo creation */ + if (HDclock_gettime(CLOCK_MONOTONIC, &last) < 0) { + H5_FAILED(); AT(); + printf("HDclock_gettime failed"); + goto error; + } - if ((nread = pread(fd, &shared, sizeof(shared), 0)) == -1) - err(EXIT_FAILURE, "%s: pread", __func__); + /* Notify the reader of finishing zoo creation by sending the timestamp */ + if (HDwrite(fd_writer_to_reader, &last, sizeof(last)) < 0) { + H5_FAILED(); AT(); + printf("HDwrite failed"); + goto error; + } - if (nread != sizeof(shared)) - errx(EXIT_FAILURE, "%s: pread", __func__); + /* During the wait, writer makes repeated HDF5 API calls so as to trigger + * EOT at approximately the correct time */ + for(i = 0; i < swmr_config.max_lag + 1; i++) { + decisleep(swmr_config.tick_len); - // TBD convert endianness + H5E_BEGIN_TRY { + H5Aexists(fid, "nonexistent"); + } H5E_END_TRY; + } - if (shared.reader_tick == 0) { - tick_stats->reader_tick_was_zero++; - return true; - } + /* Wait until the reader finishes validating zoo creation */ + if (HDread(fd_reader_to_writer, ¬ify, sizeof(int)) < 0) { + H5_FAILED(); AT(); + printf("HDread failed"); + goto error; + } - if (new_tick < shared.reader_tick) { - tick_stats->reader_tick_lead_writer++; - return true; - } - if (new_tick <= shared.reader_tick + swmr_config.max_lag - 1) { - uint64_t lead = new_tick - shared.reader_tick; - assert(lead <= swmr_config.max_lag - 1); - tick_stats->writer_lead_reader_by[lead]++; - return true; - } + if (notify != verify) { + H5_FAILED(); AT(); + printf("expected %d but read %d", verify, notify); + goto error; } - if (wait_for_reader && !do_try) - errx(EXIT_FAILURE, "%s: timed out waiting for reader", __func__); - tick_stats->writer_aborted_increase++; + return 0; - return false; +error: + return -1; } -void -vfd_swmr_reader_did_increase_tick_to(uint64_t new_tick) +/* Notify the reader of finishing zoo deletion by sending the timestamp */ +static int +notify_reader(void) { - static int fd = -1; - shared_ticks_t shared; - ssize_t nwritten; + struct timespec last = {0, 0}; - dbgf(3, "%s: enter\n", __func__); + /* Get the time when finishing zoo deletion */ + if (HDclock_gettime(CLOCK_MONOTONIC, &last) < 0) { + H5_FAILED(); AT(); + printf("HDclock_gettime failed"); + goto error; + } + + /* Notify the reader about finishing zoo deletion by sending the timestamp */ + if (HDwrite(fd_writer_to_reader, &last, sizeof(last)) < 0) { + H5_FAILED(); AT(); + printf("HDwrite failed"); + goto error; + } + + return 0; + +error: + return -1; +} + +/* Wait for the writer's notice before starting to zoo validation */ +static int +reader_verify(int verify) +{ + int notify; + + if (HDread(fd_writer_to_reader, ¬ify, sizeof(int)) < 0) { + H5_FAILED(); AT(); + printf("HDread failed"); + goto error; + } + + if (notify != verify) { + H5_FAILED(); AT(); + printf("expected %d but read %d", verify, notify); + goto error; + } - if (fd == -1) { - // TBD create a temporary file, here, and move it to its final path - // after writing it. - fd = open("./shared_tick_num", O_RDWR | O_CREAT, 0600); - if (fd == -1) - err(EXIT_FAILURE, "%s: open", __func__); + return 0; + +error: + return -1; +} + +/* Receive the notice of the writer finishing zoo creation (timestamp) + * Make sure the zoo validation doesn't take longer than the expected time. + * This time period is from the writer finishing zoo creation to the reader finishing + * the validation of zoo creation */ +static int +reader_check_time_and_notify_writer(int notify) +{ + struct timespec last = {0, 0}; + + /* Receive the notice of the writer finishing zoo creation (timestamp) */ + if (HDread(fd_writer_to_reader, &last, sizeof(last)) < 0) { + H5_FAILED(); AT(); + printf("HDread failed"); + goto error; + } + + /* Make sure the zoo validation doesn't take longer than the expected time. + * This time period is from the writer finishing zoo creation to the reader finishing + * the validation of zoo creation */ + if (below_speed_limit(&last, &ival)) { + AT(); + warnx("validate_zoo took too long to finish"); } - shared.reader_tick = new_tick; + /* Notify the writer that zoo validation is finished */ + if (HDwrite(fd_reader_to_writer, ¬ify, sizeof(int)) < 0) { + H5_FAILED(); AT(); + printf("HDwrite failed"); + goto error; + } - // TBD convert endianness + return 0; - if ((nwritten = pwrite(fd, &shared, sizeof(shared), 0)) == -1) - errx(EXIT_FAILURE, "%s: pwrite", __func__); +error: + return -1; +} - if (nwritten != sizeof(shared)) - errx(EXIT_FAILURE, "%s: pwrite", __func__); +/* Receive the finish notice (timestamp) from the writer. + * Make sure validation of zoo deletion doesn't take longer than the expected time. + * This time period is from the writer finishing zoo deletion to the reader finishing + * the validation of zoo deletion */ +static int +reader_check_time_after_verify_deletion(void) +{ + struct timespec last = {0, 0}; - if (new_tick == 0) { - if (unlink("./shared_tick_num") == -1) - warn("%s: unlink", __func__); - if (close(fd) == -1) - err(EXIT_FAILURE, "%s: close", __func__); - fd = -1; + if (HDread(fd_writer_to_reader, &last, sizeof(last)) < 0) { + H5_FAILED(); AT(); + printf("HDread failed"); + goto error; } + + if (below_speed_limit(&last, &ival)) { + AT(); + warnx("validate_deleted_zoo took too long to finish"); + } + + return 0; + +error: + return -1; +} + +/* Close and remove the named pipes */ +static int +close_named_pipes(void) +{ + /* Close the named pipes */ + if (HDclose(fd_writer_to_reader) < 0) { + H5_FAILED(); AT(); + printf("HDclose failed\n"); + goto error; + } + + if (HDclose(fd_reader_to_writer) < 0) { + H5_FAILED(); AT(); + printf("HDclose failed\n"); + goto error; + } + + /* Reader finishes last and deletes the named pipes */ + if(!writer) { + if(HDremove(fifo_writer_to_reader) != 0) { + H5_FAILED(); AT(); + printf("HDremove failed\n"); + goto error; + } + + if(HDremove(fifo_reader_to_writer) != 0) { + H5_FAILED(); AT(); + printf("HDremove failed\n"); + goto error; + } + } + + return 0; + +error: + return -1; } int main(int argc, char **argv) { - hid_t fapl, fcpl, fid; - H5F_t * f; - H5C_t * cache; - sigset_t oldsigs; - herr_t ret; - zoo_config_t config = {.proc_num = 0, - .skip_compact = false, - .skip_varlen = true, - .max_pause_msecs = 0, - .msgival = {.tv_sec = 5, .tv_nsec = 0}}; - struct timespec lastmsgtime = {.tv_sec = 0, .tv_nsec = 0}; - bool wait_for_signal; - int ch; - unsigned seed; - unsigned long tmpl; - char * end; - const char * seedvar = "H5_ZOO_STEP_SEED"; - bool use_vfd_swmr = true; - bool print_estack = false; - const char * progname = basename(argv[0]); - const char * personality = strstr(progname, "vfd_swmr_zoo_"); - estack_state_t es; - char step = 'b'; + hid_t fapl = H5I_INVALID_HID, fcpl = H5I_INVALID_HID, fid = H5I_INVALID_HID; + H5F_t *f; + H5C_t *cache; + struct timespec lastmsgtime = {.tv_sec = 0, .tv_nsec = 0}; + char *progname = NULL; + char *personality; + estack_state_t es; H5F_vfd_swmr_config_t vfd_swmr_config; + int notify = 0, verify = 0; + + if (H5_basename(argv[0], &progname) < 0) { + H5_FAILED(); AT(); + printf("H5_basename failed\n"); + goto error; + } + + personality = HDstrstr(progname, "vfd_swmr_zoo_"); if (personality != NULL && strcmp(personality, "vfd_swmr_zoo_writer") == 0) - writer = wait_for_signal = true; + writer = true; else if (personality != NULL && strcmp(personality, "vfd_swmr_zoo_reader") == 0) writer = false; else { - errx(EXIT_FAILURE, "unknown personality, expected vfd_swmr_zoo_{reader,writer}"); + H5_FAILED(); AT(); + printf("unknown personality, expected vfd_swmr_zoo_{reader,writer}"); + goto error; } - if (writer) - config.max_pause_msecs = 50; - - while ((ch = getopt(argc, argv, "CSWaem:qv")) != -1) { - switch (ch) { - case 'C': - config.skip_compact = true; - break; - case 'S': - use_vfd_swmr = false; - break; - case 'W': - wait_for_signal = false; - break; - case 'a': - config.skip_varlen = false; - break; - case 'e': - print_estack = true; - break; - case 'm': - errno = 0; - tmpl = strtoul(optarg, &end, 0); - if (end == optarg || *end != '\0') - errx(EXIT_FAILURE, "couldn't parse `-m` argument `%s`", optarg); - else if (errno != 0) - err(EXIT_FAILURE, "couldn't parse `-m` argument `%s`", optarg); - else if (tmpl > UINT_MAX) - errx(EXIT_FAILURE, "`-m` argument `%lu` too large", tmpl); - config.max_pause_msecs = (unsigned)tmpl; - break; - case 'q': - verbosity = 1; - break; - case 'v': - verbosity = 3; - break; - default: - usage(argv[0]); - break; - } - } - argv += optind; - argc -= optind; - - if (argc > 0) - errx(EXIT_FAILURE, "unexpected command-line arguments"); + parse_command_line_options(argc, argv); /* config, tick_len, max_lag, writer, flush_raw_data, md_pages_reserved, md_file_path */ - init_vfd_swmr_config(&vfd_swmr_config, 4, 7, writer, FALSE, 128, "./zoo-shadow"); + init_vfd_swmr_config(&vfd_swmr_config, TICK_LEN, 7, writer, FALSE, 128, "./zoo-shadow"); /* ? turn off use latest format argument via 1st argument? since later on it reset to early format */ /* use_latest_format, use_vfd_swmr, only_meta_page, config */ - fapl = vfd_swmr_create_fapl(true, use_vfd_swmr, true, &vfd_swmr_config); - - if (use_vfd_swmr && H5Pget_vfd_swmr_config(fapl, &swmr_config) < 0) - errx(EXIT_FAILURE, "H5Pget_vfd_swmr_config"); + if ((fapl = vfd_swmr_create_fapl(true, use_vfd_swmr, true, &vfd_swmr_config)) < 0) { + H5_FAILED(); AT(); + printf("vfd_swmr_create_fapl"); + goto error; + } - if (fapl < 0) - errx(EXIT_FAILURE, "vfd_swmr_create_fapl"); + if (use_vfd_swmr && H5Pget_vfd_swmr_config(fapl, &swmr_config) < 0) { + H5_FAILED(); AT(); + printf("H5Pget_vfd_swmr_config failed"); + goto error; + } if (H5Pset_libver_bounds(fapl, H5F_LIBVER_EARLIEST, H5F_LIBVER_LATEST) < 0) { - errx(EXIT_FAILURE, "%s.%d: H5Pset_libver_bounds", __func__, __LINE__); + H5_FAILED(); AT(); + printf("H5Pset_libver_bounds failed"); + goto error; } - if ((fcpl = H5Pcreate(H5P_FILE_CREATE)) < 0) - errx(EXIT_FAILURE, "H5Pcreate"); + if ((fcpl = H5Pcreate(H5P_FILE_CREATE)) < 0) { + H5_FAILED(); AT(); + printf("H5Pcreate failed"); + goto error; + } - ret = H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_PAGE, false, 1); - if (ret < 0) - errx(EXIT_FAILURE, "H5Pset_file_space_strategy"); + if (H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_PAGE, false, 1) < 0) { + H5_FAILED(); AT(); + printf("H5Pset_file_space_strategy failed"); + goto error; + } if (writer) fid = H5Fcreate("vfd_swmr_zoo.h5", H5F_ACC_TRUNC, fcpl, fapl); else fid = H5Fopen("vfd_swmr_zoo.h5", H5F_ACC_RDONLY, fapl); - if (fid == badhid) - errx(EXIT_FAILURE, writer ? "H5Fcreate" : "H5Fopen"); + if (fid < 0) { + H5_FAILED(); AT(); + printf(writer ? "H5Fcreate failed" : "H5Fopen failed"); + goto error; + } - if ((f = H5VL_object_verify(fid, H5I_FILE)) == NULL) - errx(EXIT_FAILURE, "H5VL_object_verify"); + if ((f = H5VL_object_verify(fid, H5I_FILE)) == NULL) { + H5_FAILED(); AT(); + printf("H5VL_object_verify failed"); + goto error; + } cache = f->shared->cache; - if (wait_for_signal) - block_signals(&oldsigs); + /* Writer creates two named pipes(FIFO) to coordinate two-way communication + * between the writer and the reader. Both the writer and reader open the named pipes */ + if (use_named_pipe && create_open_named_pipes() < 0) { + H5_FAILED(); AT(); + printf("create_open_named_pipes failed"); + goto error; + } print_cache_hits(cache); es = print_estack ? estack_get_state() : disable_estack(); if (writer) { - dbgf(2, "Writing zoo...\n"); - /* get seed from environment or else from time(3) */ - switch (fetch_env_ulong(seedvar, UINT_MAX, &tmpl)) { - case -1: - errx(EXIT_FAILURE, "%s: fetch_env_ulong", __func__); - case 0: - seed = (unsigned int)time(NULL); - break; - default: - seed = (unsigned int)tmpl; - break; + /* Writer tells reader to start */ + notify = 1; + if (use_named_pipe && HDwrite(fd_writer_to_reader, ¬ify, sizeof(int)) < 0) { + H5_FAILED(); AT(); + printf("HDwrite failed"); + goto error; } - dbgf(1, "To reproduce, set seed (%s) to %u.\n", seedvar, seed); - - HDsrandom(seed); - - if (!create_zoo(fid, ".", &lastmsgtime, config)) - errx(EXIT_FAILURE, "create_zoo didn't pass self-check"); - - /* Avoid deadlock: flush the file before waiting for the reader's - * message. - */ - if (H5Fflush(fid, H5F_SCOPE_GLOBAL) < 0) - errx(EXIT_FAILURE, "%s: H5Fflush failed", __func__); + /* Start to create the zoo */ + if (!create_zoo(fid, ".", &lastmsgtime, config)) { + H5_FAILED(); AT(); + printf("create_zoo failed"); + goto error; + } - if (read(STDIN_FILENO, &step, sizeof(step)) == -1) - err(EXIT_FAILURE, "read"); + /* Notify the reader of finishing zoo creation by sending the timestamp + * and wait for the reader to finish validation before proceeding */ + verify = 2; + if (use_named_pipe && notify_and_wait_for_reader(fid, verify) < 0) { + H5_FAILED(); AT(); + printf("notify_and_wait_for_reader failed"); + goto error; + } - if (step != 'b') - errx(EXIT_FAILURE, "expected 'b' read '%c'", step); + /* Start to delete the zoo */ + if (!delete_zoo(fid, ".", &lastmsgtime, config)) { + H5_FAILED(); AT(); + printf("delete_zoo failed"); + goto error; + } - if (!delete_zoo(fid, ".", &lastmsgtime, config)) - errx(EXIT_FAILURE, "delete_zoo failed"); - } - else { + /* Notify the reader of finishing zoo deletion by sending the timestamp */ + if (use_named_pipe && notify_reader() < 0) { + H5_FAILED(); AT(); + printf("notify_reader failed"); + goto error; + } + } else { dbgf(2, "Reading zoo...\n"); + /* Wait for the writer's notice before starting to zoo validation */ + verify = 1; + if (use_named_pipe && reader_verify(verify) < 0) { + H5_FAILED(); AT(); + printf("reader_verify failed"); + goto error; + } + + /* Validate the zoo creation */ while (!validate_zoo(fid, ".", &lastmsgtime, config)) ; - if (write(STDOUT_FILENO, &step, sizeof(step)) == -1) - err(EXIT_FAILURE, "write"); + + /* Receive the notice of the writer finishing zoo creation (timestamp) + * Make sure the zoo validation doesn't take longer than the expected time. + * This time period is from the writer finishing zoo creation to the reader finishing + * the validation of zoo creation */ + notify = 2; + if (use_named_pipe && reader_check_time_and_notify_writer(notify) < 0) { + H5_FAILED(); AT(); + printf("reader_check_time_and_notify_writer failed"); + goto error; + } + + /* Start to validate the zoo deletion */ while (!validate_deleted_zoo(fid, ".", &lastmsgtime, config)) ; + + /* Receive the finish notice (timestamp) from the writer. + * Make sure validation of zoo deletion doesn't take longer than the expected time. + * This time period is from the writer finishing zoo deletion to the reader finishing + * the validation of zoo deletion */ + if (use_named_pipe && reader_check_time_after_verify_deletion() < 0) { + H5_FAILED(); AT(); + printf("reader_check_time_and_notify_writer failed"); + goto error; + } } restore_estack(es); - if (use_vfd_swmr && wait_for_signal) - await_signal(fid); + if (H5Pclose(fapl) < 0) { + H5_FAILED(); AT(); + printf("H5Pclose failed"); + goto error; + } + + if (H5Pclose(fcpl) < 0) { + H5_FAILED(); AT(); + printf("H5Pclose failed"); + goto error; + } - if (writer && tick_stats != NULL) { - uint64_t lead; + if (H5Fclose(fid) < 0) { + H5_FAILED(); AT(); + printf("H5Fclose failed"); + goto error; + } - dbgf(2, "writer tried tick increase %" PRIu64 "\n", tick_stats->writer_tried_increase); - dbgf(2, "writer aborted tick increase %" PRIu64 "\n", tick_stats->writer_aborted_increase); - dbgf(2, "writer read shared file %" PRIu64 "\n", tick_stats->writer_read_shared_file); - dbgf(2, "writer read reader tick equal to 0 %" PRIu64 "\n", tick_stats->reader_tick_was_zero); - dbgf(2, "writer read reader tick leading writer %" PRIu64 "\n", tick_stats->reader_tick_lead_writer); + if (progname) + HDfree(progname); - for (lead = 0; lead < swmr_config.max_lag; lead++) { - dbgf(2, "writer tick lead writer by %" PRIu64 " %" PRIu64 "\n", lead, - tick_stats->writer_lead_reader_by[lead]); - } + if (use_named_pipe && close_named_pipes() < 0) { + H5_FAILED(); AT(); + printf("close_named_pipes failed"); + goto error; } - if (H5Pclose(fapl) < 0) - errx(EXIT_FAILURE, "H5Pclose(fapl)"); + return EXIT_SUCCESS; - if (H5Pclose(fcpl) < 0) - errx(EXIT_FAILURE, "H5Pclose(fcpl)"); +error: + H5E_BEGIN_TRY { + H5Pclose(fapl); + H5Pclose(fcpl); + H5Fclose(fid); + } H5E_END_TRY; - if (H5Fclose(fid) < 0) - errx(EXIT_FAILURE, "H5Fclose"); + if (use_named_pipe && fd_writer_to_reader >= 0) + HDclose(fd_writer_to_reader); - if (wait_for_signal) - restore_signals(&oldsigs); + if (use_named_pipe && fd_reader_to_writer >= 0) + HDclose(fd_reader_to_writer); - return EXIT_SUCCESS; + if(use_named_pipe && !writer) { + HDremove(fifo_writer_to_reader); + HDremove(fifo_reader_to_writer); + } + + return EXIT_FAILURE; } |