diff options
author | Quincey Koziol <koziol@hdfgroup.org> | 2012-03-31 08:49:35 (GMT) |
---|---|---|
committer | Quincey Koziol <koziol@hdfgroup.org> | 2012-03-31 08:49:35 (GMT) |
commit | c2a9dcb8977f81ff8e66bfd41c72f106993d3086 (patch) | |
tree | a73dacf5ae2aa108fce2d14dc731f9558baddfc8 /hl | |
parent | b51ffb25fe610675a7470cf50efed5bcdf2bf79f (diff) | |
download | hdf5-c2a9dcb8977f81ff8e66bfd41c72f106993d3086.zip hdf5-c2a9dcb8977f81ff8e66bfd41c72f106993d3086.tar.gz hdf5-c2a9dcb8977f81ff8e66bfd41c72f106993d3086.tar.bz2 |
[svn-r22219] Description:
Merge "file image" changes from feature branch back to trunk.
Tested on:
Mac OSX/64 10.7.3 (amazon) w/debug
(h5committest upcoming)
Diffstat (limited to 'hl')
-rw-r--r-- | hl/src/H5LT.c | 571 | ||||
-rw-r--r-- | hl/src/H5LTpublic.h | 18 | ||||
-rw-r--r-- | hl/test/Makefile.am | 4 | ||||
-rw-r--r-- | hl/test/Makefile.in | 27 | ||||
-rw-r--r-- | hl/test/h5hltest.h | 6 | ||||
-rw-r--r-- | hl/test/test_file_image.c | 518 |
6 files changed, 1129 insertions, 15 deletions
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 <stdlib.h> #include <assert.h> #include <stdio.h> + #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 <empty>", indt + 4, ""); + HDsnprintf(tmp_str, TMP_LEN, "\n%*s <empty>", (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; +} + |