430 lines
13 KiB
C
430 lines
13 KiB
C
/*
|
|
* Copyright by The HDF Group.
|
|
* Copyright by the Board of Trustees of the University of Illinois.
|
|
* All rights reserved.
|
|
*
|
|
* This file is part of HDF5. The full HDF5 copyright notice, including
|
|
* terms governing use, modification, and redistribution, is contained in
|
|
* the COPYING file, which can be found at the root of the source code
|
|
* distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.
|
|
* If you do not have access to either file, you may request a copy from
|
|
* help@hdfgroup.org.
|
|
*/
|
|
|
|
#include <err.h>
|
|
|
|
#define H5F_FRIEND /*suppress error about including H5Fpkg */
|
|
|
|
#include "hdf5.h"
|
|
|
|
#include "H5Fpkg.h"
|
|
#include "H5HGprivate.h"
|
|
#include "H5VLprivate.h"
|
|
|
|
#include "testhdf5.h"
|
|
#include "vfd_swmr_common.h"
|
|
|
|
typedef struct {
|
|
hid_t file, filetype, one_by_one_sid;
|
|
char filename[PATH_MAX];
|
|
char progname[PATH_MAX];
|
|
unsigned int asteps;
|
|
unsigned int csteps;
|
|
unsigned int nsteps;
|
|
bool wait_for_signal;
|
|
bool use_vfd_swmr;
|
|
} state_t;
|
|
|
|
#define ALL_HID_INITIALIZER (state_t){ \
|
|
.file = H5I_INVALID_HID \
|
|
, .one_by_one_sid = H5I_INVALID_HID \
|
|
, .filename = "" \
|
|
, .filetype = H5T_NATIVE_UINT32 \
|
|
, .asteps = 10 \
|
|
, .csteps = 10 \
|
|
, .nsteps = 100 \
|
|
, .wait_for_signal = true \
|
|
, .use_vfd_swmr = true}
|
|
|
|
static void state_init(state_t *, int, char **);
|
|
|
|
static const hid_t badhid = H5I_INVALID_HID;
|
|
|
|
static void
|
|
usage(const char *progname)
|
|
{
|
|
fprintf(stderr, "usage: %s [-S] [-W] [-a steps] [-b] [-c]\n"
|
|
" [-n iterations]\n"
|
|
"\n"
|
|
"-S: do not use VFD SWMR\n"
|
|
"-W: do not wait for a signal before\n"
|
|
" exiting\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 iterations: how many times to expand each dataset\n"
|
|
" to %s.h5\n"
|
|
"\n",
|
|
progname, progname);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
static void
|
|
state_init(state_t *s, int argc, char **argv)
|
|
{
|
|
unsigned long tmp;
|
|
int ch;
|
|
const hsize_t dims = 1;
|
|
char tfile[PATH_MAX];
|
|
char *end;
|
|
|
|
*s = ALL_HID_INITIALIZER;
|
|
esnprintf(tfile, sizeof(tfile), "%s", argv[0]);
|
|
esnprintf(s->progname, sizeof(s->progname), "%s", HDbasename(tfile));
|
|
|
|
while ((ch = getopt(argc, argv, "SWa:bc:n:q")) != -1) {
|
|
switch (ch) {
|
|
case 'S':
|
|
s->use_vfd_swmr = false;
|
|
break;
|
|
case 'W':
|
|
s->wait_for_signal = false;
|
|
break;
|
|
case 'a':
|
|
case 'c':
|
|
case 'n':
|
|
errno = 0;
|
|
tmp = strtoul(optarg, &end, 0);
|
|
if (end == optarg || *end != '\0') {
|
|
errx(EXIT_FAILURE, "couldn't parse `-%c` argument `%s`", ch,
|
|
optarg);
|
|
} else if (errno != 0) {
|
|
err(EXIT_FAILURE, "couldn't parse `-%c` argument `%s`", ch,
|
|
optarg);
|
|
} else if (tmp > UINT_MAX)
|
|
errx(EXIT_FAILURE, "`-%c` argument `%lu` too large", ch, tmp);
|
|
|
|
if (ch == 'a')
|
|
s->asteps = (unsigned)tmp;
|
|
else if (ch == 'c')
|
|
s->csteps = (unsigned)tmp;
|
|
else if (ch == 'n')
|
|
s->nsteps = (unsigned)tmp;
|
|
break;
|
|
case 'b':
|
|
s->filetype = H5T_STD_U32BE;
|
|
break;
|
|
case 'q':
|
|
verbosity = 0;
|
|
break;
|
|
case '?':
|
|
default:
|
|
usage(s->progname);
|
|
break;
|
|
}
|
|
}
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
/* space for attributes */
|
|
if ((s->one_by_one_sid = H5Screate_simple(1, &dims, &dims)) < 0)
|
|
errx(EXIT_FAILURE, "H5Screate_simple failed");
|
|
|
|
if( s->csteps < 1 || s->csteps > s->nsteps)
|
|
errx(EXIT_FAILURE, "communication interval is out of bounds");
|
|
|
|
if( s->asteps < 1 || s->asteps > s->nsteps)
|
|
errx(EXIT_FAILURE, "attribute interval is out of bounds");
|
|
|
|
if (argc > 0)
|
|
errx(EXIT_FAILURE, "unexpected command-line arguments");
|
|
|
|
esnprintf(s->filename, sizeof(s->filename), "vfd_swmr_group.h5");
|
|
}
|
|
|
|
static void
|
|
add_group_attribute(const state_t *s, hid_t g, hid_t sid, unsigned int which)
|
|
{
|
|
hid_t aid;
|
|
char name[sizeof("attr-9999999999")];
|
|
|
|
esnprintf(name, sizeof(name), "attr-%u", which);
|
|
|
|
dbgf(1, "setting attribute %s on group %u to %u\n", name, which, which);
|
|
|
|
if ((aid = H5Acreate2(g, name, s->filetype, sid, H5P_DEFAULT,
|
|
H5P_DEFAULT)) < 0)
|
|
errx(EXIT_FAILURE, "H5Acreate2 failed");
|
|
|
|
if (H5Awrite(aid, H5T_NATIVE_UINT, &which) < 0)
|
|
errx(EXIT_FAILURE, "H5Awrite failed");
|
|
if (H5Aclose(aid) < 0)
|
|
errx(EXIT_FAILURE, "H5Aclose failed");
|
|
}
|
|
|
|
|
|
static void
|
|
write_group(state_t *s, unsigned int which)
|
|
{
|
|
char name[sizeof("/group-9999999999")];
|
|
hid_t g;
|
|
|
|
assert(which < s->nsteps);
|
|
|
|
esnprintf(name, sizeof(name), "/group-%d", which);
|
|
|
|
g = H5Gcreate2(s->file, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
|
|
|
|
if (g < 0)
|
|
errx(EXIT_FAILURE, "H5Gcreate(, \"%s\", ) failed", name);
|
|
|
|
if (s->asteps != 0 && which % s->asteps == 0)
|
|
add_group_attribute(s, g, s->one_by_one_sid, which);
|
|
|
|
if (H5Gclose(g) < 0)
|
|
errx(EXIT_FAILURE, "H5Gclose failed");
|
|
}
|
|
|
|
static bool
|
|
verify_group_attribute(hid_t g, unsigned int which)
|
|
{
|
|
estack_state_t es;
|
|
unsigned int read_which;
|
|
hid_t aid;
|
|
char name[sizeof("attr-9999999999")];
|
|
|
|
esnprintf(name, sizeof(name), "attr-%u", which);
|
|
|
|
dbgf(1, "verifying attribute %s on group %u equals %u\n", name, which,
|
|
which);
|
|
|
|
es = disable_estack();
|
|
if ((aid = H5Aopen(g, name, H5P_DEFAULT)) < 0) {
|
|
restore_estack(es);
|
|
return false;
|
|
}
|
|
|
|
if (H5Aread(aid, H5T_NATIVE_UINT, &read_which) < 0) {
|
|
restore_estack(es);
|
|
if (H5Aclose(aid) < 0)
|
|
errx(EXIT_FAILURE, "H5Aclose failed");
|
|
return false;
|
|
}
|
|
|
|
restore_estack(es);
|
|
|
|
if (H5Aclose(aid) < 0)
|
|
errx(EXIT_FAILURE, "H5Aclose failed");
|
|
|
|
return read_which == which;
|
|
}
|
|
|
|
static bool
|
|
verify_group(state_t *s, unsigned int which)
|
|
{
|
|
char name[sizeof("/group-9999999999")];
|
|
hid_t g;
|
|
estack_state_t es;
|
|
bool result;
|
|
|
|
assert(which < s->nsteps);
|
|
|
|
esnprintf(name, sizeof(name), "/group-%d", which);
|
|
|
|
es = disable_estack();
|
|
g = H5Gopen(s->file, name, H5P_DEFAULT);
|
|
restore_estack(es);
|
|
|
|
if (g < 0)
|
|
return false;
|
|
|
|
if (s->asteps != 0 && which % s->asteps == 0)
|
|
result = verify_group_attribute(g, which);
|
|
else
|
|
result = true;
|
|
|
|
if (H5Gclose(g) < 0)
|
|
errx(EXIT_FAILURE, "H5Gclose failed");
|
|
|
|
return result;
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
hid_t fapl, fcpl;
|
|
herr_t ret;
|
|
unsigned step;
|
|
bool writer;
|
|
state_t s;
|
|
const char *personality;
|
|
H5F_vfd_swmr_config_t config;
|
|
const char *fifo_writer_to_reader = "./fifo_group_writer_to_reader";
|
|
const char *fifo_reader_to_writer = "./fifo_group_reader_to_writer";
|
|
int fd_writer_to_reader, fd_reader_to_writer;
|
|
int notify = 0, verify = 0;
|
|
unsigned int i;
|
|
|
|
state_init(&s, argc, argv);
|
|
|
|
personality = strstr(s.progname, "vfd_swmr_group_");
|
|
|
|
if (personality != NULL &&
|
|
strcmp(personality, "vfd_swmr_group_writer") == 0)
|
|
writer = true;
|
|
else if (personality != NULL &&
|
|
strcmp(personality, "vfd_swmr_group_reader") == 0)
|
|
writer = false;
|
|
else {
|
|
errx(EXIT_FAILURE,
|
|
"unknown personality, expected vfd_swmr_group_{reader,writer}");
|
|
}
|
|
|
|
/* config, tick_len, max_lag, writer, flush_raw_data, md_pages_reserved, md_file_path */
|
|
init_vfd_swmr_config(&config, 4, 7, writer, FALSE, 128, "./group-shadow");
|
|
|
|
/* use_latest_format, use_vfd_swmr, only_meta_page, config */
|
|
fapl = vfd_swmr_create_fapl(true, s.use_vfd_swmr, true, &config);
|
|
|
|
if (fapl < 0)
|
|
errx(EXIT_FAILURE, "vfd_swmr_create_fapl");
|
|
|
|
if ((fcpl = H5Pcreate(H5P_FILE_CREATE)) < 0)
|
|
errx(EXIT_FAILURE, "H5Pcreate");
|
|
|
|
ret = H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_PAGE, false, 1);
|
|
if (ret < 0)
|
|
errx(EXIT_FAILURE, "H5Pset_file_space_strategy");
|
|
|
|
if (writer)
|
|
s.file = H5Fcreate(s.filename, H5F_ACC_TRUNC, fcpl, fapl);
|
|
else
|
|
s.file = H5Fopen(s.filename, H5F_ACC_RDONLY, fapl);
|
|
|
|
if (s.file == badhid)
|
|
errx(EXIT_FAILURE, writer ? "H5Fcreate" : "H5Fopen");
|
|
|
|
/* Use two named pipes(FIFO) to coordinate the writer and reader for
|
|
* 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) {
|
|
/* Writer creates two named pipes(FIFO) */
|
|
if (HDmkfifo(fifo_writer_to_reader, 0600) < 0)
|
|
errx(EXIT_FAILURE, "HDmkfifo");
|
|
|
|
if (HDmkfifo(fifo_reader_to_writer, 0600) < 0)
|
|
errx(EXIT_FAILURE, "HDmkfifo");
|
|
}
|
|
|
|
/* Both the writer and reader open the pipes */
|
|
if ((fd_writer_to_reader = HDopen(fifo_writer_to_reader, O_RDWR)) < 0)
|
|
errx(EXIT_FAILURE, "fifo_writer_to_reader open failed");
|
|
|
|
if ((fd_reader_to_writer = HDopen(fifo_reader_to_writer, O_RDWR)) < 0)
|
|
errx(EXIT_FAILURE, "fifo_reader_to_writer open failed");
|
|
|
|
if (writer) {
|
|
/* Writer tells reader to start */
|
|
if (HDwrite(fd_writer_to_reader, ¬ify, sizeof(int)) < 0)
|
|
err(EXIT_FAILURE, "write failed");
|
|
|
|
for (step = 0; step < s.nsteps; step++) {
|
|
dbgf(2, "writer: step %d\n", step);
|
|
|
|
write_group(&s, step);
|
|
|
|
/* At communication interval, notifies the reader and waits for its response */
|
|
if (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)
|
|
err(EXIT_FAILURE, "write failed");
|
|
|
|
/* During the wait, writer makes repeated HDF5 API calls
|
|
* to trigger EOT at approximately the correct time */
|
|
for(i = 0; i < config.max_lag + 1; i++) {
|
|
decisleep(config.tick_len);
|
|
H5Aexists(s.file, "nonexistent");
|
|
}
|
|
|
|
/* Receive the same value from the reader and verify it */
|
|
verify++;
|
|
if (HDread(fd_reader_to_writer, ¬ify, sizeof(int)) < 0)
|
|
err(EXIT_FAILURE, "read failed");
|
|
|
|
if (notify != verify)
|
|
errx(EXIT_FAILURE, "received message %d, expecting %d", notify, verify);
|
|
}
|
|
}
|
|
} else {
|
|
/* Start to verify group creation after receiving the writer's notice */
|
|
if (HDread(fd_writer_to_reader, ¬ify, sizeof(int)) < 0)
|
|
err(EXIT_FAILURE, "read failed");
|
|
|
|
/* Both notify and verify are 0 now */
|
|
if (notify != verify)
|
|
errx(EXIT_FAILURE, "received message %d, expecting %d", notify, verify);
|
|
|
|
for (step = 0; step < s.nsteps; step++) {
|
|
dbgf(2, "reader: step %d\n", step);
|
|
|
|
while (!verify_group(&s, step))
|
|
;
|
|
|
|
/* At communication interval, waits for the writer's notice and responds back */
|
|
if (step % s.csteps == 0) {
|
|
/* The writer should have bumped up the value of notify.
|
|
* Do the same with verify and confirm it */
|
|
verify++;
|
|
|
|
if (HDread(fd_writer_to_reader, ¬ify, sizeof(int)) < 0)
|
|
err(EXIT_FAILURE, "read failed");
|
|
|
|
if (notify != verify)
|
|
errx(EXIT_FAILURE, "received message %d, expecting %d", notify, verify);
|
|
|
|
/* Send back the same nofity value for acknowledgement */
|
|
if (HDwrite(fd_reader_to_writer, ¬ify, sizeof(int)) < 0)
|
|
err(EXIT_FAILURE, "write failed");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (H5Pclose(fapl) < 0)
|
|
errx(EXIT_FAILURE, "H5Pclose(fapl)");
|
|
|
|
if (H5Pclose(fcpl) < 0)
|
|
errx(EXIT_FAILURE, "H5Pclose(fcpl)");
|
|
|
|
if (H5Fclose(s.file) < 0)
|
|
errx(EXIT_FAILURE, "H5Fclose");
|
|
|
|
/* Both the writer and reader close the named pipes */
|
|
if (HDclose(fd_writer_to_reader) < 0)
|
|
errx(EXIT_FAILURE, "HDclose");
|
|
|
|
if (HDclose(fd_reader_to_writer) < 0)
|
|
errx(EXIT_FAILURE, "HDclose");
|
|
|
|
/* Reader finishes last and deletes the named pipes */
|
|
if(!writer) {
|
|
if(HDremove(fifo_writer_to_reader) != 0)
|
|
errx(EXIT_FAILURE, "fifo_writer_to_reader deletion failed");
|
|
|
|
if(HDremove(fifo_reader_to_writer) != 0)
|
|
errx(EXIT_FAILURE, "fifo_reader_to_writer deletion failed");
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|