#include #include #include #include #include #include "h5core/h5_core.h" #include "h5_core_private.h" /*! \ingroup h5_core \defgroup h5_core_filehandling */ /*! \ingroup h5_core_filehandling Check whether \c f points to a valid file handle. \return H5_SUCCESS or error code */ h5_err_t h5_check_filehandle ( h5_file_t* const f /*!< filehandle to check validity of */ ) { if (f == NULL || f->file < 0 || f->u == NULL || f->b == NULL) { return h5_error ( H5_ERR_BADFD, "Called with bad filehandle."); } return H5_SUCCESS; } /*! Initialize H5Part */ static herr_t hdf5_error_handler ( hid_t estack_id, void* __f ) { UNUSED_ARGUMENT (__f); if (h5_get_debuglevel() >= 5) { H5Eprint (estack_id, stderr); } return 0; } /*! \ingroup h5_private \internal Initialize unstructured data internal data structure. TODO: Move to file "h5u_openclose.c" \return H5_SUCCESS or error code */ static h5_err_t h5upriv_open_file ( h5_file_t* const f /*!< IN: file handle */ ) { H5_PRIV_API_ENTER (h5_err_t, "f=%p", f); TRY (f->u = (h5u_fdata_t*)h5_calloc (1, sizeof (*f->u))); h5u_fdata_t *u = f->u; u->shape = -1; u->diskshape = H5S_ALL; u->memshape = H5S_ALL; u->viewstart = -1; u->viewend = -1; u->viewindexed = 0; TRY (u->dcreate_prop = hdf5_create_property (H5P_DATASET_CREATE)); H5_PRIV_API_RETURN (H5_SUCCESS); } /*! \ingroup h5_private \internal Initialize H5Block internal structure. TODO: Move to file "h5b_openclose.c" \return H5_SUCCESS or error code */ static h5_err_t h5bpriv_open_file ( h5_file_t * const f /*!< IN: file handle */ ) { H5_PRIV_API_ENTER (h5_err_t, "f=%p", f); h5b_fdata_t* b; if (f->b) H5_PRIV_API_LEAVE (H5_SUCCESS); TRY (f->b = (h5b_fdata_t*)h5_calloc (1, sizeof (*f->b))); b = f->b; memset (b, 0, sizeof (*b)); #if defined(PARALLEL_IO) size_t n = sizeof (struct h5b_partition) / sizeof (h5_int64_t); TRY (h5priv_mpi_type_contiguous(n, MPI_LONG_LONG, &b->partition_mpi_t)); #endif memset (b->user_layout, 0, sizeof(*b->user_layout)); memset (b->write_layout, 0, sizeof(*b->write_layout)); b->shape = -1; b->diskshape = -1; b->memshape = -1; b->block_gid = -1; b->field_gid = -1; b->have_layout = 0; TRY (b->dcreate_prop = hdf5_create_property (H5P_DATASET_CREATE)); H5_PRIV_API_RETURN (H5_SUCCESS); } static inline h5_err_t mpi_init ( h5_file_t* const f, MPI_Comm comm ) { H5_INLINE_FUNC_ENTER (h5_err_t); #ifdef PARALLEL_IO TRY (h5priv_mpi_comm_size (comm, &f->nprocs)); TRY (h5priv_mpi_comm_rank (comm, &f->myproc)); /* xfer_prop: also used for parallel I/O, during actual writes rather than the access_prop which is for file creation. */ TRY (f->xfer_prop = hdf5_create_property(H5P_DATASET_XFER)); TRY (f->access_prop = hdf5_create_property(H5P_FILE_ACCESS)); /* select the HDF5 VFD */ if (f->mode & H5_VFD_MPIPOSIX) { h5_info("Selecting MPI-POSIX VFD"); hbool_t use_gpfs = 0; // TODO autodetect GPFS? TRY (hdf5_set_fapl_mpiposix_property(f->access_prop, comm, use_gpfs)); } else { h5_info("Selecting MPI-IO VFD"); TRY (hdf5_set_fapl_mpio_property(f->access_prop, comm, MPI_INFO_NULL)); if (f->mode & H5_VFD_INDEPENDENT) { h5_info("MPI-IO: Using independent mode"); } else { h5_info("MPI-IO: Using collective mode"); TRY (hdf5_set_dxpl_mpio_property(f->xfer_prop, H5FD_MPIO_COLLECTIVE) ); } } #ifdef H5_USE_LUSTRE if (f->flags & H5_FS_LUSTRE) { TRY (h5_optimize_for_lustre(f, filename)); } #endif #endif /* PARALLEL_IO */ H5_INLINE_FUNC_RETURN (H5_SUCCESS); } static inline h5_err_t set_alignment ( h5_file_t* const f, h5_size_t align ) { H5_INLINE_FUNC_ENTER (h5_err_t); if ( align != 0 ) { h5_info ("Setting HDF5 alignment to %llu bytes", align); TRY (hdf5_set_alignment_property (f->access_prop, 0, align)); h5_info ("Setting HDF5 meta block to %llu bytes", align); TRY (H5Pset_meta_block_size (f->access_prop, align)); } H5_INLINE_FUNC_RETURN (H5_SUCCESS); } static inline h5_err_t open_file ( h5_file_t* const f, const char* const filename ) { H5_INLINE_FUNC_ENTER (h5_err_t); if (f->mode & H5_O_RDONLY) { f->file = H5Fopen (filename, H5F_ACC_RDONLY, f->access_prop); } else if (f->mode & H5_O_WRONLY){ f->file = H5Fcreate (filename, H5F_ACC_TRUNC, f->create_prop, f->access_prop); f->empty = 1; } else if (f->mode & H5_O_APPEND || f->mode & H5_O_RDWR) { int fd = open (filename, O_RDONLY, 0); if ((fd == -1) && (errno == ENOENT)) { f->file = H5Fcreate (filename, H5F_ACC_TRUNC, f->create_prop, f->access_prop); f->empty = 1; } else if (fd != -1) { close (fd); f->file = H5Fopen (filename, H5F_ACC_RDWR, f->access_prop); } } else { H5_PRIV_FUNC_LEAVE ( h5_error ( H5_ERR_INVAL, "Invalid file access mode '%d'.", f->mode)); } if (f->file < 0) H5_PRIV_FUNC_LEAVE ( h5_error ( H5_ERR_HDF5, "Cannot open file '%s' with mode '%d'", filename, f->mode)); H5_INLINE_FUNC_RETURN (H5_SUCCESS); } /*! \ingroup h5_core_filehandling Open file with name \c filename. This function is available in the paralell and serial version. In the serial case \c comm may have any value. \param[in] filename The name of the data file to open. \param[in] flags The access mode for the file. \param[in] comm MPI communicator \param[in] align Number of bytes for setting alignment, metadata block size, etc. Set to 0 to disable. \return File handle. \return H5_ERR on error. */ h5_file_p h5_open_file ( const char* filename, h5_int32_t flags, MPI_Comm comm, h5_size_t align ) { H5_CORE_API_ENTER (h5_file_p, "filename='%s', flags=%d, comm=?, align=%llu", filename, flags, align); h5_info ("Opening file %s.", filename); h5_file_p f = NULL; TRY2 (f = h5_calloc (1, sizeof (h5_file_t))); TRY2 (hdf5_set_errorhandler (H5E_DEFAULT, hdf5_error_handler, NULL)); TRY2 (h5_set_stepname_fmt (f, H5_STEPNAME, H5_STEPWIDTH)); /* init values */ f->comm = comm; f->nprocs = 1; // queried later f->myproc = 0; // queried later f->mode = flags; f->step_gid = -1; f->throttle = 0; sprintf ( f->step_name, "%s#%0*lld", f->prefix_step_name, f->width_step_idx, (long long)f->step_idx); f->xfer_prop = f->access_prop = H5P_DEFAULT; TRY2 (f->create_prop = hdf5_create_property(H5P_FILE_CREATE)); TRY2 (mpi_init (f, comm)); TRY2 (set_alignment (f, align)); TRY2 (open_file (f, filename)); TRY2 (f->root_gid = hdf5_open_group (f->file, "/" )); TRY2 (h5upriv_open_file (f)); TRY2 (h5bpriv_open_file (f)); H5_CORE_API_RETURN (f); } /*! \ingroup h5_private \internal De-initialize H5Block internal structure. Open HDF5 objects are closed and allocated memory freed. \return H5_SUCCESS or error code */ static h5_err_t h5upriv_close_file ( h5_file_t* const f /*!< file handle */ ) { H5_PRIV_API_ENTER (h5_err_t, "f=%p", f); struct h5u_fdata* u = f->u; h5_errno = H5_SUCCESS; TRY (hdf5_close_dataspace (u->shape)); TRY (hdf5_close_dataspace (u->diskshape)); TRY (hdf5_close_dataspace (u->memshape)); TRY (hdf5_close_property (u->dcreate_prop)); TRY (h5_free (f->u)); f->u = NULL; H5_PRIV_API_RETURN (H5_SUCCESS); } /*! \ingroup h5block_private \internal De-initialize H5Block internal structure. Open HDF5 objects are closed and allocated memory freed. \return H5_SUCCESS or error code */ static h5_err_t h5bpriv_close_file ( h5_file_t* const f /*!< IN: file handle */ ) { H5_PRIV_API_ENTER (h5_err_t, "f=%p", f); struct h5b_fdata* b = f->b; TRY (hdf5_close_group (b->block_gid)); TRY (hdf5_close_group (b->field_gid)); TRY (hdf5_close_dataspace (b->shape)); TRY (hdf5_close_dataspace (b->diskshape)); TRY (hdf5_close_dataspace (b->memshape)); TRY (hdf5_close_property (b->dcreate_prop)); #if defined(PARALLEL_IO) TRY (h5priv_mpi_type_free (&b->partition_mpi_t)); #endif TRY (h5_free (f->b)); f->b = NULL; H5_PRIV_API_RETURN (H5_SUCCESS); } /*! \ingroup h5_core_filehandling The h5_close_file() call writes all buffered data to disk, releases all previously allocated memory and terminates access to the associated HDF5 file. \return H5_SUCCESS or error code */ h5_err_t h5_close_file ( h5_file_t* const f /*!< file handle */ ) { H5_CORE_API_ENTER (h5_err_t, "f=%p", f); h5_errno = H5_SUCCESS; CHECK_FILEHANDLE (f); TRY (h5priv_close_step (f)); TRY (h5upriv_close_file (f)); TRY (h5bpriv_close_file (f)); TRY (hdf5_close_property (f->xfer_prop)); TRY (hdf5_close_property (f->access_prop)); TRY (hdf5_close_property (f->create_prop)); TRY (hdf5_close_group (f->root_gid)); TRY (hdf5_close_file (f->file)); h5_free (f); H5_CORE_API_RETURN (H5_SUCCESS); } h5_err_t h5_close_hdf5 ( void ) { H5_CORE_API_ENTER (h5_err_t, "%s", ""); H5_CORE_API_RETURN (hdf5_close ()); } h5_err_t h5_flush_step ( h5_file_t* const f ) { H5_CORE_API_ENTER (h5_err_t, "f=%p", f); H5_CORE_API_RETURN (hdf5_flush (f->step_gid, H5F_SCOPE_LOCAL)); } h5_err_t h5_flush_file ( h5_file_t* const f ) { H5_CORE_API_ENTER (h5_err_t, "f=%p", f); H5_CORE_API_RETURN (hdf5_flush (f->file, H5F_SCOPE_GLOBAL)); } /*! \ingroup h5_core_filehandling Define format of the step names. Example: ==H5FedDefineStepNameFormat( f, "Step", 6 )== defines step names like ==Step#000042==. \return \c H5_SUCCESS or error code */ h5_err_t h5_set_stepname_fmt ( h5_file_t* const f, const char* name, int width ) { H5_CORE_API_ENTER (h5_err_t, "f=%p, name='%s', width=%d", f, name, width); if (width < 0) width = 0; else if (width > H5_STEPNAME_LEN - 1) width = H5_STEPNAME_LEN - 1; strncpy ( f->prefix_step_name, name, //H5_STEPNAME_LEN - 1); 63); f->width_step_idx = width; H5_CORE_API_RETURN (H5_SUCCESS); } /*! \ingroup h5_core_filehandling Get format of the step names. \return \c H5_SUCCESS or error code */ h5_err_t h5_get_stepname_fmt ( h5_file_t* const f, /*!< Handle to file */ char* name, /*!< OUT: Prefix */ int l_name, /*!< length of buffer name */ int* width /*!< OUT: Width of the number */ ) { UNUSED_ARGUMENT (f); UNUSED_ARGUMENT (name); UNUSED_ARGUMENT (l_name); UNUSED_ARGUMENT (width); return h5_error_not_implemented (); } /*! \ingroup h5_core_filehandling Get current step number. \return Current step number or error code */ h5_id_t h5_get_step ( h5_file_t* const f /*!< file handle */ ) { UNUSED_ARGUMENT (f); return h5_error_not_implemented (); } /*! \ingroup h5_core_filehandling Get number of processes. \return Number of processes or error code */ int h5_get_num_procs ( h5_file_t* const f /*!< file handle */ ) { H5_CORE_API_ENTER (int, "f=%p", f); H5_CORE_API_RETURN (f->nprocs); } /*! \ingroup h5_core_filehandling Provides access to the underlying HDF5 file handle. \return Number of steps or error code */ hid_t h5_get_hdf5_file( h5_file_t* const f /*!< file handle */ ) { H5_CORE_API_ENTER (hid_t, "f=%p", f); H5_CORE_API_RETURN (f->file); } /*! \ingroup h5_core_filehandling Get number of steps. \return Number of steps or error code */ h5_ssize_t h5_get_num_steps( h5_file_t* const f /*!< file handle */ ) { return hdf5_get_num_groups_matching_prefix ( f->root_gid, f->prefix_step_name); } char * h5_strdupfor2c ( const char *s, const ssize_t len ) { char *dup = (char*)malloc ( len + 1 ); strncpy ( dup, s, len ); dup[len] = '\0'; for (int i=len-1; i>=0; i--) { if (dup[i] == ' ') dup[i] = '\0'; else break; } return dup; } char * h5_strc2for ( char * const str, const ssize_t l_str ) { size_t len = strlen ( str ); memset ( str+len, ' ', l_str-len ); return str; } h5_file_t * h5_filehandlefor2c ( const h5_int64_t *ptr ) { return (h5_file_t*)(size_t)*ptr; }