From 378717659a21d89dd9e73cbdaa4fd069b46c949e Mon Sep 17 00:00:00 2001 From: Neil Fortner Date: Tue, 14 Dec 2010 12:07:26 -0500 Subject: [svn-r19890] Add initial implementation for H5Ocompare and usage in h5diff. Currently incomplete/experimental. Note that if 2 datasets are not comparable by direct binary comparison, H5Ocompare (and h5diff!) will report that they are different. Do not use in production. Tested: Fedora, jam --- src/H5Dchunk.c | 198 ++++++++++++- src/H5Dcompact.c | 47 ++- src/H5Dcontig.c | 85 +++++- src/H5Doh.c | 303 +++++++++++++++++++- src/H5Dpkg.h | 14 + src/H5Ocompare.c | 749 ++++++++++++++++++++++++++++++++++++++++++++++++ src/H5Opkg.h | 3 + src/H5Oprivate.h | 4 + src/H5Opublic.h | 2 + src/H5S.c | 48 ++++ src/H5Sprivate.h | 1 + src/Makefile.am | 4 +- src/Makefile.in | 5 +- tools/lib/h5diff_dset.c | 12 + 14 files changed, 1467 insertions(+), 8 deletions(-) create mode 100644 src/H5Ocompare.c diff --git a/src/H5Dchunk.c b/src/H5Dchunk.c index e7a5bf1..34c7e1a 100644 --- a/src/H5Dchunk.c +++ b/src/H5Dchunk.c @@ -186,6 +186,9 @@ static herr_t H5D_chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *typ H5D_chunk_map_t *fm); static herr_t H5D_chunk_flush(H5D_t *dset, hid_t dxpl_id); static herr_t H5D_chunk_io_term(const H5D_chunk_map_t *fm); +static htri_t H5D_chunk_compare(const H5F_t *f1, const H5F_t *f2, + const H5O_layout_t *layout1, const H5O_layout_t *layout2, hid_t dxpl1_id, + hid_t dxpl2_id, H5D_cmp_ud_t *udata); /* "Nonexistent" layout operation callback */ static ssize_t @@ -237,7 +240,8 @@ const H5D_layout_ops_t H5D_LOPS_CHUNK[1] = {{ NULL, NULL, H5D_chunk_flush, - H5D_chunk_io_term + H5D_chunk_io_term, + H5D_chunk_compare }}; @@ -260,6 +264,7 @@ const H5D_layout_ops_t H5D_LOPS_NONEXISTENT[1] = {{ H5D_nonexistent_readvv, NULL, NULL, + NULL, NULL }}; @@ -5045,3 +5050,194 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* H5D_nonexistent_readvv() */ + +/*------------------------------------------------------------------------- + * Function: H5D_chunk_compare + * + * Purpose: fnord + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Neil Fortner + * Friday, December 3, 2010 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5D_chunk_compare(const H5F_t *f1, const H5F_t *f2, + const H5O_layout_t *layout1, const H5O_layout_t *layout2, hid_t dxpl1_id, + hid_t dxpl2_id, H5D_cmp_ud_t *udata) +{ + void *buf1 = NULL; + void *buf2 = NULL; + size_t buf_size = 0; + H5D_chk_idx_info_t idx_info1; /* Chunked index info */ + H5D_chk_idx_info_t idx_info2; /* Chunked index info */ + hbool_t idx_info1_init = FALSE; + hbool_t idx_info2_init = FALSE; + H5D_chunk_ud_t chk_udata1; + H5D_chunk_ud_t chk_udata2; + int space_ndims; /* Dataset's space rank */ + hsize_t space_dim[H5O_LAYOUT_NDIMS]; /* Current dataspace dimensions */ + hsize_t chunk_offset[H5O_LAYOUT_NDIMS]; /* Offset of current chunk */ + hbool_t carry = FALSE; /* Flag to indicate that chunk increment carries to higher dimension (sorta) */ + int i; + htri_t ret_value = FALSE; /* Return value */ + + FUNC_ENTER_NOAPI(H5D_chunk_compare, FAIL) + + /* Sanity check */ + HDassert(f1); + HDassert(f2); + HDassert(layout1); + HDassert(layout2); + HDassert(udata); + + if(H5F_addr_defined(layout1->storage.u.chunk.idx_addr)) { + if(H5F_addr_defined(layout2->storage.u.chunk.idx_addr)) { + /* Both have space allocated. Read both datasets into memory and + * compare, chunk by chunk. */ + /* Go get the rank & dimensions */ + if((space_ndims = H5S_get_simple_extent_dims(udata->space, + space_dim, NULL)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get dataset dimensions") + + /* Create index info structs */ + idx_info1.f = f1; + idx_info1.dxpl_id = dxpl1_id; + idx_info1.pline = udata->pline1; + idx_info1.layout = &layout1->u.chunk; + idx_info1.storage = &layout1->storage.u.chunk; + if((layout1->storage.u.chunk.ops->init)(&idx_info1, udata->space, + udata->addr1) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't init index info") + idx_info1_init = TRUE; + + idx_info2.f = f2; + idx_info2.dxpl_id = dxpl2_id; + idx_info2.pline = udata->pline2; + idx_info2.layout = &layout2->u.chunk; + idx_info2.storage = &(layout2->storage.u.chunk); + if((layout2->storage.u.chunk.ops->init)(&idx_info2, udata->space, + udata->addr2) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't init index info") + idx_info2_init = TRUE; + + /* Initialize chunk udatas */ + chk_udata1.common.layout = &(layout1->u.chunk); + chk_udata1.common.storage = &(layout1->storage.u.chunk); + chk_udata1.common.offset = chunk_offset; + chk_udata1.common.rdcc = NULL; + chk_udata1.idx_hint = UINT_MAX; + + chk_udata2.common.layout = &(layout2->u.chunk); + chk_udata2.common.storage = &(layout2->storage.u.chunk); + chk_udata2.common.offset = chunk_offset; + chk_udata2.common.rdcc = NULL; + chk_udata2.idx_hint = UINT_MAX; + + /* Loop over all chunks logically according to offset */ + HDmemset(chunk_offset, 0, sizeof(chunk_offset)); + while(!carry) { + /* Lookup chunk 1 */ + chk_udata1.nbytes = 0; + chk_udata1.filter_mask = 0; + chk_udata1.addr = HADDR_UNDEF; + if((layout1->storage.u.chunk.ops->get_addr)(&idx_info1, + &chk_udata1) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't query chunk address") + + /* Lookup chunk 2 */ + chk_udata2.nbytes = 0; + chk_udata2.filter_mask = 0; + chk_udata2.addr = HADDR_UNDEF; + if((layout2->storage.u.chunk.ops->get_addr)(&idx_info2, + &chk_udata2) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't query chunk address") + + if(H5F_addr_defined(chk_udata1.addr)) { + if(H5F_addr_defined(chk_udata2.addr)) { + /* Both chunks exist, read from disk and compare */ + /* Check that the sizes are identical */ + if(chk_udata1.nbytes != chk_udata2.nbytes) + HGOTO_DONE(TRUE) + + /* Allocate new buffer, if necessary */ + if(chk_udata1.nbytes > buf_size) { + buf_size = chk_udata1.nbytes; + if(NULL == (buf1 = H5MM_realloc(buf1, buf_size))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "unable to allocate memory") + if(NULL == (buf2 = H5MM_realloc(buf2, buf_size))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "unable to allocate memory") + } /* end if */ + + /* Read chunks */ + if(H5F_block_read(f1, H5FD_MEM_DRAW, chk_udata1.addr, + chk_udata1.nbytes, dxpl1_id, buf1) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed") + if(H5F_block_read(f2, H5FD_MEM_DRAW, chk_udata2.addr, + chk_udata1.nbytes, dxpl2_id, buf2) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed") + + /* Compare */ + if(HDmemcmp(buf1, buf2, chk_udata1.nbytes)) + HGOTO_DONE(TRUE) + } /* end if */ + else + /* One chunk exists and the other doesn't. Assume they + * are different. Eventually should check data in 1 + * against fill value in 2. */ + HGOTO_DONE(TRUE) + } /* end if */ + else + if(H5F_addr_defined(chk_udata2.addr)) + /* One chunk exists and the other doesn't. Assume they + * are different. Eventually should check data in 2 + * against fill value in 1. */ + HGOTO_DONE(TRUE) + else + /* Neither chunk exists. If their fill values are not + * identical, they are different. */ + if(!udata->fill_identical) + HGOTO_DONE(TRUE) + + /* Increment indices */ + carry = TRUE; + for(i = space_ndims - 1; i >= 0; --i) { + chunk_offset[i] += layout1->u.chunk.dim[i]; + if(chunk_offset[i] >= space_dim[i]) + chunk_offset[i] = 0; + else { + carry = FALSE; + break; + } /* end else */ + } /* end for */ + } /* end while */ + } /* end if */ + else + /* One has space allocated and the other doesn't. Assume they are + * different. Eventually should check data in 1 against fill value + * in 2. */ + HGOTO_DONE(TRUE) + } /* end if */ + else + if(H5F_addr_defined(layout2->storage.u.chunk.idx_addr)) + /* One has space allocated and the other doesn't. Assume they are + * different. Eventually should check data in 2 against fill value + * in 1. */ + HGOTO_DONE(TRUE) + else + /* Neither has space allocated. If their fill values are not + * identical, they are different. */ + if(!udata->fill_identical) + HGOTO_DONE(TRUE) + +done: + if(idx_info1_init && (layout1->storage.u.chunk.ops->dest)(&idx_info1) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't destroy index info") + if(idx_info2_init && (layout2->storage.u.chunk.ops->dest)(&idx_info2) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't destroy index info") + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_chunk_compare() */ + diff --git a/src/H5Dcompact.c b/src/H5Dcompact.c index b98f2cb..dc9bdba 100644 --- a/src/H5Dcompact.c +++ b/src/H5Dcompact.c @@ -70,6 +70,9 @@ static ssize_t H5D_compact_writevv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_size_arr[], hsize_t dset_offset_arr[], size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_size_arr[], hsize_t mem_offset_arr[]); static herr_t H5D_compact_flush(H5D_t *dset, hid_t dxpl_id); +static htri_t H5D_compact_compare(const H5F_t *f1, const H5F_t *f2, + const H5O_layout_t *layout1, const H5O_layout_t *layout2, hid_t dxpl1_id, + hid_t dxpl2_id, H5D_cmp_ud_t *udata); /*********************/ @@ -91,7 +94,8 @@ const H5D_layout_ops_t H5D_LOPS_COMPACT[1] = {{ H5D_compact_readvv, H5D_compact_writevv, H5D_compact_flush, - NULL + NULL, + H5D_compact_compare }}; @@ -576,3 +580,44 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D_compact_copy() */ + +/*------------------------------------------------------------------------- + * Function: H5D_compact_compare + * + * Purpose: fnord + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Neil Fortner + * Tuesday, November 30, 2010 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5D_compact_compare(const H5F_t UNUSED *f1, const H5F_t UNUSED *f2, + const H5O_layout_t *layout1, const H5O_layout_t *layout2, + hid_t UNUSED dxpl1_id, hid_t UNUSED dxpl2_id, H5D_cmp_ud_t UNUSED *udata) +{ + htri_t ret_value = FALSE; /* Return value */ + + FUNC_ENTER_NOAPI_NOFUNC(H5D_compact_compare) + + /* Sanity check */ + HDassert(f1); + HDassert(f2); + HDassert(layout1); + HDassert(layout2); + HDassert(layout1->storage.u.compact.buf); + HDassert(layout2->storage.u.compact.buf); + HDassert(layout1->storage.u.compact.size + == layout2->storage.u.compact.size); + + /* Compare the two datasets */ + if(HDmemcmp(layout1->storage.u.compact.buf, layout2->storage.u.compact.buf, + layout1->storage.u.compact.size)) + HGOTO_DONE(TRUE) + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_compact_compare() */ + diff --git a/src/H5Dcontig.c b/src/H5Dcontig.c index 9a6e08f..c6d9318 100644 --- a/src/H5Dcontig.c +++ b/src/H5Dcontig.c @@ -41,6 +41,7 @@ #include "H5FLprivate.h" /* Free Lists */ #include "H5Iprivate.h" /* IDs */ #include "H5MFprivate.h" /* File memory management */ +#include "H5MMprivate.h" /* Memory management */ #include "H5Oprivate.h" /* Object headers */ #include "H5Pprivate.h" /* Property lists */ #include "H5Vprivate.h" /* Vector and array functions */ @@ -106,6 +107,9 @@ static ssize_t H5D_contig_writevv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]); static herr_t H5D_contig_flush(H5D_t *dset, hid_t dxpl_id); +static htri_t H5D_contig_compare(const H5F_t *f1, const H5F_t *f2, + const H5O_layout_t *layout1, const H5O_layout_t *layout2, hid_t dxpl1_id, + hid_t dxpl2_id, H5D_cmp_ud_t *udata); /* Helper routines */ static herr_t H5D_contig_write_one(H5D_io_info_t *io_info, hsize_t offset, @@ -131,7 +135,8 @@ const H5D_layout_ops_t H5D_LOPS_CONTIG[1] = {{ H5D_contig_readvv, H5D_contig_writevv, H5D_contig_flush, - NULL + NULL, + H5D_contig_compare }}; @@ -1525,3 +1530,81 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D_contig_copy() */ + +/*------------------------------------------------------------------------- + * Function: H5D_contig_compare + * + * Purpose: fnord + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Neil Fortner + * Tuesday, November 30, 2010 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5D_contig_compare(const H5F_t *f1, const H5F_t *f2, + const H5O_layout_t *layout1, const H5O_layout_t *layout2, hid_t dxpl1_id, + hid_t dxpl2_id, H5D_cmp_ud_t *udata) +{ + void *buf1 = NULL; + void *buf2 = NULL; + htri_t ret_value = FALSE; /* Return value */ + + FUNC_ENTER_NOAPI(H5D_contig_compare, FAIL) + + /* Sanity check */ + HDassert(f1); + HDassert(f2); + HDassert(layout1); + HDassert(layout2); + HDassert(udata); + + if(H5F_addr_defined(layout1->storage.u.contig.addr)) { + if(H5F_addr_defined(layout2->storage.u.contig.addr)) { + /* Both have space allocated. Read both datasets into memory and + * compare. Will eventually want to use a buffer with a + * user-configurable size so we don't alloc something too big. */ + HDassert(layout1->storage.u.contig.size + == layout2->storage.u.contig.size); + if(NULL == (buf1 = H5MM_malloc(layout1->storage.u.contig.size))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "unable to allocate memory") + if(NULL == (buf2 = H5MM_malloc(layout1->storage.u.contig.size))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "unable to allocate memory") + + if(H5F_block_read(f1, H5FD_MEM_DRAW, layout1->storage.u.contig.addr, + layout1->storage.u.contig.size, dxpl1_id, buf1) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed") + if(H5F_block_read(f2, H5FD_MEM_DRAW, layout2->storage.u.contig.addr, + layout1->storage.u.contig.size, dxpl2_id, buf2) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed") + + if(HDmemcmp(buf1, buf2, layout1->storage.u.contig.size)) + HGOTO_DONE(TRUE) + } /* end if */ + else + /* One has space allocated and the other doesn't. Assume they are + * different. Eventually should check data in 1 against fill value + * in 2. */ + HGOTO_DONE(TRUE) + } /* end if */ + else + if(H5F_addr_defined(layout2->storage.u.contig.addr)) + /* One has space allocated and the other doesn't. Assume they are + * different. Eventually should check data in 2 against fill value + * in 1. */ + HGOTO_DONE(TRUE) + else + /* Neither has space allocated. If their fill values are not + * identical, they are different. */ + if(!udata->fill_identical) + HGOTO_DONE(TRUE) + +done: + buf1 = H5MM_xfree(buf1); + buf2 = H5MM_xfree(buf2); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_contig_compare() */ + diff --git a/src/H5Doh.c b/src/H5Doh.c index 8de28ce..278bc71 100644 --- a/src/H5Doh.c +++ b/src/H5Doh.c @@ -55,6 +55,9 @@ static void *H5O_dset_create(H5F_t *f, void *_crt_info, H5G_loc_t *obj_loc, static H5O_loc_t *H5O_dset_get_oloc(hid_t obj_id); static herr_t H5O_dset_bh_info(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5_ih_info_t *bh_info); +static htri_t H5O_dset_compare(const H5F_t *f1, const H5F_t *f2, + const H5O_t *oh1, const H5O_t *oh2, haddr_t addr1, haddr_t addr2, + hid_t dxpl1_id, hid_t dxpl2_id, H5O_cmp_t *cmp_info); /*********************/ @@ -81,7 +84,8 @@ const H5O_obj_class_t H5O_OBJ_DATASET[1] = {{ H5O_dset_open, /* open an object of this class */ H5O_dset_create, /* create an object of this class */ H5O_dset_get_oloc, /* get an object header location for an object */ - H5O_dset_bh_info /* get the index & heap info for an object */ + H5O_dset_bh_info, /* get the index & heap info for an object */ + H5O_dset_compare /* compare two datasets */ }}; /* Declare a free list to manage the H5D_copy_file_ud_t struct */ @@ -431,3 +435,300 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_dset_bh_info() */ + +/*------------------------------------------------------------------------- + * Function: H5O_dset_compare + * + * Purpose: fnord + * + * Return: Success: 0 (equal) or 1 (not equal) + * Failure: negative + * + * Programmer: Neil Fortner + * October 27, 2010 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5O_dset_compare(const H5F_t *f1, const H5F_t *f2, const H5O_t *oh1, + const H5O_t *oh2, haddr_t addr1, haddr_t addr2, hid_t dxpl1_id, + hid_t dxpl2_id, H5O_cmp_t UNUSED *cmp_info) +{ + H5S_t *space1; /* Dataspace message */ + H5S_t *space2; /* Dataspace message */ + H5O_layout_t layout1; /* Data storage layout message */ + H5O_layout_t layout2; /* Data storage layout message */ + H5O_pline_t pline1 = H5O_CRT_PIPELINE_DEF; /* I/O pipeline message */ + H5O_pline_t pline2 = H5O_CRT_PIPELINE_DEF; /* I/O pipeline message */ + H5T_t *dtype1; /* Datatype message */ + H5T_t *dtype2; /* Datatype message */ + H5O_fill_t fill1; /* Fill value message */ + H5O_fill_t fill2; /* Fill value message */ + hbool_t space_read = FALSE; /* Whether the dataspace messages were read */ + hbool_t layout_read = FALSE; /* Whether the layout messages were read */ + hbool_t pline_read = FALSE; /* Whether the I/O pipeline messages were read */ + hbool_t dtype_read = FALSE; /* Whether the datatype messages were read */ + hbool_t fill1_read = FALSE; /* Whether the fill value message was read */ + hbool_t fill2_read = FALSE; /* Whether the fill value message was read */ + int ndims1; + int ndims2; + hsize_t dims1[H5O_LAYOUT_NDIMS]; + hsize_t dims2[H5O_LAYOUT_NDIMS]; + H5D_cmp_ud_t udata; + htri_t tri_ret; /* htri_t return value */ + unsigned i; + htri_t ret_value; /* Return value */ + + FUNC_ENTER_NOAPI(H5O_dset_compare, FAIL) + + /* Sanity check */ + HDassert(f1); + HDassert(f2); + HDassert(oh1); + HDassert(oh2); + + /* Save the dset oh addresses in udata */ + udata.addr1 = addr1; + udata.addr2 = addr2; + + /* Get the dataspace messages */ + if(NULL == (space1 = H5S_read_oh(f1, oh1, dxpl1_id))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't read dataspace message") + if(NULL == (space2 = H5S_read_oh(f2, oh2, dxpl2_id))) { + if(H5S_close(space1) < 0) + HERROR(H5E_DATASET, H5E_CANTFREE, "can't close dataspace"); + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't read dataspace message") + } /* end if */ + space_read = TRUE; + + /* Check if the dataspace extents are identical */ + if((ndims1 = H5S_get_simple_extent_dims(space1, dims1, NULL)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get dataspace dimensions") + if((ndims2 = H5S_get_simple_extent_dims(space2, dims2, NULL)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get dataspace dimensions") + if(ndims1 != ndims2 || HDmemcmp(dims1, dims2, (size_t)ndims1 * sizeof(dims1[0]))) + HGOTO_DONE(TRUE) + + /* Save the dataspace in udata */ + udata.space = space1; + + /* Get the layout messages */ + if(NULL == H5O_msg_read_oh(f1, dxpl1_id, oh1, H5O_LAYOUT_ID, &layout1)) + HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't find layout message") + if(NULL == H5O_msg_read_oh(f2, dxpl2_id, oh2, H5O_LAYOUT_ID, &layout2)) { + if(H5O_msg_reset(H5O_LAYOUT_ID, &layout1) < 0) + HERROR(H5E_DATASET, H5E_CANTRESET, "unable to reset data storage layout message"); + HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't find layout message") + } /* end if */ + layout_read = TRUE; + + /* Check if the layout messages are identical */ + /* Will eventually want to check if they are compatible, even if not + * identical -NAF */ + /*FIXME fnord Note we do not handle external datasets! */ + if(layout1.type != layout2.type) + HGOTO_DONE(TRUE) + else if(layout1.type == H5D_CHUNKED) { + if(layout1.u.chunk.ndims != layout2.u.chunk.ndims || + HDmemcmp(layout1.u.chunk.dim, layout2.u.chunk.dim, + layout1.u.chunk.ndims * sizeof(layout1.u.chunk.dim[0]))) + HGOTO_DONE(TRUE) + HDassert(layout1.u.chunk.size == layout2.u.chunk.size); + HDassert(layout1.u.chunk.nchunks == layout2.u.chunk.nchunks); + HDassert(!HDmemcmp(layout1.u.chunk.chunks, layout2.u.chunk.chunks, + layout1.u.chunk.ndims * sizeof(layout1.u.chunk.dim[0]))); + HDassert(!HDmemcmp(layout1.u.chunk.down_chunks, + layout2.u.chunk.down_chunks, layout1.u.chunk.ndims + * sizeof(layout1.u.chunk.dim[0]))); + } /* end if */ + + /* Get the pipeline messages */ + if((tri_ret = H5O_msg_exists_oh(oh1, H5O_PLINE_ID)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to read object header") + if(tri_ret) { + /* Make sure both objects have a pipeline - mix/match not supported yet + */ + if((tri_ret = H5O_msg_exists_oh(oh2 , H5O_PLINE_ID)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to read object header") + if(!tri_ret) + HGOTO_DONE(TRUE) + + if(NULL == H5O_msg_read_oh(f1, dxpl1_id, oh1, H5O_PLINE_ID, &pline1)) + HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't find pipeline message") + if(NULL == H5O_msg_read_oh(f2, dxpl2_id, oh2, H5O_PLINE_ID, &pline2)) { + if(H5O_msg_reset(H5O_PLINE_ID, &pline1) < 0) + HERROR(H5E_DATASET, H5E_CANTRESET, "unable to reset pipeline message"); + HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't find pipeline message") + } /* end if */ + pline_read = TRUE; + + /* Check if the pipeline messages are identical */ + /* Will eventually want to handle different pipelines */ + if(pline1.nused != pline2.nused) + HGOTO_DONE(TRUE) + else + for(i=0; icompare); + if((ret_value = layout1.ops->compare(f1, f2, &layout1, &layout2, dxpl1_id, + dxpl2_id, &udata)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTCOMPARE, FAIL, "unable to compare datasets") + +done: + /* Free messages, if they've been read in */ + if(space_read) { + if(H5S_close(space1) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't close dataspace") + if(H5S_close(space2) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't close dataspace") + } /* end if */ + if(layout_read) { + if(H5O_msg_reset(H5O_LAYOUT_ID, &layout1) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTRESET, FAIL, "unable to reset data storage layout message") + if(H5O_msg_reset(H5O_LAYOUT_ID, &layout2) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTRESET, FAIL, "unable to reset data storage layout message") + } /* end if */ + if(pline_read) { + if(H5O_msg_reset(H5O_PLINE_ID, &pline1) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTRESET, FAIL, "unable to reset I/O pipeline message") + if(H5O_msg_reset(H5O_PLINE_ID, &pline2) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTRESET, FAIL, "unable to reset I/O pipeline message") + } /* end if */ + if(dtype_read) { + (void)H5O_msg_free(H5O_DTYPE_ID, dtype1); + (void)H5O_msg_free(H5O_DTYPE_ID, dtype2); + } /* end if */ + /* Note that we take advantage of the fact that both versions of the fill + * message use the same reset routine. If this changes, we will have to + * change this to pass the correct message ID. */ + if(fill1_read) + (void)H5O_msg_reset(H5O_FILL_NEW_ID, &fill1); + if(fill2_read) + (void)H5O_msg_reset(H5O_FILL_NEW_ID, &fill2); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_dset_compare() */ + diff --git a/src/H5Dpkg.h b/src/H5Dpkg.h index 44b44d9..d03335f 100644 --- a/src/H5Dpkg.h +++ b/src/H5Dpkg.h @@ -94,6 +94,16 @@ typedef struct H5D_type_info_t { hbool_t bkg_buf_allocated; /* Whether the background buffer was allocated */ } H5D_type_info_t; +/* Typedef for udata struct shared between functions when comparing datasets */ +typedef struct H5D_cmp_ud_t { + hbool_t fill_identical; /* Whether the fill values are identical */ + const H5O_pline_t *pline1; /* Pipeline for dataset "1" */ + const H5O_pline_t *pline2; /* Pipeline for dataset "2" */ + H5S_t *space; /* Dataspace (must be the same for datasets 1 and 2) */ + haddr_t addr1; /* Address for dataset 1 */ + haddr_t addr2; /* Address for dataset 2 */ +} H5D_cmp_ud_t; + /* Forward declaration of structs used below */ struct H5D_io_info_t; struct H5D_chunk_map_t; @@ -121,6 +131,9 @@ typedef ssize_t (*H5D_layout_writevv_func_t)(const struct H5D_io_info_t *io_info size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]); typedef herr_t (*H5D_layout_flush_func_t)(H5D_t *dataset, hid_t dxpl_id); typedef herr_t (*H5D_layout_io_term_func_t)(const struct H5D_chunk_map_t *cm); +typedef htri_t (*H5D_layout_compare_func_t)(const H5F_t *f1, const H5F_t *f2, + const H5O_layout_t *layout1, const H5O_layout_t *layout2, + hid_t dxpl1_id, hid_t dxpl2_id, H5D_cmp_ud_t *udata); /* Typedef for grouping layout I/O routines */ typedef struct H5D_layout_ops_t { @@ -138,6 +151,7 @@ typedef struct H5D_layout_ops_t { H5D_layout_writevv_func_t writevv; /* Low-level I/O routine for writing data */ H5D_layout_flush_func_t flush; /* Low-level I/O routine for flushing raw data */ H5D_layout_io_term_func_t io_term; /* I/O shutdown routine */ + H5D_layout_compare_func_t compare; /* Data comparison routine */ } H5D_layout_ops_t; /* Function pointers for either multiple or single block I/O access */ diff --git a/src/H5Ocompare.c b/src/H5Ocompare.c new file mode 100644 index 0000000..c45e689 --- /dev/null +++ b/src/H5Ocompare.c @@ -0,0 +1,749 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*------------------------------------------------------------------------- + * + * Created: H5Ocompare.c + * Oct 12 2010 + * Neil Fortner + * + * Purpose: Object comparison routines. + * + *------------------------------------------------------------------------- + */ + +/****************/ +/* Module Setup */ +/****************/ + +#define H5O_PACKAGE /*suppress error about including H5Opkg */ + +/***********/ +/* Headers */ +/***********/ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5Iprivate.h" /* IDs */ +#include "H5MMprivate.h" /* Memory management */ +#include "H5Opkg.h" /* Object headers */ +#include "H5Pprivate.h" /* Property lists */ + + +/****************/ +/* Local Macros */ +/****************/ + + +/******************/ +/* Local Typedefs */ +/******************/ + + +/********************/ +/* Package Typedefs */ +/********************/ + + +/********************/ +/* Local Prototypes */ +/********************/ + +static herr_t H5O_compare_obj(const H5O_loc_t *oloc1, const H5O_loc_t *oloc2, + hid_t ocmppl_id); + +/*********************/ +/* Package Variables */ +/*********************/ + + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + + +/*******************/ +/* Local Variables */ +/*******************/ + + + +/*------------------------------------------------------------------------- + * Function: H5Ocompare + * + * Purpose: fnord + * + * Usage: fnord + * + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Neil Fortner + * October 12, 2010 + * + *------------------------------------------------------------------------- + */ +htri_t +H5Ocompare(hid_t loc1_id, const char *name1, hid_t loc2_id, const char *name2, + hid_t ocmppl_id) +{ + H5G_loc_t base_loc1; /* Base location for object 1 */ + H5G_loc_t base_loc2; /* Base location for object 2 */ + H5G_loc_t loc1; /* Object location for object 1 */ + H5G_loc_t loc2; /* Object location for object 2 */ + + /* for opening the objects */ + H5G_name_t path1; /* Opened object 1 hier. path */ + H5G_name_t path2; /* Opened object 2 hier. path */ + H5O_loc_t oloc1; /* Opened object 1 object location */ + H5O_loc_t oloc2; /* Opened object 2 object location */ + hbool_t loc1_found = FALSE; /* Location at 'name1' found */ + hbool_t loc2_found = FALSE; /* Location at 'name2' found */ + hbool_t obj1_open = FALSE; /* Entry at 'name1' found */ + hbool_t obj2_open = FALSE; /* Entry at 'name2' found */ + + htri_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(H5Ocompare, FAIL) + + /* Check arguments */ + if(H5G_loc(loc1_id, &base_loc1) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "loc1_id not a location") + if(H5G_loc(loc2_id, &base_loc2) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "loc2_id not a location") + if(!name1 || !*name2) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified for object 1") + if(!name2 || !*name2) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified for object 2") + + /* Set up opened group locations to fill in */ + loc1.oloc = &oloc1; + loc1.path = &path1; + H5G_loc_reset(&loc1); + loc2.oloc = &oloc2; + loc2.path = &path2; + H5G_loc_reset(&loc2); + + /* Find the objects to compare */ + if(H5G_loc_find(&base_loc1, name1, &loc1/*out*/, H5P_DEFAULT, H5AC_dxpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object 1 not found") + loc1_found = TRUE; + if(H5G_loc_find(&base_loc2, name2, &loc2/*out*/, H5P_DEFAULT, H5AC_dxpl_id) < 0) + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object 2 not found") + loc2_found = TRUE; + + /* Open the objects' object headers */ + if(H5O_open(&oloc1) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open object 1") + obj1_open = TRUE; + if(H5O_open(&oloc2) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open object 2") + obj2_open = TRUE; +#if 0 + /* Get correct property lists */ + if(H5P_DEFAULT == lcpl_id) { + if((lcpl_id = H5L_get_default_lcpl()) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "unable to get default lcpl") + } /* end if */ + else + if(TRUE != H5P_isa_class(lcpl_id, H5P_LINK_CREATE)) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not link creation property list") + + /* Get object copy property list */ + if(H5P_DEFAULT == ocpypl_id) + ocpypl_id = H5P_OBJECT_COPY_DEFAULT; + else + if(TRUE != H5P_isa_class(ocpypl_id, H5P_OBJECT_COPY)) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not object copy property list") +#endif + /* Do the actual copying of the object */ + if((ret_value = H5O_compare_obj(&oloc1, &oloc2, ocmppl_id)) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTCOMPARE, FAIL, "unable to compare object") + +done: + if(loc1_found && H5G_loc_free(&loc1) < 0) + HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "can't free location 1") + if(loc2_found && H5G_loc_free(&loc2) < 0) + HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "can't free location 2") + if(obj1_open) + H5O_close(&oloc1); + if(obj2_open) + H5O_close(&oloc2); + + FUNC_LEAVE_API(ret_value) +} /* end H5Ocompare() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_compare_obj + * + * Purpose: fnord + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Neil Fortner + * Novermeber 23, 2010 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5O_compare_obj(const H5O_loc_t *oloc1, const H5O_loc_t *oloc2, hid_t ocmppl_id) +{ + H5O_t *oh1 = NULL; /* Object header for object 1 */ + H5O_t *oh2 = NULL; /* Object header for object 2 */ + const H5O_obj_class_t *obj1_class = NULL; /* Type of object 1 */ + const H5O_obj_class_t *obj2_class = NULL; /* Type of object 2 */ + hid_t dxpl1_id = H5AC_dxpl_id; + hid_t dxpl2_id = -1; + H5P_genplist_t *dxpl = NULL; + haddr_t prev_tag1 = HADDR_UNDEF; + haddr_t prev_tag2 = HADDR_UNDEF; + htri_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT(H5O_compare_obj) + + HDassert(oloc1); + HDassert(oloc1->file); + HDassert(H5F_addr_defined(oloc1->addr)); + HDassert(oloc2); + HDassert(oloc2->file); + HDassert(H5F_addr_defined(oloc2->addr)); + + /* Copy dxpl1 to dxpl2 */ + if(NULL == (dxpl = (H5P_genplist_t *)H5I_object_verify(dxpl1_id, H5I_GENPROP_LST))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list") + if((dxpl2_id = H5P_copy_plist((H5P_genplist_t *)dxpl, FALSE)) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy property list"); + + /* Set up metadata tagging */ + if(H5AC_tag(dxpl1_id, oloc1->addr, &prev_tag1) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "unable to apply metadata tag") + if(H5AC_tag(dxpl2_id, oloc2->addr, &prev_tag2) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "unable to apply metadata tag") + + /* Get object headers */ + /*FIXME fnord Set up tagging here? */ + if(NULL == (oh1 = H5O_protect(oloc1, dxpl1_id, H5AC_READ))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") + if(NULL == (oh2 = H5O_protect(oloc2, dxpl2_id, H5AC_READ))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") + + /* Get pointer to object class for objects */ + if(NULL == (obj1_class = H5O_obj_class_real(oh1))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object type") + if(NULL == (obj2_class = H5O_obj_class_real(oh1))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object type") + if(obj1_class->type != obj2_class->type) + HGOTO_DONE(TRUE) + + /* Do the comparison */ + HDassert(obj1_class->compare); + if((ret_value = obj1_class->compare(oloc1->file, oloc2->file, oh1, oh2, + oloc1->addr, oloc2->addr, dxpl1_id, dxpl2_id, NULL)) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTCOMPARE, FAIL, "unable to compare objects") + +done: + /* Release pointer to object headers and their derived objects */ + if(oh1 && H5O_unprotect(oloc1, dxpl1_id, oh1, H5AC__NO_FLAGS_SET) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") + if(oh2 && H5O_unprotect(oloc2, dxpl2_id, oh2, H5AC__NO_FLAGS_SET) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") + + if(H5AC_tag(dxpl1_id, prev_tag1, NULL) < 0) + HDONE_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "unable to apply metadata tag") + if(H5AC_tag(dxpl2_id, prev_tag2, NULL) < 0) + HDONE_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "unable to apply metadata tag") + + if(dxpl2_id >= 0 && H5I_dec_ref(dxpl2_id) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTDEC, FAIL, "can't decrement ID ref count") + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_compare_obj() */ + +#if 0 + +/*------------------------------------------------------------------------- + * Function: H5O_copy_header_map + * + * Purpose: Copy header object from one location to another, detecting + * already mapped objects, etc. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * November 1, 2005 + * + *------------------------------------------------------------------------- + */ +herr_t +H5O_copy_header_map(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */, + hid_t dxpl_id, H5O_copy_t *cpy_info, hbool_t inc_depth, + H5O_type_t *obj_type, void **udata) +{ + H5O_addr_map_t *addr_map = NULL; /* Address mapping of object copied */ + H5_obj_t src_obj_pos; /* Position of source object */ + hbool_t inc_link; /* Whether to increment the link count for the object */ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5O_copy_header_map, FAIL) + + /* Sanity check */ + HDassert(oloc_src); + HDassert(oloc_src->file); + HDassert(oloc_dst); + HDassert(oloc_dst->file); + HDassert(cpy_info); + + /* Create object "position" struct */ + H5F_GET_FILENO(oloc_src->file, src_obj_pos.fileno); + src_obj_pos.addr = oloc_src->addr; + + /* Search for the object in the skip list of copied objects */ + addr_map = (H5O_addr_map_t *)H5SL_search(cpy_info->map_list, + &src_obj_pos); + + /* Check if address is already in list of objects copied */ + if(addr_map == NULL) { + /* Copy object for the first time */ + + /* Check for incrementing the depth of copy */ + /* (Can't do this for all copies, since committed datatypes should always be copied) */ + if(inc_depth) + cpy_info->curr_depth++; + + /* Copy object referred to */ + if(H5O_copy_header_real(oloc_src, oloc_dst, dxpl_id, cpy_info, obj_type, + udata) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object") + + /* Check for incrementing the depth of copy */ + if(inc_depth) + cpy_info->curr_depth--; + + /* When an object is copied for the first time, increment it's link */ + inc_link = TRUE; + + /* indicate that a new object is created */ + ret_value++; + } /* end if */ + else { + /* Object has already been copied, set its address in destination file */ + oloc_dst->addr = addr_map->dst_addr; + + /* Return saved obj_type and udata, if requested */ + if(obj_type) { + HDassert(udata); + *obj_type = addr_map->obj_class->type; + *udata = addr_map->udata; + } /* end if */ + + /* If the object is locked currently (because we are copying a group + * hierarchy and this is a link to a group higher in the hierarchy), + * increment it's deferred reference count instead of incrementing the + * reference count now. + */ + if(addr_map->is_locked) { + addr_map->inc_ref_count++; + inc_link = FALSE; + } /* end if */ + else + inc_link = TRUE; + } /* end else */ + + /* Increment destination object's link count, if allowed */ + if(inc_link) + if(H5O_link(oloc_dst, 1, dxpl_id) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to increment object link count") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_copy_header_map() */ + + +/*-------------------------------------------------------------------------- + NAME + H5O_copy_free_addrmap_cb + PURPOSE + Internal routine to free address maps from the skip list for copying objects + USAGE + herr_t H5O_copy_free_addrmap_cb(item, key, op_data) + void *item; IN/OUT: Pointer to addr + void *key; IN/OUT: (unused) + void *op_data; IN: (unused) + RETURNS + Returns zero on success, negative on failure. + DESCRIPTION + Releases the memory for the address. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5O_copy_free_addrmap_cb(void *_item, void UNUSED *key, void UNUSED *op_data) +{ + H5O_addr_map_t *item = (H5O_addr_map_t *)_item; + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_copy_free_addrmap_cb) + + HDassert(item); + + /* Release user data for particular type of object */ + if(item->udata) { + HDassert(item->obj_class); + HDassert(item->obj_class->free_copy_file_udata); + (item->obj_class->free_copy_file_udata)(item->udata); + } /* end if */ + + /* Release the item */ + item = H5FL_FREE(H5O_addr_map_t, item); + + FUNC_LEAVE_NOAPI(0) +} /* H5O_copy_free_addrmap_cb() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_copy_header + * + * Purpose: copy header object from one location to another. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Peter Cao + * May 30, 2005 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_copy_header(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */, + hid_t dxpl_id, unsigned cpy_option) +{ + H5O_copy_t cpy_info; /* Information for copying object */ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT(H5O_copy_header) + + HDassert(oloc_src); + HDassert(oloc_src->file); + HDassert(H5F_addr_defined(oloc_src->addr)); + HDassert(oloc_dst->file); + + /* Convert copy flags into copy struct */ + HDmemset(&cpy_info, 0, sizeof(H5O_copy_t)); + if((cpy_option & H5O_COPY_SHALLOW_HIERARCHY_FLAG) > 0) { + cpy_info.copy_shallow = TRUE; + cpy_info.max_depth = 1; + } /* end if */ + else + cpy_info.max_depth = -1; /* Current default is for full, recursive hier. copy */ + cpy_info.curr_depth = 0; + if((cpy_option & H5O_COPY_EXPAND_SOFT_LINK_FLAG) > 0) + cpy_info.expand_soft_link = TRUE; + if((cpy_option & H5O_COPY_EXPAND_EXT_LINK_FLAG) > 0) + cpy_info.expand_ext_link = TRUE; + if((cpy_option & H5O_COPY_EXPAND_REFERENCE_FLAG) > 0) + cpy_info.expand_ref = TRUE; + if((cpy_option & H5O_COPY_WITHOUT_ATTR_FLAG) > 0) + cpy_info.copy_without_attr = TRUE; + if((cpy_option & H5O_COPY_PRESERVE_NULL_FLAG) > 0) + cpy_info.preserve_null = TRUE; + + /* Create a skip list to keep track of which objects are copied */ + if((cpy_info.map_list = H5SL_create(H5SL_TYPE_OBJ)) == NULL) + HGOTO_ERROR(H5E_SLIST, H5E_CANTCREATE, FAIL, "cannot make skip list") + + /* copy the object from the source file to the destination file */ + if(H5O_copy_header_real(oloc_src, oloc_dst, dxpl_id, &cpy_info, NULL, NULL) + < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object") + +done: + if(cpy_info.map_list) + H5SL_destroy(cpy_info.map_list, H5O_copy_free_addrmap_cb, NULL); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_copy_header() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_copy_obj + * + * Purpose: Copy an object to destination location + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Peter Cao + * June 4, 2005 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_copy_obj(H5G_loc_t *src_loc, H5G_loc_t *dst_loc, const char *dst_name, + hid_t ocpypl_id, hid_t lcpl_id) +{ + H5P_genplist_t *ocpy_plist=NULL; /* Object copy property list created */ + hid_t dxpl_id=H5AC_dxpl_id; + H5G_name_t new_path; /* Copied object group hier. path */ + H5O_loc_t new_oloc; /* Copied object object location */ + H5G_loc_t new_loc; /* Group location of object copied */ + H5F_t *cached_dst_file; /* Cached destination file */ + hbool_t entry_inserted=FALSE; /* Flag to indicate that the new entry was inserted into a group */ + unsigned cpy_option = 0; /* Copy options */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5O_copy_obj, FAIL) + + HDassert(src_loc); + HDassert(src_loc->oloc->file); + HDassert(dst_loc); + HDassert(dst_loc->oloc->file); + HDassert(dst_name); + + /* Get the copy property list */ + if(NULL == (ocpy_plist = (H5P_genplist_t *)H5I_object(ocpypl_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list") + + /* Retrieve the copy parameters */ + if(H5P_get(ocpy_plist, H5O_CPY_OPTION_NAME, &cpy_option) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get object copy flag") + + /* Set up copied object location to fill in */ + new_loc.oloc = &new_oloc; + new_loc.path = &new_path; + H5G_loc_reset(&new_loc); + new_oloc.file = dst_loc->oloc->file; + + /* Make a copy of the destination file, in case the original is changed by + * H5O_copy_header. If and when oloc's point to the shared file struct, + * this will no longer be necessary, so this code can be removed. */ + cached_dst_file = dst_loc->oloc->file; + + /* Copy the object from the source file to the destination file */ + if(H5O_copy_header(src_loc->oloc, &new_oloc, dxpl_id, cpy_option) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object") + + /* Patch dst_loc. Again, this can be removed once oloc's point to shared + * file structs. */ + dst_loc->oloc->file = cached_dst_file; + + /* Insert the new object in the destination file's group */ + if(H5L_link(dst_loc, dst_name, &new_loc, lcpl_id, H5P_DEFAULT, dxpl_id) < 0) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to insert link") + entry_inserted = TRUE; + +done: + /* Free the ID to name buffers */ + if(entry_inserted) + H5G_loc_free(&new_loc); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_copy_obj() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_copy_obj_by_ref + * + * Purpose: Copy the object pointed by _src_ref. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Peter Cao + * Aug 7 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_copy_obj_by_ref(H5O_loc_t *src_oloc, hid_t dxpl_id, H5O_loc_t *dst_oloc, + H5G_loc_t *dst_root_loc, H5O_copy_t *cpy_info) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5O_copy_obj_by_ref, FAIL) + + HDassert(src_oloc); + HDassert(dst_oloc); + + /* Perform the copy, or look up existing copy */ + if((ret_value = H5O_copy_header_map(src_oloc, dst_oloc, dxpl_id, cpy_info, + FALSE, NULL, NULL)) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object") + + /* Check if a new valid object is copied to the destination */ + if(H5F_addr_defined(dst_oloc->addr) && (ret_value > SUCCEED)) { + char tmp_obj_name[80]; + H5G_name_t new_path; + H5O_loc_t new_oloc; + H5G_loc_t new_loc; + + /* Set up group location for new object */ + new_loc.oloc = &new_oloc; + new_loc.path = &new_path; + H5G_loc_reset(&new_loc); + new_oloc.file = dst_oloc->file; + new_oloc.addr = dst_oloc->addr; + + /* Pick a default name for the new object */ + sprintf(tmp_obj_name, "~obj_pointed_by_%llu", (unsigned long long)dst_oloc->addr); + + /* Create a link to the newly copied object */ + /* Note: since H5O_copy_header_map actually copied the target object, it + * must exist either in cache or on disk, therefore it is is safe to not + * pass the obj_type and udata fields returned by H5O_copy_header_map. + * This could be changed in the future to slightly improve performance + * --NAF */ + if(H5L_link(dst_root_loc, tmp_obj_name, &new_loc, H5P_DEFAULT, H5P_DEFAULT, dxpl_id) < 0) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to insert link") + + H5G_loc_free(&new_loc); + } /* if (H5F_addr_defined(dst_oloc.addr)) */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_copy_obj_by_ref() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_copy_expand_ref + * + * Purpose: Copy the object pointed by _src_ref. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Peter Cao + * Aug 7 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5O_copy_expand_ref(H5F_t *file_src, void *_src_ref, hid_t dxpl_id, + H5F_t *file_dst, void *_dst_ref, size_t ref_count, H5R_type_t ref_type, + H5O_copy_t *cpy_info) +{ + H5O_loc_t dst_oloc; /* Copied object object location */ + H5O_loc_t src_oloc; /* Temporary object location for source object */ + H5G_loc_t dst_root_loc; /* The location of root group of the destination file */ + uint8_t *p; /* Pointer to OID to store */ + size_t i; /* Local index variable */ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5O_copy_expand_ref, FAIL) + + /* Sanity checks */ + HDassert(file_src); + HDassert(_src_ref); + HDassert(file_dst); + HDassert(_dst_ref); + HDassert(ref_count); + HDassert(cpy_info); + + /* Initialize object locations */ + H5O_loc_reset(&src_oloc); + H5O_loc_reset(&dst_oloc); + src_oloc.file = file_src; + dst_oloc.file = file_dst; + + /* Set up the root group in the destination file */ + if(NULL == (dst_root_loc.oloc = H5G_oloc(H5G_rootof(file_dst)))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location for root group") + if(NULL == (dst_root_loc.path = H5G_nameof(H5G_rootof(file_dst)))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path for root group") + + /* Copy object references */ + if(H5R_OBJECT == ref_type) { + hobj_ref_t *src_ref = (hobj_ref_t *)_src_ref; + hobj_ref_t *dst_ref = (hobj_ref_t *)_dst_ref; + + /* Making equivalent references in the destination file */ + for(i = 0; i < ref_count; i++) { + /* Set up for the object copy for the reference */ + p = (uint8_t *)(&src_ref[i]); + H5F_addr_decode(src_oloc.file, (const uint8_t **)&p, &(src_oloc.addr)); + dst_oloc.addr = HADDR_UNDEF; + + /* Attempt to copy object from source to destination file */ + if(src_oloc.addr != (haddr_t)0) { + if(H5O_copy_obj_by_ref(&src_oloc, dxpl_id, &dst_oloc, &dst_root_loc, cpy_info) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object") + } /* end if */ + else + /* Set parameters so the reference is written as all 0's */ + HDmemset(&dst_oloc.addr, 0, sizeof(dst_oloc.addr)); + + /* Set the object reference info for the destination file */ + p = (uint8_t *)(&dst_ref[i]); + H5F_addr_encode(dst_oloc.file, &p, dst_oloc.addr); + } /* end for */ + } /* end if */ + /* Copy region references */ + else if(H5R_DATASET_REGION == ref_type) { + hdset_reg_ref_t *src_ref = (hdset_reg_ref_t *)_src_ref; + hdset_reg_ref_t *dst_ref = (hdset_reg_ref_t *)_dst_ref; + uint8_t *buf = NULL; /* Buffer to store serialized selection in */ + H5HG_t hobjid; /* Heap object ID */ + size_t buf_size; /* Length of object in heap */ + + /* Making equivalent references in the destination file */ + for(i = 0; i < ref_count; i++) { + /* Get the heap ID for the dataset region */ + p = (uint8_t *)(&src_ref[i]); + H5F_addr_decode(src_oloc.file, (const uint8_t **)&p, &(hobjid.addr)); + INT32DECODE(p, hobjid.idx); + + if(hobjid.addr != (haddr_t)0) { + /* Get the dataset region from the heap (allocate inside routine) */ + if((buf = (uint8_t *)H5HG_read(src_oloc.file, dxpl_id, &hobjid, NULL, &buf_size)) == NULL) + HGOTO_ERROR(H5E_REFERENCE, H5E_READERROR, FAIL, "Unable to read dataset region information") + + /* Get the object oid for the dataset */ + p = (uint8_t *)buf; + H5F_addr_decode(src_oloc.file, (const uint8_t **)&p, &(src_oloc.addr)); + dst_oloc.addr = HADDR_UNDEF; + + /* copy the object pointed by the ref to the destination */ + if(H5O_copy_obj_by_ref(&src_oloc, dxpl_id, &dst_oloc, &dst_root_loc, cpy_info) < 0) { + H5MM_xfree(buf); + HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object") + } /* end if */ + + /* Serialize object ID */ + p = (uint8_t *)buf; + H5F_addr_encode(dst_oloc.file, &p, dst_oloc.addr); + + /* Save the serialized buffer to the destination */ + if(H5HG_insert(dst_oloc.file, dxpl_id, buf_size, buf, &hobjid) < 0) { + H5MM_xfree(buf); + HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "Unable to write dataset region information") + } /* end if */ + } /* end if */ + else + /* Set parameters so the reference is written as all 0's */ + HDmemset(&hobjid, 0, sizeof(hobjid)); + + /* Set the dataset region reference info for the destination file */ + p = (uint8_t *)(&dst_ref[i]); + H5F_addr_encode(dst_oloc.file, &p, hobjid.addr); + INT32ENCODE(p, hobjid.idx); + + /* Free the buffer allocated in H5HG_read() */ + H5MM_xfree(buf); + } /* end for */ + } /* end if */ + else + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid reference type") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_copy_expand_ref() */ +#endif + diff --git a/src/H5Opkg.h b/src/H5Opkg.h index 54e7233..2931381 100644 --- a/src/H5Opkg.h +++ b/src/H5Opkg.h @@ -325,6 +325,9 @@ typedef struct H5O_obj_class_t { void *(*create)(H5F_t *, void *, H5G_loc_t *, hid_t ); /*create an object of this class */ H5O_loc_t *(*get_oloc)(hid_t ); /*get the object header location for an object */ herr_t (*bh_info)(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5_ih_info_t *bh_info); /*get the index & heap info for an object */ + htri_t (*compare)(const H5F_t *f1, const H5F_t *f2, const H5O_t *oh1, + const H5O_t *oh2, haddr_t addr1, haddr_t addr2, hid_t dxpl1_id, + hid_t dxpl2_id, H5O_cmp_t *cmp_info); /*compare two objects of this class */ } H5O_obj_class_t; /* Node in skip list to map addresses from one file to another during object header copy */ diff --git a/src/H5Oprivate.h b/src/H5Oprivate.h index 56901f3..5ca93b4 100644 --- a/src/H5Oprivate.h +++ b/src/H5Oprivate.h @@ -145,6 +145,10 @@ typedef struct H5O_copy_t { H5O_t *oh_dst; /* The destination object header */ } H5O_copy_t; +/* Settings/flags for comparing objects */ +/* Empty for now */ +typedef void H5O_cmp_t; + /* Header message IDs */ #define H5O_NULL_ID 0x0000 /* Null Message. */ #define H5O_SDSPACE_ID 0x0001 /* Dataspace Message. */ diff --git a/src/H5Opublic.h b/src/H5Opublic.h index c5ae3c1..2334bd5 100644 --- a/src/H5Opublic.h +++ b/src/H5Opublic.h @@ -172,6 +172,8 @@ H5_DLL herr_t H5Ovisit(hid_t obj_id, H5_index_t idx_type, H5_iter_order_t order, H5_DLL herr_t H5Ovisit_by_name(hid_t loc_id, const char *obj_name, H5_index_t idx_type, H5_iter_order_t order, H5O_iterate_t op, void *op_data, hid_t lapl_id); +H5_DLL htri_t H5Ocompare(hid_t loc1_id, const char *name1, hid_t loc2_id, + const char *name2, hid_t ocmppl_id); H5_DLL herr_t H5Oclose(hid_t object_id); /* Symbols defined for compatibility with previous versions of the HDF5 API. diff --git a/src/H5S.c b/src/H5S.c index e7cac9d..c92df45 100644 --- a/src/H5S.c +++ b/src/H5S.c @@ -1063,6 +1063,54 @@ done: } /* end H5S_read() */ +/*------------------------------------------------------------------------- + * Function: H5S_read_oh + * + * Purpose: Reads the dataspace from an object header. + * + * Return: Success: Pointer to a new dataspace. + * + * Failure: NULL + * + * Programmer: Robb Matzke + * Tuesday, December 9, 1997 + * + *------------------------------------------------------------------------- + */ +H5S_t * +H5S_read_oh(const H5F_t *f, const H5O_t *oh, hid_t dxpl_id) +{ + H5S_t *ds = NULL; /* Dataspace to return */ + H5S_t *ret_value; /* Return value */ + + FUNC_ENTER_NOAPI(H5S_read_oh, NULL) + + /* check args */ + HDassert(oh); + + if(NULL == (ds = H5FL_CALLOC(H5S_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + + if(H5O_msg_read_oh(f, dxpl_id, oh, H5O_SDSPACE_ID, &(ds->extent)) == NULL) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, NULL, "unable to load dataspace info from dataset header") + + /* Default to entire dataspace being selected */ + if(H5S_select_all(ds, FALSE) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, NULL, "unable to set all selection") + + /* Set the value for successful return */ + ret_value = ds; + +done: + if(ret_value == NULL) { + if(ds != NULL) + ds = H5FL_FREE(H5S_t, ds); + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_read_oh() */ + + /*-------------------------------------------------------------------------- NAME H5S_is_simple diff --git a/src/H5Sprivate.h b/src/H5Sprivate.h index 0e67af1..eb97a4d 100644 --- a/src/H5Sprivate.h +++ b/src/H5Sprivate.h @@ -188,6 +188,7 @@ H5_DLL herr_t H5S_write(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned update_flag H5S_t *ds); H5_DLL herr_t H5S_append(H5F_t *f, hid_t dxpl_id, struct H5O_t *oh, H5S_t *ds); H5_DLL H5S_t *H5S_read(const struct H5O_loc_t *loc, hid_t dxpl_id); +H5_DLL H5S_t *H5S_read_oh(const H5F_t *f, const H5O_t *oh, hid_t dxpl_id); H5_DLL htri_t H5S_set_extent(H5S_t *space, const hsize_t *size); H5_DLL herr_t H5S_set_extent_real(H5S_t *space, const hsize_t *size); H5_DLL H5S_t *H5S_create(H5S_class_t type); diff --git a/src/Makefile.am b/src/Makefile.am index dc0edb3..f0e1614 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -77,8 +77,8 @@ libhdf5_la_SOURCES= H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \ H5MM.c H5MP.c H5MPtest.c \ H5O.c H5Oainfo.c H5Oalloc.c H5Oattr.c \ H5Oattribute.c H5Obogus.c H5Obtreek.c H5Ocache.c H5Ochunk.c \ - H5Ocont.c H5Ocopy.c H5Odbg.c H5Odrvinfo.c H5Odtype.c H5Oefl.c \ - H5Ofill.c H5Ofsinfo.c H5Oginfo.c \ + H5Ocompare.c H5Ocont.c H5Ocopy.c H5Odbg.c H5Odrvinfo.c H5Odtype.c \ + H5Oefl.c H5Ofill.c H5Ofsinfo.c H5Oginfo.c \ H5Olayout.c \ H5Olinfo.c H5Olink.c H5Omessage.c H5Omtime.c \ H5Oname.c H5Onull.c H5Opline.c H5Orefcount.c \ diff --git a/src/Makefile.in b/src/Makefile.in index 55e52ae..0700f23 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -126,7 +126,7 @@ am_libhdf5_la_OBJECTS = H5.lo H5checksum.lo H5dbg.lo H5system.lo \ H5L.lo H5Lexternal.lo H5lib_settings.lo H5MF.lo H5MFaggr.lo \ H5MFdbg.lo H5MFsection.lo H5MM.lo H5MP.lo H5MPtest.lo H5O.lo \ H5Oainfo.lo H5Oalloc.lo H5Oattr.lo H5Oattribute.lo H5Obogus.lo \ - H5Obtreek.lo H5Ocache.lo H5Ochunk.lo H5Ocont.lo H5Ocopy.lo \ + H5Obtreek.lo H5Ocache.lo H5Ochunk.lo H5Ocompare.lo H5Ocont.lo H5Ocopy.lo \ H5Odbg.lo H5Odrvinfo.lo H5Odtype.lo H5Oefl.lo H5Ofill.lo \ H5Ofsinfo.lo H5Oginfo.lo H5Olayout.lo H5Olinfo.lo H5Olink.lo \ H5Omessage.lo H5Omtime.lo H5Oname.lo H5Onull.lo H5Opline.lo \ @@ -510,7 +510,7 @@ libhdf5_la_SOURCES = H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \ H5MM.c H5MP.c H5MPtest.c \ H5O.c H5Oainfo.c H5Oalloc.c H5Oattr.c \ H5Oattribute.c H5Obogus.c H5Obtreek.c H5Ocache.c H5Ochunk.c \ - H5Ocont.c H5Ocopy.c H5Odbg.c H5Odrvinfo.c H5Odtype.c H5Oefl.c \ + H5Ocompare.c H5Ocont.c H5Ocopy.c H5Odbg.c H5Odrvinfo.c H5Odtype.c H5Oefl.c \ H5Ofill.c H5Ofsinfo.c H5Oginfo.c \ H5Olayout.c \ H5Olinfo.c H5Olink.c H5Omessage.c H5Omtime.c \ @@ -835,6 +835,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Obtreek.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ocache.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ochunk.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ocompare.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ocont.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ocopy.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Odbg.Plo@am__quote@ diff --git a/tools/lib/h5diff_dset.c b/tools/lib/h5diff_dset.c index 8e25b6d..905cbbc 100644 --- a/tools/lib/h5diff_dset.c +++ b/tools/lib/h5diff_dset.c @@ -44,7 +44,16 @@ hsize_t diff_dataset( hid_t file1_id, hid_t dcpl1 = -1; hid_t dcpl2 = -1; hsize_t nfound = 0; + htri_t tri_ret; + /* Do the comparison */ + if((tri_ret = H5Ocompare(file1_id, obj1_name, file2_id, obj2_name, H5P_DEFAULT)) < 0) + goto error; + + if(tri_ret) + nfound = 1; + +#if 0 /*------------------------------------------------------------------------- * open the handles *------------------------------------------------------------------------- @@ -102,12 +111,14 @@ hsize_t diff_dataset( hid_t file1_id, H5Dclose(did2); /* enable error reporting */ } H5E_END_TRY; +#endif return nfound; error: options->err_stat=1; +#if 0 /* disable error reporting */ H5E_BEGIN_TRY { H5Pclose(dcpl1); @@ -116,6 +127,7 @@ error: H5Dclose(did2); /* enable error reporting */ } H5E_END_TRY; +#endif return nfound; } -- cgit v0.12