Files
hdf5/test/vfd_swmr_zoo_writer.c
2021-05-03 22:02:43 +00:00

697 lines
20 KiB
C

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* 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://www.hdfgroup.org/licenses. *
* If you do not have access to either file, you may request a copy from *
* help@hdfgroup.org. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <err.h>
#define H5C_FRIEND /* suppress error about including H5Cpkg */
#define H5F_FRIEND /* suppress error about including H5Fpkg */
#include "hdf5.h"
#include "H5private.h"
#include "H5retry_private.h"
#include "H5Cpkg.h"
#include "H5Fpkg.h"
#include "H5HGprivate.h"
#include "H5VLprivate.h"
#include "testhdf5.h"
#include "genall5.h"
#include "vfd_swmr_common.h"
#define MAX_READ_LEN_IN_SECONDS 2
#define TICK_LEN 4
typedef struct _shared_ticks {
uint64_t reader_tick;
} shared_ticks_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 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
print_cache_hits(H5C_t *cache)
{
int i;
for (i = 0; i < H5AC_NTYPES; i++) {
dbgf(3, "type-%d cache hits %" PRId64 "%s\n", i, cache->hits[i], (i == H5AC_GHEAP_ID) ? " *" : "");
}
dbgf(3, "\n");
}
#else
print_cache_hits(H5C_t H5_ATTR_UNUSED *cache)
{
return;
}
#endif
void
zoo_create_hook(hid_t H5_ATTR_UNUSED fid)
{
dbgf(3, "%s: enter\n", __func__);
if (writer)
decisleep(1);
}
/* Print out the menu for the command-line options */
static void
usage(const char *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, " -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);
}
/* Private function to help parsing command-line options */
static int
parse_command_line_options(int argc, char **argv)
{
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;
if (argc > 0) {
H5_FAILED();
AT();
printf("unexpected command-line arguments");
goto error;
}
return 0;
error:
return -1;
}
/* 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;
}
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;
}
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;
}
return 0;
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;
}
/* 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;
}
/* 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);
H5E_BEGIN_TRY
{
H5Aexists(fid, "nonexistent");
}
H5E_END_TRY;
}
/* Wait until the reader finishes validating zoo creation */
if (HDread(fd_reader_to_writer, &notify, 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;
}
return 0;
error:
return -1;
}
/* Notify the reader of finishing zoo deletion by sending the timestamp */
static int
notify_reader(void)
{
struct timespec last = {0, 0};
/* 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, &notify, 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;
}
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");
}
/* Notify the writer that zoo validation is finished */
if (HDwrite(fd_reader_to_writer, &notify, sizeof(int)) < 0) {
H5_FAILED();
AT();
printf("HDwrite failed");
goto error;
}
return 0;
error:
return -1;
}
/* 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 (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 = 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 = true;
else if (personality != NULL && strcmp(personality, "vfd_swmr_zoo_reader") == 0)
writer = false;
else {
H5_FAILED();
AT();
printf("unknown personality, expected vfd_swmr_zoo_{reader,writer}");
goto error;
}
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, 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 */
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 (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) {
H5_FAILED();
AT();
printf("H5Pset_libver_bounds failed");
goto error;
}
if ((fcpl = H5Pcreate(H5P_FILE_CREATE)) < 0) {
H5_FAILED();
AT();
printf("H5Pcreate failed");
goto error;
}
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 < 0) {
H5_FAILED();
AT();
printf(writer ? "H5Fcreate failed" : "H5Fopen failed");
goto error;
}
if ((f = H5VL_object_verify(fid, H5I_FILE)) == NULL) {
H5_FAILED();
AT();
printf("H5VL_object_verify failed");
goto error;
}
cache = f->shared->cache;
/* 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");
/* Writer tells reader to start */
notify = 1;
if (use_named_pipe && HDwrite(fd_writer_to_reader, &notify, sizeof(int)) < 0) {
H5_FAILED();
AT();
printf("HDwrite failed");
goto error;
}
/* Start to create the zoo */
if (!create_zoo(fid, ".", &lastmsgtime, config)) {
H5_FAILED();
AT();
printf("create_zoo failed");
goto error;
}
/* 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;
}
/* Start to delete the zoo */
if (!delete_zoo(fid, ".", &lastmsgtime, config)) {
H5_FAILED();
AT();
printf("delete_zoo failed");
goto error;
}
/* 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))
;
/* 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 (H5Pclose(fapl) < 0) {
H5_FAILED();
AT();
printf("H5Pclose failed");
goto error;
}
if (H5Pclose(fcpl) < 0) {
H5_FAILED();
AT();
printf("H5Pclose failed");
goto error;
}
if (H5Fclose(fid) < 0) {
H5_FAILED();
AT();
printf("H5Fclose failed");
goto error;
}
if (progname)
HDfree(progname);
if (use_named_pipe && close_named_pipes() < 0) {
H5_FAILED();
AT();
printf("close_named_pipes failed");
goto error;
}
return EXIT_SUCCESS;
error:
H5E_BEGIN_TRY
{
H5Pclose(fapl);
H5Pclose(fcpl);
H5Fclose(fid);
}
H5E_END_TRY;
if (use_named_pipe && fd_writer_to_reader >= 0)
HDclose(fd_writer_to_reader);
if (use_named_pipe && fd_reader_to_writer >= 0)
HDclose(fd_reader_to_writer);
if (use_named_pipe && !writer) {
HDremove(fifo_writer_to_reader);
HDremove(fifo_reader_to_writer);
}
return EXIT_FAILURE;
}