/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "h5test.h" /* This test uses many POSIX things that are not available on * Windows. */ #if defined(H5_HAVE_FORK) && defined(H5_HAVE_WAITPID) #include "use.h" #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[], options_t *opts) { /* use case defaults */ memset(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: * 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; bool send_wait = false; hid_t fapl = H5I_INVALID_HID; /* File access property list */ hid_t fid = H5I_INVALID_HID; /* File ID */ 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) { 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) { printf("Creating skeleton data file for test...\n"); if ((UC_opts.fapl_id = h5_fileaccess()) < 0) { fprintf(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) { fprintf(stderr, "can't set creation FAPL libver bounds\n"); Hgoto_error(1); } if (create_uc_file(&UC_opts) < 0) { fprintf(stderr, "***encounter error\n"); Hgoto_error(1); } else { printf("File created.\n"); } /* Close FAPL to prevent issues with forking later */ if (H5Pclose(UC_opts.fapl_id) < 0) { fprintf(stderr, "can't close creation FAPL\n"); Hgoto_error(1); } UC_opts.fapl_id = H5I_INVALID_HID; } /* ============ */ /* Fork process */ /* ============ */ if (UC_opts.launch == UC_READWRITE) { if ((childpid = fork()) < 0) { perror("fork"); Hgoto_error(1); } } mypid = HDgetpid(); /* ============= */ /* launch reader */ /* ============= */ if (UC_opts.launch != UC_WRITER) { /* child process launch the reader */ if (0 == childpid) { printf("%d: launch reader process\n", mypid); if ((UC_opts.fapl_id = h5_fileaccess()) < 0) { fprintf(stderr, "can't create read FAPL\n"); exit(EXIT_FAILURE); } if (read_uc_file(send_wait, &UC_opts) < 0) { fprintf(stderr, "read_uc_file encountered error\n"); exit(EXIT_FAILURE); } if (H5Pclose(UC_opts.fapl_id) < 0) { fprintf(stderr, "can't close read FAPL\n"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } } /* ============= */ /* launch writer */ /* ============= */ /* this process continues to launch the writer */ printf("%d: continue as the writer process\n", mypid); if ((fapl = h5_fileaccess()) < 0) { fprintf(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) { fprintf(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), fapl)) < 0) { fprintf(stderr, "H5Fopen failed\n"); Hgoto_error(1); } if (write_uc_file(send_wait, fid, &UC_opts) < 0) { fprintf(stderr, "write_uc_file encountered error\n"); Hgoto_error(1); } if (H5Fclose(fid) < 0) { fprintf(stderr, "Failed to close write\n"); Hgoto_error(1); } if (H5Pclose(fapl) < 0) { fprintf(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) { perror("waitpid"); Hgoto_error(1); } if (WIFEXITED(child_status)) { if ((child_ret_value = WEXITSTATUS(child_status)) != 0) { printf("%d: child process exited with non-zero code (%d)\n", mypid, child_ret_value); Hgoto_error(2); } } else { printf("%d: child process terminated abnormally\n", mypid); Hgoto_error(2); } } done: if (ret_value != 0) { printf("Error(s) encountered\n"); } else { printf("All passed\n"); } return (ret_value); } #else /* defined(H5_HAVE_FORK) && defined(H5_HAVE_WAITPID) */ int main(void) { fprintf(stderr, "Non-POSIX platform. Skipping.\n"); return EXIT_SUCCESS; } /* end main() */ #endif /* defined(H5_HAVE_FORK) && defined(H5_HAVE_WAITPID) */