diff options
-rw-r--r-- | src/H5Dio.c | 98 | ||||
-rw-r--r-- | test/tvltypes.c | 191 |
2 files changed, 267 insertions, 22 deletions
diff --git a/src/H5Dio.c b/src/H5Dio.c index ceaf86c..f841f13 100644 --- a/src/H5Dio.c +++ b/src/H5Dio.c @@ -228,16 +228,23 @@ done: parameter is NULL, use "buf_type" for the fill value datatype. EXAMPLES REVISION LOG + Raymond Lu - 20 March 2007 + If there's VL type of data, the address of the data is copied multiple + times into the buffer, causing some trouble when the data is released. + Instead, make multiple copies of fill value first, then do conversion + on each element so that each of them has a copy of the VL data. --------------------------------------------------------------------------*/ static herr_t H5D_fill(const void *fill, const H5T_t *fill_type, void *buf, const H5T_t *buf_type, const H5S_t *space, hid_t dxpl_id) { H5T_path_t *tpath = NULL; /* Conversion information*/ uint8_t *tconv_buf = NULL; /* Data type conv buffer */ - uint8_t *bkg_buf = NULL; /* Temp conversion buffer */ + uint8_t *bkg_buf = NULL; /* Background conversion buffer */ + uint8_t *tmp_buf = NULL; /* Temp conversion buffer */ hid_t src_id = -1, dst_id = -1; /* Temporary type IDs */ size_t src_type_size; /* Size of source type */ size_t dst_type_size; /* Size of destination type*/ + hssize_t nelmts; /* Number of data elements */ size_t buf_size; /* Desired buffer size */ herr_t ret_value=SUCCEED; /* Return value */ @@ -259,42 +266,91 @@ H5D_fill(const void *fill, const H5T_t *fill_type, void *buf, const H5T_t *buf_t /* Get the maximum buffer size needed and allocate it */ buf_size=MAX(src_type_size,dst_type_size); - if(NULL == (tconv_buf = H5FL_BLK_MALLOC(type_elem,buf_size)) || NULL==(bkg_buf = H5FL_BLK_CALLOC(type_elem,buf_size))) + + /* Allocate space for conversion buffer */ + if(NULL == (tconv_buf = H5FL_BLK_MALLOC(type_elem,buf_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") - /* Check for actual fill value to replicate */ - if(fill==NULL) - /* If there's no fill value, just use zeros */ + /* If there's no fill value, just use zeros */ + if(fill==NULL) { HDmemset(tconv_buf,0,dst_type_size); - else { - /* Copy the user's data into the buffer for conversion */ - HDmemcpy(tconv_buf,fill,src_type_size); - /* Set up type conversion function */ - if(NULL == (tpath = H5T_path_find(fill_type, buf_type, NULL, NULL, dxpl_id, FALSE))) - HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to convert between src and dest data types") + /* Fill the selection in the memory buffer */ + if(H5S_select_fill(tconv_buf, dst_type_size, space, buf) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTENCODE, FAIL, "filling selection failed") + + HGOTO_DONE(ret_value); + } + + /* Set up type conversion function */ + if(NULL == (tpath = H5T_path_find(fill_type, buf_type, NULL, NULL, dxpl_id, FALSE))) + HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to convert between src and dest data types") + + if(!H5T_path_noop(tpath)) { + if((src_id = H5I_register(H5I_DATATYPE, H5T_copy(fill_type, H5T_COPY_ALL))) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "unable to register types for conversion") + + if((dst_id = H5I_register(H5I_DATATYPE, H5T_copy(buf_type, H5T_COPY_ALL))) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "unable to register types for conversion") + } + + /* Copy the user's data into the buffer for conversion */ + HDmemcpy(tconv_buf,fill,src_type_size); + + if(TRUE == H5T_detect_class(fill_type, H5T_VLEN)) { + /* If there's VL type of data, make multiple copies of fill value first, + * then do conversion on each element so that each of them has a copy + * of the VL data. + */ + + /* Get the number of elements */ + nelmts = H5S_get_simple_extent_npoints(space); - /* Convert memory buffer into disk buffer */ + /* Allocate a temporary buffer and background buffer */ + if(NULL == (tmp_buf = H5FL_BLK_MALLOC(type_conv,(size_t)nelmts*buf_size)) || NULL==(bkg_buf = H5FL_BLK_CALLOC(type_conv,(size_t)nelmts*buf_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + + /* Fill the selection in the temporary buffer */ + if(H5S_select_fill(tconv_buf, src_type_size, space, tmp_buf) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTENCODE, FAIL, "filling selection failed") + + /* Convert disk buffer into memory buffer */ if(!H5T_path_noop(tpath)) { - if((src_id = H5I_register(H5I_DATATYPE, H5T_copy(fill_type, H5T_COPY_ALL))) < 0 || - (dst_id = H5I_register(H5I_DATATYPE, H5T_copy(buf_type, H5T_COPY_ALL))) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "unable to register types for conversion") + if(H5T_convert(tpath, src_id, dst_id, (size_t)nelmts, (size_t)0, (size_t)0, tmp_buf, bkg_buf, dxpl_id) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "data type conversion failed") + } /* end if */ + /* Copy the final data into the memory buffer */ + HDmemcpy(buf, tmp_buf, (size_t)nelmts*dst_type_size); + } else { + /* If there's no VL type of data, do conversion first then fill the data into + * the memory buffer. */ + if(NULL==(bkg_buf = H5FL_BLK_CALLOC(type_elem,buf_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + + /* Convert disk buffer into memory buffer */ + if(!H5T_path_noop(tpath)) { /* Perform data type conversion */ if(H5T_convert(tpath, src_id, dst_id, (size_t)1, (size_t)0, (size_t)0, tconv_buf, bkg_buf, dxpl_id) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "data type conversion failed") } /* end if */ - } /* end if */ - /* Fill the selection in the memory buffer */ - if(H5S_select_fill(tconv_buf, dst_type_size, space, buf) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTENCODE, FAIL, "filling selection failed") + /* Fill the selection in the memory buffer */ + if(H5S_select_fill(tconv_buf, dst_type_size, space, buf) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTENCODE, FAIL, "filling selection failed") + } done: + if (tmp_buf) + H5FL_BLK_FREE(type_conv,tmp_buf); if (tconv_buf) H5FL_BLK_FREE(type_elem,tconv_buf); - if (bkg_buf) - H5FL_BLK_FREE(type_elem,bkg_buf); + if (bkg_buf) { + if(TRUE == H5T_detect_class(fill_type, H5T_VLEN)) + H5FL_BLK_FREE(type_conv,bkg_buf); + else + H5FL_BLK_FREE(type_elem,bkg_buf); + } FUNC_LEAVE_NOAPI(ret_value) } /* H5D_fill() */ diff --git a/test/tvltypes.c b/test/tvltypes.c index d8941e5..de51f4a 100644 --- a/test/tvltypes.c +++ b/test/tvltypes.c @@ -29,7 +29,7 @@ /* 1-D dataset with fixed dimensions */ #define SPACE1_RANK 1 -#define SPACE1_DIM1 4 +#define SPACE1_DIM1 4 /* 2-D dataset with fixed dimensions */ #define SPACE2_RANK 2 @@ -2388,6 +2388,194 @@ rewrite_shorter_vltypes_vlen_vlen_atomic(void) /**************************************************************** ** +** test_vltypes_fill_value(): Test fill value for VL data. +** One tests data space isn't allocated; another tests data +** space is allocated. +** +****************************************************************/ +static void +test_vltypes_fill_value(void) +{ + typedef struct dtype1_struct { + int i1; + char *str; + int i2; + int i3; + int i4; + int i5; + int i6; + int i7; + int i8; + float f1; + } dtype1_struct; + + herr_t ret; + hid_t file_id; + hid_t dtype1_id = -1; + hid_t str_id = -1; + hid_t dspace_id; + hid_t dcpl_id, xfer_pid; + hid_t dset_id; + hsize_t dim1[] = {SPACE1_DIM1}; + const dtype1_struct fill1 = {1, "foobar", 2, 3, 4, 5, 6, 7, 8, 9.0}; + dtype1_struct buf[SPACE1_DIM1]; + size_t mem_used=0; /* Memory used during allocation */ + int i; + + /* Output message about test being performed */ + MESSAGE(5, ("Check fill value for VL data\n")); + + /* Create a compound data type */ + dtype1_id = H5Tcreate(H5T_COMPOUND, sizeof(struct dtype1_struct)); + CHECK(dtype1_id, FAIL, "H5Tcreate"); + + ret = H5Tinsert(dtype1_id,"i1",HOFFSET(struct dtype1_struct,i1),H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + str_id = H5Tcopy(H5T_C_S1); + CHECK(str_id, FAIL, "H5Tcopy"); + ret = H5Tset_size(str_id,H5T_VARIABLE); + CHECK(ret, FAIL, "H5Tset_size"); + + ret = H5Tinsert(dtype1_id,"vl_string",HOFFSET(dtype1_struct,str),str_id); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(dtype1_id,"i2",HOFFSET(struct dtype1_struct,i2),H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(dtype1_id,"i3",HOFFSET(struct dtype1_struct,i3),H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(dtype1_id,"i4",HOFFSET(struct dtype1_struct,i4),H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(dtype1_id,"i5",HOFFSET(struct dtype1_struct,i5),H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(dtype1_id,"i6",HOFFSET(struct dtype1_struct,i6),H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(dtype1_id,"i7",HOFFSET(struct dtype1_struct,i7),H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(dtype1_id,"i8",HOFFSET(struct dtype1_struct,i8),H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(dtype1_id,"f1",HOFFSET(struct dtype1_struct,f1),H5T_NATIVE_FLOAT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tclose(str_id); + CHECK(ret, FAIL, "H5Tclose"); + + /* Create dataset create property list and set the fill value */ + dcpl_id = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl_id, FAIL, "H5Pcreate"); + + ret = H5Pset_fill_value(dcpl_id, dtype1_id, &fill1); + CHECK(ret, FAIL, "H5Pset_fill_value"); + + /* Create the file */ + file_id = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file_id, FAIL, "H5Fcreate"); + + dspace_id=H5Screate_simple(SPACE1_RANK,dim1,NULL); + CHECK(dspace_id, FAIL, "H5Screate_simple"); + + /* Create first data set with default setting - no space is allocated */ + dset_id = H5Dcreate(file_id, "dataset1", dtype1_id, dspace_id, dcpl_id); + CHECK(dset_id, FAIL, "H5Dcreate"); + + ret = H5Dclose(dset_id); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create a second data set with space allocated and fill value written */ + ret = H5Pset_fill_time(dcpl_id, H5D_FILL_TIME_IFSET); + CHECK(ret, FAIL, "H5Pset_fill_time"); + + ret = H5Pset_alloc_time(dcpl_id, H5D_ALLOC_TIME_EARLY); + CHECK(ret, FAIL, "H5Pset_alloc_time"); + + dset_id = H5Dcreate(file_id, "dataset2", dtype1_id, dspace_id, dcpl_id); + CHECK(dset_id, FAIL, "H5Dcreate"); + + ret = H5Dclose(dset_id); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Fclose(file_id); + CHECK(ret, FAIL, "H5Fclose"); + + + /* Open the file to check data set value */ + file_id = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(file_id, FAIL, "H5Fopen"); + + /* Open first data set */ + dset_id = H5Dopen(file_id, "dataset1"); + CHECK(dset_id, FAIL, "H5Dopen"); + + /* Change to the custom memory allocation routines for reading VL data */ + xfer_pid=H5Pcreate(H5P_DATASET_XFER); + CHECK(xfer_pid, FAIL, "H5Pcreate"); + + ret=H5Pset_vlen_mem_manager(xfer_pid,test_vltypes_alloc_custom,&mem_used,test_vltypes_free_custom,&mem_used); + CHECK(ret, FAIL, "H5Pset_vlen_mem_manager"); + + /* Read in the data of fill value */ + ret = H5Dread(dset_id, dtype1_id, dspace_id, dspace_id,xfer_pid, buf); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read in */ + for(i=0; i<SPACE1_DIM1; i++) { + if(strcmp(buf[i].str, "foobar")) { + TestErrPrintf("%d: VL data doesn't match!, buf[%d].str=%s\n",__LINE__,(int)i,buf[i].str); + /*continue;*/ + } /* end if */ + } /* end for */ + + ret = H5Dclose(dset_id); + CHECK(ret, FAIL, "H5Dclose"); + + /* Release the space */ + ret = H5Dvlen_reclaim(dtype1_id,dspace_id,xfer_pid,buf); + CHECK(ret, FAIL, "H5Dvlen_reclaim"); + + /* Open the second data set to check the value of data */ + dset_id = H5Dopen(file_id, "dataset2"); + CHECK(dset_id, FAIL, "H5Dopen"); + + ret = H5Dread(dset_id, dtype1_id, dspace_id, dspace_id,xfer_pid, buf); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read in */ + for(i=0; i<SPACE1_DIM1; i++) { + if(strcmp(buf[i].str, "foobar")) { + TestErrPrintf("%d: VL data doesn't match!, buf[%d].str=%s\n",__LINE__,(int)i,buf[i].str); + /*continue;*/ + } /* end if */ + } /* end for */ + + ret = H5Dclose(dset_id); + CHECK(ret, FAIL, "H5Dclose"); + + /* Release the space */ + ret = H5Dvlen_reclaim(dtype1_id,dspace_id,xfer_pid,buf); + CHECK(ret, FAIL, "H5Dvlen_reclaim"); + + ret = H5Sclose(dspace_id); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Pclose(dcpl_id); + CHECK(ret, FAIL, "H5Pclose"); + + ret = H5Tclose(dtype1_id); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Fclose(file_id); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_vltypes_fill_value() */ + +/**************************************************************** +** ** test_vltypes(): Main VL datatype testing routine. ** ****************************************************************/ @@ -2412,6 +2600,7 @@ test_vltypes(void) rewrite_shorter_vltypes_vlen_vlen_atomic(); /*overwrite with VL data of shorted sequence*/ test_vltypes_compound_vlen_vlen();/* Test compound datatypes with VL atomic components */ test_vltypes_compound_vlstr(); /* Test data rewritten of nested VL data */ + test_vltypes_fill_value(); /* Test fill value for VL data */ } /* test_vltypes() */ |