From 362f22119d9cb25424f7cdf181219bfa6330b6b8 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Sun, 1 Apr 2012 17:27:15 -0500 Subject: [svn-r22228] Description: Bring r22219 from trunk to 1.8 branch: (with release manager's blessing) Merge "file image" changes from feature branch back to trunk. Tested on: h5committested --- MANIFEST | 44 +- bin/trace | 1 + configure | 2 +- hl/src/H5LT.c | 571 +++++++++++++++++- hl/src/H5LTpublic.h | 18 + hl/test/Makefile.am | 4 +- hl/test/Makefile.in | 27 +- hl/test/h5hltest.h | 6 +- hl/test/test_file_image.c | 518 ++++++++++++++++ src/H5Dint.c | 3 +- src/H5E.c | 12 +- src/H5Edefin.h | 1 + src/H5Einit.h | 5 + src/H5Epubgen.h | 2 + src/H5Eterm.h | 3 +- src/H5F.c | 284 ++++++--- src/H5FD.c | 82 ++- src/H5FDcore.c | 301 ++++++---- src/H5FDfamily.c | 2 +- src/H5FDlog.c | 2 +- src/H5FDprivate.h | 26 +- src/H5FDpublic.h | 39 ++ src/H5FDsec2.c | 2 +- src/H5Fprivate.h | 5 +- src/H5Fpublic.h | 1 + src/H5Gname.c | 11 +- src/H5I.c | 144 +++-- src/H5Iprivate.h | 2 +- src/H5Oattribute.c | 11 +- src/H5Pfapl.c | 497 ++++++++++++++++ src/H5Pint.c | 54 +- src/H5Pocpypl.c | 2 + src/H5Ppublic.h | 6 + src/H5T.c | 3 +- src/H5err.txt | 1 + test/Makefile.am | 5 +- test/Makefile.in | 67 ++- test/file_image.c | 1335 ++++++++++++++++++++++++++++++++++++++++++ test/file_image_core_test.h5 | Bin 0 -> 18528 bytes test/gen_file_image.c | 91 +++ testpar/Makefile.am | 4 +- testpar/Makefile.in | 12 +- testpar/t_file_image.c | 395 +++++++++++++ testpar/testphdf5.c | 7 + testpar/testphdf5.h | 1 + 45 files changed, 4269 insertions(+), 340 deletions(-) create mode 100644 hl/test/test_file_image.c create mode 100644 test/file_image.c create mode 100644 test/file_image_core_test.h5 create mode 100644 test/gen_file_image.c create mode 100644 testpar/t_file_image.c diff --git a/MANIFEST b/MANIFEST index 78c4d1f..38d1f0e 100644 --- a/MANIFEST +++ b/MANIFEST @@ -852,32 +852,34 @@ ./test/family_v16_00003.h5 ./test/fheap.c ./test/freespace.c +./test/file_image.c +./test/file_image_core_test.h5 ./test/fill_old.h5 ./test/fillval.c ./test/filter_fail.c ./test/fixed_idx.h5 ./test/flush1.c ./test/flush2.c -./test/gen_bad_ohdr.c _DO_NOT_DISTRIBUTE_ -./test/gen_bad_compound.c _DO_NOT_DISTRIBUTE_ -./test/gen_bogus.c _DO_NOT_DISTRIBUTE_ -./test/gen_cross.c _DO_NOT_DISTRIBUTE_ -./test/gen_deflate.c _DO_NOT_DISTRIBUTE_ -./test/gen_idx.c _DO_NOT_DISTRIBUTE_ -./test/gen_mergemsg.c _DO_NOT_DISTRIBUTE_ -./test/gen_new_array.c _DO_NOT_DISTRIBUTE_ -./test/gen_new_fill.c _DO_NOT_DISTRIBUTE_ -./test/gen_new_group.c _DO_NOT_DISTRIBUTE_ -./test/gen_new_mtime.c _DO_NOT_DISTRIBUTE_ -./test/gen_new_super.c _DO_NOT_DISTRIBUTE_ -./test/gen_noencoder.c _DO_NOT_DISTRIBUTE_ -./test/gen_nullspace.c _DO_NOT_DISTRIBUTE_ -./test/gen_old_array.c _DO_NOT_DISTRIBUTE_ -./test/gen_old_group.c _DO_NOT_DISTRIBUTE_ -./test/gen_old_layout.c _DO_NOT_DISTRIBUTE_ -./test/gen_old_mtime.c _DO_NOT_DISTRIBUTE_ -./test/gen_sizes_lheap.c _DO_NOT_DISTRIBUTE_ -./test/gen_udlinks.c _DO_NOT_DISTRIBUTE_ +./test/gen_bad_ohdr.c _DO_NOT_DISTRIBUTE_ +./test/gen_bad_compound.c _DO_NOT_DISTRIBUTE_ +./test/gen_bogus.c _DO_NOT_DISTRIBUTE_ +./test/gen_cross.c _DO_NOT_DISTRIBUTE_ +./test/gen_deflate.c _DO_NOT_DISTRIBUTE_ +./test/gen_file_image.c _DO_NOT_DISTRIBUTE_ +./test/gen_idx.c _DO_NOT_DISTRIBUTE_ +./test/gen_mergemsg.c _DO_NOT_DISTRIBUTE_ +./test/gen_new_array.c _DO_NOT_DISTRIBUTE_ +./test/gen_new_fill.c _DO_NOT_DISTRIBUTE_ +./test/gen_new_group.c _DO_NOT_DISTRIBUTE_ +./test/gen_new_mtime.c _DO_NOT_DISTRIBUTE_ +./test/gen_new_super.c _DO_NOT_DISTRIBUTE_ +./test/gen_noencoder.c _DO_NOT_DISTRIBUTE_ +./test/gen_nullspace.c _DO_NOT_DISTRIBUTE_ +./test/gen_old_array.c _DO_NOT_DISTRIBUTE_ +./test/gen_old_group.c _DO_NOT_DISTRIBUTE_ +./test/gen_old_layout.c _DO_NOT_DISTRIBUTE_ +./test/gen_old_mtime.c _DO_NOT_DISTRIBUTE_ +./test/gen_udlinks.c _DO_NOT_DISTRIBUTE_ ./test/getname.c ./test/gheap.c ./test/group_old.h5 @@ -971,6 +973,7 @@ ./testpar/t_cache.c ./testpar/t_dset.c ./testpar/t_file.c +./testpar/t_file_image.c ./testpar/t_mdset.c ./testpar/t_mpi.c ./testpar/t_ph5basic.c @@ -1963,6 +1966,7 @@ ./hl/test/sepia.pal ./hl/test/gen_test_ds.c ./hl/test/test_ds.c +./hl/test/test_file_image.c ./hl/test/test_image.c ./hl/test/test_lite.c ./hl/test/test_packet.c diff --git a/bin/trace b/bin/trace index 579b564..e5caee3 100755 --- a/bin/trace +++ b/bin/trace @@ -106,6 +106,7 @@ $Source = ""; "H5FD_t" => "x", "H5FD_class_t" => "x", "H5FD_stream_fapl_t" => "x", + "H5FD_file_image_callbacks_t" => "x", "H5G_iterate_t" => "x", "H5G_info_t" => "x", "H5I_free_t" => "x", diff --git a/configure b/configure index d5559d6..dd32e19 100755 --- a/configure +++ b/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Id: configure.in 22141 2012-03-26 00:29:22Z hdftest . +# From configure.in Id: configure.in 22210 2012-03-30 21:00:55Z mamcgree . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.68 for HDF5 1.8.9-snap15. # diff --git a/hl/src/H5LT.c b/hl/src/H5LT.c index eeaceeb..8136b11 100644 --- a/hl/src/H5LT.c +++ b/hl/src/H5LT.c @@ -17,6 +17,7 @@ #include #include #include + #include "H5LTprivate.h" #include "H5private.h" @@ -31,7 +32,461 @@ char *myinput; size_t indent = 0; +/* File Image operations + + A file image is a representation of an HDF5 file in a memory + buffer. In order to perform operations on an image in a similar way + to a file, the application buffer is copied to a FAPL buffer, which + in turn is copied to a VFD buffer. Buffer copying can decrease + performance, especially when using large file images. A solution to + this issue is to simulate the copying of the application buffer, + when actually the same buffer is used for the FAPL and the VFD. + This is implemented by using callbacks that simulate the standard + functions for memory management (additional callbacks are used for + the management of associated data structures). From the application + standpoint, a file handle can be obtained from a file image by using + the API routine H5LTopen_file_image(). This function takes a flag + argument that indicates the HDF5 library how to handle the given image; + several flag values can be combined by using the bitwise OR operator. + Valid flag values include: + + H5LT_FILE_IMAGE_OPEN_RW indicates the HDF5 library to open the file + image in read/write mode. Default is read-only mode. + + H5LT_FILE_IMAGE_DONT_COPY indicates the HDF5 library to not copy the + supplied user buffer; the same buffer will be handled by the FAPL and + the VFD driver. Default operation copies the user buffer to the FAPL and + VFD driver. + + H5LT_FILE_IMAGE_DONT_RELEASE indicates the HDF5 library to not release + the buffer handled by the FAPL and the VFD upon closing. This flag value + is only applicable when the flag value H5LT_FILE_IMAGE_DONT_COPY is set as + well. The application is responsible to release the image buffer. +*/ + +/* Data structure to pass application data to callbacks. */ +typedef struct { + void *app_image_ptr; /* Pointer to application buffer */ + size_t app_image_size; /* Size of application buffer */ + void *fapl_image_ptr; /* Pointer to FAPL buffer */ + size_t fapl_image_size; /* Size of FAPL buffer */ + int fapl_ref_count; /* Reference counter for FAPL buffer */ + void *vfd_image_ptr; /* Pointer to VFD buffer */ + size_t vfd_image_size; /* Size of VFD buffer */ + int vfd_ref_count; /* Reference counter for VFD buffer */ + unsigned flags; /* Flags indicate how the file image will */ + /* be open */ + int ref_count; /* Reference counter on udata struct */ +} H5LT_file_image_ud_t; + +/* callbacks prototypes for file image ops */ +static void *image_malloc(size_t size, H5FD_file_image_op_t file_image_op, void *udata); +static void *image_memcpy(void *dest, const void *src, size_t size, H5FD_file_image_op_t file_image_op, void *udata); +static void *image_realloc(void *ptr, size_t size, H5FD_file_image_op_t file_image_op, void *udata); +static herr_t image_free(void *ptr, H5FD_file_image_op_t file_image_op, void *udata); +static void *udata_copy(void *udata); +static herr_t udata_free(void *udata); + +/* Definition of callbacks for file image operations. */ + + +/*------------------------------------------------------------------------- +* Function: image_malloc +* +* Purpose: Simulates malloc() function to avoid copying file images. +* The application buffer is set to the buffer on only one FAPL. +* Then the FAPL buffer can be copied to other FAPL buffers or +* to only one VFD buffer. +* +* Return: Address of "allocated" buffer, if successful. Otherwise, it returns +* NULL. +* +* Programmer: Christian Chilan +* +* Date: October 3, 2011 +* +*------------------------------------------------------------------------- +*/ +static void * +image_malloc(size_t size, H5FD_file_image_op_t file_image_op, void *_udata) +{ + H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata; + void * return_value = NULL; + + /* callback is only used if the application buffer is not actually copied */ + if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY)) + goto out; + + switch ( file_image_op ) { + /* the app buffer is "copied" to only one FAPL. Afterwards, FAPLs can be "copied" */ + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET: + if (udata->app_image_ptr == NULL) + goto out; + if (udata->app_image_size != size) + goto out; + if (udata->fapl_image_ptr != NULL) + goto out; + if (udata->fapl_image_size != 0) + goto out; + if (udata->fapl_ref_count != 0) + goto out; + + udata->fapl_image_ptr = udata->app_image_ptr; + udata->fapl_image_size = udata->app_image_size; + return_value = udata->fapl_image_ptr; + udata->fapl_ref_count++; + break; + + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY: + if (udata->fapl_image_ptr == NULL) + goto out; + if (udata->fapl_image_size != size) + goto out; + if (udata->fapl_ref_count == 0) + goto out; + return_value = udata->fapl_image_ptr; + udata->fapl_ref_count++; + break; + + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET: + goto out; + + case H5FD_FILE_IMAGE_OP_FILE_OPEN: + /* FAPL buffer is "copied" to only one VFD buffer */ + if (udata->vfd_image_ptr != NULL) + goto out; + if (udata->vfd_image_size != 0) + goto out; + if (udata->vfd_ref_count != 0) + goto out; + if (udata->fapl_image_ptr == NULL) + goto out; + if (udata->fapl_image_size != size) + goto out; + if (udata->fapl_ref_count == 0) + goto out; + + udata->vfd_image_ptr = udata->fapl_image_ptr; + udata->vfd_image_size = size; + udata->vfd_ref_count++; + return_value = udata->vfd_image_ptr; + break; + + /* added unused labels to shut the compiler up */ + case H5FD_FILE_IMAGE_OP_NO_OP: + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE: + case H5FD_FILE_IMAGE_OP_FILE_RESIZE: + case H5FD_FILE_IMAGE_OP_FILE_CLOSE: + default: + goto out; + } /* end switch */ + + return(return_value); + +out: + return NULL; +} /* end image_malloc() */ + + +/*------------------------------------------------------------------------- +* Function: image_memcpy +* +* Purpose: Simulates memcpy() function to avoid copying file images. +* The image buffer can be set to only one FAPL buffer, and +* "copied" to only one VFD buffer. The FAPL buffer can be +* "copied" to other FAPLs buffers. +* +* Return: The address of the destination buffer, if successful. Otherwise, it +* returns NULL. +* +* Programmer: Christian Chilan +* +* Date: October 3, 2011 +* +*------------------------------------------------------------------------- +*/ +static void * +image_memcpy(void *dest, const void *src, size_t size, H5FD_file_image_op_t file_image_op, + void *_udata) +{ + H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata; + + /* callback is only used if the application buffer is not actually copied */ + if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY)) + goto out; + + switch(file_image_op) { + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET: + if (dest != udata->fapl_image_ptr) + goto out; + if (src != udata->app_image_ptr) + goto out; + if (size != udata->fapl_image_size) + goto out; + if (size != udata->app_image_size) + goto out; + if (udata->fapl_ref_count == 0) + goto out; + break; + + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY: + if (dest != udata->fapl_image_ptr) + goto out; + if (src != udata->fapl_image_ptr) + goto out; + if (size != udata->fapl_image_size) + goto out; + if (udata->fapl_ref_count < 2) + goto out; + break; + + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET: + goto out; + + case H5FD_FILE_IMAGE_OP_FILE_OPEN: + if (dest != udata->vfd_image_ptr) + goto out; + if (src != udata->fapl_image_ptr) + goto out; + if (size != udata->vfd_image_size) + goto out; + if (size != udata->fapl_image_size) + goto out; + if (udata->fapl_ref_count == 0) + goto out; + if (udata->vfd_ref_count != 1) + goto out; + break; + + /* added unused labels to shut the compiler up */ + case H5FD_FILE_IMAGE_OP_NO_OP: + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE: + case H5FD_FILE_IMAGE_OP_FILE_RESIZE: + case H5FD_FILE_IMAGE_OP_FILE_CLOSE: + default: + goto out; + } /* end switch */ + + return(dest); + +out: + return NULL; +} /* end image_memcpy() */ + + +/*------------------------------------------------------------------------- +* Function: image_realloc +* +* Purpose: Reallocates the shared application image buffer and updates data +* structures that manage buffer "copying". +* +* Return: Address of reallocated buffer, if successful. Otherwise, it returns +* NULL. +* +* Programmer: Christian Chilan +* +* Date: October 3, 2011 +* +*------------------------------------------------------------------------- +*/ +static void * +image_realloc(void *ptr, size_t size, H5FD_file_image_op_t file_image_op, void *_udata) +{ + H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata; + void * return_value = NULL; + + /* callback is only used if the application buffer is not actually copied */ + if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY)) + goto out; + + /* realloc() is not allowed when the HDF5 library won't release the image + buffer because reallocation may change the address of the buffer. The + new address cannot be communicated to the application to release it. */ + if (udata->flags & H5LT_FILE_IMAGE_DONT_RELEASE) + goto out; + + /* realloc() is not allowed if the image is open in read-only mode */ + if (!(udata->flags & H5LT_FILE_IMAGE_OPEN_RW)) + goto out; + + if (file_image_op == H5FD_FILE_IMAGE_OP_FILE_RESIZE) { + if (udata->vfd_image_ptr != ptr) + goto out; + + if (udata->vfd_ref_count != 1) + goto out; + + if (NULL == (udata->vfd_image_ptr = HDrealloc(ptr, size))) + goto out; + + udata->vfd_image_size = size; + return_value = udata->vfd_image_ptr; + } /* end if */ + else + goto out; + + return(return_value); + +out: + return NULL; +} /* end image_realloc() */ + + +/*------------------------------------------------------------------------- +* Function: image_free +* +* Purpose: Simulates deallocation of FAPL and VFD buffers by decreasing +* reference counters. Shared application buffer is actually +* deallocated if there are no outstanding references. +* +* Return: SUCCEED or FAIL +* +* Programmer: Christian Chilan +* +* Date: October 3, 2011 +* +*------------------------------------------------------------------------- +*/ +static herr_t +image_free(void *ptr, H5FD_file_image_op_t file_image_op, void *_udata) +{ + H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata; + + /* callback is only used if the application buffer is not actually copied */ + if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY)) + goto out; + + switch(file_image_op) { + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE: + if (udata->fapl_image_ptr != ptr) + goto out; + if (udata->fapl_ref_count == 0) + goto out; + + udata->fapl_ref_count--; + + /* release the shared buffer only if indicated by the respective flag and there are no outstanding references */ + if (udata->fapl_ref_count == 0 && udata->vfd_ref_count == 0 && + !(udata->flags & H5LT_FILE_IMAGE_DONT_RELEASE)) { + HDfree(udata->fapl_image_ptr); + udata->app_image_ptr = NULL; + udata->fapl_image_ptr = NULL; + udata->vfd_image_ptr = NULL; + } /* end if */ + break; + + case H5FD_FILE_IMAGE_OP_FILE_CLOSE: + if (udata->vfd_image_ptr != ptr) + goto out; + if (udata->vfd_ref_count != 1) + goto out; + + udata->vfd_ref_count--; + + /* release the shared buffer only if indicated by the respective flag and there are no outstanding references */ + if (udata->fapl_ref_count == 0 && udata->vfd_ref_count == 0 && + !(udata->flags & H5LT_FILE_IMAGE_DONT_RELEASE)) { + HDfree(udata->vfd_image_ptr); + udata->app_image_ptr = NULL; + udata->fapl_image_ptr = NULL; + udata->vfd_image_ptr = NULL; + } /* end if */ + break; + + /* added unused labels to keep the compiler quite */ + case H5FD_FILE_IMAGE_OP_NO_OP: + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET: + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY: + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET: + case H5FD_FILE_IMAGE_OP_FILE_OPEN: + case H5FD_FILE_IMAGE_OP_FILE_RESIZE: + default: + goto out; + } /* end switch */ + + return(SUCCEED); + +out: + return(FAIL); +} /* end image_free() */ + + +/*------------------------------------------------------------------------- +* Function: udata_copy +* +* Purpose: Simulates the copying of the user data structure utilized in the +* management of the "copying" of file images. +* +* Return: Address of "newly allocated" structure, if successful. Otherwise, it +* returns NULL. +* +* Programmer: Christian Chilan +* +* Date: October 3, 2011 +* +*------------------------------------------------------------------------- +*/ +static void * +udata_copy(void *_udata) +{ + H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata; + + /* callback is only used if the application buffer is not actually copied */ + if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY)) + goto out; + if (udata->ref_count == 0) + goto out; + + udata->ref_count++; + + return(udata); + +out: + return NULL; +} /* end udata_copy */ + + +/*------------------------------------------------------------------------- +* Function: udata_free +* +* Purpose: Simulates deallocation of the user data structure utilized in the +* management of the "copying" of file images. The data structure is +* actually deallocated when there are no outstanding references. +* +* Return: SUCCEED or FAIL +* +* Programmer: Christian Chilan +* +* Date: October 3, 2011 +* +*------------------------------------------------------------------------- +*/ +static herr_t +udata_free(void *_udata) +{ + H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata; + + /* callback is only used if the application buffer is not actually copied */ + if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY)) + goto out; + if (udata->ref_count == 0) + goto out; + + udata->ref_count--; + + /* checks that there are no references outstanding before deallocating udata */ + if (udata->ref_count == 0 && udata->fapl_ref_count == 0 && + udata->vfd_ref_count == 0) + HDfree(udata); + + return(SUCCEED); + +out: + return(FAIL); +} /* end udata_free */ + +/* End of callbacks definitions for file image operations */ /*------------------------------------------------------------------------- * @@ -388,6 +843,120 @@ out: return -1; } + +/*------------------------------------------------------------------------- +* Function: H5LTopen_file_image +* +* Purpose: Open a user supplied file image using the core file driver. +* +* Return: File identifier, Failure: -1 +* +* Programmer: Christian Chilan +* +* Date: October 3, 2011 +* +*------------------------------------------------------------------------- +*/ +hid_t H5LTopen_file_image(void *buf_ptr, size_t buf_size, unsigned flags) +{ + hid_t fapl, file_id; /* HDF5 identifiers */ + unsigned file_open_flags;/* Flags for image open */ + char file_name[64]; /* Filename buffer */ + size_t alloc_incr; /* Buffer allocation increment */ + size_t min_incr = 65536; /* Minimum buffer increment */ + double buf_prcnt = 0.1f; /* Percentage of buffer size to set + as increment */ + static long file_name_counter; + H5FD_file_image_callbacks_t callbacks = {&image_malloc, &image_memcpy, + &image_realloc, &image_free, + &udata_copy, &udata_free, + (void *)NULL}; + + /* check arguments */ + if (buf_ptr == NULL) + goto out; + if (buf_size == 0) + goto out; + if (flags & (unsigned)~(H5LT_FILE_IMAGE_ALL)) + goto out; + + /* Create FAPL to transmit file image */ + if ((fapl = H5Pcreate(H5P_FILE_ACCESS)) < 0) + goto out; + + /* set allocation increment to a percentage of the supplied buffer size, or + * a pre-defined minimum increment value, whichever is larger + */ + if ((buf_prcnt * buf_size) > min_incr) + alloc_incr = (size_t)(buf_prcnt * buf_size); + else + alloc_incr = min_incr; + + /* Configure FAPL to use the core file driver */ + if (H5Pset_fapl_core(fapl, alloc_incr, FALSE) < 0) + goto out; + + /* Set callbacks for file image ops ONLY if the file image is NOT copied */ + if (flags & H5LT_FILE_IMAGE_DONT_COPY) { + H5LT_file_image_ud_t *udata; /* Pointer to udata structure */ + + /* Allocate buffer to communicate user data to callbacks */ + if (NULL == (udata = (H5LT_file_image_ud_t *)HDmalloc(sizeof(H5LT_file_image_ud_t)))) + goto out; + + /* Initialize udata with info about app buffer containing file image and flags */ + udata->app_image_ptr = buf_ptr; + udata->app_image_size = buf_size; + udata->fapl_image_ptr = NULL; + udata->fapl_image_size = 0; + udata->fapl_ref_count = 0; + udata->vfd_image_ptr = NULL; + udata->vfd_image_size = 0; + udata->vfd_ref_count = 0; + udata->flags = flags; + udata->ref_count = 1; /* corresponding to the first FAPL */ + + /* copy address of udata into callbacks */ + callbacks.udata = (void *)udata; + + /* Set file image callbacks */ + if (H5Pset_file_image_callbacks(fapl, &callbacks) < 0) { + HDfree(udata); + goto out; + } /* end if */ + } /* end if */ + + /* Assign file image in user buffer to FAPL */ + if (H5Pset_file_image(fapl, buf_ptr, buf_size) < 0) + goto out; + + /* set file open flags */ + if (flags & H5LT_FILE_IMAGE_OPEN_RW) + file_open_flags = H5F_ACC_RDWR; + else + file_open_flags = H5F_ACC_RDONLY; + + /* define a unique file name */ + snprintf(file_name, (sizeof(file_name) - 1), "file_image_%ld", file_name_counter++); + + /* Assign file image in FAPL to the core file driver */ + if ((file_id = H5Fopen(file_name, file_open_flags, fapl)) < 0) + goto out; + + /* Close FAPL */ + if (H5Pclose(fapl) < 0) + goto out; + + /* Return file identifier */ + return file_id; + +out: + H5E_BEGIN_TRY { + H5Pclose(fapl); + } H5E_END_TRY; + return -1; +} /* end H5LTopen_file_image() */ + /*------------------------------------------------------------------------- * Function: H5LT_read_dataset @@ -1801,7 +2370,7 @@ print_enum(hid_t type, char* str, size_t *str_len, hbool_t no_ubuf, size_t indt) out: if(0 == nmembs) { - HDsnprintf(tmp_str, TMP_LEN, "\n%*s ", indt + 4, ""); + HDsnprintf(tmp_str, TMP_LEN, "\n%*s ", (int)(indt + 4), ""); str = realloc_and_append(no_ubuf, str_len, str, tmp_str); } /* end if */ diff --git a/hl/src/H5LTpublic.h b/hl/src/H5LTpublic.h index 6efae68..929c6bd 100644 --- a/hl/src/H5LTpublic.h +++ b/hl/src/H5LTpublic.h @@ -16,6 +16,15 @@ #ifndef _H5LTpublic_H #define _H5LTpublic_H +/* Flag definitions for H5LTopen_file_image() */ +#define H5LT_FILE_IMAGE_OPEN_RW 0x0001 /* Open image for read-write */ +#define H5LT_FILE_IMAGE_DONT_COPY 0x0002 /* The HDF5 lib won't copy */ +/* user supplied image buffer. The same image is open with the core driver. */ +#define H5LT_FILE_IMAGE_DONT_RELEASE 0x0004 /* The HDF5 lib won't */ +/* deallocate user supplied image buffer. The user application is reponsible */ +/* for doing so. */ +#define H5LT_FILE_IMAGE_ALL 0x0007 + typedef enum H5LT_lang_t { H5LT_LANG_ERR = -1, /*this is the first*/ H5LT_DDL = 0, /*for DDL*/ @@ -344,6 +353,15 @@ H5_HLDLL herr_t H5LTfind_attribute( hid_t loc_id, const char *name ); H5_HLDLL htri_t H5LTpath_valid(hid_t loc_id, const char *path, hbool_t check_object_valid); +/*------------------------------------------------------------------------- + * + * File image operations functions + * + *------------------------------------------------------------------------- + */ + +H5_HLDLL hid_t H5LTopen_file_image(void *buf_ptr, size_t buf_size, unsigned flags); + #ifdef __cplusplus } #endif diff --git a/hl/test/Makefile.am b/hl/test/Makefile.am index 86e3318..76c6f90 100644 --- a/hl/test/Makefile.am +++ b/hl/test/Makefile.am @@ -29,7 +29,7 @@ LDADD=$(LIBH5_HL) $(LIBH5TEST) $(LIBHDF5) # Test programs. These are our main targets. They should be listed in the # order to be executed, generally most specific tests to least specific tests. -TEST_PROG=test_lite test_image test_table test_ds test_packet +TEST_PROG=test_lite test_image test_file_image test_table test_ds test_packet check_PROGRAMS=$(TEST_PROG) # These programs generate test files for the tests. They don't need to be @@ -45,7 +45,7 @@ endif # Temporary files. These files are the ones created by running `make test'. CHECK_CLEANFILES+=combine_tables[1-2].h5 test_ds[1-9].h5 test_image[1-3].h5 \ - test_lite[1-2].h5 test_table.h5 test_packet_table.h5 \ + file_img[1-2].h5 test_lite[1-2].h5 test_table.h5 test_packet_table.h5 \ test_packet_compress.h5 test_detach.h5 include $(top_srcdir)/config/conclude.am diff --git a/hl/test/Makefile.in b/hl/test/Makefile.in index 6aa5a2a..b7548ec 100644 --- a/hl/test/Makefile.in +++ b/hl/test/Makefile.in @@ -69,7 +69,8 @@ CONFIG_HEADER = $(top_builddir)/src/H5config.h CONFIG_CLEAN_FILES = H5srcdir_str.h CONFIG_CLEAN_VPATH_FILES = am__EXEEXT_1 = test_lite$(EXEEXT) test_image$(EXEEXT) \ - test_table$(EXEEXT) test_ds$(EXEEXT) test_packet$(EXEEXT) + test_file_image$(EXEEXT) test_table$(EXEEXT) test_ds$(EXEEXT) \ + test_packet$(EXEEXT) am__EXEEXT_2 = gen_test_ds$(EXEEXT) PROGRAMS = $(noinst_PROGRAMS) gen_test_ds_SOURCES = gen_test_ds.c @@ -83,6 +84,10 @@ test_ds_SOURCES = test_ds.c test_ds_OBJECTS = test_ds.$(OBJEXT) test_ds_LDADD = $(LDADD) test_ds_DEPENDENCIES = $(LIBH5_HL) $(LIBH5TEST) $(LIBHDF5) +test_file_image_SOURCES = test_file_image.c +test_file_image_OBJECTS = test_file_image.$(OBJEXT) +test_file_image_LDADD = $(LDADD) +test_file_image_DEPENDENCIES = $(LIBH5_HL) $(LIBH5TEST) $(LIBHDF5) test_image_SOURCES = test_image.c test_image_OBJECTS = test_image.$(OBJEXT) test_image_LDADD = $(LDADD) @@ -125,10 +130,10 @@ am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; -SOURCES = gen_test_ds.c test_ds.c test_image.c test_lite.c \ - test_packet.c test_table.c -DIST_SOURCES = gen_test_ds.c test_ds.c test_image.c test_lite.c \ - test_packet.c test_table.c +SOURCES = gen_test_ds.c test_ds.c test_file_image.c test_image.c \ + test_lite.c test_packet.c test_table.c +DIST_SOURCES = gen_test_ds.c test_ds.c test_file_image.c test_image.c \ + test_lite.c test_packet.c test_table.c ETAGS = etags CTAGS = ctags am__tty_colors = \ @@ -422,16 +427,16 @@ TRACE = perl $(top_srcdir)/bin/trace # Temporary files. These files are the ones created by running `make test'. CHECK_CLEANFILES = *.chkexe *.chklog *.clog combine_tables[1-2].h5 \ - test_ds[1-9].h5 test_image[1-3].h5 test_lite[1-2].h5 \ - test_table.h5 test_packet_table.h5 test_packet_compress.h5 \ - test_detach.h5 + test_ds[1-9].h5 test_image[1-3].h5 file_img[1-2].h5 \ + test_lite[1-2].h5 test_table.h5 test_packet_table.h5 \ + test_packet_compress.h5 test_detach.h5 # The tests depend on the hdf5, hdf5 test, and hdf5_hl libraries LDADD = $(LIBH5_HL) $(LIBH5TEST) $(LIBHDF5) # Test programs. These are our main targets. They should be listed in the # order to be executed, generally most specific tests to least specific tests. -TEST_PROG = test_lite test_image test_table test_ds test_packet +TEST_PROG = test_lite test_image test_file_image test_table test_ds test_packet # These programs generate test files for the tests. They don't need to be # compiled every time we want to test the library. However, putting @@ -515,6 +520,9 @@ gen_test_ds$(EXEEXT): $(gen_test_ds_OBJECTS) $(gen_test_ds_DEPENDENCIES) test_ds$(EXEEXT): $(test_ds_OBJECTS) $(test_ds_DEPENDENCIES) @rm -f test_ds$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_ds_OBJECTS) $(test_ds_LDADD) $(LIBS) +test_file_image$(EXEEXT): $(test_file_image_OBJECTS) $(test_file_image_DEPENDENCIES) + @rm -f test_file_image$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_file_image_OBJECTS) $(test_file_image_LDADD) $(LIBS) test_image$(EXEEXT): $(test_image_OBJECTS) $(test_image_DEPENDENCIES) @rm -f test_image$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_image_OBJECTS) $(test_image_LDADD) $(LIBS) @@ -536,6 +544,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gen_test_ds.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_ds.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_file_image.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_image.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lite.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_packet.Po@am__quote@ diff --git a/hl/test/h5hltest.h b/hl/test/h5hltest.h index 466a0e1..809c4ec 100644 --- a/hl/test/h5hltest.h +++ b/hl/test/h5hltest.h @@ -23,9 +23,6 @@ #ifndef _H5HLTEST_H #define _H5HLTEST_H -/* Get the HDF5 public header */ -#include "hdf5.h" - /* Get the HDF5 test header */ #include "h5test.h" @@ -36,5 +33,8 @@ #define TESTING2(WHAT) {printf("%-70s", "Testing " WHAT); fflush(stdout);} #define TESTING3(WHAT) {printf("%-70s", "" WHAT); fflush(stdout);} +/* Implrements verbose 'assert' with 'goto error' exit */ +#define VERIFY(condition, string) do { if (!(condition)) FAIL_PUTS_ERROR(string) } while(0) + #endif /* _H5HLTEST_H */ diff --git a/hl/test/test_file_image.c b/hl/test/test_file_image.c new file mode 100644 index 0000000..9729421 --- /dev/null +++ b/hl/test/test_file_image.c @@ -0,0 +1,518 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* 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 files COPYING and Copyright.html. COPYING can be found at the root * +* of the source code distribution tree; Copyright.html can be found at the * +* root level of an installed copy of the electronic HDF5 document set and * +* is linked from the top-level documents page. It can also be found at * +* http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * +* access to either file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "h5hltest.h" +#include "H5LTpublic.h" + +#define DSET_NAME "dset" + +#define RANK 2 + +/* Test of file image operations. + + The following code provides a means to thoroughly test the file image + operations. Main objectives are testing operations with multiple open + images and using all possible flag combinations, which are set in the + main calling routine. Since the number of open images and flag combinations + may differ, the flag combinations are assigned to the images in round-robin + fashion. In order to simulate a realistic operation environment, the code + operates on as many open objects as possible by using several for-loops + instead of using a single loop that opens image i, accesses it, and closes + it. The first loop creates the files and obtains images using the function + H5Fget_file_image(); two images are set incorrectly (one image is filled + with "wrong" data while the other image is not valid). The second loop opens + the images using the function H5LTopen_file_image(), and test whether the + images have been copied in accordance to the H5LT_FILE_IMAGE_DONT_COPY flag. + The third loop reads the open images and verifies that the contents are + correct. The fourth loop first perform writes in the images that do not + extend the image, and then performs writes that extend the images. The fifth + loop reads the extended images and verify that the content are correct. The + sixth and final loop closes the file images and deallocates the image + buffers if appropriate. */ + +/*------------------------------------------------------------------------- +* test file image operations +*------------------------------------------------------------------------- +*/ +static int +test_file_image(size_t open_images, size_t nflags, unsigned *flags) +{ + hid_t *file_id, *dset_id, file_space, plist; /* HDF5 ids */ + hsize_t dims1[RANK] = {2,3}; /* original dimension of datasets */ + hsize_t max_dims[RANK] = {H5S_UNLIMITED, H5S_UNLIMITED}; + int data1[6] = {1,2,3,4,5,6}; /* original contents of dataset */ + int data2[6] = {7,8,9,10,11,12}; /* "wrong" contents of dataset */ + hsize_t dims3[RANK]; /* array to read dataset dimensions */ + int data3[15]; /* array to read dataset contents */ + hsize_t dims4[RANK] = {3,5}; /* extended dimensions of datasets */ + int data4[15] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; + /* extended contents of dataset */ + ssize_t *buf_size; /* pointer to array of buffer sizes */ + void **buf_ptr; /* pointer to array of pointers to image buffers */ + char **filename; /* pointer to array of pointers to filenames */ + unsigned *input_flags; /* pointer to array of flag combinations */ + size_t i, j, k, nrow, n_values; + herr_t status1; + void *handle_ptr = NULL; /* pointers to driver buffer */ + unsigned char **core_buf_ptr_ptr = NULL; + + VERIFY(open_images > 1 , "The number of open images must be greater than 1"); + + VERIFY(nflags > 0, "The number of flag combinations must be greater than 0"); + + /* allocate array of flags for open images */ + if (NULL == (input_flags = (unsigned *)HDmalloc(sizeof(unsigned) * open_images))) + FAIL_PUTS_ERROR("malloc() failed"); + + /* allocate array of pointers for each of the open images */ + if (NULL == (buf_ptr = (void **)malloc(sizeof(void *) * open_images))) + FAIL_PUTS_ERROR("malloc() failed"); + + /* allocate array to store the name of each of the open images */ + if (NULL == (filename = (char **)malloc(sizeof(char *) * open_images))) + FAIL_PUTS_ERROR("malloc() failed"); + + /* allocate array to store the size of each of the open images */ + if (NULL == (buf_size = (ssize_t *)malloc(sizeof(ssize_t) * open_images))) + FAIL_PUTS_ERROR("malloc() failed"); + + /* allocate array for each of the file identifiers */ + if (NULL == (file_id = (hid_t *)malloc(sizeof(hid_t) * open_images))) + FAIL_PUTS_ERROR("malloc() failed"); + + /* allocate array for each of the dataset identifiers */ + if (NULL == (dset_id = (hid_t *)malloc(sizeof(hid_t) * open_images))) + FAIL_PUTS_ERROR("malloc() failed"); + + TESTING("get file images"); + + /* create several file images */ + for (i = 0; i < open_images; i++) { + + /* populate array for flags combinations */ + input_flags[i] = flags[(nflags + i) % nflags]; + + /* allocate name buffer for image i */ + filename[i] = (char *)HDmalloc(sizeof(char) * 32); + + /* create file name */ + sprintf(filename[i], "image_file%d.h5", (int)i); + + /* create file */ + if ((file_id[i] = H5Fcreate(filename[i], H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) + FAIL_PUTS_ERROR("H5Fcreate() failed"); + + /* define dataspace for the dataset */ + if ((file_space = H5Screate_simple(RANK, dims1, max_dims)) < 0) + FAIL_PUTS_ERROR("H5Screate_simple() failed"); + + /* create dataset property list */ + if ((plist = H5Pcreate(H5P_DATASET_CREATE)) < 0) + FAIL_PUTS_ERROR("H5Pcreate() failed"); + + /* set property list to create chunked dataset */ + if (H5Pset_chunk(plist, RANK, dims1) < 0) + FAIL_PUTS_ERROR("H5Pset_chunk() failed"); + + /* create and write an integer type dataset named "dset" */ + if ((dset_id[i] = H5Dcreate2(file_id[i], DSET_NAME, H5T_NATIVE_INT, file_space, H5P_DEFAULT, plist, H5P_DEFAULT)) < 0) + FAIL_PUTS_ERROR("H5Dcreate() failed"); + + /* dataset in open image 1 is written with "wrong" data */ + if (i == 1) { + if (H5Dwrite(dset_id[i], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data2) < 0) + FAIL_PUTS_ERROR("H5Dwrite() failed"); + } /* end if*/ + /* dataset in the rest of the open images is written with correct data */ + else { + if (H5Dwrite(dset_id[i], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data1) < 0) + FAIL_PUTS_ERROR("H5Dwrite() failed"); + } /* end else */ + + /* flush into the file */ + if (H5Fflush(file_id[i], H5F_SCOPE_LOCAL) < 0) + FAIL_PUTS_ERROR("H5Fflush() failed"); + + /* close dataset property list */ + if (H5Pclose(plist) < 0) + FAIL_PUTS_ERROR("H5Pclose() failed"); + + /* close dataspace */ + if (H5Sclose(file_space) < 0) + FAIL_PUTS_ERROR("H5Sclose() failed"); + + /* close dataset */ + if (H5Dclose(dset_id[i]) < 0) + FAIL_PUTS_ERROR("H5Dclose() failed"); + + /* get size of the file image i */ + if ((buf_size[i] = H5Fget_file_image(file_id[i], NULL, 0)) < 0) + FAIL_PUTS_ERROR("H5Fget_file_image() failed"); + + /* allocate buffer for the file image i */ + if (NULL == (buf_ptr[i] = (void *)HDmalloc((size_t)buf_size[i]))) + FAIL_PUTS_ERROR("malloc() failed"); + + /* buffer for file image 2 is filled with counter data (non-valid image) */ + if (i == 2) { + for (j = 0; j < (size_t)buf_size[i]; j++) + ((char*)(buf_ptr[i]))[j] = (char)j; + } /* end if */ + /* buffers for the rest of the file images are filled with data from the respective files */ + else { + if ((buf_size[i] = H5Fget_file_image(file_id[i], buf_ptr[i], (size_t)buf_size[i])) < 0) + FAIL_PUTS_ERROR("H5Fget_file_image() failed"); + } /* end else */ + + /* file close */ + if (H5Fclose (file_id[i]) < 0) + FAIL_PUTS_ERROR("H5Fclose() failed"); + } /* end for */ + + PASSED(); + + TESTING("open file images and check image copies"); + + /* open the file images with the core driver for data access */ + for (i = 0; i < open_images; i++) { + /* open file image 2 filled with counter data (non-valid image) */ + if (i == 2) { + H5E_BEGIN_TRY { + /* attempt to set file image in the core driver */ + file_id[i] = H5LTopen_file_image(buf_ptr[i], (size_t)buf_size[i], input_flags[i]); + } H5E_END_TRY + + VERIFY(file_id[i] < 0, "H5LTopen_file_image() should have failed"); + } /* end if */ + /* open rest of valid file images */ + else { + /* set file image in the core driver */ + if ((file_id[i] = H5LTopen_file_image(buf_ptr[i], (size_t)buf_size[i], input_flags[i])) < 0) + FAIL_PUTS_ERROR("H5LTopen_file_image() failed"); + + /* get pointer to the image buffer of the core driver */ + if (H5Fget_vfd_handle(file_id[i], H5P_DEFAULT, &handle_ptr) < 0) + FAIL_PUTS_ERROR("H5Fget_vfd_handle() failed"); + + core_buf_ptr_ptr = (unsigned char **)handle_ptr; + + /* test whether the user buffer has been copied or not */ + if (input_flags[i] & H5LT_FILE_IMAGE_DONT_COPY) + VERIFY(*core_buf_ptr_ptr == buf_ptr[i], "vfd buffer and user buffer should have been the same"); + else + VERIFY(*core_buf_ptr_ptr != buf_ptr[i], "vfd buffer and user buffer should be different"); + + /* test whether the contents of the user buffer and driver buffer */ + /* are equal. */ + if (HDmemcmp(*core_buf_ptr_ptr, buf_ptr[i], (size_t)buf_size[i]) != 0) + FAIL_PUTS_ERROR("comparison of vfd and user buffer failed"); + } /* end else */ + } /* end for */ + + PASSED(); + + TESTING("read file images"); + + /* read open file images and verify data */ + for (i = 0; i < open_images; i++) { + /* if opening the file image failed, continue next iteration */ + if (file_id[i] < 0) { + HDassert(i == 2); + continue; + } /* end if */ + + /* open dataset in file image */ + if ((dset_id[i] = H5Dopen2(file_id[i], DSET_NAME, H5P_DEFAULT)) < 0) + FAIL_PUTS_ERROR("H5Dopen() failed"); + + /* get dataspace for the dataset */ + if ((file_space = H5Dget_space(dset_id[i])) < 0) + FAIL_PUTS_ERROR("H5Dget_space() failed"); + + /* get dimensions for the dataset */ + if (H5Sget_simple_extent_dims(file_space, dims3, NULL) < 0) + FAIL_PUTS_ERROR("H5Sget_simple_extent_dims() failed"); + + /* read dataset */ + if (H5Dread(dset_id[i], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data3) < 0) + FAIL_PUTS_ERROR("H5Dread() failed"); + + /* compute number of elements in dataset */ + n_values = (size_t)(dims3[0] * dims3[1]); + + /* determine the number of rows in dataset */ + nrow = (size_t)dims3[1]; + + /* verify contents for file image 1 with "wrong" data */ + if (i == 1) { + /* compare file image values with original data */ + for (j = 0; j < n_values / nrow; j++) + for (k = 0; k < nrow; k++) + if (data3[j * nrow + k ] == data1[j * nrow + k ]) + FAIL_PUTS_ERROR("comparison of image values with original data should have failed"); + } /* end if */ + /* verify contents for the rest of the file images */ + else { + /* compare file image values with original data */ + for (j = 0; j < n_values / nrow; j++) + for (k = 0; k < nrow; k++) + if (data3[j * nrow + k ] != data1[j * nrow + k ]) + FAIL_PUTS_ERROR("comparison of image values with original data failed"); + } /* end else */ + + /* close dataspace */ + if (H5Sclose (file_space) < 0) + FAIL_PUTS_ERROR("H5Sclose() failed"); + } /* end for */ + + PASSED(); + + TESTING("write and extend file images"); + + /* write open file images and verify data */ + for (i = 0; i < open_images; i++) { + /* if opening the file image failed, continue next iteration */ + if (file_id[i] < 0) { + HDassert(i == 2); + continue; + } /* end if */ + + /* test data write when file image access is read-only */ + if (!(input_flags[i] & H5LT_FILE_IMAGE_OPEN_RW)) { + /* write dataset without extending it */ + H5E_BEGIN_TRY { + status1 = H5Dwrite(dset_id[i], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data1); + } H5E_END_TRY; + + VERIFY(status1 < 0, "H5Dwrite() should have failed"); + + /* extend dimensions of dataset */ + H5E_BEGIN_TRY { + status1 = H5Dset_extent(dset_id[i], dims4); + } H5E_END_TRY; + + VERIFY(status1 < 0, "H5Dset_extent() should have failed"); + + /* write extended dataset */ + H5E_BEGIN_TRY { + status1 = H5Dwrite(dset_id[i], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data4); + } H5E_END_TRY; + + VERIFY(status1 < 0, "H5Dwrite() should have failed"); + + /* close dataset */ + if (H5Dclose(dset_id[i]) < 0) + FAIL_PUTS_ERROR("H5Dclose() failed"); + } /* end if */ + /* test data write where file image access is read-write */ + else { + if ((input_flags[i] & H5LT_FILE_IMAGE_DONT_COPY) && (input_flags[i] & H5LT_FILE_IMAGE_DONT_RELEASE)) { +/* This test is disabled currently, since the new attribute causes the file + * to increase in size, but the realloc call in H5FD_core_write() fails, causing + * the flush operation to fail and the file to fail to close, eventually + * triggering the "infinite loop shutting down the library" problem. + * + * In theory, we could address this through a variety of methods, ranging from + * ignoring failures in H5F_dest() (when called from H5F_try_close()), to + * allocating space more aggressively when creating the attribute, etc. + * + * For now, we will just leave the test commented out and assume that + * application developers who mark their file image as "don't copy" won't + * be likely candidates for modifying their data. - QAK - March 29, 2012 + */ +#if 0 + int attr_rank = 1; + hsize_t attr_dims[] = {4096}; + int attr_data[4096]; + hid_t attr_space_id = -1; + hid_t attr_id = -1; + herr_t status2; + size_t l; + + if ((attr_space_id = H5Screate_simple(attr_rank, attr_dims, attr_dims)) < 0) + FAIL_PUTS_ERROR("attr_space H5Screate_simple() failed"); + + if((attr_id = H5Acreate_by_name(dset_id[i], ".", "int array_addr", H5T_NATIVE_INT, attr_space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) + FAIL_PUTS_ERROR("H5Acreate_by_name() failed"); + + for(l = 0; l < 4096; l++) + attr_data[l] = (int)l; + + /* write data to the attribute and then flush the file. One or the other should + * should trigger an extension to the EOA, which in turn should cause the realloc + * callback to fail. + */ + H5E_BEGIN_TRY { + status1 = status2 = -1; + + status1 = H5Awrite(attr_id, H5T_NATIVE_INT, (const void *)attr_data); + if(status1 >= 0) + status2 = H5Fflush(file_id[i], H5F_SCOPE_GLOBAL); + + VERIFY(status1 < 0 || status2 < 0, "writing and flushing attr should have failed"); + } H5E_END_TRY; + + /* close attr and attr_space -- expect errors on close */ + H5E_BEGIN_TRY { + H5Sclose(attr_space_id); + H5Aclose(attr_id); + } H5E_END_TRY; +#endif + file_id[i] = -1; + } /* end if */ + else { + /* write dataset without extending it */ + if (H5Dwrite(dset_id[i], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data1) < 0) + FAIL_PUTS_ERROR("H5Dwrite() failed"); + + /* extend dimensions of dataset */ + if (H5Dset_extent(dset_id[i], dims4) < 0) + FAIL_PUTS_ERROR("H5Dset_extent() failed"); + + /* write extended dataset */ + if (H5Dwrite(dset_id[i], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data4) < 0) + FAIL_PUTS_ERROR("H5Dwrite() failed"); + + /* close dataset */ + if (H5Dclose(dset_id[i]) < 0) + FAIL_PUTS_ERROR("H5Dclose() failed"); + } /* end else */ + } /* end else */ + } /* end for */ + + PASSED(); + + TESTING("read extended file images"); + + /* read open file images and verify data */ + for (i = 0; i < open_images; i++) { + /* if opening the file image failed, continue next iteration */ + if ((file_id[i] < 0) || (!(input_flags[i] & H5LT_FILE_IMAGE_OPEN_RW ))) + continue; + + /* open dataset in file image */ + if ((dset_id[i] = H5Dopen2(file_id[i], DSET_NAME, H5P_DEFAULT)) < 0) + FAIL_PUTS_ERROR("H5Dopen() failed"); + + /* get dataspace for the dataset */ + if ((file_space = H5Dget_space(dset_id[i])) < 0) + FAIL_PUTS_ERROR("H5Dget_space() failed"); + + /* get dimensions for the dataset */ + if (H5Sget_simple_extent_dims(file_space, dims3, NULL) < 0) + FAIL_PUTS_ERROR("H5Sget_simple_extent_dims() failed"); + + /* read dataset */ + if (H5Dread(dset_id[i], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data3) < 0) + FAIL_PUTS_ERROR("H5Dread() failed"); + + /* compute number of elements in dataset */ + n_values = (size_t)(dims3[0] * dims3[1]); + + /* determine the number of rows in dataset */ + nrow = (size_t)dims3[1]; + + /* verify contents for the file images */ + for (j = 0; j < n_values / nrow; j++) + for (k = 0; k < nrow; k++) + if (data3[j * nrow + k ] != data4[j * nrow + k ]) + FAIL_PUTS_ERROR("comparison of image values with original data failed"); + + /* close dataspace */ + if (H5Sclose (file_space) < 0) + FAIL_PUTS_ERROR("H5Sclose() failed"); + + /* close dataset */ + if (H5Dclose(dset_id[i]) < 0) + FAIL_PUTS_ERROR("H5Dclose() failed"); + } /* end for */ + + PASSED() + + TESTING("close file images"); + + /* close file images and release buffer if appropriate */ + for (i = 0; i < open_images; i++) { + /* close file is appropriate */ + if (file_id[i] >= 0) { + /* close file image */ + if (H5Fclose(file_id[i]) < 0) + FAIL_PUTS_ERROR("H5Fclose() failed"); + } /* end if */ + + /* delete test data files */ + if (HDremove(filename[i]) < 0) + FAIL_PUTS_ERROR("HDremove() failed"); + + /* free shared buffer if appropriate */ + if (!(input_flags[i] & H5LT_FILE_IMAGE_DONT_COPY) || (input_flags[i] & H5LT_FILE_IMAGE_DONT_RELEASE)) { + VERIFY(buf_ptr[i] != NULL, "buffer pointer must be non NULL"); + HDfree(buf_ptr[i]); + } /* end if */ + + } /* end for */ + + /* release temporary working buffers */ + HDfree(filename); + HDfree(file_id); + HDfree(dset_id); + HDfree(buf_ptr); + HDfree(buf_size); + HDfree(input_flags); + + PASSED(); + + H5close(); + + return 0; + +error: + H5_FAILED(); + return -1; +} + +/*------------------------------------------------------------------------- +* the main program +*------------------------------------------------------------------------- +*/ +int main( void ) +{ + int nerrors = 0; + size_t open_images = 10; /* number of open file images */ + size_t nflags = 8; /* number of flag combinations */ + unsigned flags[8]; /* array with flag combinations */ + + /* set flag combinations for testing */ + flags[0] = 0; + flags[1] = H5LT_FILE_IMAGE_DONT_RELEASE; + flags[2] = H5LT_FILE_IMAGE_DONT_COPY; + flags[3] = H5LT_FILE_IMAGE_DONT_COPY | H5LT_FILE_IMAGE_DONT_RELEASE; + flags[4] = H5LT_FILE_IMAGE_OPEN_RW; + flags[5] = H5LT_FILE_IMAGE_OPEN_RW | H5LT_FILE_IMAGE_DONT_RELEASE; + flags[6] = H5LT_FILE_IMAGE_OPEN_RW | H5LT_FILE_IMAGE_DONT_COPY; + flags[7] = H5LT_FILE_IMAGE_OPEN_RW | H5LT_FILE_IMAGE_DONT_COPY | H5LT_FILE_IMAGE_DONT_RELEASE; + + /* Test file image operations. The flag combinations are assigned to file images in round-robin fashion */ + nerrors += test_file_image(open_images, nflags, flags) < 0? 1 : 0; + + if (nerrors) goto error; + printf("File image tests passed.\n"); + return 0; + +error: + printf("***** %d IMAGE TEST%s FAILED! *****\n",nerrors, 1 == nerrors ? "" : "S"); + return 1; +} + diff --git a/src/H5Dint.c b/src/H5Dint.c index 98d3447..0fb31a4 100644 --- a/src/H5Dint.c +++ b/src/H5Dint.c @@ -2438,7 +2438,8 @@ H5D_flush(const H5F_t *f, hid_t dxpl_id) udata.dxpl_id = dxpl_id; /* Iterate over all the open datasets */ - H5I_search(H5I_DATASET, H5D_flush_cb, &udata, FALSE); + if(H5I_iterate(H5I_DATASET, H5D_flush_cb, &udata, FALSE) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_BADITER, FAIL, "unable to flush cached dataset info") done: FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5E.c b/src/H5E.c index 4c4433e..5baf7a5 100644 --- a/src/H5E.c +++ b/src/H5E.c @@ -107,7 +107,7 @@ static H5E_cls_t *H5E_register_class(const char *cls_name, const char *lib_name, const char *version); static herr_t H5E_unregister_class(H5E_cls_t *cls); static ssize_t H5E_get_class_name(const H5E_cls_t *cls, char *name, size_t size); -static int H5E_close_msg_cb(void *obj_ptr, hid_t obj_id, void *key); +static int H5E_close_msg_cb(void *obj_ptr, hid_t obj_id, void *udata); static herr_t H5E_close_msg(H5E_msg_t *err); static H5E_msg_t *H5E_create_msg(H5E_cls_t *cls, H5E_type_t msg_type, const char *msg); static H5E_t *H5E_get_current_stack(void); @@ -543,8 +543,8 @@ H5E_unregister_class(H5E_cls_t *cls) HDassert(cls); /* Iterate over all the messages and delete those in this error class */ - /* (Ignore return value, since callback isn't designed to return a particular object) */ - (void)H5I_search(H5I_ERROR_MSG, H5E_close_msg_cb, cls, FALSE); + if(H5I_iterate(H5I_ERROR_MSG, H5E_close_msg_cb, cls, FALSE) < 0) + HGOTO_ERROR(H5E_ERROR, H5E_BADITER, FAIL, "unable to free all messages in this error class") /* Free error class structure */ if(H5E_free_class(cls) < 0) @@ -631,7 +631,7 @@ H5E_get_class_name(const H5E_cls_t *cls, char *name, size_t size) /*------------------------------------------------------------------------- * Function: H5E_close_msg_cb * - * Purpose: H5I_search callback function to close error messages in the + * Purpose: H5I_iterate callback function to close error messages in the * error class. * * Return: Non-negative value on success/Negative on failure @@ -642,10 +642,10 @@ H5E_get_class_name(const H5E_cls_t *cls, char *name, size_t size) *------------------------------------------------------------------------- */ static int -H5E_close_msg_cb(void *obj_ptr, hid_t obj_id, void *key) +H5E_close_msg_cb(void *obj_ptr, hid_t obj_id, void *udata) { H5E_msg_t *err_msg = (H5E_msg_t*)obj_ptr; - H5E_cls_t *cls = (H5E_cls_t*)key; + H5E_cls_t *cls = (H5E_cls_t*)udata; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT diff --git a/src/H5Edefin.h b/src/H5Edefin.h index 9ca9371..b6bde20 100644 --- a/src/H5Edefin.h +++ b/src/H5Edefin.h @@ -91,6 +91,7 @@ hid_t H5E_CANTRELEASE_g = FAIL; /* Unable to release object */ hid_t H5E_CANTGET_g = FAIL; /* Can't get value */ hid_t H5E_CANTSET_g = FAIL; /* Can't set value */ hid_t H5E_DUPCLASS_g = FAIL; /* Duplicate class name in parent class */ +hid_t H5E_SETDISALLOWED_g = FAIL; /* Disallowed operation */ /* Free space errors */ hid_t H5E_CANTMERGE_g = FAIL; /* Can't merge objects */ diff --git a/src/H5Einit.h b/src/H5Einit.h index 36b17a0..34fac7b 100644 --- a/src/H5Einit.h +++ b/src/H5Einit.h @@ -329,6 +329,11 @@ if((msg = H5E_create_msg(cls, H5E_MINOR, "Duplicate class name in parent class") HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed") if((H5E_DUPCLASS_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0) HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message") +assert(H5E_SETDISALLOWED_g==(-1)); +if((msg = H5E_create_msg(cls, H5E_MINOR, "Disallowed operation"))==NULL) + HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed") +if((H5E_SETDISALLOWED_g = H5I_register(H5I_ERROR_MSG, msg, FALSE))<0) + HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message") /* Free space errors */ assert(H5E_CANTMERGE_g==(-1)); diff --git a/src/H5Epubgen.h b/src/H5Epubgen.h index 68fd177..1540b07 100644 --- a/src/H5Epubgen.h +++ b/src/H5Epubgen.h @@ -151,9 +151,11 @@ H5_DLLVAR hid_t H5E_CANTRELEASE_g; /* Unable to release object */ #define H5E_CANTGET (H5OPEN H5E_CANTGET_g) #define H5E_CANTSET (H5OPEN H5E_CANTSET_g) #define H5E_DUPCLASS (H5OPEN H5E_DUPCLASS_g) +#define H5E_SETDISALLOWED (H5OPEN H5E_SETDISALLOWED_g) H5_DLLVAR hid_t H5E_CANTGET_g; /* Can't get value */ H5_DLLVAR hid_t H5E_CANTSET_g; /* Can't set value */ H5_DLLVAR hid_t H5E_DUPCLASS_g; /* Duplicate class name in parent class */ +H5_DLLVAR hid_t H5E_SETDISALLOWED_g; /* Disallowed operation */ /* Free space errors */ #define H5E_CANTMERGE (H5OPEN H5E_CANTMERGE_g) diff --git a/src/H5Eterm.h b/src/H5Eterm.h index 85eb19e..10a6014 100644 --- a/src/H5Eterm.h +++ b/src/H5Eterm.h @@ -92,7 +92,8 @@ H5E_CANTRELEASE_g= /* Property list errors */ H5E_CANTGET_g= H5E_CANTSET_g= -H5E_DUPCLASS_g= +H5E_DUPCLASS_g= +H5E_SETDISALLOWED_g= /* Free space errors */ H5E_CANTMERGE_g= diff --git a/src/H5F.c b/src/H5F.c index a74570a..79a3c41 100644 --- a/src/H5F.c +++ b/src/H5F.c @@ -65,7 +65,7 @@ typedef struct H5F_olist_t { } H5F_olist_t; /* PRIVATE PROTOTYPES */ -static size_t H5F_get_objects(const H5F_t *f, unsigned types, size_t max_objs, hid_t *obj_id_list, hbool_t app_ref); +static herr_t H5F_get_objects(const H5F_t *f, unsigned types, size_t max_index, hid_t *obj_id_list, hbool_t app_ref, size_t *obj_id_count_ptr); static int H5F_get_objects_cb(void *obj_ptr, hid_t obj_id, void *key); static H5F_t *H5F_new(H5F_file_t *shared, hid_t fcpl_id, hid_t fapl_id, H5FD_t *lf); @@ -376,11 +376,6 @@ done: * * Programmer: Raymond Lu * Wednesday, Dec 5, 2001 - * Modification: - * Raymond Lu - * 24 September 2008 - * Changed the return value to ssize_t to accommadate - * potential large number of objects. * *------------------------------------------------------------------------- */ @@ -388,18 +383,24 @@ ssize_t H5Fget_obj_count(hid_t file_id, unsigned types) { H5F_t *f = NULL; /* File to query */ - ssize_t ret_value; /* Return value */ + size_t obj_count = 0; /* Number of opened objects */ + ssize_t ret_value; /* Return value */ FUNC_ENTER_API(FAIL) H5TRACE2("Zs", "iIu", file_id, types); + /* Check arguments */ if(file_id != (hid_t)H5F_OBJ_ALL && (NULL == (f = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file id") if(0 == (types & H5F_OBJ_ALL)) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not an object type") - /* H5F_get_obj_count doesn't fail */ - ret_value = (ssize_t)H5F_get_obj_count(f, types, TRUE); + /* Perform the query */ + if(H5F_get_obj_count(f, types, TRUE, &obj_count) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "H5F_get_obj_count failed") + + /* Set the return value */ + ret_value = (ssize_t)obj_count; done: FUNC_LEAVE_API(ret_value) @@ -412,31 +413,30 @@ done: * Purpose: Private function return the number of opened object IDs * (files, datasets, groups, datatypes) in the same file. * - * Return: Non-negative on success; can't fail. + * Return: SUCCEED on success, FAIL on failure. * * Programmer: Raymond Lu * Wednesday, Dec 5, 2001 * - * Modification: - * Raymond Lu - * 24 September 2008 - * Changed the return value to size_t to accommadate - * potential large number of objects. - * *------------------------------------------------------------------------- */ -size_t -H5F_get_obj_count(const H5F_t *f, unsigned types, hbool_t app_ref) +herr_t +H5F_get_obj_count(const H5F_t *f, unsigned types, hbool_t app_ref, size_t *obj_id_count_ptr) { - size_t ret_value; /* Return value */ + herr_t ret_value = SUCCEED; - FUNC_ENTER_NOAPI_NOINIT_NOERR + FUNC_ENTER_NOAPI(FAIL) + + /* Sanity check */ + HDassert(obj_id_count_ptr); - /* H5F_get_objects doesn't fail */ - ret_value = H5F_get_objects(f, types, 0, NULL, app_ref); + /* Perform the query */ + if((ret_value = H5F_get_objects(f, types, 0, NULL, app_ref, obj_id_count_ptr)) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "H5F_get_objects failed") +done: FUNC_LEAVE_NOAPI(ret_value) -} +} /* end H5F_get_obj_count() */ /*------------------------------------------------------------------------- @@ -461,19 +461,25 @@ ssize_t H5Fget_obj_ids(hid_t file_id, unsigned types, size_t max_objs, hid_t *oid_list) { H5F_t *f = NULL; /* File to query */ - ssize_t ret_value; /* Return value */ + size_t obj_id_count = 0; /* Number of open objects */ + ssize_t ret_value; /* Return value */ FUNC_ENTER_API(FAIL) H5TRACE4("Zs", "iIuz*i", file_id, types, max_objs, oid_list); + /* Check arguments */ if(file_id != (hid_t)H5F_OBJ_ALL && (NULL == (f = (H5F_t *)H5I_object_verify(file_id, H5I_FILE)))) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file id") if(0 == (types & H5F_OBJ_ALL)) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not an object type") HDassert(oid_list); - /* H5F_get_objects doesn't fail */ - ret_value = (ssize_t)H5F_get_obj_ids(f, types, max_objs, oid_list, TRUE); + /* Perform the query */ + if(H5F_get_obj_ids(f, types, max_objs, oid_list, TRUE, &obj_id_count) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "H5F_get_obj_ids failed") + + /* Set the return value */ + ret_value = (ssize_t)obj_id_count; done: FUNC_LEAVE_API(ret_value) @@ -490,26 +496,25 @@ done: * Programmer: Raymond Lu * Wednesday, Dec 5, 2001 * - * Modification: - * Raymond Lu - * 24 September 2008 - * Changed the return value and MAX_OBJTS to size_t to accommadate - * potential large number of objects. - * *------------------------------------------------------------------------- */ -size_t -H5F_get_obj_ids(const H5F_t *f, unsigned types, size_t max_objs, hid_t *oid_list, hbool_t app_ref) +herr_t +H5F_get_obj_ids(const H5F_t *f, unsigned types, size_t max_objs, hid_t *oid_list, hbool_t app_ref, size_t *obj_id_count_ptr) { - size_t ret_value; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT_NOERR + FUNC_ENTER_NOAPI(FAIL) + + /* Sanity check */ + HDassert(obj_id_count_ptr); - /* H5F_get_objects doesn't fail */ - ret_value = H5F_get_objects(f, types, max_objs, oid_list, app_ref); + /* Perform the query */ + if((ret_value = H5F_get_objects(f, types, max_objs, oid_list, app_ref, obj_id_count_ptr)) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "H5F_get_objects failed") +done: FUNC_LEAVE_NOAPI(ret_value) -} +} /* end H5F_get_obj_ids() */ /*--------------------------------------------------------------------------- @@ -525,14 +530,18 @@ H5F_get_obj_ids(const H5F_t *f, unsigned types, size_t max_objs, hid_t *oid_list * *--------------------------------------------------------------------------- */ -static size_t -H5F_get_objects(const H5F_t *f, unsigned types, size_t max_index, hid_t *obj_id_list, hbool_t app_ref) +static herr_t +H5F_get_objects(const H5F_t *f, unsigned types, size_t max_index, hid_t *obj_id_list, hbool_t app_ref, size_t *obj_id_count_ptr) { size_t obj_id_count=0; /* Number of open IDs */ H5F_olist_t olist; /* Structure to hold search results */ - size_t ret_value; /* Return value */ + htri_t type_exists; /* Whether objects of a type are open */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT_NOERR + FUNC_ENTER_NOAPI_NOINIT + + /* Sanity check */ + HDassert(obj_id_count_ptr); /* Set up search information */ olist.obj_id_list = (max_index==0 ? NULL : obj_id_list); @@ -550,45 +559,50 @@ H5F_get_objects(const H5F_t *f, unsigned types, size_t max_index, hid_t *obj_id_ olist.file_info.ptr.shared = f ? f->shared : NULL; } /* end else */ - /* Search through file IDs to count the number, and put their - * IDs on the object list. H5I_search returns NULL if no object - * is found, so don't return failure in this function. */ + /* Iterate through file IDs to count the number, and put their + * IDs on the object list. */ if(types & H5F_OBJ_FILE) { olist.obj_type = H5I_FILE; - (void)H5I_search(H5I_FILE, H5F_get_objects_cb, &olist, app_ref); + if(H5I_iterate(H5I_FILE, H5F_get_objects_cb, &olist, app_ref) < 0) + HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed(1)") } /* end if */ /* Search through dataset IDs to count number of datasets, and put their * IDs on the object list */ if(types & H5F_OBJ_DATASET) { olist.obj_type = H5I_DATASET; - (void)H5I_search(H5I_DATASET, H5F_get_objects_cb, &olist, app_ref); - } + if(H5I_iterate(H5I_DATASET, H5F_get_objects_cb, &olist, app_ref) < 0) + HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed(2)") + } /* end if */ /* Search through group IDs to count number of groups, and put their * IDs on the object list */ if(types & H5F_OBJ_GROUP) { olist.obj_type = H5I_GROUP; - (void)H5I_search(H5I_GROUP, H5F_get_objects_cb, &olist, app_ref); - } + if(H5I_iterate(H5I_GROUP, H5F_get_objects_cb, &olist, app_ref) < 0) + HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed(3)") + } /* end if */ /* Search through datatype IDs to count number of named datatypes, and put their * IDs on the object list */ if(types & H5F_OBJ_DATATYPE) { olist.obj_type = H5I_DATATYPE; - (void)H5I_search(H5I_DATATYPE, H5F_get_objects_cb, &olist, app_ref); - } + if(H5I_iterate(H5I_DATATYPE, H5F_get_objects_cb, &olist, app_ref) < 0) + HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed(4)") + } /* end if */ /* Search through attribute IDs to count number of attributes, and put their * IDs on the object list */ if(types & H5F_OBJ_ATTR) { olist.obj_type = H5I_ATTR; - (void)H5I_search(H5I_ATTR, H5F_get_objects_cb, &olist, app_ref); - } + if(H5I_iterate(H5I_ATTR, H5F_get_objects_cb, &olist, app_ref) < 0) + HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed(5)") + } /* end if */ /* Set the number of objects currently open */ - ret_value = obj_id_count; + *obj_id_count_ptr = obj_id_count; +done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5F_get_objects() */ @@ -606,8 +620,6 @@ H5F_get_objects(const H5F_t *f, unsigned types, size_t max_index, hid_t *obj_id_ * Programmer: Raymond Lu * Wednesday, Dec 5, 2001 * - * Modification: - * *------------------------------------------------------------------------- */ static int @@ -639,8 +651,8 @@ H5F_get_objects_cb(void *obj_ptr, hid_t obj_id, void *key) /* Check if we've filled up the array. Return TRUE only if * we have filled up the array. Otherwise return FALSE(RET_VALUE is - * preset to FALSE) because H5I_search needs the return value of FALSE - * to continue searching. */ + * preset to FALSE) because H5I_iterate needs the return value of + * FALSE to continue the iteration. */ if(olist->max_index>0 && olist->list_index>=olist->max_index) HGOTO_DONE(TRUE) /* Indicate that the iterator should stop */ } @@ -704,8 +716,8 @@ H5F_get_objects_cb(void *obj_ptr, hid_t obj_id, void *key) /* Check if we've filled up the array. Return TRUE only if * we have filled up the array. Otherwise return FALSE(RET_VALUE is - * preset to FALSE) because H5I_search needs the return value of FALSE - * to continue searching. */ + * preset to FALSE) because H5I_iterate needs the return value of + * FALSE to continue iterating. */ if(olist->max_index>0 && olist->list_index>=olist->max_index) HGOTO_DONE(TRUE) /* Indicate that the iterator should stop */ } /* end if */ @@ -1792,8 +1804,6 @@ done: * Programmer: Quincey Koziol * Tuesday, July 19, 2005 * - * Modifications: - * *------------------------------------------------------------------------- */ herr_t @@ -1875,27 +1885,36 @@ H5F_try_close(H5F_t *f) if(f->nopen_objs > 0) { size_t obj_count; /* # of open objects */ hid_t objs[128]; /* Array of objects to close */ + herr_t result; /* Local result from obj ID query */ size_t u; /* Local index variable */ /* Get the list of IDs of open dataset, group, & attribute objects */ - while((obj_count = H5F_get_obj_ids(f, H5F_OBJ_LOCAL|H5F_OBJ_DATASET|H5F_OBJ_GROUP|H5F_OBJ_ATTR, (int)(sizeof(objs)/sizeof(objs[0])), objs, FALSE)) != 0) { + while((result = H5F_get_obj_ids(f, H5F_OBJ_LOCAL | H5F_OBJ_DATASET | H5F_OBJ_GROUP | H5F_OBJ_ATTR, (int)(sizeof(objs) / sizeof(objs[0])), objs, FALSE, &obj_count)) <= 0 + && obj_count != 0 ) { + /* Try to close all the open objects in this file */ for(u = 0; u < obj_count; u++) if(H5I_dec_ref(objs[u]) < 0) HGOTO_ERROR(H5E_ATOM, H5E_CLOSEERROR, FAIL, "can't close object") } /* end while */ + if(result < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "H5F_get_obj_ids failed(1)") /* Get the list of IDs of open named datatype objects */ /* (Do this separately from the dataset & attribute IDs, because * they could be using one of the named datatypes and then the * open named datatype ID will get closed twice) */ - while((obj_count = H5F_get_obj_ids(f, H5F_OBJ_LOCAL|H5F_OBJ_DATATYPE, (int)(sizeof(objs)/sizeof(objs[0])), objs, FALSE)) != 0) { + while((result = H5F_get_obj_ids(f, H5F_OBJ_LOCAL | H5F_OBJ_DATATYPE, (int)(sizeof(objs) / sizeof(objs[0])), objs, FALSE, &obj_count)) <= 0 + && obj_count != 0) { + /* Try to close all the open objects in this file */ for(u = 0; u < obj_count; u++) if(H5I_dec_ref(objs[u]) < 0) HGOTO_ERROR(H5E_ATOM, H5E_CLOSEERROR, FAIL, "can't close object") } /* end while */ + if(result < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "H5F_get_obj_ids failed(2)") } /* end if */ } /* end if */ @@ -2558,6 +2577,139 @@ done: /*------------------------------------------------------------------------- + * Function: H5Fget_file_image + * + * Purpose: If a buffer is provided (via the buf_ptr argument) and is + * big enough (size in buf_len argument), load *buf_ptr with + * an image of the open file whose ID is provided in the + * file_id parameter, and return the number of bytes copied + * to the buffer. + * + * If the buffer exists, but is too small to contain an image + * of the indicated file, return a negative number. + * + * Finally, if no buffer is provided, return the size of the + * buffer needed. This value is simply the eoa of the target + * file. + * + * Note that any user block is skipped. + * + * Also note that the function may not be used on files + * opened with either the split/multi file driver or the + * family file driver. + * + * In the former case, the sparse address space makes the + * get file image operation impractical, due to the size of + * the image typically required. + * + * In the case of the family file driver, the problem is + * the driver message in the super block, which will prevent + * the image being opened with any driver other than the + * family file driver -- which negates the purpose of the + * operation. This can be fixed, but no resources for + * this now. + * + * Return: Success: Bytes copied / number of bytes needed. + * Failure: negative value + * + * Programmer: John Mainzer + * 11/15/11 + * + *------------------------------------------------------------------------- + */ +ssize_t +H5Fget_file_image(hid_t file_id, void *buf_ptr, size_t buf_len) +{ + H5F_t *file; /* File object for file ID */ + H5FD_t *fd_ptr; /* file driver */ + haddr_t eoa; /* End of file address */ + ssize_t ret_value; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE3("Zs", "i*xz", file_id, buf_ptr, buf_len); + + /* Check args */ + if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file ID") + if(!file || !file->shared || !file->shared->lf) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "file_id yields invalid file pointer") + fd_ptr = file->shared->lf; + if(!fd_ptr->cls) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "fd_ptr yields invalid class pointer") + + /* the address space used by the split and multi file drivers is not + * a good fit for this call. Since the plan is to depreciate these + * drivers anyway, don't bother to do a "force fit". + * + * The following clause tests for the multi file driver, and fails + * if the supplied file has the multi file driver as its top level + * file driver. However, this test will not work if there is some + * other file driver sitting on top of the multi file driver. + * + * I'm not sure if this is possible at present, but in all likelyhood, + * it will become possible in the future. On the other hand, we may + * remove the split/multi file drivers before then. + * + * I am leaving this solution in for now, but we should review it, + * and improve the solution if necessary. + * + * JRM -- 11/11/22 + */ + if(HDstrcmp(fd_ptr->cls->name, "multi") == 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Not supported for multi file driver.") + + /* While the family file driver is conceptually fully compatible + * with the get file image operation, it sets a file driver message + * in the super block that prevents the image being opened with any + * driver other than the family file driver. Needless to say, this + * rather defeats the purpose of the get file image operation. + * + * While this problem is quire solvable, the required time and + * resources are lacking at present. Hence, for now, we don't + * allow the get file image operation to be perfomed on files + * opened with the family file driver. + * + * Observe that the following test only looks at the top level + * driver, and fails if there is some other driver sitting on to + * of the family file driver. + * + * I don't think this can happen at present, but that may change + * in the future. + * JRM -- 12/21/11 + */ + if(HDstrcmp(fd_ptr->cls->name, "family") == 0) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "Not supported for family file driver.") + + + /* Go get the actual file size */ + if(HADDR_UNDEF == (eoa = H5FD_get_eoa(file->shared->lf, H5FD_MEM_DEFAULT))) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get file size") + + /* set ret_value = to eoa -- will overwrite this if appropriate */ + ret_value = (ssize_t)eoa; + + /* test to see if a buffer was provided -- if not, we are done */ + if(buf_ptr != NULL) { + size_t space_needed; /* size of file image */ + + /* Check for buffer too small */ + if((haddr_t)buf_len < eoa) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "supplied buffer too small") + + space_needed = (size_t)eoa; + + /* read in the file image */ + /* (Note compensation for base address addition in internal routine) */ + if(H5FD_read(fd_ptr, H5AC_ind_dxpl_id, H5FD_MEM_DEFAULT, 0, space_needed, buf_ptr) < 0) + HGOTO_ERROR(H5E_FILE, H5E_READERROR, FAIL, "file image read request failed") + } /* end if */ + +done: + FUNC_LEAVE_API(ret_value) +} /* H5Fget_file_image() */ + + +/*------------------------------------------------------------------------- * Function: H5Fget_mdc_config * * Purpose: Retrieves the current automatic cache resize configuration diff --git a/src/H5FD.c b/src/H5FD.c index ba2bee4..99dd076 100644 --- a/src/H5FD.c +++ b/src/H5FD.c @@ -81,6 +81,10 @@ static herr_t H5FD_pl_copy(void *(*copy_func)(const void *), size_t pl_size, static herr_t H5FD_pl_close(hid_t driver_id, herr_t (*free_func)(void *), void *pl); static herr_t H5FD_free_cls(H5FD_class_t *cls); +static herr_t H5FD_fapl_copy(hid_t driver_id, const void *fapl, void **copied_fapl); +static herr_t H5FD_dxpl_copy(hid_t driver_id, const void *dxpl, void **copied_dxpl); +static int H5FD_query(const H5FD_t *f, unsigned long *flags/*out*/); +static int H5FD_driver_query(const H5FD_class_t *driver, unsigned long *flags/*out*/); /*********************/ /* Package Variables */ @@ -768,17 +772,15 @@ done: * Programmer: Robb Matzke * Tuesday, August 3, 1999 * - * Modifications: - * *------------------------------------------------------------------------- */ -herr_t +static herr_t H5FD_fapl_copy(hid_t driver_id, const void *old_fapl, void **copied_fapl) { H5FD_class_t *driver; herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI(FAIL) + FUNC_ENTER_NOAPI_NOINIT /* Check args */ if(NULL == (driver = (H5FD_class_t *)H5I_object(driver_id))) @@ -889,17 +891,15 @@ done: * Programmer: Robb Matzke * Tuesday, August 3, 1999 * - * Modifications: - * *------------------------------------------------------------------------- */ -herr_t +static herr_t H5FD_dxpl_copy(hid_t driver_id, const void *old_dxpl, void **copied_dxpl) { H5FD_class_t *driver; herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI(FAIL) + FUNC_ENTER_NOAPI_NOINIT /* Check args */ if(NULL == (driver = (H5FD_class_t *)H5I_object(driver_id))) @@ -1057,6 +1057,8 @@ H5FD_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr) H5FD_t *file = NULL; /* VFD file struct */ hid_t driver_id = -1; /* VFD ID */ H5P_genplist_t *plist; /* Property list pointer */ + unsigned long driver_flags = 0; /* File-inspecific driver feature flags */ + H5FD_file_image_info_t file_image_info; /* Initial file image */ H5FD_t *ret_value; /* Return value */ FUNC_ENTER_NOAPI(NULL) @@ -1079,6 +1081,19 @@ H5FD_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr) if(NULL == driver->open) HGOTO_ERROR(H5E_VFL, H5E_UNSUPPORTED, NULL, "file driver has no `open' method") + /* Query driver flag */ + H5FD_driver_query(driver, &driver_flags); + + /* Get initial file image info */ + if(H5P_get(plist, H5F_ACS_FILE_IMAGE_INFO_NAME, &file_image_info) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get file image info") + + /* If an image is provided, make sure the driver supports this feature */ + HDassert(((file_image_info.buffer != NULL) && (file_image_info.size > 0)) || + ((file_image_info.buffer == NULL) && (file_image_info.size == 0))); + if((file_image_info.buffer != NULL) && !(driver_flags & H5FD_FEAT_ALLOW_FILE_IMAGE)) + HGOTO_ERROR(H5E_VFL, H5E_UNSUPPORTED, NULL, "file image set, but not supported.") + /* Dispatch to file driver */ if(HADDR_UNDEF == maxaddr) maxaddr = driver->maxaddr; @@ -1336,19 +1351,17 @@ done: * Programmer: Quincey Koziol * Friday, August 25, 2000 * - * Modifications: - * *------------------------------------------------------------------------- */ -int +static int H5FD_query(const H5FD_t *f, unsigned long *flags/*out*/) { - int ret_value=0; + int ret_value = 0; /* Return value */ - FUNC_ENTER_NOAPI(FAIL) + FUNC_ENTER_NOAPI_NOINIT - assert(f); - assert(flags); + HDassert(f); + HDassert(flags); /* Check for query driver and call it */ if(f->cls->query) @@ -1358,7 +1371,44 @@ H5FD_query(const H5FD_t *f, unsigned long *flags/*out*/) done: FUNC_LEAVE_NOAPI(ret_value) -} +} /* end H5FD_query() */ + + +/*------------------------------------------------------------------------- +* Function: H5FD_driver_query +* +* Purpose: Similar to H5FD_query(), but intended for cases when we don't +* have a file available (e.g. before one is opened). Since we +* can't use the file to get the driver, the driver is passed in +* as a parameter. +* +* Return: Success: non-negative +* Failure: negative +* +* Programmer: Jacob Gruber +* Wednesday, August 17, 2011 +* +*------------------------------------------------------------------------- +*/ +static int +H5FD_driver_query(const H5FD_class_t *driver, unsigned long *flags/*out*/) +{ + int ret_value = 0; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(driver); + HDassert(flags); + + /* Check for the driver to query and then query it */ + if(driver->query) + ret_value = (driver->query)(NULL, flags); + else + *flags = 0; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_driver_query() */ /*------------------------------------------------------------------------- diff --git a/src/H5FDcore.c b/src/H5FDcore.c index 68b9dfc..6f9a41a 100644 --- a/src/H5FDcore.c +++ b/src/H5FDcore.c @@ -101,6 +101,7 @@ typedef struct H5FD_core_t { HANDLE hFile; /* Native windows file handle */ #endif /* H5_HAVE_WIN32_API */ hbool_t dirty; /*changes not saved? */ + H5FD_file_image_callbacks_t fi_callbacks; /* file image callbacks */ } H5FD_core_t; /* Driver-specific file access properties */ @@ -408,9 +409,10 @@ H5FD_core_open(const char *name, unsigned flags, hid_t fapl_id, #ifdef H5_HAVE_WIN32_API struct _BY_HANDLE_FILE_INFORMATION fileinfo; #endif - h5_stat_t sb; - int fd=-1; - H5FD_t *ret_value; + h5_stat_t sb; + int fd=-1; + H5FD_file_image_info_t file_image_info; + H5FD_t *ret_value; FUNC_ENTER_NOAPI_NOINIT @@ -432,10 +434,32 @@ H5FD_core_open(const char *name, unsigned flags, hid_t fapl_id, if(H5F_ACC_CREAT & flags) o_flags |= O_CREAT; if(H5F_ACC_EXCL & flags) o_flags |= O_EXCL; + /* Retrieve initial file image info */ + if(H5P_get(plist, H5F_ACS_FILE_IMAGE_INFO_NAME, &file_image_info) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get initial file image info") + + /* If the file image exists and this is an open, make sure the file doesn't exist */ + HDassert(((file_image_info.buffer != NULL) && (file_image_info.size > 0)) || + ((file_image_info.buffer == NULL) && (file_image_info.size == 0))); + if((file_image_info.buffer != NULL) && !(H5F_ACC_CREAT & flags)) { + if(HDopen(name, o_flags, 0666) >= 0) + HGOTO_ERROR(H5E_FILE, H5E_FILEEXISTS, NULL, "file already exists") + + /* If backing store is requested, create and stat the file + * Note: We are forcing the O_CREAT flag here, even though this is + * technically an open. + */ + if(fa->backing_store) { + if((fd = HDopen(name, o_flags | O_CREAT, 0666)) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to create file") + if(HDfstat(fd, &sb) < 0) + HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, NULL, "unable to fstat file") + } /* end if */ + } /* end if */ /* Open backing store, and get stat() from file. The only case that backing * store is off is when the backing_store flag is off and H5F_ACC_CREAT is * on. */ - if(fa->backing_store || !(H5F_ACC_CREAT & flags)) { + else if(fa->backing_store || !(H5F_ACC_CREAT & flags)) { if(fa && (fd = HDopen(name, o_flags, 0666)) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to open file") if(HDfstat(fd, &sb) < 0) @@ -458,6 +482,9 @@ H5FD_core_open(const char *name, unsigned flags, hid_t fapl_id, /* If save data in backing store. */ file->backing_store = fa->backing_store; + /* Save file image callbacks */ + file->fi_callbacks = file_image_info.callbacks; + if(fd >= 0) { /* Retrieve information for determining uniqueness of file */ #ifdef H5_HAVE_WIN32_API @@ -489,51 +516,70 @@ H5FD_core_open(const char *name, unsigned flags, hid_t fapl_id, size_t size; /* Retrieve file size */ - size = (size_t)sb.st_size; + if(file_image_info.buffer && file_image_info.size > 0) + size = file_image_info.size; + else + size = (size_t)sb.st_size; /* Check if we should allocate the memory buffer and read in existing data */ if(size) { - /* Allocate memory for the file's data */ - if(NULL == (file->mem = (unsigned char*)H5MM_malloc(size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate memory block") + /* Allocate memory for the file's data, using the file image callback if available. */ + if(file->fi_callbacks.image_malloc) { + if(NULL == (file->mem = (unsigned char*)file->fi_callbacks.image_malloc(size, H5FD_FILE_IMAGE_OP_FILE_OPEN, file->fi_callbacks.udata))) + HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, NULL, "image malloc callback failed") + } /* end if */ + else { + if(NULL == (file->mem = (unsigned char*)H5MM_malloc(size))) + HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, NULL, "unable to allocate memory block") + } /* end else */ /* Set up data structures */ file->eof = size; - /* Read in existing data, being careful of interrupted system calls, - * partial results, and the end of the file. - */ - while(size > 0) { - - h5_core_io_t bytes_in = 0; /* # of bytes to read */ - h5_core_io_ret_t bytes_read = -1; /* # of bytes actually read */ - - /* Trying to read more bytes than the return type can handle is - * undefined behavior in POSIX. - */ - if(size > H5_CORE_MAX_IO_BYTES_g) - bytes_in = H5_CORE_MAX_IO_BYTES_g; - else - bytes_in = (h5_core_io_t)size; - - do { - bytes_read = HDread(file->fd, file->mem, bytes_in); - } while(-1 == bytes_read && EINTR == errno); - - if(-1 == bytes_read) { /* error */ - int myerrno = errno; - time_t mytime = HDtime(NULL); - HDoff_t myoffset = HDlseek(file->fd, (HDoff_t)0, SEEK_CUR); - - HGOTO_ERROR(H5E_IO, H5E_READERROR, NULL, "file read failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, error message = '%s', file->mem = %p, size = %lu, offset = %llu", HDctime(&mytime), file->name, file->fd, myerrno, HDstrerror(myerrno), file->mem, (unsigned long)size, (unsigned long long)myoffset); + /* If there is an initial file image, copy it, using the callback if possible */ + if(file_image_info.buffer && file_image_info.size > 0) { + if(file->fi_callbacks.image_memcpy) { + if(file->mem != file->fi_callbacks.image_memcpy(file->mem, file_image_info.buffer, size, H5FD_FILE_IMAGE_OP_FILE_OPEN, file->fi_callbacks.udata)) + HGOTO_ERROR(H5E_FILE, H5E_CANTCOPY, NULL, "image_memcpy callback failed") } /* end if */ - - HDassert(bytes_read >= 0); - HDassert((size_t)bytes_read <= size); - - size -= (size_t)bytes_read; - - } /* end while */ + else + HDmemcpy(file->mem, file_image_info.buffer, size); + } /* end if */ + /* Read in existing data from the file if there is no image */ + else { + /* Read in existing data, being careful of interrupted system calls, + * partial results, and the end of the file. + */ + while(size > 0) { + h5_core_io_t bytes_in = 0; /* # of bytes to read */ + h5_core_io_ret_t bytes_read = -1; /* # of bytes actually read */ + + /* Trying to read more bytes than the return type can handle is + * undefined behavior in POSIX. + */ + if(size > H5_CORE_MAX_IO_BYTES_g) + bytes_in = H5_CORE_MAX_IO_BYTES_g; + else + bytes_in = (h5_core_io_t)size; + + do { + bytes_read = HDread(file->fd, file->mem, bytes_in); + } while(-1 == bytes_read && EINTR == errno); + + if(-1 == bytes_read) { /* error */ + int myerrno = errno; + time_t mytime = HDtime(NULL); + HDoff_t myoffset = HDlseek(file->fd, (HDoff_t)0, SEEK_CUR); + + HGOTO_ERROR(H5E_IO, H5E_READERROR, NULL, "file read failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, error message = '%s', file->mem = %p, size = %lu, offset = %llu", HDctime(&mytime), file->name, file->fd, myerrno, HDstrerror(myerrno), file->mem, (unsigned long)size, (unsigned long long)myoffset); + } /* end if */ + + HDassert(bytes_read >= 0); + HDassert((size_t)bytes_read <= size); + + size -= (size_t)bytes_read; + } /* end while */ + } /* end else */ } /* end if */ } /* end if */ @@ -576,8 +622,15 @@ H5FD_core_close(H5FD_t *_file) HDclose(file->fd); if(file->name) H5MM_xfree(file->name); - if(file->mem) - H5MM_xfree(file->mem); + if(file->mem) { + /* Use image callback if available */ + if(file->fi_callbacks.image_free) { + if(file->fi_callbacks.image_free(file->mem, H5FD_FILE_IMAGE_OP_FILE_CLOSE, file->fi_callbacks.udata) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "image_free callback failed") + } /* end if */ + else + H5MM_xfree(file->mem); + } /* end if */ HDmemset(file, 0, sizeof(H5FD_core_t)); H5MM_xfree(file); @@ -698,9 +751,11 @@ H5FD_core_query(const H5FD_t * _file, unsigned long *flags /* out */) *flags |= H5FD_FEAT_ACCUMULATE_METADATA; /* OK to accumulate metadata for faster writes */ *flags |= H5FD_FEAT_DATA_SIEVE; /* OK to perform data sieving for faster raw data reads & writes */ *flags |= H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */ + *flags |= H5FD_FEAT_ALLOW_FILE_IMAGE; /* OK to use file image feature with this VFD */ + *flags |= H5FD_FEAT_CAN_USE_FILE_IMAGE_CALLBACKS; /* OK to use file image callbacks with this VFD */ /* If the backing store is open, a POSIX file handle is available */ - if(file->fd >= 0 && file->backing_store) + if(file && file->fd >= 0 && file->backing_store) *flags |= H5FD_FEAT_POSIX_COMPAT_HANDLE; /* VFD handle is POSIX I/O call compatible */ } /* end if */ @@ -974,9 +1029,16 @@ H5FD_core_write(H5FD_t *_file, H5FD_mem_t UNUSED type, hid_t UNUSED dxpl_id, had if((addr + size) % file->increment) new_eof += file->increment; - /* (Re)allocate memory for the file buffer */ - if(NULL == (x = (unsigned char *)H5MM_realloc(file->mem, new_eof))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory block of %llu bytes", (unsigned long long)new_eof) + /* (Re)allocate memory for the file buffer, using callbacks if available */ + if(file->fi_callbacks.image_realloc) { + if(NULL == (x = (unsigned char *)file->fi_callbacks.image_realloc(file->mem, new_eof, H5FD_FILE_IMAGE_OP_FILE_RESIZE, file->fi_callbacks.udata))) + HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "unable to allocate memory block of %llu bytes with callback", (unsigned long long)new_eof) + } /* end if */ + else { + if(NULL == (x = (unsigned char *)H5MM_realloc(file->mem, new_eof))) + HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "unable to allocate memory block of %llu bytes", (unsigned long long)new_eof) + } /* end else */ + #ifdef H5_CLEAR_MEMORY HDmemset(x + file->eof, 0, (size_t)(new_eof - file->eof)); #endif /* H5_CLEAR_MEMORY */ @@ -987,6 +1049,8 @@ HDmemset(x + file->eof, 0, (size_t)(new_eof - file->eof)); /* Write from BUF to memory */ HDmemcpy(file->mem + addr, buf, size); + + /* Mark memory buffer as modified */ file->dirty = TRUE; done: @@ -1073,8 +1137,30 @@ done: * Purpose: Makes sure that the true file size is the same (or larger) * than the end-of-address. * - * Return: Success: Non-negative - * Failure: Negative + * Addendum -- 12/2/11 + * For file images opened with the core file driver, it is + * necessary that we avoid reallocating the core file driver's + * buffer uneccessarily. + * + * To this end, I have made the following functional changes + * to this function. + * + * If we are closing, and there is no backing store, this + * function becomes a no-op. + * + * If we are closing, and there is backing store, we set the + * eof to equal the eoa, and truncate the backing store to + * the new eof + * + * If we are not closing, we realloc the buffer to size equal + * to the smallest multiple of the allocation increment that + * equals or exceeds the eoa and set the eof accordingly. + * Note that we no longer truncate the backing store to the + * new eof if applicable. + * -- JRM + * + * Return: Success: Non-negative + * Failure: Negative * * Programmer: Quincey Koziol * Tuesday, October 7, 2008 @@ -1083,7 +1169,7 @@ done: */ /* ARGSUSED */ static herr_t -H5FD_core_truncate(H5FD_t *_file, hid_t UNUSED dxpl_id, hbool_t UNUSED closing) +H5FD_core_truncate(H5FD_t *_file, hid_t UNUSED dxpl_id, hbool_t closing) { H5FD_core_t *file = (H5FD_core_t*)_file; size_t new_eof; /* New size of memory buffer */ @@ -1093,68 +1179,81 @@ H5FD_core_truncate(H5FD_t *_file, hid_t UNUSED dxpl_id, hbool_t UNUSED closing) HDassert(file); - /* Determine new size of memory buffer */ - H5_ASSIGN_OVERFLOW(new_eof, file->increment * (file->eoa / file->increment), hsize_t, size_t); - if(file->eoa % file->increment) - new_eof += file->increment; - - /* Extend the file to make sure it's large enough */ - if(!H5F_addr_eq(file->eof, (haddr_t)new_eof)) { - unsigned char *x; /* Pointer to new buffer for file data */ + /* if we are closing and not using backing store, do nothing */ + if(!closing || file->backing_store) { + if(closing) /* set eof to eoa */ + new_eof = file->eoa; + else { /* set eof to smallest multiple of increment that exceeds eoa */ + /* Determine new size of memory buffer */ + H5_ASSIGN_OVERFLOW(new_eof, file->increment * (file->eoa / file->increment), hsize_t, size_t); + if(file->eoa % file->increment) + new_eof += file->increment; + } /* end else */ + + /* Extend the file to make sure it's large enough */ + if(!H5F_addr_eq(file->eof, (haddr_t)new_eof)) { + unsigned char *x; /* Pointer to new buffer for file data */ + + /* (Re)allocate memory for the file buffer, using callback if available */ + if(file->fi_callbacks.image_realloc) { + if(NULL == (x = (unsigned char *)file->fi_callbacks.image_realloc(file->mem, new_eof, H5FD_FILE_IMAGE_OP_FILE_RESIZE, file->fi_callbacks.udata))) + HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "unable to allocate memory block with callback") + } /* end if */ + else { + if(NULL == (x = (unsigned char *)H5MM_realloc(file->mem, new_eof))) + HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "unable to allocate memory block") + } /* end else */ - /* (Re)allocate memory for the file buffer */ - if(NULL == (x = (unsigned char *)H5MM_realloc(file->mem, new_eof))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory block") #ifdef H5_CLEAR_MEMORY -if(file->eof < new_eof) - HDmemset(x + file->eof, 0, (size_t)(new_eof - file->eof)); + if(file->eof < new_eof) + HDmemset(x + file->eof, 0, (size_t)(new_eof - file->eof)); #endif /* H5_CLEAR_MEMORY */ - file->mem = x; + file->mem = x; - /* Update backing store, if using it */ - if(file->fd >= 0 && file->backing_store) { + /* Update backing store, if using it and if closing */ + if(closing && (file->fd >= 0) && file->backing_store) { #ifdef H5_HAVE_WIN32_API - LARGE_INTEGER li; /* 64-bit (union) integer for SetFilePointer() call */ - DWORD dwPtrLow; /* Low-order pointer bits from SetFilePointer() - * Only used as an error code here. - */ - DWORD dwError; /* DWORD error code from GetLastError() */ - BOOL bError; /* Boolean error flag */ - - /* Windows uses this odd QuadPart union for 32/64-bit portability */ - li.QuadPart = (__int64)file->eoa; - - /* Extend the file to make sure it's large enough. - * - * Since INVALID_SET_FILE_POINTER can technically be a valid return value - * from SetFilePointer(), we also need to check GetLastError(). - */ - dwPtrLow = SetFilePointer(file->hFile, li.LowPart, &li.HighPart, FILE_BEGIN); - if(INVALID_SET_FILE_POINTER == dwPtrLow) { - dwError = GetLastError(); - if(dwError != NO_ERROR ) - HGOTO_ERROR(H5E_FILE, H5E_FILEOPEN, FAIL, "unable to set file pointer") - } - - bError = SetEndOfFile(file->hFile); - if(0 == bError) - HGOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly") + LARGE_INTEGER li; /* 64-bit (union) integer for SetFilePointer() call */ + DWORD dwPtrLow; /* Low-order pointer bits from SetFilePointer() + * Only used as an error code here. + */ + DWORD dwError; /* DWORD error code from GetLastError() */ + BOOL bError; /* Boolean error flag */ + + /* Windows uses this odd QuadPart union for 32/64-bit portability */ + li.QuadPart = (__int64)file->eoa; + + /* Extend the file to make sure it's large enough. + * + * Since INVALID_SET_FILE_POINTER can technically be a valid return value + * from SetFilePointer(), we also need to check GetLastError(). + */ + dwPtrLow = SetFilePointer(file->hFile, li.LowPart, &li.HighPart, FILE_BEGIN); + if(INVALID_SET_FILE_POINTER == dwPtrLow) { + dwError = GetLastError(); + if(dwError != NO_ERROR ) + HGOTO_ERROR(H5E_FILE, H5E_FILEOPEN, FAIL, "unable to set file pointer") + } + + bError = SetEndOfFile(file->hFile); + if(0 == bError) + HGOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly") #else /* H5_HAVE_WIN32_API */ #ifdef H5_VMS - /* Reset seek offset to the beginning of the file, so that the file isn't - * re-extended later. This may happen on Open VMS. */ - if(-1 == HDlseek(file->fd, (HDoff_t)0, SEEK_SET)) - HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position") + /* Reset seek offset to the beginning of the file, so that the file isn't + * re-extended later. This may happen on Open VMS. */ + if(-1 == HDlseek(file->fd, (HDoff_t)0, SEEK_SET)) + HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position") #endif - if(-1 == HDftruncate(file->fd, (HDoff_t)new_eof)) - HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly") + if(-1 == HDftruncate(file->fd, (HDoff_t)new_eof)) + HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly") #endif /* H5_HAVE_WIN32_API */ + } /* end if */ + /* Update the eof value */ + file->eof = new_eof; } /* end if */ - - /* Update the eof value */ - file->eof = new_eof; - } /* end if */ + } /* end if(file->eof < file->eoa) */ done: FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5FDfamily.c b/src/H5FDfamily.c index 8b6b819..736efb8 100644 --- a/src/H5FDfamily.c +++ b/src/H5FDfamily.c @@ -996,7 +996,7 @@ H5FD_family_query(const H5FD_t * _file, unsigned long *flags /* out */) *flags |= H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */ /* Check for flags that are set by h5repart */ - if(file->repart_members) + if(file && file->repart_members) *flags |= H5FD_FEAT_DIRTY_SBLK_LOAD; /* Mark the superblock dirty when it is loaded (so the family member sizes are rewritten) */ } /* end if */ diff --git a/src/H5FDlog.c b/src/H5FDlog.c index 8bb2392..e3d67359 100644 --- a/src/H5FDlog.c +++ b/src/H5FDlog.c @@ -916,7 +916,7 @@ H5FD_log_query(const H5FD_t *_file, unsigned long *flags /* out */) *flags |= H5FD_FEAT_POSIX_COMPAT_HANDLE; /* VFD handle is POSIX I/O call compatible */ /* Check for flags that are set by h5repart */ - if(file->fam_to_sec2) + if(file && file->fam_to_sec2) *flags |= H5FD_FEAT_IGNORE_DRVRINFO; /* Ignore the driver info when file is opened (which eliminates it) */ } /* end if */ diff --git a/src/H5FDprivate.h b/src/H5FDprivate.h index 4f7d059..9c19562 100644 --- a/src/H5FDprivate.h +++ b/src/H5FDprivate.h @@ -52,6 +52,29 @@ typedef enum { } H5FD_file_op_t; +/* Define structure to hold initial file image and other relevant information */ +typedef struct { + void *buffer; + size_t size; + H5FD_file_image_callbacks_t callbacks; +} H5FD_file_image_info_t; + +/* Define default file image info */ +#define H5FD_DEFAULT_FILE_IMAGE_INFO { \ + /* file image buffer */ NULL, \ + /* buffer size */ 0, \ + { /* Callbacks */ \ + /* image_malloc */ NULL, \ + /* image_memcpy */ NULL, \ + /* image_realloc */ NULL, \ + /* image_free */ NULL, \ + /* udata_copy */ NULL, \ + /* udata_free */ NULL, \ + /* udata */ NULL, \ + } \ +} + + /*****************************/ /* Library Private Variables */ /*****************************/ @@ -72,17 +95,14 @@ H5_DLL herr_t H5FD_sb_encode(H5FD_t *file, char *name/*out*/, uint8_t *buf); H5_DLL herr_t H5FD_sb_decode(H5FD_t *file, const char *name, const uint8_t *buf); H5_DLL void *H5FD_fapl_get(H5FD_t *file); H5_DLL herr_t H5FD_fapl_open(struct H5P_genplist_t *plist, hid_t driver_id, const void *driver_info); -H5_DLL herr_t H5FD_fapl_copy(hid_t driver_id, const void *fapl, void **copied_fapl); H5_DLL herr_t H5FD_fapl_close(hid_t driver_id, void *fapl); H5_DLL herr_t H5FD_dxpl_open(struct H5P_genplist_t *plist, hid_t driver_id, const void *driver_info); -H5_DLL herr_t H5FD_dxpl_copy(hid_t driver_id, const void *dxpl, void **copied_dxpl); H5_DLL herr_t H5FD_dxpl_close(hid_t driver_id, void *dxpl); H5_DLL hid_t H5FD_register(const void *cls, size_t size, hbool_t app_ref); H5_DLL H5FD_t *H5FD_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr); H5_DLL herr_t H5FD_close(H5FD_t *file); H5_DLL int H5FD_cmp(const H5FD_t *f1, const H5FD_t *f2); -H5_DLL int H5FD_query(const H5FD_t *f, unsigned long *flags/*out*/); H5_DLL haddr_t H5FD_alloc(H5FD_t *file, hid_t dxpl_id, H5FD_mem_t type, struct H5F_t *f, hsize_t size, haddr_t *align_addr, hsize_t *align_size); H5_DLL herr_t H5FD_free(H5FD_t *file, hid_t dxpl_id, H5FD_mem_t type, struct H5F_t *f, diff --git a/src/H5FDpublic.h b/src/H5FDpublic.h index cd6c964..0c5605c 100644 --- a/src/H5FDpublic.h +++ b/src/H5FDpublic.h @@ -177,6 +177,18 @@ typedef enum H5F_mem_t H5FD_mem_t; * of type 'int' and is compatible with POSIX I/O calls. */ #define H5FD_FEAT_POSIX_COMPAT_HANDLE 0x00000080 + /* + * Defining the H5FD_FEAT_ALLOW_FILE_IMAGE for a VFL driver means that + * the driver is able to use a file image in the fapl as the initial + * contents of a file. + */ +#define H5FD_FEAT_ALLOW_FILE_IMAGE 0x00000400 + /* + * Defining the H5FD_FEAT_CAN_USE_FILE_IMAGE_CALLBACKS for a VFL driver + * means that the driver is able to use callbacks to make a copy of the + * image to store in memory. + */ +#define H5FD_FEAT_CAN_USE_FILE_IMAGE_CALLBACKS 0x00000800 /* Forward declaration */ @@ -246,6 +258,33 @@ struct H5FD_t { hsize_t alignment; /* Allocation alignment */ }; +/* Define enum for the source of file image callbacks */ +typedef enum { + H5FD_FILE_IMAGE_OP_NO_OP, + H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET, + H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY, + H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET, + H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE, + H5FD_FILE_IMAGE_OP_FILE_OPEN, + H5FD_FILE_IMAGE_OP_FILE_RESIZE, + H5FD_FILE_IMAGE_OP_FILE_CLOSE, +} H5FD_file_image_op_t; + +/* Define structure to hold file image callbacks */ +typedef struct { + void *(*image_malloc)(size_t size, H5FD_file_image_op_t file_image_op, + void *udata); + void *(*image_memcpy)(void *dest, const void *src, size_t size, + H5FD_file_image_op_t file_image_op, void *udata); + void *(*image_realloc)(void *ptr, size_t size, + H5FD_file_image_op_t file_image_op, void *udata); + herr_t (*image_free)(void *ptr, H5FD_file_image_op_t file_image_op, + void *udata); + void *(*udata_copy)(void *udata); + herr_t (*udata_free)(void *udata); + void *udata; +} H5FD_file_image_callbacks_t; + #ifdef __cplusplus extern "C" { #endif diff --git a/src/H5FDsec2.c b/src/H5FDsec2.c index c3a25c9..868d4a4 100644 --- a/src/H5FDsec2.c +++ b/src/H5FDsec2.c @@ -558,7 +558,7 @@ H5FD_sec2_query(const H5FD_t *_file, unsigned long *flags /* out */) *flags |= H5FD_FEAT_POSIX_COMPAT_HANDLE; /* VFD handle is POSIX I/O call compatible */ /* Check for flags that are set by h5repart */ - if(file->fam_to_sec2) + if(file && file->fam_to_sec2) *flags |= H5FD_FEAT_IGNORE_DRVRINFO; /* Ignore the driver info when file is opened (which eliminates it) */ } /* end if */ diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h index f659491..b0aaeec 100644 --- a/src/H5Fprivate.h +++ b/src/H5Fprivate.h @@ -415,6 +415,7 @@ typedef struct H5F_blk_aggr_t H5F_blk_aggr_t; #define H5F_ACS_LATEST_FORMAT_NAME "latest_format" /* 'Use latest format version' flag */ #define H5F_ACS_WANT_POSIX_FD_NAME "want_posix_fd" /* Internal: query the file descriptor from the core VFD, instead of the memory address */ #define H5F_ACS_EFC_SIZE_NAME "efc_size" /* Size of external file cache */ +#define H5F_ACS_FILE_IMAGE_INFO_NAME "file_image_info" /* struct containing initial file image and callback info */ /* ======================== File Mount properties ====================*/ #define H5F_MNT_SYM_LOCAL_NAME "local" /* Whether absolute symlinks local to file. */ @@ -516,8 +517,8 @@ H5_DLL H5F_t *H5F_get_parent(const H5F_t *f); H5_DLL unsigned H5F_get_nmounts(const H5F_t *f); H5_DLL hid_t H5F_get_access_plist(H5F_t *f, hbool_t app_ref); H5_DLL hid_t H5F_get_id(H5F_t *file, hbool_t app_ref); -H5_DLL size_t H5F_get_obj_count(const H5F_t *f, unsigned types, hbool_t app_ref); -H5_DLL size_t H5F_get_obj_ids(const H5F_t *f, unsigned types, size_t max_objs, hid_t *obj_id_list, hbool_t app_ref); +H5_DLL herr_t H5F_get_obj_count(const H5F_t *f, unsigned types, hbool_t app_ref, size_t *obj_id_count_ptr); +H5_DLL herr_t H5F_get_obj_ids(const H5F_t *f, unsigned types, size_t max_objs, hid_t *oid_list, hbool_t app_ref, size_t *obj_id_count_ptr); /* Functions than retrieve values set/cached from the superblock/FCPL */ H5_DLL haddr_t H5F_get_base_addr(const H5F_t *f); diff --git a/src/H5Fpublic.h b/src/H5Fpublic.h index 454e43a..8466a26 100644 --- a/src/H5Fpublic.h +++ b/src/H5Fpublic.h @@ -169,6 +169,7 @@ H5_DLL herr_t H5Fmount(hid_t loc, const char *name, hid_t child, hid_t plist); H5_DLL herr_t H5Funmount(hid_t loc, const char *name); H5_DLL hssize_t H5Fget_freespace(hid_t file_id); H5_DLL herr_t H5Fget_filesize(hid_t file_id, hsize_t *size); +H5_DLL ssize_t H5Fget_file_image(hid_t file_id, void * buf_ptr, size_t buf_len); H5_DLL herr_t H5Fget_mdc_config(hid_t file_id, H5AC_cache_config_t * config_ptr); H5_DLL herr_t H5Fset_mdc_config(hid_t file_id, diff --git a/src/H5Gname.c b/src/H5Gname.c index 25639f2d..e925313 100644 --- a/src/H5Gname.c +++ b/src/H5Gname.c @@ -782,7 +782,7 @@ done: /*------------------------------------------------------------------------- * Function: H5G_name_replace_cb * - * Purpose: H5I_search callback function to replace group entry names + * Purpose: H5I_iterate callback function to replace group entry names * * Return: Success: 0, Failure: -1 * @@ -1166,15 +1166,18 @@ H5G_name_replace(const H5O_link_t *lnk, H5G_names_op_t op, H5F_t *src_file, /* Search through group IDs */ if(search_group) - H5I_search(H5I_GROUP, H5G_name_replace_cb, &names, FALSE); + if(H5I_iterate(H5I_GROUP, H5G_name_replace_cb, &names, FALSE) < 0) + HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over groups") /* Search through dataset IDs */ if(search_dataset) - H5I_search(H5I_DATASET, H5G_name_replace_cb, &names, FALSE); + if(H5I_iterate(H5I_DATASET, H5G_name_replace_cb, &names, FALSE) < 0) + HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over datasets") /* Search through datatype IDs */ if(search_datatype) - H5I_search(H5I_DATATYPE, H5G_name_replace_cb, &names, FALSE); + if(H5I_iterate(H5I_DATATYPE, H5G_name_replace_cb, &names, FALSE) < 0) + HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over datatypes") } /* end if */ } /* end if */ diff --git a/src/H5I.c b/src/H5I.c index 13a07f9..ce81f3c 100644 --- a/src/H5I.c +++ b/src/H5I.c @@ -115,6 +115,11 @@ typedef struct { H5I_id_info_t **id_list; /*pointer to an array of ptrs to IDs */ } H5I_id_type_t; +typedef struct { + H5I_search_func_t app_cb; /* Application's callback routine */ + void *app_key; /* Application's "key" (user data) */ + void *ret_obj; /* Object to return */ +} H5I_search_ud_t; /*-------------------- Locally scoped variables -----------------------------*/ @@ -134,6 +139,7 @@ H5FL_DEFINE_STATIC(H5I_id_info_t); /*--------------------- Local function prototypes ---------------------------*/ static H5I_id_info_t *H5I_find_id(hid_t id); +static int H5I_search_cb(void *obj, hid_t id, void *udata); #ifdef H5I_DEBUG_OUTPUT static herr_t H5I_debug(H5I_type_t type); #endif /* H5I_DEBUG_OUTPUT */ @@ -1978,6 +1984,40 @@ done: /*------------------------------------------------------------------------- + * Function: H5I_search_cb + * + * Purpose: Callback routine for H5Isearch, when it calls H5I_iterate. + * Calls "user" callback search function, and then sets return + * value, based on the result of that callback. + * + * Return: Success: The first object in the type for which FUNC + * returns non-zero. NULL if FUNC returned zero + * for every object in the type. + * Failure: NULL + * + * Programmer: Quincey Koziol + * Friday, March 30, 2012 + * + *------------------------------------------------------------------------- + */ +static int +H5I_search_cb(void *obj, hid_t id, void *_udata) +{ + H5I_search_ud_t *udata = (H5I_search_ud_t *)_udata; /* User data for callback */ + int ret_value; /* Callback return value */ + + FUNC_ENTER_NOAPI_NOINIT + + ret_value = (*udata->app_cb)(obj, id, udata->app_key); + if(ret_value > 0) + udata->ret_obj = obj; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5I_search_cb() */ + + +/*------------------------------------------------------------------------- * Function: H5Isearch * * Purpose: Apply function FUNC to each member of type TYPE and return a @@ -2004,14 +2044,27 @@ done: void * H5Isearch(H5I_type_t type, H5I_search_func_t func, void *key) { - void * ret_value; /* Return value */ + H5I_search_ud_t udata; /* Context for iteration */ + void *ret_value; /* Return value */ FUNC_ENTER_API(NULL) + /* Check arguments */ if(H5I_IS_LIB_TYPE(type)) HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, NULL, "cannot call public function on library type") - ret_value = H5I_search(type, func, key, TRUE); + /* Set up udata struct */ + udata.app_cb = func; + udata.app_key = key; + udata.ret_obj = NULL; + + /* Note that H5I_iterate returns an error code. We ignore it + * here, as we can't do anything with it without revising the API. + */ + H5I_iterate(type, H5I_search_cb, &udata, TRUE); + + /* Set return value */ + ret_value = udata.ret_obj; done: FUNC_LEAVE_API(ret_value) @@ -2019,62 +2072,71 @@ done: /*------------------------------------------------------------------------- - * Function: H5I_search + * Function: H5I_iterate * - * Purpose: Apply function FUNC to each member of type TYPE and return a - * pointer to the first object for which FUNC returns non-zero. - * The FUNC should take a pointer to the object and the KEY as - * arguments and return non-zero to terminate the search (zero - * to continue). + * Purpose: Apply function FUNC to each member of type TYPE (with + * non-zero application reference count if app_ref is TRUE). + * Stop if FUNC returns a non zero value (i.e. anything + * other than H5_ITER_CONT). * - * Limitation: Currently there is no way to start searching from where a - * previous search left off. + * If FUNC returns a positive value (i.e. H5_ITER_STOP), + * return SUCCEED. * - * Return: Success: The first object in the type for which FUNC - * returns non-zero. NULL if FUNC returned zero - * for every object in the type. - * Failure: NULL + * If FUNC returns a negative value (i.e. H5_ITER_ERROR), + * return FAIL. + * + * The FUNC should take a pointer to the object and the + * udata as arguments and return non-zero to terminate + * siteration, and zero to continue. * - * Programmer: Robb Matzke - * Friday, February 19, 1999 + * Limitation: Currently there is no way to start the iteration from + * where a previous iteration left off. + * + * Return: Success: SUCCEED + * Failure: FAIL * - * Modifications: Neil Fortner - * Wednesday, October 1, 2008 - * Added app_ref parameter. When set to TRUE, the function will only - * operate on ids that have a nonzero application reference count. + * Programmer: John Mainzer + * Monday, December 6, 2011 * *------------------------------------------------------------------------- */ -void * -H5I_search(H5I_type_t type, H5I_search_func_t func, void *key, hbool_t app_ref) +herr_t +H5I_iterate(H5I_type_t type, H5I_search_func_t func, void *udata, hbool_t app_ref) { - H5I_id_type_t *type_ptr; /*ptr to the type */ - void *ret_value = NULL; /*return value */ + H5I_id_type_t *type_ptr; /*ptr to the type */ + herr_t ret_value = SUCCEED; /*return value */ - FUNC_ENTER_NOAPI(NULL) + FUNC_ENTER_NOAPI(FAIL) /* Check arguments */ if(type <= H5I_BADID || type >= H5I_next_type) - HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "invalid type number") + HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number") type_ptr = H5I_id_type_list_g[type]; - if(type_ptr == NULL || type_ptr->count <= 0) - HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, NULL, "invalid type") - /* Only iterate through hash table if there are IDs in group */ - if(type_ptr->ids > 0) { - H5I_id_info_t *id_ptr; /*ptr to the new ID */ - H5I_id_info_t *next_id; /*ptr to the next ID */ - unsigned i; /*counter */ + /* Only iterate through hash table if it is initialized and there are IDs in group */ + if(type_ptr && type_ptr->count > 0 && type_ptr->ids > 0) { + unsigned u; /* Counter */ /* Start at the beginning of the array */ - for(i = 0; i < type_ptr->hash_size; i++) { - id_ptr = type_ptr->id_list[i]; + for(u = 0; u < type_ptr->hash_size; u++) { + H5I_id_info_t *id_ptr; /* Ptr to the new ID */ + + id_ptr = type_ptr->id_list[u]; while(id_ptr) { - next_id = id_ptr->next; /* Protect against ID being deleted in callback */ - /* (Casting away const OK -QAK) */ - if((!app_ref || id_ptr->app_count) && (*func)((void *)id_ptr->obj_ptr, id_ptr->id, key)) - /* (Casting away const OK -QAK) */ - HGOTO_DONE((void *)id_ptr->obj_ptr); /*found the item*/ + H5I_id_info_t *next_id; /* Ptr to the next ID */ + + /* Protect against ID being deleted in callback */ + next_id = id_ptr->next; + if((!app_ref) || (id_ptr->app_count > 0)) { + herr_t cb_ret_val; /* Callback return value */ + + /* (Casting away const OK) */ + cb_ret_val = (*func)((void *)id_ptr->obj_ptr, id_ptr->id, udata); + if(cb_ret_val > 0) + HGOTO_DONE(SUCCEED) /* terminate iteration early */ + else if(cb_ret_val < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "func failed") + } /* end if */ id_ptr = next_id; } /* end while */ } /* end for */ @@ -2082,7 +2144,7 @@ H5I_search(H5I_type_t type, H5I_search_func_t func, void *key, hbool_t app_ref) done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5I_search() */ +} /* end H5I_iterate() */ /*------------------------------------------------------------------------- diff --git a/src/H5Iprivate.h b/src/H5Iprivate.h index 98423df..bc0ef41 100644 --- a/src/H5Iprivate.h +++ b/src/H5Iprivate.h @@ -62,7 +62,7 @@ H5_DLL H5I_type_t H5I_get_type(hid_t id); H5_DLL hid_t H5I_get_file_id(hid_t obj_id, hbool_t app_ref); H5_DLL void *H5I_remove(hid_t id); H5_DLL void *H5I_remove_verify(hid_t id, H5I_type_t id_type); -H5_DLL void *H5I_search(H5I_type_t type, H5I_search_func_t func, void *key, hbool_t app_ref); +H5_DLL herr_t H5I_iterate(H5I_type_t type, H5I_search_func_t func, void *udata, hbool_t app_ref); H5_DLL int H5I_get_ref(hid_t id, hbool_t app_ref); H5_DLL int H5I_inc_ref(hid_t id, hbool_t app_ref); H5_DLL int H5I_dec_ref(hid_t id); diff --git a/src/H5Oattribute.c b/src/H5Oattribute.c index bbaf72b..0ab74ac 100644 --- a/src/H5Oattribute.c +++ b/src/H5Oattribute.c @@ -711,18 +711,23 @@ H5O_attr_find_opened_attr(const H5O_loc_t *loc, H5A_t **attr, const char* name_t HGOTO_ERROR(H5E_ATTR, H5E_BADVALUE, FAIL, "can't get file serial number") /* Count all opened attributes */ - num_open_attr = H5F_get_obj_count(loc->file, H5F_OBJ_ATTR | H5F_OBJ_LOCAL, FALSE); + if(H5F_get_obj_count(loc->file, H5F_OBJ_ATTR | H5F_OBJ_LOCAL, FALSE, &num_open_attr) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't count opened attributes") /* Find out whether the attribute has been opened */ if(num_open_attr) { + size_t check_num_attr; /* Number of open attribute IDs */ size_t u; /* Local index variable */ /* Allocate space for the attribute ID list */ if(NULL == (attr_id_list = (hid_t *)H5MM_malloc(num_open_attr * sizeof(hid_t)))) - HGOTO_ERROR(H5E_ATTR, H5E_NOSPACE, FAIL, "unable to allocate memory for attribute ID list") + HGOTO_ERROR(H5E_ATTR, H5E_CANTALLOC, FAIL, "unable to allocate memory for attribute ID list") /* Retrieve the IDs of all opened attributes */ - H5F_get_obj_ids(loc->file, H5F_OBJ_ATTR | H5F_OBJ_LOCAL, num_open_attr, attr_id_list, FALSE); + if(H5F_get_obj_ids(loc->file, H5F_OBJ_ATTR | H5F_OBJ_LOCAL, num_open_attr, attr_id_list, FALSE, &check_num_attr) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get IDs of opened attributes") + if(check_num_attr != num_open_attr) + HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "open attribute count mismatch") /* Iterate over the attributes */ for(u = 0; u < num_open_attr; u++) { diff --git a/src/H5Pfapl.c b/src/H5Pfapl.c index c3371c9..7f72c85 100644 --- a/src/H5Pfapl.c +++ b/src/H5Pfapl.c @@ -40,6 +40,7 @@ #include "H5Fprivate.h" /* Files */ #include "H5FDprivate.h" /* File drivers */ #include "H5Iprivate.h" /* IDs */ +#include "H5MMprivate.h" /* Memory Management */ #include "H5Ppkg.h" /* Property lists */ /* Includes needed to set as default file driver */ @@ -122,6 +123,12 @@ /* Definition for external file cache size */ #define H5F_ACS_EFC_SIZE_SIZE sizeof(unsigned) #define H5F_ACS_EFC_SIZE_DEF 0 +/* Definition of pointer to initial file image info */ +#define H5F_ACS_FILE_IMAGE_INFO_SIZE sizeof(H5FD_file_image_info_t) +#define H5F_ACS_FILE_IMAGE_INFO_DEF H5FD_DEFAULT_FILE_IMAGE_INFO +#define H5F_ACS_FILE_IMAGE_INFO_DEL H5P_file_image_info_del +#define H5F_ACS_FILE_IMAGE_INFO_COPY H5P_file_image_info_copy +#define H5F_ACS_FILE_IMAGE_INFO_CLOSE H5P_file_image_info_close /******************/ @@ -149,6 +156,10 @@ static herr_t H5P_facc_reg_prop(H5P_genclass_t *pclass); static herr_t H5P_facc_create(hid_t fapl_id, void *copy_data); static herr_t H5P_facc_copy(hid_t new_plist_t, hid_t old_plist_t, void *copy_data); +/* File image info property callbacks */ +static herr_t H5P_file_image_info_del(hid_t prop_id, const char *name, size_t size, void *value); +static herr_t H5P_file_image_info_copy(const char *name, size_t size, void *value); +static herr_t H5P_file_image_info_close(const char *name, size_t size, void *value); /*********************/ /* Package Variables */ @@ -215,6 +226,7 @@ H5P_facc_reg_prop(H5P_genclass_t *pclass) hbool_t latest_format = H5F_ACS_LATEST_FORMAT_DEF; /* Default setting for "use the latest version of the format" flag */ hbool_t want_posix_fd = H5F_ACS_WANT_POSIX_FD_DEF; /* Default setting for retrieving 'handle' from core VFD */ unsigned efc_size = H5F_ACS_EFC_SIZE_DEF; /* Default external file cache size */ + H5FD_file_image_info_t file_image_info = H5F_ACS_FILE_IMAGE_INFO_DEF; /* Default file image info and callbacks */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT @@ -300,6 +312,10 @@ H5P_facc_reg_prop(H5P_genclass_t *pclass) if(H5P_register_real(pclass, H5F_ACS_EFC_SIZE_NAME, H5F_ACS_EFC_SIZE_SIZE, &efc_size, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class") + /* Register the initial file image info */ + if(H5P_register_real(pclass, H5F_ACS_FILE_IMAGE_INFO_NAME, H5F_ACS_FILE_IMAGE_INFO_SIZE, &file_image_info, NULL, NULL, NULL, H5F_ACS_FILE_IMAGE_INFO_DEL, H5F_ACS_FILE_IMAGE_INFO_COPY, NULL, H5F_ACS_FILE_IMAGE_INFO_CLOSE) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class") + done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5P_facc_reg_prop() */ @@ -2101,3 +2117,484 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Pget_elink_file_cache_size() */ + +/*------------------------------------------------------------------------- + * Function: H5Pset_file_image + * + * Purpose: Sets the initial file image. Some file drivers can initialize + * the starting data in a file from a buffer. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Jacob Gruber + * Thurday, August 11, 2011 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Pset_file_image(hid_t fapl_id, void *buf_ptr, size_t buf_len) +{ + H5P_genplist_t *fapl; /* Property list pointer */ + H5FD_file_image_info_t image_info; /* File image info */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE3("e", "i*xz", fapl_id, buf_ptr, buf_len); + + /* validate parameters */ + if(!(((buf_ptr == NULL) && (buf_len == 0)) || ((buf_ptr != NULL) && (buf_len > 0)))) + HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "inconsistant buf_ptr and buf_len"); + + /* Get the plist structure */ + if(NULL == (fapl = H5P_object_verify(fapl_id, H5P_FILE_ACCESS))) + HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID") + + /* Get old image info */ + if(H5P_get(fapl, H5F_ACS_FILE_IMAGE_INFO_NAME, &image_info) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get old file image pointer") + + /* Release previous buffer, if it exists */ + if(image_info.buffer != NULL) { + if(image_info.callbacks.image_free) { + if(SUCCEED != image_info.callbacks.image_free(image_info.buffer, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET, image_info.callbacks.udata)) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "image_free callback failed") + } /* end if */ + else + H5MM_xfree(image_info.buffer); + } /* end if */ + + /* Update struct */ + if(buf_ptr) { + /* Allocate memory */ + if(image_info.callbacks.image_malloc) { + if(NULL == (image_info.buffer = image_info.callbacks.image_malloc(buf_len, + H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET, image_info.callbacks.udata))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "image malloc callback failed") + } /* end if */ + else + if(NULL == (image_info.buffer = H5MM_malloc(buf_len))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory block") + + /* Copy data */ + if(image_info.callbacks.image_memcpy) { + if(image_info.buffer != image_info.callbacks.image_memcpy(image_info.buffer, + buf_ptr, buf_len, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET, + image_info.callbacks.udata)) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTCOPY, FAIL, "image_memcpy callback failed") + } /* end if */ + else + HDmemcpy(image_info.buffer, buf_ptr, buf_len); + } /* end if */ + else + image_info.buffer = NULL; + + image_info.size = buf_len; + + /* Set values */ + if(H5P_set(fapl, H5F_ACS_FILE_IMAGE_INFO_NAME, &image_info) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set file image info") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Pset_file_image() */ + + +/*------------------------------------------------------------------------- + * Function: H5Pget_file_image + * + * Purpose: If the file image exists and buf_ptr_ptr is not NULL, + * allocate a buffer of the correct size, copy the image into + * the new buffer, and return the buffer to the caller in + * *buf_ptr_ptr. Do this using the file image callbacks + * if defined. + * + * NB: It is the responsibility of the caller to free the + * buffer whose address is returned in *buf_ptr_ptr. Do + * this using free if the file image callbacks are not + * defined, or with whatever method is appropriate if + * the callbacks are defined. + * + * If buf_ptr_ptr is not NULL, and no image exists, set + * *buf_ptr_ptr to NULL. + * + * If buf_len_ptr is not NULL, set *buf_len_ptr equal + * to the length of the file image if it exists, and + * to 0 if it does not. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Jacob Gruber + * Thurday, August 11, 2011 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Pget_file_image(hid_t fapl_id, void **buf_ptr_ptr, size_t *buf_len_ptr) +{ + H5P_genplist_t *fapl; /* Property list pointer */ + H5FD_file_image_info_t image_info; /* File image info */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE3("e", "i**x*z", fapl_id, buf_ptr_ptr, buf_len_ptr); + + /* Get the plist structure */ + if(NULL == (fapl = H5P_object_verify(fapl_id, H5P_FILE_ACCESS))) + HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID") + + /* Get values */ + if(H5P_get(fapl, H5F_ACS_FILE_IMAGE_INFO_NAME, &image_info) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get file image info") + + /* verify file image field consistancy */ + HDassert(((image_info.buffer != NULL) && (image_info.size > 0)) || + ((image_info.buffer == NULL) && (image_info.size == 0))); + + /* Set output size */ + if(buf_len_ptr != NULL) + *buf_len_ptr = image_info.size; + + /* Duplicate the image if desired, using callbacks if available */ + if(buf_ptr_ptr != NULL) { + void * copy_ptr = NULL; /* Copy of memory image */ + + if(image_info.buffer != NULL) { + /* Allocate memory */ + if(image_info.callbacks.image_malloc) { + if(NULL == (copy_ptr = image_info.callbacks.image_malloc(image_info.size, + H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET, image_info.callbacks.udata))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "image malloc callback failed") + } /* end if */ + else + if(NULL == (copy_ptr = H5MM_malloc(image_info.size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate copy") + + /* Copy data */ + if(image_info.callbacks.image_memcpy) { + if(copy_ptr != image_info.callbacks.image_memcpy(copy_ptr, image_info.buffer, + image_info.size, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET, + image_info.callbacks.udata)) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTCOPY, FAIL, "image_memcpy callback failed") + } /* end if */ + else + HDmemcpy(copy_ptr, image_info.buffer, image_info.size); + } /* end if */ + + *buf_ptr_ptr = copy_ptr; + } /* end if */ + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Pget_file_image */ + + +/*------------------------------------------------------------------------- + * Function: H5Pset_file_image_callbacks + * + * Purpose: Sets the callbacks for file images. Some file drivers allow + * the use of user-defined callbacks for allocating, freeing and + * copying the drivers internal buffer, potentially allowing a + * clever user to do optimizations such as avoiding large mallocs + * and memcpys or to perform detailed logging. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Jacob Gruber + * Thurday, August 11, 2011 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Pset_file_image_callbacks(hid_t fapl_id, H5FD_file_image_callbacks_t *callbacks_ptr) +{ + H5P_genplist_t *fapl; /* Property list pointer */ + H5FD_file_image_info_t info; /* File image info */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE2("e", "i*x", fapl_id, callbacks_ptr); + + /* Get the plist structure */ + if(NULL == (fapl = H5P_object_verify(fapl_id, H5P_FILE_ACCESS))) + HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID") + + /* Get old info */ + if(H5P_get(fapl, H5F_ACS_FILE_IMAGE_INFO_NAME, &info) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get old file image info") + + /* verify file image field consistancy */ + HDassert(((info.buffer != NULL) && (info.size > 0)) || + ((info.buffer == NULL) && (info.size == 0))); + + /* Make sure a file image hasn't already been set */ + if(info.buffer != NULL || info.size > 0) + HGOTO_ERROR(H5E_PLIST, H5E_SETDISALLOWED, FAIL, "setting callbacks when an image is already set is forbidden. It could cause memory leaks.") + + /* verify that callbacks_ptr is not NULL */ + if(NULL == callbacks_ptr) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL callbacks_ptr") + + /* Make sure udata callbacks are going to be set if udata is going to be set */ + if(callbacks_ptr->udata) + if(callbacks_ptr->udata_copy == NULL || callbacks_ptr->udata_free == NULL) + HGOTO_ERROR(H5E_PLIST, H5E_SETDISALLOWED, FAIL, "udata callbacks must be set if udata is set") + + /* Release old udata if it exists */ + if(info.callbacks.udata != NULL) { + HDassert(info.callbacks.udata_free); + if(info.callbacks.udata_free(info.callbacks.udata) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "udata_free callback failed") + } /* end if */ + + /* Update struct */ + info.callbacks = *callbacks_ptr; + + if(callbacks_ptr->udata) { + HDassert(callbacks_ptr->udata_copy); + HDassert(callbacks_ptr->udata_free); + if((info.callbacks.udata = callbacks_ptr->udata_copy(callbacks_ptr->udata)) == NULL) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't copy the suppplied udata") + } /* end if */ + + /* Set values */ + if(H5P_set(fapl, H5F_ACS_FILE_IMAGE_INFO_NAME, &info) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set file image info") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Pset_file_image_callbacks() */ + + +/*------------------------------------------------------------------------- + * Function: H5Pget_file_image_callbacks + * + * Purpose: Sets the callbacks for file images. Some file drivers allow + * the use of user-defined callbacks for allocating, freeing and + * copying the drivers internal buffer, potentially allowing a + * clever user to do optimizations such as avoiding large mallocs + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Jacob Gruber + * Thurday, August 11, 2011 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Pget_file_image_callbacks(hid_t fapl_id, H5FD_file_image_callbacks_t *callbacks_ptr) +{ + H5P_genplist_t *fapl; /* Property list pointer */ + H5FD_file_image_info_t info; /* File image info */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE2("e", "i*x", fapl_id, callbacks_ptr); + + /* Get the plist structure */ + if(NULL == (fapl = H5P_object_verify(fapl_id, H5P_FILE_ACCESS))) + HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID") + + /* Get old info */ + if(H5P_get(fapl, H5F_ACS_FILE_IMAGE_INFO_NAME, &info) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get file image info") + + /* verify file image field consistancy */ + HDassert(((info.buffer != NULL) && (info.size > 0)) || + ((info.buffer == NULL) && (info.size == 0))); + + /* verify that callbacks_ptr is not NULL */ + if(NULL == callbacks_ptr) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL callbacks_ptr") + + /* Transfer values to parameters */ + *callbacks_ptr = info.callbacks; + + /* Copy udata if it exists */ + if(info.callbacks.udata != NULL) { + HDassert(info.callbacks.udata_copy); + if((callbacks_ptr->udata = info.callbacks.udata_copy(info.callbacks.udata)) == 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't copy udata") + } /* end if */ + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Pget_file_image_callbacks() */ + + +/*------------------------------------------------------------------------- + * Function: H5P_file_image_info_del + * + * Purpose: Delete callback for the file image info property, called + * when the property is deleted from the plist. The buffer + * and udata may need to be freed, possibly using their + * respective callbacks so the default free won't work. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Jacob Gruber + * Thurday, August 11, 2011 + * + *------------------------------------------------------------------------- + */ +herr_t +H5P_file_image_info_del(hid_t UNUSED prop_id, const char UNUSED *name, size_t UNUSED size, void *value) +{ + H5FD_file_image_info_t info; /* Image info struct */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + if(value) { + info = *(H5FD_file_image_info_t *)value; + + /* verify file image field consistancy */ + HDassert(((info.buffer != NULL) && (info.size > 0)) || + ((info.buffer == NULL) && (info.size == 0))); + + if(info.buffer && info.size > 0) { + /* Free buffer */ + if(info.callbacks.image_free) { + if(info.callbacks.image_free(info.buffer, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE, info.callbacks.udata) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "image_free callback failed") + } /* end if */ + else + free(info.buffer); + } /* end if */ + + /* Free udata if it exists */ + if(info.callbacks.udata) { + if(NULL == info.callbacks.udata_free) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "udata_free not defined") + + if(info.callbacks.udata_free(info.callbacks.udata) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "udata_free callback failed") + } /* end if */ + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5P_file_image_info_del() */ + + +/*------------------------------------------------------------------------- + * Function: H5P_file_image_info_copy + * + * Purpose: Copy callback for the file image info property. The buffer + * and udata may need to be copied, possibly using their + * respective callbacks so the default copy won't work. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Jacob Gruber + * Thurday, August 11, 2011 + * + *------------------------------------------------------------------------- + */ +herr_t +H5P_file_image_info_copy(const char UNUSED *name, size_t UNUSED size, void *value) +{ + H5FD_file_image_info_t *info; /* Image info struct */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + if(value) { + info = (H5FD_file_image_info_t *)value; + + /* verify file image field consistancy */ + HDassert(((info->buffer != NULL) && (info->size > 0)) || + ((info->buffer == NULL) && (info->size == 0))); + + if(info->buffer && info->size > 0) { + void *old_buffer; /* Pointer to old image buffer */ + + /* Store the old buffer */ + old_buffer = info->buffer; + + /* Allocate new buffer */ + if(info->callbacks.image_malloc) { + if(NULL == (info->buffer = info->callbacks.image_malloc(info->size, + H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY, info->callbacks.udata))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "image malloc callback failed") + } /* end if */ + else { + if(NULL == (info->buffer = H5MM_malloc(info->size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory block") + } /* end else */ + + /* Copy data to new buffer */ + if(info->callbacks.image_memcpy) { + if(info->buffer != info->callbacks.image_memcpy(info->buffer, old_buffer, + info->size, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY, + info->callbacks.udata)) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTCOPY, FAIL, "image_memcpy callback failed") + } /* end if */ + else + HDmemcpy(info->buffer, old_buffer, info->size); + } /* end if */ + } /* end if */ + + /* Copy udata if it exists */ + if(info->callbacks.udata) { + void *old_udata = info->callbacks.udata; + + if(NULL == info->callbacks.udata_copy) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "udata_copy not defined") + + info->callbacks.udata = info->callbacks.udata_copy(old_udata); + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5P_file_image_info_copy() */ + + +/*------------------------------------------------------------------------- + * Function: H5P_file_image_info_close + * + * Purpose: Close callback for the file image info property. The buffer + * and udata may need to be freed, possibly using their + * respective callbacks so the standard free won't work. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Jacob Gruber + * Thurday, August 11, 2011 + * + *------------------------------------------------------------------------- + */ +herr_t +H5P_file_image_info_close(const char UNUSED *name, size_t UNUSED size, void *value) +{ + H5FD_file_image_info_t info; /* Image info struct */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + if(value) { + info = *(H5FD_file_image_info_t *)value; + + if(info.buffer != NULL && info.size > 0) { + /* Free buffer */ + if(info.callbacks.image_free) { + if(info.callbacks.image_free(info.buffer, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE, + info.callbacks.udata) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "image_free callback failed") + } /* end if */ + else + H5MM_xfree(info.buffer); + } /* end if */ + } /* end if */ + + /* Free udata if it exists */ + if(info.callbacks.udata) { + if(NULL == info.callbacks.udata_free) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "udata_free not defined") + if(info.callbacks.udata_free(info.callbacks.udata) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "udata_free callback failed") + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5P_file_image_info_close() */ + diff --git a/src/H5Pint.c b/src/H5Pint.c index 08b8af6..46a06a0 100644 --- a/src/H5Pint.c +++ b/src/H5Pint.c @@ -51,6 +51,7 @@ typedef struct { const H5P_genclass_t *parent; /* Pointer to parent class */ const char *name; /* Pointer to name to check */ + H5P_genclass_t *new_class; /* Pointer to class during path traversal */ } H5P_check_class_t; @@ -1358,11 +1359,11 @@ H5P_access_class(H5P_genclass_t *pclass, H5P_class_mod_t mod) /*-------------------------------------------------------------------------- NAME - H5P_check_class + H5P_open_class_path_cb PURPOSE Internal callback routine to check for duplicated names in parent class. USAGE - int H5P_check_class(obj, id, key) + int H5P_open_class_path_cb(obj, id, key) H5P_genclass_t *obj; IN: Pointer to class hid_t id; IN: ID of object being looked at const void *key; IN: Pointer to information used to compare @@ -1378,27 +1379,29 @@ H5P_access_class(H5P_genclass_t *pclass, H5P_class_mod_t mod) REVISION LOG --------------------------------------------------------------------------*/ static int -H5P_check_class(void *_obj, hid_t UNUSED id, void *_key) +H5P_open_class_path_cb(void *_obj, hid_t UNUSED id, void *_key) { - H5P_genclass_t *obj=(H5P_genclass_t *)_obj; /* Pointer to the class for this ID */ - const H5P_check_class_t *key=(const H5P_check_class_t *)_key; /* Pointer to key information for comparison */ - int ret_value=0; /* Return value */ + H5P_genclass_t *obj = (H5P_genclass_t *)_obj; /* Pointer to the class for this ID */ + H5P_check_class_t *key = (H5P_check_class_t *)_key; /* Pointer to key information for comparison */ + int ret_value = 0; /* Return value */ FUNC_ENTER_NOAPI_NOINIT_NOERR HDassert(obj); - HDassert(H5I_GENPROP_CLS==H5I_get_type(id)); + HDassert(H5I_GENPROP_CLS == H5I_get_type(id)); HDassert(key); /* Check if the class object has the same parent as the new class */ - if(obj->parent==key->parent) { + if(obj->parent == key->parent) { /* Check if they have the same name */ - if(HDstrcmp(obj->name,key->name)==0) - ret_value=1; /* Indicate a match */ + if(HDstrcmp(obj->name, key->name) == 0) { + key->new_class = obj; + ret_value = 1; /* Indicate a match */ + } /* end if */ } /* end if */ FUNC_LEAVE_NOAPI(ret_value) -} /* end H5P_check_class() */ +} /* end H5P_open_class_path_cb() */ /*-------------------------------------------------------------------------- @@ -4555,8 +4558,8 @@ H5P_open_class_path(const char *path) char *curr_name; /* Pointer to current component of path name */ char *delimit; /* Pointer to path delimiter during traversal */ H5P_genclass_t *curr_class; /* Pointer to class during path traversal */ - H5P_genclass_t *ret_value; /* Return value */ H5P_check_class_t check_info; /* Structure to hold the information for checking duplicate names */ + H5P_genclass_t *ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT @@ -4569,20 +4572,24 @@ H5P_open_class_path(const char *path) /* Find the generic property class with this full path */ curr_name = tmp_path; curr_class = NULL; - while((delimit=HDstrchr(curr_name,'/'))!=NULL) { + while(NULL != (delimit = HDstrchr(curr_name, '/'))) { /* Change the delimiter to terminate the string */ - *delimit='\0'; + *delimit = '\0'; /* Set up the search structure */ - check_info.parent=curr_class; - check_info.name=curr_name; + check_info.parent = curr_class; + check_info.name = curr_name; + check_info.new_class = NULL; /* Find the class with this name & parent by iterating over the open classes */ - if(NULL == (curr_class = (H5P_genclass_t *)H5I_search(H5I_GENPROP_CLS, H5P_check_class, &check_info, FALSE))) - HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, NULL, "can't locate class") + if(H5I_iterate(H5I_GENPROP_CLS, H5P_open_class_path_cb, &check_info, FALSE) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_BADITER, NULL, "can't iterate over classes") + else if(NULL == check_info.new_class) + HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, NULL, "can't locate class") /* Advance the pointer in the path to the start of the next component */ - curr_name=delimit+1; + curr_class = check_info.new_class; + curr_name = delimit + 1; } /* end while */ /* Should be pointing to the last component in the path name now... */ @@ -4590,13 +4597,16 @@ H5P_open_class_path(const char *path) /* Set up the search structure */ check_info.parent = curr_class; check_info.name = curr_name; + check_info.new_class = NULL; /* Find the class with this name & parent by iterating over the open classes */ - if(NULL == (curr_class = (H5P_genclass_t *)H5I_search(H5I_GENPROP_CLS, H5P_check_class, &check_info, FALSE))) + if(H5I_iterate(H5I_GENPROP_CLS, H5P_open_class_path_cb, &check_info, FALSE) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_BADITER, NULL, "can't iterate over classes") + else if(NULL == check_info.new_class) HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, NULL, "can't locate class") /* Copy it */ - if(NULL == (ret_value = H5P_copy_pclass(curr_class))) + if(NULL == (ret_value = H5P_copy_pclass(check_info.new_class))) HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, NULL, "can't copy property class") done: @@ -4604,7 +4614,7 @@ done: H5MM_xfree(tmp_path); FUNC_LEAVE_NOAPI(ret_value) -} /* H5P_open_class_path() */ +} /* H5P_open_class_path() */ /*-------------------------------------------------------------------------- diff --git a/src/H5Pocpypl.c b/src/H5Pocpypl.c index e61a0d7..1aceab2 100644 --- a/src/H5Pocpypl.c +++ b/src/H5Pocpypl.c @@ -469,6 +469,7 @@ H5Padd_merge_committed_dtype_path(hid_t plist_id, const char *path) herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(FAIL) + H5TRACE2("e", "i*s", plist_id, path); /* Check parameters */ if(!path) @@ -528,6 +529,7 @@ H5Pfree_merge_committed_dtype_paths(hid_t plist_id) herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(FAIL) + H5TRACE1("e", "i", plist_id); /* Get the plist structure */ if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_COPY))) diff --git a/src/H5Ppublic.h b/src/H5Ppublic.h index e33b685..c06ab39 100644 --- a/src/H5Ppublic.h +++ b/src/H5Ppublic.h @@ -323,6 +323,12 @@ H5_DLL herr_t H5Pget_libver_bounds(hid_t plist_id, H5F_libver_t *low, H5F_libver_t *high); H5_DLL herr_t H5Pset_elink_file_cache_size(hid_t plist_id, unsigned efc_size); H5_DLL herr_t H5Pget_elink_file_cache_size(hid_t plist_id, unsigned *efc_size); +H5_DLL herr_t H5Pset_file_image(hid_t fapl_id, void *buf_ptr, size_t buf_len); +H5_DLL herr_t H5Pget_file_image(hid_t fapl_id, void **buf_ptr_ptr, size_t *buf_len_ptr); +H5_DLL herr_t H5Pset_file_image_callbacks(hid_t fapl_id, + H5FD_file_image_callbacks_t *callbacks_ptr); +H5_DLL herr_t H5Pget_file_image_callbacks(hid_t fapl_id, + H5FD_file_image_callbacks_t *callbacks_ptr); /* Dataset creation property list (DCPL) routines */ H5_DLL herr_t H5Pset_layout(hid_t plist_id, H5D_layout_t layout); diff --git a/src/H5T.c b/src/H5T.c index fcc4ab3..37d4b68 100644 --- a/src/H5T.c +++ b/src/H5T.c @@ -1449,7 +1449,8 @@ H5T_term_interface(void) H5T_g.asoft = 0; /* Unlock all datatypes, then free them */ - H5I_search(H5I_DATATYPE, H5T_unlock_cb, NULL, FALSE); + /* note that we are ignoring the return value from H5I_iterate() */ + H5I_iterate(H5I_DATATYPE, H5T_unlock_cb, NULL, FALSE); H5I_dec_type_ref(H5I_DATATYPE); /* Reset all the datatype IDs */ diff --git a/src/H5err.txt b/src/H5err.txt index 275a8ff..b61e8d0 100644 --- a/src/H5err.txt +++ b/src/H5err.txt @@ -214,6 +214,7 @@ MINOR, DSPACE, H5E_CANTCOMPARE, Can't compare objects MINOR, PLIST, H5E_CANTGET, Can't get value MINOR, PLIST, H5E_CANTSET, Can't set value MINOR, PLIST, H5E_DUPCLASS, Duplicate class name in parent class +MINOR, PLIST, H5E_SETDISALLOWED, Disallowed operation # Link errors MINOR, LINK, H5E_TRAVERSE, Link traversal failure diff --git a/test/Makefile.am b/test/Makefile.am index 50bbe5b..e2ad3fa 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -42,7 +42,7 @@ TEST_PROG=testhdf5 lheap ohdr stab gheap cache cache_api \ big mtime fillval mount flush1 flush2 app_ref enum \ set_extent ttsafe \ getname vfd ntypes dangle dtransform reserved cross_read \ - freespace mf btree2 fheap + freespace mf btree2 fheap file_image # List programs to be built when testing here. error_test and err_compat are # built at the same time as the other tests, but executed by testerror.sh. @@ -62,7 +62,8 @@ check_PROGRAMS=$(TEST_PROG) error_test err_compat tcheck_version testmeta links_ # so do not appear in this list. BUILD_ALL_PROGS=gen_bad_ohdr gen_bogus gen_cross gen_deflate gen_filters gen_idx \ gen_new_array gen_new_fill gen_new_group gen_new_mtime gen_new_super \ - gen_noencoder gen_nullspace gen_udlinks space_overflow gen_sizes_lheap + gen_noencoder gen_nullspace gen_udlinks space_overflow gen_sizes_lheap \ + gen_file_image if BUILD_ALL_CONDITIONAL noinst_PROGRAMS=$(BUILD_ALL_PROGS) diff --git a/test/Makefile.in b/test/Makefile.in index dc954db..736b61d 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -91,14 +91,16 @@ am__EXEEXT_1 = testhdf5$(EXEEXT) lheap$(EXEEXT) ohdr$(EXEEXT) \ set_extent$(EXEEXT) ttsafe$(EXEEXT) getname$(EXEEXT) \ vfd$(EXEEXT) ntypes$(EXEEXT) dangle$(EXEEXT) \ dtransform$(EXEEXT) reserved$(EXEEXT) cross_read$(EXEEXT) \ - freespace$(EXEEXT) mf$(EXEEXT) btree2$(EXEEXT) fheap$(EXEEXT) + freespace$(EXEEXT) mf$(EXEEXT) btree2$(EXEEXT) fheap$(EXEEXT) \ + file_image$(EXEEXT) am__EXEEXT_2 = gen_bad_ohdr$(EXEEXT) gen_bogus$(EXEEXT) \ gen_cross$(EXEEXT) gen_deflate$(EXEEXT) gen_filters$(EXEEXT) \ gen_idx$(EXEEXT) gen_new_array$(EXEEXT) gen_new_fill$(EXEEXT) \ gen_new_group$(EXEEXT) gen_new_mtime$(EXEEXT) \ gen_new_super$(EXEEXT) gen_noencoder$(EXEEXT) \ gen_nullspace$(EXEEXT) gen_udlinks$(EXEEXT) \ - space_overflow$(EXEEXT) gen_sizes_lheap$(EXEEXT) + space_overflow$(EXEEXT) gen_sizes_lheap$(EXEEXT) \ + gen_file_image$(EXEEXT) PROGRAMS = $(noinst_PROGRAMS) accum_SOURCES = accum.c accum_OBJECTS = accum.$(OBJEXT) @@ -184,6 +186,10 @@ fheap_SOURCES = fheap.c fheap_OBJECTS = fheap.$(OBJEXT) fheap_LDADD = $(LDADD) fheap_DEPENDENCIES = libh5test.la $(LIBHDF5) +file_image_SOURCES = file_image.c +file_image_OBJECTS = file_image.$(OBJEXT) +file_image_LDADD = $(LDADD) +file_image_DEPENDENCIES = libh5test.la $(LIBHDF5) fillval_SOURCES = fillval.c fillval_OBJECTS = fillval.$(OBJEXT) fillval_LDADD = $(LDADD) @@ -220,6 +226,10 @@ gen_deflate_SOURCES = gen_deflate.c gen_deflate_OBJECTS = gen_deflate.$(OBJEXT) gen_deflate_LDADD = $(LDADD) gen_deflate_DEPENDENCIES = libh5test.la $(LIBHDF5) +gen_file_image_SOURCES = gen_file_image.c +gen_file_image_OBJECTS = gen_file_image.$(OBJEXT) +gen_file_image_LDADD = $(LDADD) +gen_file_image_DEPENDENCIES = libh5test.la $(LIBHDF5) gen_filters_SOURCES = gen_filters.c gen_filters_OBJECTS = gen_filters.$(OBJEXT) gen_filters_LDADD = $(LDADD) @@ -400,30 +410,30 @@ SOURCES = $(libh5test_la_SOURCES) accum.c app_ref.c big.c bittests.c \ btree2.c cache.c cache_api.c cmpd_dset.c cross_read.c dangle.c \ dsets.c dt_arith.c dtransform.c dtypes.c efc.c enum.c \ err_compat.c error_test.c extend.c external.c fheap.c \ - fillval.c filter_fail.c flush1.c flush2.c freespace.c \ - gen_bad_ohdr.c gen_bogus.c gen_cross.c gen_deflate.c \ - gen_filters.c gen_idx.c gen_new_array.c gen_new_fill.c \ - gen_new_group.c gen_new_mtime.c gen_new_super.c \ - gen_noencoder.c gen_nullspace.c gen_sizes_lheap.c \ - gen_udlinks.c getname.c gheap.c hyperslab.c istore.c lheap.c \ - links.c links_env.c mf.c mount.c mtime.c ntypes.c objcopy.c \ - ohdr.c pool.c reserved.c set_extent.c space_overflow.c stab.c \ - tcheck_version.c $(testhdf5_SOURCES) testmeta.c \ - $(ttsafe_SOURCES) unlink.c vfd.c + file_image.c fillval.c filter_fail.c flush1.c flush2.c \ + freespace.c gen_bad_ohdr.c gen_bogus.c gen_cross.c \ + gen_deflate.c gen_file_image.c gen_filters.c gen_idx.c \ + gen_new_array.c gen_new_fill.c gen_new_group.c gen_new_mtime.c \ + gen_new_super.c gen_noencoder.c gen_nullspace.c \ + gen_sizes_lheap.c gen_udlinks.c getname.c gheap.c hyperslab.c \ + istore.c lheap.c links.c links_env.c mf.c mount.c mtime.c \ + ntypes.c objcopy.c ohdr.c pool.c reserved.c set_extent.c \ + space_overflow.c stab.c tcheck_version.c $(testhdf5_SOURCES) \ + testmeta.c $(ttsafe_SOURCES) unlink.c vfd.c DIST_SOURCES = $(libh5test_la_SOURCES) accum.c app_ref.c big.c \ bittests.c btree2.c cache.c cache_api.c cmpd_dset.c \ cross_read.c dangle.c dsets.c dt_arith.c dtransform.c dtypes.c \ efc.c enum.c err_compat.c error_test.c extend.c external.c \ - fheap.c fillval.c filter_fail.c flush1.c flush2.c freespace.c \ - gen_bad_ohdr.c gen_bogus.c gen_cross.c gen_deflate.c \ - gen_filters.c gen_idx.c gen_new_array.c gen_new_fill.c \ - gen_new_group.c gen_new_mtime.c gen_new_super.c \ - gen_noencoder.c gen_nullspace.c gen_sizes_lheap.c \ - gen_udlinks.c getname.c gheap.c hyperslab.c istore.c lheap.c \ - links.c links_env.c mf.c mount.c mtime.c ntypes.c objcopy.c \ - ohdr.c pool.c reserved.c set_extent.c space_overflow.c stab.c \ - tcheck_version.c $(testhdf5_SOURCES) testmeta.c \ - $(ttsafe_SOURCES) unlink.c vfd.c + fheap.c file_image.c fillval.c filter_fail.c flush1.c flush2.c \ + freespace.c gen_bad_ohdr.c gen_bogus.c gen_cross.c \ + gen_deflate.c gen_file_image.c gen_filters.c gen_idx.c \ + gen_new_array.c gen_new_fill.c gen_new_group.c gen_new_mtime.c \ + gen_new_super.c gen_noencoder.c gen_nullspace.c \ + gen_sizes_lheap.c gen_udlinks.c getname.c gheap.c hyperslab.c \ + istore.c lheap.c links.c links_env.c mf.c mount.c mtime.c \ + ntypes.c objcopy.c ohdr.c pool.c reserved.c set_extent.c \ + space_overflow.c stab.c tcheck_version.c $(testhdf5_SOURCES) \ + testmeta.c $(ttsafe_SOURCES) unlink.c vfd.c ETAGS = etags CTAGS = ctags am__tty_colors = \ @@ -760,7 +770,7 @@ TEST_PROG = testhdf5 lheap ohdr stab gheap cache cache_api \ big mtime fillval mount flush1 flush2 app_ref enum \ set_extent ttsafe \ getname vfd ntypes dangle dtransform reserved cross_read \ - freespace mf btree2 fheap + freespace mf btree2 fheap file_image # These programs generate test files for the tests. They don't need to be @@ -772,7 +782,8 @@ TEST_PROG = testhdf5 lheap ohdr stab gheap cache cache_api \ # so do not appear in this list. BUILD_ALL_PROGS = gen_bad_ohdr gen_bogus gen_cross gen_deflate gen_filters gen_idx \ gen_new_array gen_new_fill gen_new_group gen_new_mtime gen_new_super \ - gen_noencoder gen_nullspace gen_udlinks space_overflow gen_sizes_lheap + gen_noencoder gen_nullspace gen_udlinks space_overflow gen_sizes_lheap \ + gen_file_image # The libh5test library provides common support code for the tests. @@ -950,6 +961,9 @@ external$(EXEEXT): $(external_OBJECTS) $(external_DEPENDENCIES) fheap$(EXEEXT): $(fheap_OBJECTS) $(fheap_DEPENDENCIES) @rm -f fheap$(EXEEXT) $(AM_V_CCLD)$(LINK) $(fheap_OBJECTS) $(fheap_LDADD) $(LIBS) +file_image$(EXEEXT): $(file_image_OBJECTS) $(file_image_DEPENDENCIES) + @rm -f file_image$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(file_image_OBJECTS) $(file_image_LDADD) $(LIBS) fillval$(EXEEXT): $(fillval_OBJECTS) $(fillval_DEPENDENCIES) @rm -f fillval$(EXEEXT) $(AM_V_CCLD)$(LINK) $(fillval_OBJECTS) $(fillval_LDADD) $(LIBS) @@ -977,6 +991,9 @@ gen_cross$(EXEEXT): $(gen_cross_OBJECTS) $(gen_cross_DEPENDENCIES) gen_deflate$(EXEEXT): $(gen_deflate_OBJECTS) $(gen_deflate_DEPENDENCIES) @rm -f gen_deflate$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gen_deflate_OBJECTS) $(gen_deflate_LDADD) $(LIBS) +gen_file_image$(EXEEXT): $(gen_file_image_OBJECTS) $(gen_file_image_DEPENDENCIES) + @rm -f gen_file_image$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gen_file_image_OBJECTS) $(gen_file_image_LDADD) $(LIBS) gen_filters$(EXEEXT): $(gen_filters_OBJECTS) $(gen_filters_DEPENDENCIES) @rm -f gen_filters$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gen_filters_OBJECTS) $(gen_filters_LDADD) $(LIBS) @@ -1111,6 +1128,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/extend.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/external.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fheap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_image.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fillval.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filter_fail.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flush1.Po@am__quote@ @@ -1120,6 +1138,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gen_bogus.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gen_cross.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gen_deflate.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gen_file_image.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gen_filters.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gen_idx.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gen_new_array.Po@am__quote@ diff --git a/test/file_image.c b/test/file_image.c new file mode 100644 index 0000000..7c2c3ff --- /dev/null +++ b/test/file_image.c @@ -0,0 +1,1335 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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 files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*********************************************************** +* +* Test program: file_image +* +* Test setting file images +* +*************************************************************/ + +#include "h5test.h" +#include "H5srcdir.h" +#include "H5Fprivate.h" /* required to test property removals */ +#define VERIFY(condition, string) do { if (!(condition)) FAIL_PUTS_ERROR(string) } while(0) + +/* Values for callback bit field */ +#define MALLOC 0x01 +#define MEMCPY 0x02 +#define REALLOC 0x04 +#define FREE 0x08 +#define UDATA_COPY 0x10 +#define UDATA_FREE 0x20 + +#define RANK 2 +#define DIM0 1024 +#define DIM1 32 +#define DSET_NAME "test_dset" + +#define FAMILY_SIZE (2 * 1024) + +const char *FILENAME[] = { + "file_image_core_test", + NULL +}; + +/* need a second file name array, as the first file name array contains + * files we don't want to delete on cleanup. + */ +const char *FILENAME2[] = { + "sec2_get_file_image_test", + "stdio_get_file_image_test", + "core_get_file_image_test", + "family_get_file_image_test", + "multi_get_file_image_test", + "split_get_file_image_test", + "get_file_image_error_rejection_test", + NULL +}; + +typedef struct { + unsigned char used_callbacks; /* Bitfield for tracking callbacks */ + H5FD_file_image_op_t malloc_src; /* Source of file image callbacks */ + H5FD_file_image_op_t memcpy_src; + H5FD_file_image_op_t realloc_src; + H5FD_file_image_op_t free_src; +} udata_t; + + +/****************************************************************************** + * Function: test_properties + * + * Purpose: Tests that the file image properties (buffer pointer and length) + * are set properly. Image callbacks are not set in this test. + * + * Returns: Success: 0 + * Failure: 1 + * + * Programmer: Jacob Gruber + * Monday, August 22, 2011 + * + ****************************************************************************** + */ +static int +test_properties(void) +{ + hid_t fapl_1; + hid_t fapl_2; + char *buffer; + int count = 10; + void *temp; + char *temp2; + int i; + size_t size; + size_t temp_size; + + TESTING("File image property list functions"); + + /* Initialize file image buffer + * + * Note: this image will not contain a valid HDF5 file, as it complicates testing + * property list functions. In the file driver tests further down, this will + * not be the case. + */ + size = (size_t)count * sizeof(char); + buffer = (char *)HDmalloc(size); + for(i = 0; i < count - 1; i++) + buffer[i] = (char)(65 + i); + buffer[count] = '\0'; + + /* Create fapl */ + if((fapl_1 = H5Pcreate(H5P_FILE_ACCESS)) < 0) FAIL_STACK_ERROR + + /* Get file image stuff */ + if(H5Pget_file_image(fapl_1, (void **)&temp, &temp_size) < 0) FAIL_STACK_ERROR + + /* Check default values */ + VERIFY(temp == NULL, "Default pointer is wrong"); + VERIFY(temp_size == 0, "Default size is wrong"); + + /* Set file image stuff */ + if(H5Pset_file_image(fapl_1, (void *)buffer, size) < 0) FAIL_STACK_ERROR + + /* Get the same */ + if(H5Pget_file_image(fapl_1, (void **)&temp, &temp_size) < 0) FAIL_STACK_ERROR + + /* Check that sizes are the same, and that the buffers are identical but separate */ + VERIFY(temp != NULL, "temp is null!"); + VERIFY(temp_size == size, "Sizes of buffers don't match"); + VERIFY(temp != buffer, "Retrieved buffer is the same as original"); + VERIFY(0 == HDmemcmp(temp, buffer, size), "Buffers contain different data"); + + /* Copy the fapl */ + if((fapl_2 = H5Pcopy(fapl_1)) < 0) FAIL_STACK_ERROR + + /* Get values from the new fapl */ + if(H5Pget_file_image(fapl_2, (void **)&temp2, &temp_size) < 0) FAIL_STACK_ERROR + + /* Check that sizes are the same, and that the buffers are identical but separate */ + VERIFY(temp_size == size,"Sizes of buffers don't match"); + VERIFY(temp2 != NULL,"Recieved buffer not set"); + VERIFY(temp2 != buffer, "Retrieved buffer is the same as original"); + VERIFY(temp2 != temp, "Retrieved buffer is the same as previously retrieved buffer"); + VERIFY(0 == HDmemcmp(temp2, buffer, size),"Buffers contain different data"); + + /* Close everything */ + if(H5Pclose(fapl_1) < 0) FAIL_STACK_ERROR + if(H5Pclose(fapl_2) < 0) FAIL_STACK_ERROR + HDfree(buffer); + HDfree(temp); + HDfree(temp2); + + PASSED(); + return 0; + +error: + return 1; +} /* end test_properties() */ + +/****************************************************************************** + * Function: malloc_cb + * + * Purpose: This function allows calls to the malloc callback to be tracked. + * + * Returns: The result of a standard malloc + * + * Programmer: Jacob Gruber + * Monday, August 22, 2011 + * + ****************************************************************************** + */ +static void * +malloc_cb(size_t size, H5FD_file_image_op_t op, void *udata) +{ + udata_t *u = (udata_t *)udata; + + u->used_callbacks |= MALLOC; + u->malloc_src = op; + return HDmalloc(size); +} + +/****************************************************************************** + * Function: memcpy_cb + * + * Purpose: This function allows calls to the memcpy callback to be tracked. + * + * Returns: The result of a standard memcpy + * + * Programmer: Jacob Gruber + * Monday, August 22, 2011 + * + ****************************************************************************** + */ +static void * +memcpy_cb(void *dest, const void *src, size_t size, H5FD_file_image_op_t op, void *udata) +{ + udata_t *u = (udata_t *)udata; + + u->used_callbacks |= MEMCPY; + u->memcpy_src = op; + return HDmemcpy(dest, src, size); +} + +/****************************************************************************** + * Function: realloc_cb + * + * Purpose: This function allows calls to the realloc callback to be tracked. + * + * Returns: The result of a standard realloc + * + * Programmer: Jacob Gruber + * Monday, August 22, 2011 + * + ****************************************************************************** + */ +static void * +realloc_cb(void *ptr, size_t size, H5FD_file_image_op_t op, void *udata) +{ + udata_t *u = (udata_t *)udata; + + u->used_callbacks |= REALLOC; + u->realloc_src = op; + return HDrealloc(ptr,size); +} + +/****************************************************************************** + * Function: free_cb + * + * Purpose: This function allows calls to the free callback to be tracked. + * + * Programmer: Jacob Gruber + * Monday, August 22, 2011 + * + ****************************************************************************** + */ +static herr_t +free_cb(void *ptr, H5FD_file_image_op_t op, void *udata) +{ + udata_t *u = (udata_t *)udata; + + u->used_callbacks |= FREE; + u->free_src = op; + HDfree(ptr); + return(SUCCEED); +} + +/****************************************************************************** + * Function: udata_copy_cb + * + * Purpose: This function allows calls to the udata_copy callback to be tracked. + * No copying actualy takes place; it is easier to deal with only one + * instance of the udata. + * + * Returns: A pointer to the same udata that was passed in. + * + * Programmer: Jacob Gruber + * Monday, August 22, 2011 + * + ****************************************************************************** + */ +static void * +udata_copy_cb(void *udata) +{ + udata_t *u = (udata_t *)udata; + + u->used_callbacks |= UDATA_COPY; + return udata; +} + +/****************************************************************************** + * Function: udata_free_cb + * + * Purpose: This function allows calls to the udata_free callback to be tracked. + * + * Note: this callback doesn't actually do anything. Since the + * udata_copy callback doesn't copy, only one instance of the udata + * is kept alive and such it must be freed explicitly at the end of the tests. + * + * Programmer: Jacob Gruber + * Monday, August 22, 2011 + * + ****************************************************************************** + */ +static herr_t +udata_free_cb(void *udata) +{ + udata_t *u = (udata_t *)udata; + + u->used_callbacks |= UDATA_FREE; + return(SUCCEED); +} + +/****************************************************************************** + * Function: reset_udata + * + * Purpose: Resets the udata to default values. This facilitates storing only + * the results of a single operation in the udata. + * + * Programmer: Jacob Gruber + * Monday, August 22, 2011 + * + ****************************************************************************** + */ +static void +reset_udata(udata_t *u) +{ + u->used_callbacks = 0; + u->malloc_src = u->memcpy_src = u->realloc_src = u->free_src = H5FD_FILE_IMAGE_OP_NO_OP; +} + +/****************************************************************************** + * Function: test_callbacks + * + * Purpose: Tests that callbacks are called properly in property list functions. + * + * Programmer: Jacob Gruber + * Monday, August 22, 2011 + * + ****************************************************************************** + */ +static int +test_callbacks(void) +{ + H5FD_file_image_callbacks_t real_callbacks = {&malloc_cb, &memcpy_cb, &realloc_cb, + &free_cb, &udata_copy_cb, &udata_free_cb, NULL}; + H5FD_file_image_callbacks_t null_callbacks = {NULL, NULL, NULL, NULL, NULL, NULL, NULL}; + H5FD_file_image_callbacks_t callbacks; + hid_t fapl_1; + hid_t fapl_2; + udata_t *udata; + char *file_image; + char *temp_file_image; + int count = 10; + int i; + size_t size; + size_t temp_size; + + TESTING("Callback use in property list operations"); + + /* Allocate and initialize udata */ + udata = (udata_t *)HDmalloc(sizeof(udata_t)); + reset_udata(udata); + + /* copy the address of the user data into read_callbacks */ + real_callbacks.udata = (void *)udata; + + /* Allocate and initialize file image buffer */ + size = (size_t)count * sizeof(char); + file_image = (char *)HDmalloc(size); + for(i = 0; i < count - 1; i++) + file_image[i] = (char)(65 + i); + file_image[count] = '\0'; + + /* Create fapl */ + if((fapl_1 = H5Pcreate(H5P_FILE_ACCESS)) < 0) FAIL_STACK_ERROR + + /* Get file image stuff */ + callbacks = real_callbacks; + if(H5Pget_file_image_callbacks(fapl_1, &callbacks) < 0) FAIL_STACK_ERROR + + /* Check default values */ + VERIFY(callbacks.image_malloc == NULL, "Default malloc callback is wrong"); + VERIFY(callbacks.image_memcpy == NULL, "Default memcpy callback is wrong"); + VERIFY(callbacks.image_realloc == NULL, "Default realloc callback is wrong"); + VERIFY(callbacks.image_free == NULL, "Default free callback is wrong"); + VERIFY(callbacks.udata_copy == NULL, "Default udata copy callback is wrong"); + VERIFY(callbacks.udata_free == NULL, "Default udata free callback is wrong"); + VERIFY(callbacks.udata == NULL, "Default udata is wrong"); + + + /* Set file image callbacks */ + callbacks = real_callbacks; + if(H5Pset_file_image_callbacks(fapl_1, &callbacks) < 0) FAIL_STACK_ERROR + + /* Get file image callbacks */ + callbacks = null_callbacks; + if(H5Pget_file_image_callbacks(fapl_1, &callbacks) < 0) FAIL_STACK_ERROR + + /* Verify values */ + VERIFY(callbacks.image_malloc == &malloc_cb, "malloc callback was not set or retrieved properly"); + VERIFY(callbacks.image_memcpy == &memcpy_cb, "memcpy callback was not set or retrieved properly"); + VERIFY(callbacks.image_realloc == &realloc_cb, "realloc callback was not set or retrieved properly"); + VERIFY(callbacks.image_free == &free_cb, "free callback was not set or retrieved properly"); + VERIFY(callbacks.udata_copy == &udata_copy_cb, "udata copy callback was not set or retrieved properly"); + VERIFY(callbacks.udata_free == &udata_free_cb, "udata free callback was not set or retrieved properly"); + VERIFY(callbacks.udata == udata, "udata was not set or retrieved properly"); + + + /* + * Check callbacks in internal function without a previously set file image + */ + + /* Copy fapl */ + reset_udata(udata); + if((fapl_2 = H5Pcopy(fapl_1)) < 0) FAIL_STACK_ERROR + + /* Verify that the property's copy callback used the correct image callbacks */ + VERIFY(udata->used_callbacks == (UDATA_COPY), "Copying a fapl with no image used incorrect callbacks"); + + /* Close fapl */ + reset_udata(udata); + if(H5Pclose(fapl_2) < 0) FAIL_STACK_ERROR + + /* Verify that the udata free callback was used */ + VERIFY(udata->used_callbacks == (UDATA_FREE), "Closing a fapl with no image used incorrect callbacks"); + + /* Copy again */ + if((fapl_2 = H5Pcopy(fapl_1)) < 0) FAIL_STACK_ERROR + + /* Remove property from fapl */ + reset_udata(udata); + if(H5Premove(fapl_2, H5F_ACS_FILE_IMAGE_INFO_NAME) < 0) FAIL_STACK_ERROR + + /* Verify that the property's delete callback was called using the correct image callbacks */ + VERIFY(udata->used_callbacks == (UDATA_FREE), "Removing a property from a fapl with no image used incorrect callbacks"); + + /* Close it again */ + if(H5Pclose(fapl_2) < 0) FAIL_STACK_ERROR + + /* Get file image */ + reset_udata(udata); + if(H5Pget_file_image(fapl_1, (void **)&temp_file_image, &temp_size) < 0) FAIL_STACK_ERROR + + /* Verify that the correct callbacks were used */ + VERIFY(udata->used_callbacks == 0, "attempting to retrieve the image from a fapl without an image has an unexpected callback"); + + /* Set file image */ + reset_udata(udata); + if(H5Pset_file_image(fapl_1, (void *)file_image, size) < 0) FAIL_STACK_ERROR + + VERIFY(udata->used_callbacks == (MALLOC | MEMCPY), "Setting a file image (first time) used incorrect callbacks"); + + /* + * Check callbacks in internal functions with a previously set file image + */ + + /* Copy fapl */ + reset_udata(udata); + if((fapl_2 = H5Pcopy(fapl_1)) < 0) FAIL_STACK_ERROR + + /* Verify that the property's copy callback used the correct image callbacks */ + VERIFY(udata->used_callbacks == (MALLOC | MEMCPY | UDATA_COPY), "Copying a fapl with an image used incorrect callbacks"); + VERIFY(udata->malloc_src == H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY, "malloc callback has wrong source"); + VERIFY(udata->memcpy_src == H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY, "memcpy callback has wrong source"); + + /* Close fapl */ + reset_udata(udata); + if(H5Pclose(fapl_2) < 0) FAIL_STACK_ERROR + + /* Verify that the udata free callback was used */ + VERIFY(udata->used_callbacks == (FREE | UDATA_FREE), "Closing a fapl with an image used incorrect callbacks"); + VERIFY(udata->free_src == H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE, "free callback has wrong source"); + + /* Copy again */ + if((fapl_2 = H5Pcopy(fapl_1)) < 0) FAIL_STACK_ERROR + + /* Remove property from fapl */ + reset_udata(udata); + if(H5Premove(fapl_2, H5F_ACS_FILE_IMAGE_INFO_NAME) < 0) FAIL_STACK_ERROR + + /* Verify that the property's delete callback was called using the correct image callbacks */ + VERIFY(udata->used_callbacks == (FREE | UDATA_FREE), "Removing a property from a fapl with an image used incorrect callbacks"); + VERIFY(udata->free_src == H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE, "free callback has wrong source"); + + /* Close it again */ + if(H5Pclose(fapl_2) < 0) FAIL_STACK_ERROR + + /* Get file image */ + reset_udata(udata); + if(H5Pget_file_image(fapl_1, (void **)&temp_file_image, &temp_size) < 0) FAIL_STACK_ERROR + + /* Verify that the correct callbacks were used */ + VERIFY(udata->used_callbacks == (MALLOC | MEMCPY), "attempting to retrieve the image from a fapl with an image has an unexpected callback"); + VERIFY(udata->malloc_src == H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET, "malloc callback has wrong source"); + VERIFY(udata->memcpy_src == H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET, "memcpy callback has wrong source"); + + /* Set file image */ + reset_udata(udata); + if(H5Pset_file_image(fapl_1, (void *)file_image, size) < 0) FAIL_STACK_ERROR + + VERIFY(udata->used_callbacks == (FREE | MALLOC | MEMCPY), "Setting a file image (second time) used incorrect callbacks"); + VERIFY(udata->malloc_src == H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET, "malloc callback has wrong source"); + VERIFY(udata->memcpy_src == H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET, "memcpy callback has wrong source"); + VERIFY(udata->free_src == H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET, "freec callback has wrong source"); + + /* Close stuff */ + if(H5Pclose(fapl_1) < 0) FAIL_STACK_ERROR + HDfree(file_image); + HDfree(temp_file_image); + HDfree(udata); + + PASSED(); + return 0; + +error: + return 1; +} /* test_callbacks() */ + +/****************************************************************************** + * Function: test_core + * + * Purpose: Tests that callbacks are called properly in the core VFD and + * that the initial file image works properly. + * + * Programmer: Jacob Gruber + * Monday, August 22, 2011 + * + ****************************************************************************** + */ +static int +test_core(void) +{ + hid_t fapl; + hid_t file; + hid_t dset; + hid_t space; + udata_t *udata; + unsigned char *file_image; + char filename[1024]; + char src_dir_filename[1024]; + const char *tmp = NULL; + size_t size; + hsize_t dims[2]; + int fd; + h5_stat_t sb; + herr_t ret; + H5FD_file_image_callbacks_t callbacks = {&malloc_cb, &memcpy_cb, &realloc_cb, + &free_cb, &udata_copy_cb, &udata_free_cb, NULL}; + + TESTING("Initial file image and callbacks in Core VFD"); + + /* Create fapl */ + fapl = h5_fileaccess(); + VERIFY(fapl >= 0, "fapl creation failed"); + + /* Set up the core VFD */ + ret = H5Pset_fapl_core(fapl, 0, 0); + VERIFY(ret >= 0, "setting core driver in fapl failed"); + + tmp = h5_fixname(FILENAME[0], fapl, filename, sizeof(filename)); + VERIFY(tmp != NULL, "h5_fixname failed"); + + /* convert file name to srcdir file name. Make a copy as + * H5_get_srcdir_filename() simply sets up the file name in its + * own buffer each time it is called -- overwriting the previous + * value. + */ + tmp = H5_get_srcdir_filename(filename); + VERIFY(tmp != NULL, "H5_get_srcdir_filename failed"); + VERIFY(strlen(tmp) < 1023, "srcdir file name too long."); + HDstrncpy(src_dir_filename, tmp, 1023); + src_dir_filename[1023] = '\0'; + + /* Allocate and initialize udata */ + udata = (udata_t *)HDmalloc(sizeof(udata_t)); + VERIFY(udata != NULL, "udata malloc failed"); + + /* copy the address of the udata into the callbacks structure */ + callbacks.udata = (void *)udata; + + /* Set file image callbacks */ + ret = H5Pset_file_image_callbacks(fapl, &callbacks); + VERIFY(ret >= 0, "set image callbacks failed"); + + /* Test open (no file image) */ + reset_udata(udata); + file = H5Fopen(src_dir_filename, H5F_ACC_RDWR, fapl); + VERIFY(file >= 0, "H5Fopen failed"); + VERIFY(udata->used_callbacks == MALLOC, "opening a core file used the wrong callbacks"); + VERIFY(udata->malloc_src == H5FD_FILE_IMAGE_OP_FILE_OPEN, "Malloc callback came from wrong sourc in core open"); + + /* Close file */ + reset_udata(udata); + ret = H5Fclose(file); + VERIFY(ret >= 0, "H5Fclose failed"); + VERIFY(udata->used_callbacks == FREE, "Closing a core file used the wrong callbacks"); + VERIFY(udata->free_src == H5FD_FILE_IMAGE_OP_FILE_CLOSE, "Free callback came from wrong sourc in core close"); + + /* Reopen file */ + file = H5Fopen(src_dir_filename, H5F_ACC_RDWR, fapl); + VERIFY(file >= 0, "H5Fopen failed"); + + /* Set up a new dset */ + dims[0] = DIM0; + dims[1] = DIM1; + space = H5Screate_simple(RANK, dims, dims); + VERIFY(space >= 0, "H5Screate failed"); + + /* Create new dset, invoking H5FD_core_write */ + reset_udata(udata); + dset = H5Dcreate2(file, DSET_NAME, H5T_NATIVE_INT, space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VERIFY(dset >=0, "H5Dcreate failed"); + + /* Flush the write and check the realloc callback */ + ret = H5Fflush(file, H5F_SCOPE_LOCAL); + VERIFY(ret >= 0, "H5Fflush failed"); + VERIFY(udata->used_callbacks == (REALLOC), "core write used the wrong callbacks"); + VERIFY(udata->realloc_src == H5FD_FILE_IMAGE_OP_FILE_RESIZE, "Realloc callback came from wrong source in core write"); + + /* Close dset and space */ + ret = H5Dclose(dset); + VERIFY(ret >= 0, "H5Dclose failed"); + ret = H5Sclose(space); + VERIFY(ret >= 0, "H5Sclose failed"); + + /* Test file close */ + reset_udata(udata); + ret = H5Fclose(file); + VERIFY(ret >= 0, "H5Fclose failed"); + VERIFY(udata->used_callbacks == (FREE), "Closing a core file used the wrong callbacks"); + VERIFY(udata->free_src == H5FD_FILE_IMAGE_OP_FILE_CLOSE, "Free callback came from wrong sourc in core close"); + + /* Create file image buffer */ + fd = HDopen(src_dir_filename, O_RDONLY, 0666); + VERIFY(fd > 0, "open failed"); + ret = HDfstat(fd, &sb); + VERIFY(ret == 0, "fstat failed"); + size = (size_t)sb.st_size; + file_image = (unsigned char *)HDmalloc(size); + HDread(fd, file_image, size); + ret = HDclose(fd); + VERIFY(ret == 0, "close failed"); + + /* Set file image in plist */ + if(H5Pset_file_image(fapl, file_image, size) < 0) FAIL_STACK_ERROR + + /* Test open with file image */ + if((file = H5Fopen("dne.h5", H5F_ACC_RDWR, fapl)) < 0) FAIL_STACK_ERROR + if(H5Fclose(file) < 0) FAIL_STACK_ERROR + + /* Release resources */ + h5_cleanup(FILENAME, fapl); + HDfree(udata); + HDfree(file_image); + + PASSED(); + + return 0; + +error: + return 1; +} /* end test_core() */ + +/****************************************************************************** + * Function: test_get_file_image + * + * Purpose: Test the H5Fget_file_image() call. + * + * Programmer: John Mainzer + * Tuesday, November 15, 2011 + * + ****************************************************************************** + */ +static int +test_get_file_image(const char * test_banner, + const int file_name_num, + hid_t fapl) +{ + char file_name[1024] = "\0"; + void * insertion_ptr = NULL; + void * image_ptr = NULL; + void * file_image_ptr = NULL; + hbool_t is_family_file = FALSE; + hbool_t identical; + int data[100]; + int i; + int fd = -1; + int result; + hid_t driver = -1; + hid_t file_id = -1; + hid_t dset_id = -1; + hid_t space_id = -1; + hid_t core_fapl_id = -1; + hid_t core_file_id = -1; + herr_t err; + hsize_t dims[2]; + ssize_t bytes_read; + ssize_t image_size; + ssize_t file_size; + h5_stat_t stat_buf; + + TESTING(test_banner); + + /* set flag if we are dealing with a family file */ + driver = H5Pget_driver(fapl); + VERIFY(driver >= 0, "H5Pget_driver(fapl) failed"); + + if(driver == H5FD_FAMILY) + is_family_file = TRUE; + + /* setup the file name */ + h5_fixname(FILENAME2[file_name_num], fapl, file_name, sizeof(file_name)); + VERIFY(HDstrlen(file_name)>0, "h5_fixname failed"); + + /* create the file */ + file_id = H5Fcreate(file_name, 0, H5P_DEFAULT, fapl); + VERIFY(file_id >= 0, "H5Fcreate() failed."); + + /* Set up data space for new new data set */ + dims[0] = 10; + dims[1] = 10; + space_id = H5Screate_simple(2, dims, dims); + VERIFY(space_id >= 0, "H5Screate() failed"); + + /* Create a dataset */ + dset_id = H5Dcreate2(file_id, "dset 0", H5T_NATIVE_INT, space_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VERIFY(dset_id >=0, "H5Dcreate() failed"); + + /* write some data to the data set */ + for (i = 0; i < 100; i++) + data[i] = i; + err = H5Dwrite(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, (void *)data); + VERIFY(err >= 0, "H5Dwrite() failed."); + + /* Flush the file */ + err = H5Fflush(file_id, H5F_SCOPE_GLOBAL); + VERIFY(err >= 0, "H5Fflush failed"); + + /* get the size of the file */ + image_size = H5Fget_file_image(file_id, NULL, (size_t)0); + VERIFY(image_size > 0, "H5Fget_file_image(1) failed."); + + /* allocate a buffer of the appropriate size */ + image_ptr = HDmalloc((size_t)image_size); + VERIFY(image_ptr != NULL, "HDmalloc(1) failed."); + + /* load the image of the file into the buffer */ + bytes_read = H5Fget_file_image(file_id, image_ptr, (size_t)image_size); + VERIFY(bytes_read == image_size, "H5Fget_file_image(2) failed."); + + /* Close dset and space */ + err = H5Dclose(dset_id); + VERIFY(err >= 0, "H5Dclose failed"); + err = H5Sclose(space_id); + VERIFY(err >= 0, "H5Sclose failed"); + + /* close the test file */ + err = H5Fclose(file_id); + VERIFY(err == SUCCEED, "H5Fclose(file_id) failed."); + + if(is_family_file) { + char member_file_name[1024]; + ssize_t bytes_to_read; + ssize_t member_size; + ssize_t size_remaining; + + i = 0; + file_size = 0; + + do { + HDsnprintf(member_file_name, 1024, file_name, i); + + /* get the size of the member file */ + result = HDstat(member_file_name, &stat_buf); + VERIFY(result == 0, "HDstat() failed."); + + member_size = (ssize_t)stat_buf.st_size; + + i++; + file_size += member_size; + } while(member_size > 0); + + /* Since we use the eoa to calculate the image size, the file size + * may be larger. This is OK, as long as (in this specialized instance) + * the remainder of the file is all '\0's. + */ + VERIFY(file_size >= image_size, "file size != image size."); + + /* allocate a buffer for the test file image */ + file_image_ptr = HDmalloc((size_t)file_size); + VERIFY(file_image_ptr != NULL, "HDmalloc(2f) failed."); + + size_remaining = image_size; + insertion_ptr = file_image_ptr; + i = 0; + + while(size_remaining > 0) { + /* construct the member file name */ + HDsnprintf(member_file_name, 1024, file_name, i); + + /* open the test file using standard I/O calls */ + fd = HDopen(member_file_name, O_RDONLY, 0666); + VERIFY(fd >= 0, "HDopen() failed."); + + if(size_remaining >= FAMILY_SIZE ){ + bytes_to_read = FAMILY_SIZE; + size_remaining -= FAMILY_SIZE; + } else { + bytes_to_read = size_remaining; + size_remaining = 0; + } + + /* read the member file from disk into the buffer */ + bytes_read = HDread(fd, insertion_ptr, (size_t)bytes_to_read); + VERIFY(bytes_read == bytes_to_read, "HDread() failed."); + + insertion_ptr = (void *)(((char *)insertion_ptr) + bytes_to_read); + + i++; + + /* close the test file */ + result = HDclose(fd); + VERIFY(result == 0, "HDclose() failed."); + } + } else { + /* get the size of the test file */ + result = HDstat(file_name, &stat_buf); + VERIFY(result == 0, "HDstat() failed."); + + /* Since we use the eoa to calculate the image size, the file size + * may be larger. This is OK, as long as (in this specialized instance) + * the remainder of the file is all '\0's. + */ + file_size = (ssize_t)stat_buf.st_size; + + /* with latest mods to truncate call in core file drive, + * file size should match image size + */ + VERIFY(file_size == image_size, "file size != image size."); + + /* allocate a buffer for the test file image */ + file_image_ptr = HDmalloc((size_t)file_size); + VERIFY(file_image_ptr != NULL, "HDmalloc(2) failed."); + + /* open the test file using standard I/O calls */ + fd = HDopen(file_name, O_RDONLY, 0666); + VERIFY(fd >= 0, "HDopen() failed."); + + /* read the test file from disk into the buffer */ + bytes_read = HDread(fd, file_image_ptr, (size_t)file_size); + VERIFY(bytes_read == file_size, "HDread() failed."); + + /* close the test file */ + result = HDclose(fd); + VERIFY(result == 0, "HDclose() failed."); + } + + /* verify that the file and the image contain the same data */ + identical = TRUE; + i = 0; + while((i < (int)image_size) && identical) { + if(((char *)image_ptr)[i] != ((char *)file_image_ptr)[i]) + identical = FALSE; + i++; + } + VERIFY(identical, "file and image differ."); + + + /* finally, verify that we can use the core file driver to open the image */ + + /* create fapl for core file driver */ + core_fapl_id = H5Pcreate(H5P_FILE_ACCESS); + VERIFY(core_fapl_id >=0, "H5Pcreate() failed"); + + /* setup core_fapl_id to use the core file driver */ + err = H5Pset_fapl_core(core_fapl_id, (size_t)(64 * 1024), FALSE); + VERIFY(err == SUCCEED, "H5Pset_fapl_core() failed."); + + /* Set file image in core fapl */ + err = H5Pset_file_image(core_fapl_id, image_ptr, (size_t)image_size); + VERIFY(err == SUCCEED, "H5Pset_file_image() failed."); + + /* open the file image with the core file driver */ + core_file_id = H5Fopen("nonesuch", H5F_ACC_RDWR, core_fapl_id); + VERIFY(core_file_id >= 0, "H5Fopen() of file image failed."); + + /* close the file image with the core file driver */ + err = H5Fclose(core_file_id); + VERIFY(err == SUCCEED, "H5Fclose(core_file_id) failed."); + + /* dicard core fapl */ + err = H5Pclose(core_fapl_id); + VERIFY(err == SUCCEED, "H5Pclose(core_fapl_id) failed."); + + /* tidy up */ + result = h5_cleanup(FILENAME2, fapl); + VERIFY(result != 0, "h5_cleanup() failed."); + + /* discard the image buffer if it exists */ + if(image_ptr != NULL) + HDfree(image_ptr); + + /* discard the image buffer if it exists */ + if(file_image_ptr != NULL) + HDfree(file_image_ptr); + + PASSED(); + + return 0; + +error: + return 1; +} /* end test_get_file_image() */ + +/****************************************************************************** + * Function: test_get_file_image_error_rejection + * + * Purpose: Verify that H5Fget_file_image() rejects invalid input. + * + * Programmer: John Mainzer + * Tuesday, November 22, 2011 + * + ****************************************************************************** + */ + +#define TYPE_SLICE ((haddr_t)0x10000LL) + +static int +test_get_file_image_error_rejection(void) +{ + const char *memb_name[H5FD_MEM_NTYPES]; + char file_name[1024] = "\0"; + void * image_ptr = NULL; + int data[100]; + int i; + int result; + hid_t fapl_id = -1; + hid_t file_id = -1; + hid_t dset_id = -1; + hid_t space_id = -1; + herr_t err; + hsize_t dims[2]; + ssize_t bytes_read; + ssize_t image_size; + hid_t memb_fapl[H5FD_MEM_NTYPES]; + haddr_t memb_addr[H5FD_MEM_NTYPES]; + H5FD_mem_t mt; + H5FD_mem_t memb_map[H5FD_MEM_NTYPES]; + + + TESTING("H5Fget_file_image() error rejection"); + + /************************ Sub-Test #1 ********************************/ + /* set up a test file, and try to get its image with a buffer that is + * too small. Call to H5Fget_file_image() should fail. + * + * Since we have already done the necessary setup, verify that + * H5Fget_file_image() will fail with: + * + * bad file id, or + * + * good id, but not a file id + */ + + + /* setup fapl -- driver type doesn't matter much, so make it stdio */ + fapl_id = H5Pcreate(H5P_FILE_ACCESS); + VERIFY(fapl_id >= 0, "H5Pcreate(1) failed"); + + err = H5Pset_fapl_stdio(fapl_id); + VERIFY(err >= 0, "H5Pset_fapl_stdio() failed"); + + /* setup the file name */ + h5_fixname(FILENAME2[6], fapl_id, file_name, sizeof(file_name)); + VERIFY(HDstrlen(file_name)>0, "h5_fixname failed"); + + /* create the file */ + file_id = H5Fcreate(file_name, 0, H5P_DEFAULT, fapl_id); + VERIFY(file_id >= 0, "H5Fcreate() failed."); + + /* Set up data space for new new data set */ + dims[0] = 10; + dims[1] = 10; + space_id = H5Screate_simple(2, dims, dims); + VERIFY(space_id >= 0, "H5Screate() failed"); + + /* Create a dataset */ + dset_id = H5Dcreate2(file_id, "dset 0", H5T_NATIVE_INT, space_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VERIFY(dset_id >=0, "H5Dcreate() failed"); + + /* write some data to the data set */ + for (i = 0; i < 100; i++) + data[i] = i; + err = H5Dwrite(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, + H5P_DEFAULT, (void *)data); + VERIFY(err >= 0, "H5Dwrite() failed."); + + /* Flush the file */ + err = H5Fflush(file_id, H5F_SCOPE_GLOBAL); + VERIFY(err >= 0, "H5Fflush failed"); + + /* get the size of the file */ + image_size = H5Fget_file_image(file_id, NULL, (size_t)0); + VERIFY(image_size > 0, "H5Fget_file_image(1 -- test 1) failed."); + + /* allocate a buffer of the appropriate size */ + image_ptr = HDmalloc((size_t)image_size); + VERIFY(image_ptr != NULL, "HDmalloc(1) failed."); + + /* load the image of the file into the buffer */ + H5E_BEGIN_TRY { + bytes_read = H5Fget_file_image(file_id, image_ptr, (size_t)(image_size - 1)); + } H5E_END_TRY; + VERIFY(bytes_read < 0, "H5Fget_file_image(2 -- test 1) succeeded."); + + /* Call H5Fget_file_image() with good buffer and buffer size, + * but non-existant file_id. Should fail. + */ + H5E_BEGIN_TRY { + bytes_read = H5Fget_file_image((hid_t)0, image_ptr, (size_t)(image_size)); + } H5E_END_TRY; + VERIFY(bytes_read < 0, "H5Fget_file_image(3 -- test 1) succeeded."); + + /* Call H5Fget_file_image() with good buffer and buffer size, + * but a file_id of the wrong type. Should fail. + */ + H5E_BEGIN_TRY { + bytes_read = H5Fget_file_image(dset_id, image_ptr, (size_t)(image_size)); + } H5E_END_TRY; + VERIFY(bytes_read < 0, "H5Fget_file_image(4 -- test 1) succeeded."); + + /* Close dset and space */ + err = H5Dclose(dset_id); + VERIFY(err >= 0, "H5Dclose failed"); + err = H5Sclose(space_id); + VERIFY(err >= 0, "H5Sclose failed"); + + /* close the test file */ + err = H5Fclose(file_id); + VERIFY(err == SUCCEED, "H5Fclose(file_id) failed."); + + /* tidy up */ + result = h5_cleanup(FILENAME2, fapl_id); + VERIFY(result != 0, "h5_cleanup(1) failed."); + + /* discard the image buffer if it exists */ + if(image_ptr != NULL) + HDfree(image_ptr); + + /************************** Test #2 **********************************/ + /* set up a multi file driver test file, and try to get its image + * with H5Fget_file_image(). Attempt should fail. + */ + + /* setup parameters for multi file driver */ + for(mt = (H5FD_mem_t)0; mt < H5FD_MEM_NTYPES; mt = (H5FD_mem_t)(mt + 1)) { + memb_addr[mt] = HADDR_UNDEF; + memb_fapl[mt] = H5P_DEFAULT; + memb_map[mt] = H5FD_MEM_DRAW; + memb_name[mt] = NULL; + } + + memb_map[H5FD_MEM_SUPER] = H5FD_MEM_SUPER; + memb_fapl[H5FD_MEM_SUPER] = H5P_DEFAULT; + memb_name[H5FD_MEM_SUPER] = "%s-s.h5"; + memb_addr[H5FD_MEM_SUPER] = 0; + + memb_map[H5FD_MEM_BTREE] = H5FD_MEM_BTREE; + memb_fapl[H5FD_MEM_BTREE] = H5P_DEFAULT; + memb_name[H5FD_MEM_BTREE] = "%s-b.h5"; + memb_addr[H5FD_MEM_BTREE] = memb_addr[H5FD_MEM_SUPER] + TYPE_SLICE; + + memb_map[H5FD_MEM_DRAW] = H5FD_MEM_DRAW; + memb_fapl[H5FD_MEM_DRAW] = H5P_DEFAULT; + memb_name[H5FD_MEM_DRAW] = "%s-r.h5"; + memb_addr[H5FD_MEM_DRAW] = memb_addr[H5FD_MEM_BTREE] + TYPE_SLICE; + + memb_map[H5FD_MEM_GHEAP] = H5FD_MEM_GHEAP; + memb_fapl[H5FD_MEM_GHEAP] = H5P_DEFAULT; + memb_name[H5FD_MEM_GHEAP] = "%s-g.h5"; + memb_addr[H5FD_MEM_GHEAP] = memb_addr[H5FD_MEM_DRAW] + TYPE_SLICE; + + memb_map[H5FD_MEM_LHEAP] = H5FD_MEM_LHEAP; + memb_fapl[H5FD_MEM_LHEAP] = H5P_DEFAULT; + memb_name[H5FD_MEM_LHEAP] = "%s-l.h5"; + memb_addr[H5FD_MEM_LHEAP] = memb_addr[H5FD_MEM_GHEAP] + TYPE_SLICE; + + memb_map[H5FD_MEM_OHDR] = H5FD_MEM_OHDR; + memb_fapl[H5FD_MEM_OHDR] = H5P_DEFAULT; + memb_name[H5FD_MEM_OHDR] = "%s-o.h5"; + memb_addr[H5FD_MEM_OHDR] = memb_addr[H5FD_MEM_LHEAP] + TYPE_SLICE; + + /* setup fapl */ + fapl_id = H5Pcreate(H5P_FILE_ACCESS); + VERIFY(fapl_id >= 0, "H5Pcreate(2) failed"); + + /* setup the fapl for the multi file driver */ + err = H5Pset_fapl_multi(fapl_id, memb_map, memb_fapl, memb_name, + memb_addr, FALSE); + VERIFY(err >= 0, "H5Pset_fapl_multi failed"); + + /* setup the file name */ + h5_fixname(FILENAME2[4], fapl_id, file_name, sizeof(file_name)); + VERIFY(HDstrlen(file_name)>0, "h5_fixname failed"); + + /* create the file */ + file_id = H5Fcreate(file_name, 0, H5P_DEFAULT, fapl_id); + VERIFY(file_id >= 0, "H5Fcreate() failed."); + + /* Set up data space for new new data set */ + dims[0] = 10; + dims[1] = 10; + space_id = H5Screate_simple(2, dims, dims); + VERIFY(space_id >= 0, "H5Screate() failed"); + + /* Create a dataset */ + dset_id = H5Dcreate2(file_id, "dset 0", H5T_NATIVE_INT, space_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VERIFY(dset_id >=0, "H5Dcreate() failed"); + + /* write some data to the data set */ + for (i = 0; i < 100; i++) + data[i] = i; + err = H5Dwrite(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, + H5P_DEFAULT, (void *)data); + VERIFY(err >= 0, "H5Dwrite() failed."); + + /* Flush the file */ + err = H5Fflush(file_id, H5F_SCOPE_GLOBAL); + VERIFY(err >= 0, "H5Fflush failed"); + + /* attempt to get the size of the file -- should fail */ + H5E_BEGIN_TRY { + image_size = H5Fget_file_image(file_id, NULL, (size_t)0); + } H5E_END_TRY; + VERIFY(image_size == -1, "H5Fget_file_image(5) succeeded."); + + /* Close dset and space */ + err = H5Dclose(dset_id); + VERIFY(err >= 0, "H5Dclose failed"); + err = H5Sclose(space_id); + VERIFY(err >= 0, "H5Sclose failed"); + + /* close the test file */ + err = H5Fclose(file_id); + VERIFY(err == SUCCEED, "H5Fclose(2) failed."); + + /* tidy up */ + result = h5_cleanup(FILENAME2, fapl_id); + VERIFY(result != 0, "h5_cleanup(2 failed."); + + /************************** Test #3 **********************************/ + /* set up a split file driver test file, and try to get its image + * with H5Fget_file_image(). Attempt should fail. + */ + + /* create fapl */ + fapl_id = H5Pcreate(H5P_FILE_ACCESS); + VERIFY(fapl_id >= 0, "H5Pcreate(3) failed"); + + /* setup the fapl for the split file driver */ + err = H5Pset_fapl_split(fapl_id, "-m.h5", H5P_DEFAULT, "-r.h5", H5P_DEFAULT); + VERIFY(err >= 0, "H5Pset_fapl_split failed"); + + /* setup the file name */ + h5_fixname(FILENAME2[5], fapl_id, file_name, sizeof(file_name)); + VERIFY(HDstrlen(file_name)>0, "h5_fixname failed"); + + /* create the file */ + file_id = H5Fcreate(file_name, 0, H5P_DEFAULT, fapl_id); + VERIFY(file_id >= 0, "H5Fcreate() failed."); + + /* Set up data space for new new data set */ + dims[0] = 10; + dims[1] = 10; + space_id = H5Screate_simple(2, dims, dims); + VERIFY(space_id >= 0, "H5Screate() failed"); + + /* Create a dataset */ + dset_id = H5Dcreate2(file_id, "dset 0", H5T_NATIVE_INT, space_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VERIFY(dset_id >=0, "H5Dcreate() failed"); + + /* write some data to the data set */ + for (i = 0; i < 100; i++) + data[i] = i; + err = H5Dwrite(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, + H5P_DEFAULT, (void *)data); + VERIFY(err >= 0, "H5Dwrite() failed."); + + /* Flush the file */ + err = H5Fflush(file_id, H5F_SCOPE_GLOBAL); + VERIFY(err >= 0, "H5Fflush failed"); + + /* attempt to get the size of the file -- should fail */ + H5E_BEGIN_TRY { + image_size = H5Fget_file_image(file_id, NULL, (size_t)0); + } H5E_END_TRY; + VERIFY(image_size == -1, "H5Fget_file_image(6) succeeded."); + + /* Close dset and space */ + err = H5Dclose(dset_id); + VERIFY(err >= 0, "H5Dclose failed"); + err = H5Sclose(space_id); + VERIFY(err >= 0, "H5Sclose failed"); + + /* close the test file */ + err = H5Fclose(file_id); + VERIFY(err == SUCCEED, "H5Fclose(2) failed."); + + + /************************** Test #4 **********************************/ + /* set up a family file driver test file, and try to get its image + * with H5Fget_file_image(). Attempt should fail. + */ + + /* create fapl */ + fapl_id = H5Pcreate(H5P_FILE_ACCESS); + VERIFY(fapl_id >= 0, "H5Pcreate(3) failed"); + + err = H5Pset_fapl_family(fapl_id, (hsize_t)FAMILY_SIZE, H5P_DEFAULT); + VERIFY(err >= 0, "H5Pset_fapl_family failed"); + + h5_fixname(FILENAME2[3], fapl_id, file_name, sizeof(file_name)); + VERIFY(HDstrlen(file_name)>0, "h5_fixname failed"); + + /* create the file */ + file_id = H5Fcreate(file_name, 0, H5P_DEFAULT, fapl_id); + VERIFY(file_id >= 0, "H5Fcreate() failed."); + + /* Set up data space for new new data set */ + dims[0] = 10; + dims[1] = 10; + space_id = H5Screate_simple(2, dims, dims); + VERIFY(space_id >= 0, "H5Screate() failed"); + + /* Create a dataset */ + dset_id = H5Dcreate2(file_id, "dset 0", H5T_NATIVE_INT, space_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VERIFY(dset_id >=0, "H5Dcreate() failed"); + + /* write some data to the data set */ + for (i = 0; i < 100; i++) + data[i] = i; + err = H5Dwrite(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, + H5P_DEFAULT, (void *)data); + VERIFY(err >= 0, "H5Dwrite() failed."); + + /* Flush the file */ + err = H5Fflush(file_id, H5F_SCOPE_GLOBAL); + VERIFY(err >= 0, "H5Fflush failed"); + + /* attempt to get the size of the file -- should fail */ + H5E_BEGIN_TRY { + image_size = H5Fget_file_image(file_id, NULL, (size_t)0); + } H5E_END_TRY; + VERIFY(image_size == -1, "H5Fget_file_image(7) succeeded."); + + /* Close dset and space */ + err = H5Dclose(dset_id); + VERIFY(err >= 0, "H5Dclose failed"); + err = H5Sclose(space_id); + VERIFY(err >= 0, "H5Sclose failed"); + + /* close the test file */ + err = H5Fclose(file_id); + VERIFY(err == SUCCEED, "H5Fclose(2) failed."); + + /* tidy up */ + result = h5_cleanup(FILENAME2, fapl_id); + VERIFY(result != 0, "h5_cleanup(2 failed."); + + PASSED(); + + return 0; + +error: + return 1; +} + +int +main(void) +{ + int errors = 0; + hid_t fapl; + + h5_reset(); + + printf("Testing File Image Functionality.\n"); + + errors += test_properties(); + errors += test_callbacks(); + errors += test_core(); + + /* test H5Fget_file_image() with sec2 driver */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + if(0 > H5Pset_fapl_sec2(fapl)) + errors++; + else + errors += test_get_file_image("H5Fget_file_image() with sec2 driver", + 0, fapl); + + /* test H5Fget_file_image() with stdio driver */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + if(0 > H5Pset_fapl_stdio(fapl)) + errors++; + else + errors += test_get_file_image("H5Fget_file_image() with stdio driver", + 1, fapl); + + /* test H5Fget_file_image() with core driver */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + if(0 > H5Pset_fapl_core(fapl, (size_t)(64 *1024), TRUE)) + errors++; + else + errors += test_get_file_image("H5Fget_file_image() with core driver", + 2, fapl); + +#if 0 + /* at present, H5Fget_file_image() rejects files opened with the + * family file driver, due to the addition of a driver info message + * in the super block. This message prevents the image being opened + * with any driver other than the family file driver, which sort of + * defeats the purpose of the get file image operation. + * + * While this issues is quite fixable, we don't have time or resources + * for this right now. Once we do, the following code should be + * suitable for testing the fix. + */ + /* test H5Fget_file_image() with family file driver */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + if(H5Pset_fapl_family(fapl, (hsize_t)FAMILY_SIZE, H5P_DEFAULT) < 0) + errors++; + else + errors += test_get_file_image("H5Fget_file_image() with family driver", + 3, fapl); +#endif + + errors += test_get_file_image_error_rejection(); + + + if(errors) { + printf("***** %d File Image TEST%s FAILED! *****\n", + errors, errors > 1 ? "S" : ""); + return 1; + } + + printf("All File Image tests passed.\n"); + return 0; +} + diff --git a/test/file_image_core_test.h5 b/test/file_image_core_test.h5 new file mode 100644 index 0000000..1cc5130 Binary files /dev/null and b/test/file_image_core_test.h5 differ diff --git a/test/gen_file_image.c b/test/gen_file_image.c new file mode 100644 index 0000000..bc9de29 --- /dev/null +++ b/test/gen_file_image.c @@ -0,0 +1,91 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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 files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Programmer: Quincey Koziol + * Friday, March 30, 2012 + * + * Purpose: Create a simple file for use with the file image tests. + * + */ +#include "hdf5.h" + +#define TESTFILE "file_image_core_test.h5" + +/* 2-D dataset with fixed dimensions */ +#define SPACE_RANK 2 +#define SPACE_DIM1 128 +#define SPACE_DIM2 32 + +/* Dataset data */ +int data[SPACE_DIM1][SPACE_DIM2]; + + +/*------------------------------------------------------------------------- + * Function: main + * + * Purpose: + * + * Return: Success: + * + * Failure: + * + * Programmer: Quincey Koziol + * Friday, March 30, 2012 + * + *------------------------------------------------------------------------- + */ +int +main(void) +{ + hid_t file, space, dset; + hsize_t dims[SPACE_RANK] = {SPACE_DIM1, SPACE_DIM2}; + size_t i, j; /* Local index variables */ + + /* Initialize the data */ + for(i = 0; i < SPACE_DIM1; i++) + for(j = 0; j < SPACE_DIM2; j++) + data[i][j] = (int)(j % 5); + + /* Create the file */ + file = H5Fcreate(TESTFILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + if(file < 0) + printf("file < 0!\n"); + + /* Create the dataspace */ + space = H5Screate_simple(SPACE_RANK, dims, NULL); + if(space < 0) + printf("space < 0!\n"); + + /* Create the compressed dataset */ + dset = H5Dcreate2(file, "Dataset1", H5T_NATIVE_INT, space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if(dset < 0) + printf("dset < 0!\n"); + + /* Write the data to the dataset */ + if(H5Dwrite(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data) < 0) + printf("H5Dwrite() failed!\n"); + + /* Close everything */ + if(H5Dclose(dset) < 0) + printf("H5Dclose() failed!\n"); + if(H5Sclose(space) < 0) + printf("H5Sclose() failed!\n"); + if(H5Fclose(file) < 0) + printf("H5Fclose() failed!\n"); + + return 0; +} + diff --git a/testpar/Makefile.am b/testpar/Makefile.am index 5a7a3f3..b2fb97c 100644 --- a/testpar/Makefile.am +++ b/testpar/Makefile.am @@ -31,8 +31,8 @@ TEST_SCRIPT_PARA=testph5.sh check_PROGRAMS = $(TEST_PROG_PARA) check_SCRIPTS= $(TEST_SCRIPT) -testphdf5_SOURCES=testphdf5.c t_dset.c t_file.c t_mdset.c t_ph5basic.c \ - t_coll_chunk.c t_span_tree.c t_chunk_alloc.c t_filter_read.c +testphdf5_SOURCES=testphdf5.c t_dset.c t_file.c t_file_image.c t_mdset.c \ + t_ph5basic.c t_coll_chunk.c t_span_tree.c t_chunk_alloc.c t_filter_read.c # The tests all depend on the hdf5 library and the test library LDADD = $(LIBH5TEST) $(LIBHDF5) diff --git a/testpar/Makefile.in b/testpar/Makefile.in index ae0c7d0..a9a4135 100644 --- a/testpar/Makefile.in +++ b/testpar/Makefile.in @@ -95,9 +95,10 @@ t_shapesame_OBJECTS = t_shapesame.$(OBJEXT) t_shapesame_LDADD = $(LDADD) t_shapesame_DEPENDENCIES = $(LIBH5TEST) $(LIBHDF5) am_testphdf5_OBJECTS = testphdf5.$(OBJEXT) t_dset.$(OBJEXT) \ - t_file.$(OBJEXT) t_mdset.$(OBJEXT) t_ph5basic.$(OBJEXT) \ - t_coll_chunk.$(OBJEXT) t_span_tree.$(OBJEXT) \ - t_chunk_alloc.$(OBJEXT) t_filter_read.$(OBJEXT) + t_file.$(OBJEXT) t_file_image.$(OBJEXT) t_mdset.$(OBJEXT) \ + t_ph5basic.$(OBJEXT) t_coll_chunk.$(OBJEXT) \ + t_span_tree.$(OBJEXT) t_chunk_alloc.$(OBJEXT) \ + t_filter_read.$(OBJEXT) testphdf5_OBJECTS = $(am_testphdf5_OBJECTS) testphdf5_LDADD = $(LDADD) testphdf5_DEPENDENCIES = $(LIBH5TEST) $(LIBHDF5) @@ -431,8 +432,8 @@ INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/test TEST_PROG_PARA = t_mpi t_posix_compliant testphdf5 t_cache t_pflush1 t_pflush2 t_shapesame TEST_SCRIPT_PARA = testph5.sh check_SCRIPTS = $(TEST_SCRIPT) -testphdf5_SOURCES = testphdf5.c t_dset.c t_file.c t_mdset.c t_ph5basic.c \ - t_coll_chunk.c t_span_tree.c t_chunk_alloc.c t_filter_read.c +testphdf5_SOURCES = testphdf5.c t_dset.c t_file.c t_file_image.c t_mdset.c \ + t_ph5basic.c t_coll_chunk.c t_span_tree.c t_chunk_alloc.c t_filter_read.c # The tests all depend on the hdf5 library and the test library @@ -532,6 +533,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t_coll_chunk.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t_dset.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t_file.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t_file_image.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t_filter_read.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t_mdset.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t_mpi.Po@am__quote@ diff --git a/testpar/t_file_image.c b/testpar/t_file_image.c new file mode 100644 index 0000000..d265957 --- /dev/null +++ b/testpar/t_file_image.c @@ -0,0 +1,395 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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 files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Parallel tests for file image operations + */ + +#include "testphdf5.h" + +/* file_image_daisy_chain_test + * + * Process zero: + * + * 1) Creates a core file with an integer vector data set of + * length n (= mpi_size), + * + * 2) Initializes the vector to zero in * location 0, and to -1 + * everywhere else. + * + * 3) Flushes the core file, and gets an image of it. Closes + * the core file. + * + * 4) Sends the image to process 1. + * + * 5) Awaits receipt on a file image from process n-1. + * + * 6) opens the image received from process n-1, verifies that + * it contains a vector of length equal to mpi_size, and + * that the vector contains (0, 1, 2, ... n-1) + * + * 7) closes the core file and exits. + * + * Process i (0 < i < n) + * + * 1) Await receipt of file image from process (i - 1). + * + * 2) Open the image with the core file driver, verify that i + * contains a vector v of length, and that v[j] = j for + * 0 <= j < i, and that v[j] == -1 for i <= j < n + * + * 3) Set v[i] = i in the core file. + * + * 4) Flush the core file and send it to process (i + 1) % n. + * + * 5) close the core file and exit. + * + * Test fails on a hang (if an image is not received), or on invalid data. + * + * JRM -- 11/28/11 + */ +void +file_image_daisy_chain_test(void) +{ + char file_name[1024] = "\0"; + int mpi_size, mpi_rank; + int mpi_result; + int i; + int space_ndims; + MPI_Status rcvstat; + int * vector_ptr = NULL; + hid_t fapl_id = -1; + hid_t file_id; /* file IDs */ + hid_t dset_id = -1; + hid_t dset_type_id = -1; + hid_t space_id = -1; + herr_t err; + hsize_t dims[1]; + void * image_ptr = NULL; + ssize_t bytes_read; + ssize_t image_len; + hbool_t vector_ok = TRUE; + htri_t tri_result; + + + /* set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* setup file name */ + HDsnprintf(file_name, 1024, "file_image_daisy_chain_test_%05d.h5", + (int)mpi_rank); + + if(mpi_rank == 0) { + + /* 1) Creates a core file with an integer vector data set + * of length mpi_size, + */ + fapl_id = H5Pcreate(H5P_FILE_ACCESS); + VRFY((fapl_id >= 0), "creating fapl"); + + err = H5Pset_fapl_core(fapl_id, (size_t)(64 *1024), FALSE); + VRFY((err >= 0), "setting core file driver in fapl."); + + file_id = H5Fcreate(file_name, 0, H5P_DEFAULT, fapl_id); + VRFY((file_id >= 0), "created core file"); + + dims[0] = (hsize_t)mpi_size; + space_id = H5Screate_simple(1, dims, dims); + VRFY((space_id >= 0), "created data space"); + + dset_id = H5Dcreate2(file_id, "v", H5T_NATIVE_INT, space_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dset_id >= 0), "created data set"); + + + /* 2) Initialize the vector to zero in location 0, and + * to -1 everywhere else. + */ + + vector_ptr = (int *)HDmalloc((size_t)(mpi_size) * sizeof(int)); + VRFY((vector_ptr != NULL), "allocated in memory representation of vector"); + + vector_ptr[0] = 0; + for(i = 1; i < mpi_size; i++) + vector_ptr[i] = -1; + + err = H5Dwrite(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, + H5P_DEFAULT, (void *)vector_ptr); + VRFY((err >= 0), "wrote initial data to vector."); + + HDfree(vector_ptr); + vector_ptr = NULL; + + + /* 3) Flush the core file, and get an image of it. Close + * the core file. + */ + err = H5Fflush(file_id, H5F_SCOPE_GLOBAL); + VRFY((err >= 0), "flushed core file."); + + image_len = H5Fget_file_image(file_id, NULL, (size_t)0); + VRFY((image_len > 0), "got image file size"); + + image_ptr = (void *)HDmalloc((size_t)image_len); + VRFY(image_ptr != NULL, "allocated file image buffer."); + + bytes_read = H5Fget_file_image(file_id, image_ptr, (size_t)image_len); + VRFY(bytes_read == image_len, "wrote file into image buffer"); + + err = H5Sclose(space_id); + VRFY((err >= 0), "closed data space."); + + err = H5Dclose(dset_id); + VRFY((err >= 0), "closed data set."); + + err = H5Fclose(file_id); + VRFY((err >= 0), "closed core file(1)."); + + err = H5Pclose(fapl_id); + VRFY((err >= 0), "closed fapl(1)."); + + + /* 4) Send the image to process 1. */ + + mpi_result = MPI_Ssend((void *)(&image_len), (int)sizeof(ssize_t), + MPI_BYTE, 1, 0, MPI_COMM_WORLD); + VRFY((mpi_result == MPI_SUCCESS), "sent image size to process 1"); + + mpi_result = MPI_Ssend((void *)image_ptr, (int)image_len, + MPI_BYTE, 1, 0, MPI_COMM_WORLD); + VRFY((mpi_result == MPI_SUCCESS), "sent image to process 1"); + + HDfree(image_ptr); + image_ptr = NULL; + image_len = 0; + + + /* 5) Await receipt on a file image from process n-1. */ + + mpi_result = MPI_Recv((void *)(&image_len), (int)sizeof(ssize_t), + MPI_BYTE, mpi_size - 1, 0, MPI_COMM_WORLD, + &rcvstat); + VRFY((mpi_result == MPI_SUCCESS), "received image len from process n-1"); + + image_ptr = (void *)HDmalloc((size_t)image_len); + VRFY(image_ptr != NULL, "allocated file image receive buffer."); + + mpi_result = MPI_Recv((void *)image_ptr, (int)image_len, + MPI_BYTE, mpi_size - 1, 0, MPI_COMM_WORLD, + &rcvstat); + VRFY((mpi_result == MPI_SUCCESS), \ + "received file image from process n-1"); + + /* 6) open the image received from process n-1, verify that + * it contains a vector of length equal to mpi_size, and + * that the vector contains (0, 1, 2, ... n-1). + */ + fapl_id = H5Pcreate(H5P_FILE_ACCESS); + VRFY((fapl_id >= 0), "creating fapl"); + + err = H5Pset_fapl_core(fapl_id, (size_t)(64 *1024), FALSE); + VRFY((err >= 0), "setting core file driver in fapl."); + + err = H5Pset_file_image(fapl_id, image_ptr, (size_t)image_len); + VRFY((err >= 0), "set file image in fapl."); + + file_id = H5Fopen(file_name, H5F_ACC_RDWR, fapl_id); + VRFY((file_id >= 0), "opened received file image file"); + + dset_id = H5Dopen1(file_id, "v"); + VRFY((dset_id >= 0), "opened data set"); + + dset_type_id = H5Dget_type(dset_id); + VRFY((dset_type_id >= 0), "obtained data set type"); + + tri_result = H5Tequal(dset_type_id, H5T_NATIVE_INT); + VRFY((tri_result == TRUE), "verified data set type"); + + space_id = H5Dget_space(dset_id); + VRFY((space_id >= 0), "opened data space"); + + space_ndims = H5Sget_simple_extent_ndims(space_id); + VRFY((space_ndims == 1), "verified data space num dims(1)"); + + space_ndims = H5Sget_simple_extent_dims(space_id, dims, NULL); + VRFY((space_ndims == 1), "verified data space num dims(2)"); + VRFY((dims[0] == (hsize_t)mpi_size), "verified data space dims"); + + vector_ptr = (int *)HDmalloc((size_t)(mpi_size) * sizeof(int)); + VRFY((vector_ptr != NULL), "allocated in memory rep of vector"); + + err = H5Dread(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, + H5P_DEFAULT, (void *)vector_ptr); + VRFY((err >= 0), "read received vector."); + + vector_ok = TRUE; + for(i = 0; i < mpi_size; i++) + if(vector_ptr[i] != i) + vector_ok = FALSE; + VRFY((vector_ok), "verified received vector."); + + /* 7) closes the core file and exit. */ + + err = H5Sclose(space_id); + VRFY((err >= 0), "closed data space."); + + err = H5Dclose(dset_id); + VRFY((err >= 0), "closed data set."); + + err = H5Fclose(file_id); + VRFY((err >= 0), "closed core file(1)."); + + err = H5Pclose(fapl_id); + VRFY((err >= 0), "closed fapl(1)."); + + HDfree(image_ptr); + image_ptr = NULL; + image_len = 0; + } else { + /* 1) Await receipt of file image from process (i - 1). */ + + mpi_result = MPI_Recv((void *)(&image_len), (int)sizeof(ssize_t), + MPI_BYTE, mpi_rank - 1, 0, MPI_COMM_WORLD, + &rcvstat); + VRFY((mpi_result == MPI_SUCCESS), \ + "received image size from process mpi_rank-1"); + + image_ptr = (void *)HDmalloc((size_t)image_len); + VRFY(image_ptr != NULL, "allocated file image receive buffer."); + + mpi_result = MPI_Recv((void *)image_ptr, (int)image_len, + MPI_BYTE, mpi_rank - 1, 0, MPI_COMM_WORLD, + &rcvstat); + VRFY((mpi_result == MPI_SUCCESS), \ + "received file image from process mpi_rank-1"); + + /* 2) Open the image with the core file driver, verify that it + * contains a vector v of length, and that v[j] = j for + * 0 <= j < i, and that v[j] == -1 for i <= j < n + */ + fapl_id = H5Pcreate(H5P_FILE_ACCESS); + VRFY((fapl_id >= 0), "creating fapl"); + + err = H5Pset_fapl_core(fapl_id, (size_t)(64 * 1024), FALSE); + VRFY((err >= 0), "setting core file driver in fapl."); + + err = H5Pset_file_image(fapl_id, image_ptr, (size_t)image_len); + VRFY((err >= 0), "set file image in fapl."); + + file_id = H5Fopen(file_name, H5F_ACC_RDWR, fapl_id); + H5Eprint1(stderr); + VRFY((file_id >= 0), "opened received file image file"); + + dset_id = H5Dopen1(file_id, "v"); + VRFY((dset_id >= 0), "opened data set"); + + dset_type_id = H5Dget_type(dset_id); + VRFY((dset_type_id >= 0), "obtained data set type"); + + tri_result = H5Tequal(dset_type_id, H5T_NATIVE_INT); + VRFY((tri_result == TRUE), "verified data set type"); + + space_id = H5Dget_space(dset_id); + VRFY((space_id >= 0), "opened data space"); + + space_ndims = H5Sget_simple_extent_ndims(space_id); + VRFY((space_ndims == 1), "verified data space num dims(1)"); + + space_ndims = H5Sget_simple_extent_dims(space_id, dims, NULL); + VRFY((space_ndims == 1), "verified data space num dims(2)"); + VRFY((dims[0] == (hsize_t)mpi_size), "verified data space dims"); + + vector_ptr = (int *)HDmalloc((size_t)(mpi_size) * sizeof(int)); + VRFY((vector_ptr != NULL), "allocated in memory rep of vector"); + + err = H5Dread(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, + H5P_DEFAULT, (void *)vector_ptr); + VRFY((err >= 0), "read received vector."); + + vector_ok = TRUE; + for(i = 0; i < mpi_size; i++){ + if(i < mpi_rank) { + if(vector_ptr[i] != i) + vector_ok = FALSE; + } else { + if(vector_ptr[i] != -1) + vector_ok = FALSE; + } + } + VRFY((vector_ok), "verified received vector."); + + + /* 3) Set v[i] = i in the core file. */ + + vector_ptr[mpi_rank] = mpi_rank; + + err = H5Dwrite(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, + H5P_DEFAULT, (void *)vector_ptr); + VRFY((err >= 0), "wrote modified data to vector."); + + HDfree(vector_ptr); + vector_ptr = NULL; + + + /* 4) Flush the core file and send it to process (mpi_rank + 1) % n. */ + + err = H5Fflush(file_id, H5F_SCOPE_GLOBAL); + VRFY((err >= 0), "flushed core file."); + + image_len = H5Fget_file_image(file_id, NULL, (size_t)0); + VRFY((image_len > 0), "got (possibly modified) image file len"); + + image_ptr = (void *)HDrealloc((void *)image_ptr, (size_t)image_len); + VRFY(image_ptr != NULL, "re-allocated file image buffer."); + + bytes_read = H5Fget_file_image(file_id, image_ptr, (size_t)image_len); + VRFY(bytes_read == image_len, "wrote file into image buffer"); + + mpi_result = MPI_Ssend((void *)(&image_len), (int)sizeof(ssize_t), + MPI_BYTE, (mpi_rank + 1) % mpi_size, 0, + MPI_COMM_WORLD); + VRFY((mpi_result == MPI_SUCCESS), \ + "sent image size to process (mpi_rank + 1) % mpi_size"); + + mpi_result = MPI_Ssend((void *)image_ptr, (int)image_len, + MPI_BYTE, (mpi_rank + 1) % mpi_size, 0, + MPI_COMM_WORLD); + VRFY((mpi_result == MPI_SUCCESS), \ + "sent image to process (mpi_rank + 1) % mpi_size"); + + HDfree(image_ptr); + image_ptr = NULL; + image_len = 0; + + /* 5) close the core file and exit. */ + + err = H5Sclose(space_id); + VRFY((err >= 0), "closed data space."); + + err = H5Dclose(dset_id); + VRFY((err >= 0), "closed data set."); + + err = H5Fclose(file_id); + VRFY((err >= 0), "closed core file(1)."); + + err = H5Pclose(fapl_id); + VRFY((err >= 0), "closed fapl(1)."); + } + + return; + +} /* file_image_daisy_chain_test() */ + diff --git a/testpar/testphdf5.c b/testpar/testphdf5.c index c216c80..4b5506f 100644 --- a/testpar/testphdf5.c +++ b/testpar/testphdf5.c @@ -502,6 +502,13 @@ int main(int argc, char **argv) "test actual io mode proprerty", PARATESTFILE); + if((mpi_size < 2) && MAINPROCESS) { + printf("File Image Ops daisy chain test needs at least 2 processes.\n"); + printf("File Image Ops daisy chain test will be skipped \n"); + } + AddTest((mpi_size < 2)? "-fiodc" : "fiodc", file_image_daisy_chain_test, NULL, + "file image ops daisy chain", NULL); + /* Display testing information */ TestInfo(argv[0]); diff --git a/testpar/testphdf5.h b/testpar/testphdf5.h index 15ef75f..da11c62 100644 --- a/testpar/testphdf5.h +++ b/testpar/testphdf5.h @@ -269,6 +269,7 @@ void lower_dim_size_comp_test(void); void link_chunk_collective_io_test(void); void contig_hyperslab_dr_pio_test(ShapeSameTestMethods sstest_type); void checker_board_hyperslab_dr_pio_test(ShapeSameTestMethods sstest_type); +void file_image_daisy_chain_test(void); #ifdef H5_HAVE_FILTER_DEFLATE void compress_readAll(void); #endif /* H5_HAVE_FILTER_DEFLATE */ -- cgit v0.12