hdf5/testpar/t_pflush1.c
2023-09-26 13:11:22 -07:00

213 lines
6.9 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* Purpose: This is the first half of a two-part test that makes sure
* that a file can be read after a parallel application crashes
* as long as the file was flushed first. We simulate a crash by
* calling _exit() since this doesn't flush HDF5 caches but
* still exits with success.
*/
#include "h5test.h"
static const char *FILENAME[] = {"flush", "noflush", NULL};
static int *data_g = NULL;
#define N_GROUPS 100
/*-------------------------------------------------------------------------
* Function: create_test_file
*
* Purpose: Creates the file used in part 1 of the test
*
* Return: Success: A valid file ID
* Failure: H5I_INVALID_HID
*-------------------------------------------------------------------------
*/
static hid_t
create_test_file(char *name, size_t name_length, hid_t fapl_id)
{
hid_t fid = H5I_INVALID_HID;
hid_t dcpl_id = H5I_INVALID_HID;
hid_t sid = H5I_INVALID_HID;
hid_t did = H5I_INVALID_HID;
hid_t top_level_gid = H5I_INVALID_HID;
hid_t gid = H5I_INVALID_HID;
hid_t dxpl_id = H5I_INVALID_HID;
hsize_t dims[2] = {100, 100};
hsize_t chunk_dims[2] = {5, 5};
hsize_t i, j;
if ((fid = H5Fcreate(name, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0)
goto error;
/* Create a chunked dataset */
if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0)
goto error;
if (H5Pset_chunk(dcpl_id, 2, chunk_dims) < 0)
goto error;
if ((sid = H5Screate_simple(2, dims, NULL)) < 0)
goto error;
if ((did = H5Dcreate2(fid, "dset", H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
goto error;
if ((dxpl_id = H5Pcreate(H5P_DATASET_XFER)) < 0)
goto error;
if (H5Pset_dxpl_mpio(dxpl_id, H5FD_MPIO_COLLECTIVE) < 0)
goto error;
/* Write some data */
for (i = 0; i < dims[0]; i++)
for (j = 0; j < dims[1]; j++)
data_g[(i * 100) + j] = (int)(i + (i * j) + j);
if (H5Dwrite(did, H5T_NATIVE_INT, sid, sid, dxpl_id, data_g) < 0)
goto error;
/* Create some groups */
if ((top_level_gid = H5Gcreate2(fid, "some_groups", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
goto error;
for (i = 0; i < N_GROUPS; i++) {
snprintf(name, name_length, "grp%02u", (unsigned)i);
if ((gid = H5Gcreate2(top_level_gid, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
goto error;
if (H5Gclose(gid) < 0)
goto error;
}
return fid;
error:
return H5I_INVALID_HID;
} /* end create_test_file() */
/*-------------------------------------------------------------------------
* Function: main
*
* Purpose: Part 1 of a two-part parallel H5Fflush() test.
*
* Return: EXIT_FAILURE (always)
*-------------------------------------------------------------------------
*/
int
main(int argc, char *argv[])
{
hid_t fid1 = H5I_INVALID_HID;
hid_t fid2 = H5I_INVALID_HID;
hid_t fapl_id = H5I_INVALID_HID;
MPI_File *mpifh_p = NULL;
char name[1024];
const char *envval = NULL;
int mpi_size;
int mpi_rank;
MPI_Comm comm = MPI_COMM_WORLD;
MPI_Info info = MPI_INFO_NULL;
MPI_Init(&argc, &argv);
MPI_Comm_size(comm, &mpi_size);
MPI_Comm_rank(comm, &mpi_rank);
if (mpi_rank == 0)
TESTING("H5Fflush (part1)");
/* Don't run using the split VFD */
envval = getenv(HDF5_DRIVER);
if (envval == NULL)
envval = "nomatch";
if (!strcmp(envval, "split")) {
if (mpi_rank == 0) {
SKIPPED();
puts(" Test not compatible with current Virtual File Driver");
}
MPI_Finalize();
exit(EXIT_FAILURE);
}
if (NULL == (data_g = malloc(100 * 100 * sizeof(*data_g))))
goto error;
if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
goto error;
if (H5Pset_fapl_mpio(fapl_id, comm, info) < 0)
goto error;
/* Create the file */
h5_fixname(FILENAME[0], fapl_id, name, sizeof(name));
if ((fid1 = create_test_file(name, sizeof(name), fapl_id)) < 0)
goto error;
/* Flush and exit without closing the library */
if (H5Fflush(fid1, H5F_SCOPE_GLOBAL) < 0)
goto error;
/* Create the other file which will not be flushed */
h5_fixname(FILENAME[1], fapl_id, name, sizeof(name));
if ((fid2 = create_test_file(name, sizeof(name), fapl_id)) < 0)
goto error;
if (mpi_rank == 0)
PASSED();
fflush(stdout);
fflush(stderr);
/* Some systems like AIX do not like files not being closed when MPI_Finalize
* is called. So, we need to get the MPI file handles, close them by hand.
* Then the _exit is still needed to stop at_exit from happening in some systems.
* Note that MPIO VFD returns the address of the file-handle in the VFD struct
* because MPI_File_close wants to modify the file-handle variable.
*/
/* Close file 1 */
if (H5Fget_vfd_handle(fid1, fapl_id, (void **)&mpifh_p) < 0)
goto error;
if (MPI_File_close(mpifh_p) != MPI_SUCCESS)
goto error;
/* Close file 2 */
if (H5Fget_vfd_handle(fid2, fapl_id, (void **)&mpifh_p) < 0)
goto error;
if (MPI_File_close(mpifh_p) != MPI_SUCCESS)
goto error;
fflush(stdout);
fflush(stderr);
if (data_g) {
free(data_g);
data_g = NULL;
}
/* Always exit with a failure code!
*
* In accordance with the standard, not having all processes
* call MPI_Finalize() can be considered an error, so mpiexec
* et al. may indicate failure on return. It's much easier to
* always ignore the failure condition than to handle some
* platforms returning success and others failure.
*/
_exit(EXIT_FAILURE);
error:
fflush(stdout);
fflush(stderr);
printf("*** ERROR ***\n");
printf("THERE WAS A REAL ERROR IN t_pflush1.\n");
fflush(stdout);
if (data_g)
free(data_g);
_exit(EXIT_FAILURE);
} /* end main() */