diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/H5CX.c | 57 | ||||
-rw-r--r-- | src/H5CXprivate.h | 2 | ||||
-rw-r--r-- | src/H5Dvirtual.c | 119 | ||||
-rw-r--r-- | src/H5FDmpio.c | 232 | ||||
-rw-r--r-- | src/H5Fint.c | 19 | ||||
-rw-r--r-- | src/H5Olayout.c | 10 | ||||
-rw-r--r-- | src/H5Oprivate.h | 6 | ||||
-rw-r--r-- | src/H5Smpio.c | 1 | ||||
-rw-r--r-- | src/H5Sselect.c | 2 |
9 files changed, 402 insertions, 46 deletions
@@ -209,6 +209,9 @@ typedef struct H5CX_t { MPI_Datatype btype; /* MPI datatype for buffer, when using collective I/O */ MPI_Datatype ftype; /* MPI datatype for file, when using collective I/O */ hbool_t mpi_file_flushing; /* Whether an MPI-opened file is being flushed */ + + /* Internal: File open settings (not inherently related to parallel but currently only used in parallel) */ + hbool_t disable_file_locking; hbool_t rank0_bcast; /* Whether a dataset meets read-with-rank0-and-bcast requirements */ #endif /* H5_HAVE_PARALLEL */ @@ -1665,6 +1668,32 @@ H5CX_get_mpi_file_flushing(void) /*------------------------------------------------------------------------- + * Function: H5CX_get_disable_file_locking + * + * Purpose: Retrieves the "disable file locking" flag for the current API call context. + * + * Return: TRUE / FALSE on success / <can't fail> + * + * Programmer: Neil Fortner + * August 2, 2018 + * + *------------------------------------------------------------------------- + */ +hbool_t +H5CX_get_disable_file_locking(void) +{ + H5CX_node_t **head = H5CX_get_my_context(); /* Get the pointer to the head of the API context, for this thread */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Sanity check */ + HDassert(head && *head); + + FUNC_LEAVE_NOAPI((*head)->ctx.disable_file_locking) +} /* end H5CX_get_disable_file_locking() */ + + +/*------------------------------------------------------------------------- * Function: H5CX_get_mpio_rank0_bcast * * Purpose: Retrieves if the dataset meets read-with-rank0-and-bcast requirements for the current API call context. @@ -2809,6 +2838,34 @@ H5CX_set_mpi_file_flushing(hbool_t flushing) /*------------------------------------------------------------------------- + * Function: H5CX_set_disable_file_locking + * + * Purpose: Sets the "disable file locking" flag for the current API call context. + * + * Return: <none> + * + * Programmer: Neil Fortner + * August 2, 2018 + * + *------------------------------------------------------------------------- + */ +void +H5CX_set_disable_file_locking(hbool_t disable_file_locking) +{ + H5CX_node_t **head = H5CX_get_my_context(); /* Get the pointer to the head of the API context, for this thread */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Sanity check */ + HDassert(head && *head); + + (*head)->ctx.disable_file_locking = disable_file_locking; + + FUNC_LEAVE_NOAPI_VOID +} /* end H5CX_set_disable_file_locking() */ + + +/*------------------------------------------------------------------------- * Function: H5CX_set_mpio_rank0_bcast * * Purpose: Sets the "dataset meets read-with-rank0-and-bcast requirements" flag for the current API call context. diff --git a/src/H5CXprivate.h b/src/H5CXprivate.h index 638c32a..91316e4 100644 --- a/src/H5CXprivate.h +++ b/src/H5CXprivate.h @@ -97,6 +97,7 @@ H5_DLL H5AC_ring_t H5CX_get_ring(void); H5_DLL hbool_t H5CX_get_coll_metadata_read(void); H5_DLL herr_t H5CX_get_mpi_coll_datatypes(MPI_Datatype *btype, MPI_Datatype *ftype); H5_DLL hbool_t H5CX_get_mpi_file_flushing(void); +H5_DLL hbool_t H5CX_get_disable_file_locking(void); H5_DLL hbool_t H5CX_get_mpio_rank0_bcast(void); #endif /* H5_HAVE_PARALLEL */ @@ -143,6 +144,7 @@ H5_DLL void H5CX_set_coll_metadata_read(hbool_t cmdr); H5_DLL herr_t H5CX_set_mpi_coll_datatypes(MPI_Datatype btype, MPI_Datatype ftype); H5_DLL herr_t H5CX_set_mpio_coll_opt(H5FD_mpio_collective_opt_t mpio_coll_opt); H5_DLL void H5CX_set_mpi_file_flushing(hbool_t flushing); +H5_DLL void H5CX_set_disable_file_locking(hbool_t disable_file_locking); H5_DLL void H5CX_set_mpio_rank0_bcast(hbool_t rank0_bcast); #endif /* H5_HAVE_PARALLEL */ diff --git a/src/H5Dvirtual.c b/src/H5Dvirtual.c index 53640e7..61e67f9 100644 --- a/src/H5Dvirtual.c +++ b/src/H5Dvirtual.c @@ -57,6 +57,7 @@ #include "H5Dpkg.h" /* Dataset functions */ #include "H5Eprivate.h" /* Error handling */ #include "H5Fprivate.h" /* Files */ +#include "H5FDsec2.h" /* Posix unbuffered I/O file driver */ #include "H5FLprivate.h" /* Free Lists */ #include "H5Gprivate.h" /* Groups */ #include "H5HGprivate.h" /* Global Heaps */ @@ -483,12 +484,10 @@ H5D__virtual_store_layout(H5F_t *f, H5O_layout_t *layout) /* Checksum */ block_size += 4; - /* Allocate heap block */ if(NULL == (heap_block = (uint8_t *)H5MM_malloc(block_size))) HGOTO_ERROR(H5E_OHDR, H5E_RESOURCE, FAIL, "unable to allocate heap block") - /* * Encode heap block */ @@ -828,6 +827,7 @@ done: } /* end H5D__virtual_copy() */ + /*------------------------------------------------------------------------- * Function: H5D__virtual_delete * @@ -895,7 +895,6 @@ H5D__virtual_open_source_dset(const H5D_t *vdset, H5O_storage_virtual_srcdset_t *source_dset) { H5F_t *src_file = NULL; /* Source file */ - hbool_t src_file_open = FALSE; /* Whether we have opened and need to close src_file */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC @@ -908,25 +907,47 @@ H5D__virtual_open_source_dset(const H5D_t *vdset, HDassert(source_dset->dset_name); /* Check if we need to open the source file */ - if(HDstrcmp(source_dset->file_name, ".")) { + if(!HDstrcmp(source_dset->file_name, ".")) + /* Source file is ".", use the virtual dataset's file */ + src_file = vdset->oloc.file; + else if(source_dset->file) + /* Use previously opened file */ + src_file = source_dset->file; + else { unsigned intent; /* File access permissions */ +#ifdef H5_HAVE_PARALLEL + hbool_t prev_disable_file_locking = FALSE; /* Whether file locking was previously disabled */ +#endif /* H5_HAVE_PARALLEL */ /* Get the virtual dataset's file open flags ("intent") */ intent = H5F_INTENT(vdset->oloc.file); +#ifdef H5_HAVE_PARALLEL + /* Since the parallel implementation currently uses one independent open + * per process on source files, we must disable file locking on source + * files if the VDS is opened in parallel */ + if(H5F_HAS_FEATURE(vdset->oloc.file, H5FD_FEAT_HAS_MPI)) { + prev_disable_file_locking = H5CX_get_disable_file_locking(); + H5CX_set_disable_file_locking(TRUE); + } /* end if */ +#endif /* H5_HAVE_PARALLEL */ + /* Try opening the file */ src_file = H5F_prefix_open_file(vdset->oloc.file, H5F_PREFIX_VDS, vdset->shared->vds_prefix, source_dset->file_name, intent, vdset->shared->layout.storage.u.virt.source_fapl); - /* If we opened the source file here, we should close it when leaving */ - if(src_file) - src_file_open = TRUE; - else - /* Reset the error stack */ +#ifdef H5_HAVE_PARALLEL + /* Reset "disable file locking" flag */ + if(H5F_HAS_FEATURE(vdset->oloc.file, H5FD_FEAT_HAS_MPI)) { + H5CX_set_disable_file_locking(prev_disable_file_locking); + } /* end if */ +#endif /* H5_HAVE_PARALLEL */ + + /* Reset the error stack if we did not find the file */ + if(!src_file) H5E_clear_stack(NULL); + + source_dset->file = src_file; } /* end if */ - else - /* Source file is ".", use the virtual dataset's file */ - src_file = vdset->oloc.file; if(src_file) { H5G_loc_t src_root_loc; /* Object location of source file root group */ @@ -941,16 +962,11 @@ H5D__virtual_open_source_dset(const H5D_t *vdset, source_dset->dset = H5D__open_name(&src_root_loc, source_dset->dset_name, vdset->shared->layout.storage.u.virt.source_dapl); /* Dataset does not exist */ - if(NULL == source_dset->dset) { + if(NULL == source_dset->dset) /* Reset the error stack */ H5E_clear_stack(NULL); - source_dset->dset_exists = FALSE; - } /* end if */ else { - /* Dataset exists */ - source_dset->dset_exists = TRUE; - /* Patch the source selection if necessary */ if(virtual_ent->source_space_status != H5O_VIRTUAL_STATUS_CORRECT) { if(H5S_extent_copy(virtual_ent->source_select, source_dset->dset->shared->space) < 0) @@ -961,10 +977,6 @@ H5D__virtual_open_source_dset(const H5D_t *vdset, } /* end if */ done: - /* Release resources */ - if(src_file_open) - if(H5F_efc_close(vdset->oloc.file, src_file) < 0) - HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEFILE, FAIL, "can't close source file") FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__virtual_open_source_dset() */ @@ -1000,6 +1012,14 @@ H5D__virtual_reset_source_dset(H5O_storage_virtual_ent_t *virtual_ent, source_dset->dset = NULL; } /* end if */ + /* Close file */ + if(source_dset->file) { + HDassert(virtual_ent->virtual_file); + if(H5F_efc_close(virtual_ent->virtual_file, source_dset->file) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEFILE, FAIL, "can't close source file") + source_dset->file = NULL; + } /* end if */ + /* Free file name */ if(virtual_ent->parsed_source_file_name && (source_dset->file_name @@ -1578,6 +1598,12 @@ H5D__virtual_set_extent_unlim(const H5D_t *dset) /* printf mapping */ hsize_t first_missing = 0; /* First missing dataset in the current block of missing datasets */ +#ifdef H5_HAVE_PARALLEL + /* Parallel not yet supported with printf mappings */ + if(H5F_HAS_FEATURE(dset->oloc.file, H5FD_FEAT_HAS_MPI)) + HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "parallel operations on printf style datasets not supported") +#endif /* H5_HAVE_PARALLEL */ + /* Search for source datasets */ HDassert(storage->printf_gap != HSIZE_UNDEF); for(j = 0; j <= (storage->printf_gap + first_missing); j++) { @@ -1606,7 +1632,7 @@ H5D__virtual_set_extent_unlim(const H5D_t *dset) } /* end if */ /* Check if the dataset was already opened */ - if(storage->list[i].sub_dset[j].dset_exists) + if(storage->list[i].sub_dset[j].dset) first_missing = j + 1; else { /* Resolve file name */ @@ -1993,6 +2019,12 @@ H5D__virtual_init_all(const H5D_t *dset) size_t sub_dset_max; hbool_t partial_block; +#ifdef H5_HAVE_PARALLEL + /* Parallel not yet supported with printf mappings */ + if(H5F_HAS_FEATURE(dset->oloc.file, H5FD_FEAT_HAS_MPI)) + HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "parallel operations on printf style datasets not supported") +#endif /* H5_HAVE_PARALLEL */ + /* Get number of sub-source datasets in current extent */ sub_dset_max = (size_t)H5S_hyper_get_first_inc_block(storage->list[i].source_dset.virtual_select, virtual_dims[storage->list[i].unlim_dim_virtual], &partial_block); if(partial_block) @@ -2110,6 +2142,7 @@ herr_t H5D__virtual_init(H5F_t *f, const H5D_t *dset, hid_t dapl_id) { H5O_storage_virtual_t *storage; /* Convenience pointer */ + H5O_layout_t *layout_dst; /* Another convenence pointer */ H5P_genplist_t *dapl; /* Data access property list object pointer */ hssize_t old_offset[H5O_LAYOUT_NDIMS]; /* Old selection offset (unused) */ size_t i; /* Local index variables */ @@ -2121,6 +2154,7 @@ H5D__virtual_init(H5F_t *f, const H5D_t *dset, hid_t dapl_id) HDassert(dset); storage = &dset->shared->layout.storage.u.virt; HDassert(storage->list || (storage->list_nused == 0)); + layout_dst = &dset->shared->layout; /* Check that the dimensions of the VDS are large enough */ if(H5D_virtual_check_min_dims(dset) < 0) @@ -2150,6 +2184,9 @@ H5D__virtual_init(H5F_t *f, const H5D_t *dset, hid_t dapl_id) HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset") if(H5S_hyper_normalize_offset(storage->list[i].source_select, old_offset) < 0) HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset") + + /* Save pointer to virtual dataset in entry */ + storage->list[i].virtual_file = (H5F_t *)dset->oloc.file; } /* end for */ /* Get dataset access property list */ @@ -2169,10 +2206,24 @@ H5D__virtual_init(H5F_t *f, const H5D_t *dset, hid_t dapl_id) storage->printf_gap = (hsize_t)0; /* Retrieve VDS file FAPL to layout */ - if(storage->source_fapl <= 0) + if(storage->source_fapl <= 0) { if((storage->source_fapl = H5F_get_access_plist(f, FALSE)) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get fapl") +#ifdef H5_HAVE_PARALLEL + /* For now, in the parallel case, open all source files with the sec2 + * driver */ + if(H5F_HAS_FEATURE(f, H5FD_FEAT_HAS_MPI)) { + H5P_genplist_t *source_fapl_ptr; + + if(NULL == (source_fapl_ptr = H5P_object_verify(storage->source_fapl, H5P_FILE_ACCESS))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list") + if(H5P_set_driver(source_fapl_ptr, H5FD_SEC2, NULL) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't set sec2 driver on source fapl") + } /* end if */ +#endif /* H5_HAVE_PARALLEL */ + } /* end if */ + /* Copy DAPL to layout */ if(storage->source_dapl <= 0) if((storage->source_dapl = H5P_copy_plist(dapl, FALSE)) < 0) @@ -2182,6 +2233,14 @@ H5D__virtual_init(H5F_t *f, const H5D_t *dset, hid_t dapl_id) * unlimited/printf selections) */ storage->init = FALSE; + /* Insert global heap object if it does not already exist. Do this now so + * we don't have to insert an object into the cache when encoding the + * layout, which would cause problems in parallel. */ + if(storage->serial_list_hobjid.addr == HADDR_UNDEF) + /* Write the VDS data to destination file's heap */ + if(H5D__virtual_store_layout(f, layout_dst) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to store VDS info") + done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__virtual_init() */ @@ -2650,12 +2709,6 @@ H5D__virtual_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, storage = &io_info->dset->shared->layout.storage.u.virt; HDassert((storage->view == H5D_VDS_FIRST_MISSING) || (storage->view == H5D_VDS_LAST_AVAILABLE)); -#ifdef H5_HAVE_PARALLEL - /* Parallel reads are not supported (yet) */ - if(H5F_HAS_FEATURE(io_info->dset->oloc.file, H5FD_FEAT_HAS_MPI)) - HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "parallel reads not supported on virtual datasets") -#endif /* H5_HAVE_PARALLEL */ - /* Prepare for I/O operation */ if(H5D__virtual_pre_io(io_info, storage, file_space, mem_space, &tot_nelmts) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "unable to prepare for I/O operation") @@ -2840,12 +2893,6 @@ H5D__virtual_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, storage = &io_info->dset->shared->layout.storage.u.virt; HDassert((storage->view == H5D_VDS_FIRST_MISSING) || (storage->view == H5D_VDS_LAST_AVAILABLE)); -#ifdef H5_HAVE_PARALLEL - /* Parallel writes are not supported (yet) */ - if(H5F_HAS_FEATURE(io_info->dset->oloc.file, H5FD_FEAT_HAS_MPI)) - HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "parallel writes not supported on virtual datasets") -#endif /* H5_HAVE_PARALLEL */ - /* Prepare for I/O operation */ if(H5D__virtual_pre_io(io_info, storage, file_space, mem_space, &tot_nelmts) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "unable to prepare for I/O operation") diff --git a/src/H5FDmpio.c b/src/H5FDmpio.c index d5aa170..50b5676 100644 --- a/src/H5FDmpio.c +++ b/src/H5FDmpio.c @@ -59,6 +59,24 @@ static char H5FD_mpi_native_g[] = "native"; */ typedef struct H5FD_mpio_t { H5FD_t pub; /*public stuff, must be first */ + +/* For comparisons */ +#ifndef H5_HAVE_WIN32_API + /* On most systems the combination of device and i-node number uniquely + * identify a file. Note that Cygwin, MinGW and other Windows POSIX + * environments have the stat function (which fakes inodes) + * and will use the 'device + inodes' scheme as opposed to the + * Windows code further below. + */ + dev_t device; /* file device number */ + ino_t inode; /* file i-node number */ + +#else + DWORD nFileIndexLow; + DWORD nFileIndexHigh; + DWORD dwVolumeSerialNumber; + +#endif MPI_File f; /*MPIO file handle */ MPI_Comm comm; /*communicator */ MPI_Info info; /*file information */ @@ -78,8 +96,9 @@ static void *H5FD__mpio_fapl_get(H5FD_t *_file); static void *H5FD__mpio_fapl_copy(const void *_old_fa); static herr_t H5FD__mpio_fapl_free(void *_fa); static H5FD_t *H5FD__mpio_open(const char *name, unsigned flags, hid_t fapl_id, - haddr_t maxaddr); + haddr_t maxaddr); static herr_t H5FD__mpio_close(H5FD_t *_file); +static int H5FD__mpio_cmp(const H5FD_t *_f1, const H5FD_t *_f2); static herr_t H5FD__mpio_query(const H5FD_t *_f1, unsigned long *flags); static haddr_t H5FD__mpio_get_eoa(const H5FD_t *_file, H5FD_mem_t type); static herr_t H5FD__mpio_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr); @@ -115,7 +134,7 @@ static const H5FD_class_mpi_t H5FD_mpio_g = { NULL, /*dxpl_free */ H5FD__mpio_open, /*open */ H5FD__mpio_close, /*close */ - NULL, /*cmp */ + H5FD__mpio_cmp, /*cmp */ H5FD__mpio_query, /*query */ NULL, /*get_type_map */ NULL, /*alloc */ @@ -907,6 +926,87 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD_get_mpio_atomicity() */ +/* + * Function: H5FD_mpio_fileinfo_get + * + * Purpose: Implements a normal (posix) file open for MPI rank 0. + * Replicates the functionality of H5FD_sec2_open. We + * open the file and cache a few key structures before + * closing. These cached structures are those which + * are eventually utilized for MPIO file comparisons. + * + * N.B. The file handles returned by the collective MPI + * File open function are not guaranteed to have a relation to + * an actual posix file handle. This then, provides the + * requirement that we do a "normal" file open to provide + * an actual file handle with which we can gather more + * detailed information to eventually implement file + * comparisons (see: H5FD__mpio_cmp) + * + * Return: Success: Non-negative + * + * Failure: Negative + * Indicates too, that the information used for + * MPIO file comparisons will most likely not + * be initialized and this in turn can lead to + * runtime issues, e.g. File comparison failures. + */ +static herr_t +H5FD_mpio_fileinfo_get(const char *name, unsigned flags, H5FD_mpio_t *file) +{ + int status; + int fd = -1; /* File descriptor */ + int o_flags; /* Flags for open() call */ + h5_stat_t sb; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT + +#ifdef H5FDmpio_DEBUG + if (H5FD_mpio_Debug[(int)'t']) + fprintf(stdout, "Entering H5FD_mpio_fileinfo_get\n"); +#endif + +#ifdef H5_HAVE_WIN32_API + struct _BY_HANDLE_FILE_INFORMATION fileinfo; + HANDLE hFile; /* Native windows file handle */ +#endif + o_flags = (H5F_ACC_RDWR & flags) ? O_RDWR : O_RDONLY; + + /* Open the file */ + if((fd = HDopen(name, o_flags, H5_POSIX_CREATE_MODE_RW)) < 0) + HMPI_GOTO_ERROR(FAIL, "HDopen failed", fd) + + if((status = HDfstat(fd, &sb)) < 0) + HMPI_GOTO_ERROR(FAIL, "HDfstat failed", status) + +#ifdef H5_HAVE_WIN32_API + hFile = (HANDLE)_get_osfhandle(fd); + if(INVALID_HANDLE_VALUE == hFile) + HMPI_GOTO_ERROR(FAIL, "_get_osfhandle failed", -1) + + if(!GetFileInformationByHandle((HANDLE)hFile, &fileinfo)) + HMPI_GOTO_ERROR(FAIL, "GetFileInformationByHandle failed", 0) + + file->nFileIndexHigh = fileinfo.nFileIndexHigh; + file->nFileIndexLow = fileinfo.nFileIndexLow; + file->dwVolumeSerialNumber = fileinfo.dwVolumeSerialNumber; +#else /* H5_HAVE_WIN32_API */ + file->device = sb.st_dev; + file->inode = sb.st_ino; +#endif /* H5_HAVE_WIN32_API */ + +done: + if(fd >= 0) + HDclose(fd); + +#ifdef H5FDmpio_DEBUG + if (H5FD_mpio_Debug[(int)'t']) + fprintf(stdout, "Leaving H5FD_mpio_fileinfo_get\n"); +#endif + FUNC_LEAVE_NOAPI(ret_value) +} + /*------------------------------------------------------------------------- * Function: H5FD__mpio_open @@ -1039,6 +1139,11 @@ H5FD__mpio_open(const char *name, unsigned flags, hid_t fapl_id, file->eof = H5FD_mpi_MPIOff_to_haddr(size); file->local_eof = file->eof; + if (mpi_rank == 0) { + /* Gather some file info for future comparisons */ + if (H5FD_mpio_fileinfo_get( name, flags, file ) < 0) + HMPI_GOTO_ERROR(NULL, "H5FD_mpio_fileinfo_get failed", -1) + } /* Set return value */ ret_value = (H5FD_t*)file; @@ -1064,6 +1169,129 @@ done: /*------------------------------------------------------------------------- + * Function: H5FD__mpio_cmp + * + * Purpose: This version of the 'cmp' function is used to compare two + * files which have been created and opened using the MPI-IO + * driver. + * The peculiarity of this is that unlike POSIX io, the + * handle returned from an MPI_File_open operation may be + * an abstract value and not have any relation to an actual + * filestem handle. The net result is that additional + * filesystem information needs to be gathered to subsequently + * utilize the stronger filesystem based methodology used in + * other HDF5 drivers, e.g. H5FD_sec2_cmp() + * The approach is two fold: + * 1. The MPI communicators used to access parallel files + * will be compared. + * 2. MPI rank 0 is tasked with collecting the additional + * POSIX or Windows NTFS information that is subsequently + * used here for comparison purposes. The result is + * then broadcast to the participating MPI ranks to effect + * a global result. + * + * Return: An integer value similar to that returned by strcmp() + + * NOTE: This function can't FAIL. In those cases where + * where we would normally return FAILURE, e.g. when MPI + * returns an error, we treat these as unequal comparisons. + * + * Programmer: Richard Warren + * Originally borrowed from H5FD_sec2_cmp (Robb Matzke) and + * modified as described above. + * + *------------------------------------------------------------------------- + */ +static int +H5FD__mpio_cmp(const H5FD_t *_f1, const H5FD_t *_f2) +{ + const H5FD_mpio_t *f1 = (const H5FD_mpio_t *)_f1; + const H5FD_mpio_t *f2 = (const H5FD_mpio_t *)_f2; + int ret_value = 0; + int cmp_value = 0; + int mpi_result; + MPI_Group f1_grp; + MPI_Group f2_grp; + + FUNC_ENTER_NOAPI_NOINIT + + if ((mpi_result = MPI_Comm_group(f1->comm, &f1_grp)) != MPI_SUCCESS) + HMPI_GOTO_ERROR(-1, "MPI_Comm_group(comm1) failed", mpi_result) + + if ((mpi_result = MPI_Comm_group(f2->comm, &f2_grp)) != MPI_SUCCESS) + HMPI_GOTO_ERROR(-1, "MPI_Comm_group(comm2) failed", mpi_result) + + if ((mpi_result = MPI_Group_compare(f1_grp, f2_grp, &cmp_value)) != MPI_SUCCESS) + HMPI_GOTO_ERROR(-1, "MPI_Group_compare failed", mpi_result) + + /* The group compare return values can be one of the following: + * MPI_IDENT(0) == two groups/communicators are identical + * ---------------- Those below can lead to unexpected + * ---------------- results, so we will return unequal + * for the file comparison. + * MPI_CONGRUENT(1) == two groups/communicators are equal but + * are distinct communication domains + * MPI_SIMILAR(2) == two groups have the same members but + * ordering may be different + * MPI_UNEQUAL(3) == self descriptive (unequal) + * + * Note: Congruent groups would seem to satisfy the equality + * condition from the file perspective, but there may be conditions + * in which collective operations would cause an application to + * hang if two different communicators are in use, e.g. any + * sort of synchronization (Barrier, Bcast). + */ + + if (cmp_value >= MPI_CONGRUENT) + HGOTO_DONE(-1) + + if (f1->mpi_rank == 0) { + /* Because MPI file handles may NOT have any relation to + * to actual file handle, we utilize a "regular" file open + * on MPI rank 0 prior to opening with the MPI-IO routines. + * The H5FD_mpio_t structure is utilized to cache the + * relevant comparison values which we use for comparisons + * below. + */ +#ifdef H5_HAVE_WIN32_API + if ((f1->dwVolumeSerialNumber < f2->dwVolumeSerialNumber) || + (f1->nFileIndexHigh < f2->nFileIndexHigh) || + (f1->nFileIndexLow < f2->nFileIndexLow)) + cmp_value = -1; + else + if ((f1->dwVolumeSerialNumber > f2->dwVolumeSerialNumber) || + (f1->nFileIndexHigh > f2->nFileIndexHigh) || + (f1->nFileIndexLow > f2->nFileIndexLow)) + cmp_value = 1; +#else /* Not WIN32 */ +#ifdef H5_DEV_T_IS_SCALAR + if (f1->device < f2->device) cmp_value = -1; + else if(f1->device > f2->device) cmp_value = 1; +#else /* H5_DEV_T_IS_SCALAR */ + /* If dev_t isn't a scalar value on this system, just use memcmp to + * determine if the values are the same or not. The actual return value + * shouldn't really matter... + */ + cmp_value = HDmemcmp(&(f1->device), &(f2->device), sizeof(dev_t)); +#endif /* H5_DEV_T_IS_SCALAR */ + /* Continue checking ONLY if we haven't failed yet */ + if (!cmp_value) { + if(f1->inode < f2->inode) cmp_value = -1; + else if(f1->inode > f2->inode) cmp_value = 1; +#endif /* H5_HAVE_WIN32_API */ + } + } + if (MPI_SUCCESS != (mpi_result = MPI_Bcast(&cmp_value, 1, MPI_INT, 0, f1->comm))) + HMPI_GOTO_ERROR(-1, "MPI_Bcast failed", mpi_result) + + ret_value = cmp_value; +done: + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD__mpio_cmp() */ + + +/*------------------------------------------------------------------------- * Function: H5FD__mpio_close * * Purpose: Closes a file. This is collective. diff --git a/src/H5Fint.c b/src/H5Fint.c index 030fda8..bb092f3 100644 --- a/src/H5Fint.c +++ b/src/H5Fint.c @@ -1519,15 +1519,22 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id) if(NULL == (drvr = H5FD_get_class(fapl_id))) HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "unable to retrieve VFL class") - /* Check the environment variable that determines if we care - * about file locking. File locking should be used unless explicitly - * disabled. + /* Check for file locking disabled internally, then check the environment + * variable that determines if we care about file locking. File locking + * should be used unless explicitly disabled. */ - lock_env_var = HDgetenv("HDF5_USE_FILE_LOCKING"); - if(lock_env_var && !HDstrcmp(lock_env_var, "FALSE")) +#ifdef H5_HAVE_PARALLEL + if(H5CX_get_disable_file_locking()) use_file_locking = FALSE; else - use_file_locking = TRUE; +#endif /* H5_HAVE_PARALLEL */ + { + lock_env_var = HDgetenv("HDF5_USE_FILE_LOCKING"); + if(lock_env_var && !HDstrcmp(lock_env_var, "FALSE")) + use_file_locking = FALSE; + else + use_file_locking = TRUE; + } /* end block/else */ /* * Opening a file is a two step process. First we try to open the diff --git a/src/H5Olayout.c b/src/H5Olayout.c index 138f219..25cae05 100644 --- a/src/H5Olayout.c +++ b/src/H5Olayout.c @@ -679,7 +679,15 @@ H5O__layout_encode(H5F_t *f, hbool_t H5_ATTR_UNUSED disable_shared, uint8_t *p, break; case H5D_VIRTUAL: - /* Encode heap ID for VDS info */ + + /* Heap block should have been created already! */ + HDassert((mesg->storage.u.virt.serial_list_hobjid.addr != HADDR_UNDEF) + || (mesg->storage.u.virt.list_nused == 0)); + + /* Heap information + * During H5Fclose, the cache flushing can call H5O_msg_flush calls + * which we need to handle here... + */ H5F_addr_encode(f, &p, mesg->storage.u.virt.serial_list_hobjid.addr); UINT32ENCODE(p, mesg->storage.u.virt.serial_list_hobjid.idx); break; diff --git a/src/H5Oprivate.h b/src/H5Oprivate.h index 5987ecf..46e2845 100644 --- a/src/H5Oprivate.h +++ b/src/H5Oprivate.h @@ -432,6 +432,9 @@ typedef struct H5O_efl_t { * and 'size' callbacks for places to change when updating this. */ #define H5O_LAYOUT_VERSION_LATEST H5O_LAYOUT_VERSION_4 +/* Version # of encoded virtual dataset global heap blocks */ +#define H5O_LAYOUT_VDS_GH_ENC_VERS 0 + /* Forward declaration of structs used below */ struct H5D_layout_ops_t; /* Defined in H5Dpkg.h */ struct H5D_chunk_ops_t; /* Defined in H5Dpkg.h */ @@ -505,7 +508,7 @@ typedef struct H5O_storage_virtual_srcdset_t { struct H5S_t *clipped_source_select; /* Clipped version of source_select */ struct H5S_t *clipped_virtual_select; /* Clipped version of virtual_select */ struct H5D_t *dset; /* Source dataset */ - hbool_t dset_exists; /* Whether the dataset exists (was opened successfully) */ + struct H5F_t *file; /* Source file (if one was opened for this dataset) */ /* Temporary - only used during I/O operation, NULL at all other times */ struct H5S_t *projected_mem_space; /* Selection within mem_space for this mapping */ @@ -550,6 +553,7 @@ typedef struct H5O_storage_virtual_ent_t { hsize_t clip_size_source; /* Size selection would be clipped to in source selection when virtual extent == unlim_extent_virtual */ H5O_virtual_space_status_t source_space_status; /* Extent patching status of source_select */ H5O_virtual_space_status_t virtual_space_status; /* Extent patching status of virtual_select */ + H5F_t *virtual_file; /* Convenience pointer to file containing virtual dataset */ } H5O_storage_virtual_ent_t; typedef struct H5O_storage_virtual_t { diff --git a/src/H5Smpio.c b/src/H5Smpio.c index aeec566..35daed1 100644 --- a/src/H5Smpio.c +++ b/src/H5Smpio.c @@ -1478,6 +1478,7 @@ H5S__mpio_create_large_type(hsize_t num_elements, MPI_Aint stride_bytes, int block_len[2]; int mpi_code; /* MPI return code */ MPI_Datatype inner_type, outer_type, leftover_type, type[2]; + MPI_Aint lb; /* Needed as an argument for MPI_Type_get_extent */ MPI_Aint disp[2], old_extent; herr_t ret_value = SUCCEED; /* Return value */ diff --git a/src/H5Sselect.c b/src/H5Sselect.c index c383fed..fdd897c 100644 --- a/src/H5Sselect.c +++ b/src/H5Sselect.c @@ -1713,6 +1713,8 @@ H5S_select_shape_same(const H5S_t *space1, const H5S_t *space2) /* Check for different number of elements selected */ if(H5S_GET_SELECT_NPOINTS(space1) != H5S_GET_SELECT_NPOINTS(space2)) HGOTO_DONE(FALSE) + else if (space1 == space2) + HGOTO_DONE(TRUE); /* Check special cases if both dataspaces aren't scalar */ /* (If only one is, the number of selected points check is sufficient) */ |