From eec82a42194221c209868f124604dde9e2ec66ea Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Fri, 17 Nov 2006 13:48:00 -0500 Subject: [svn-r12933] Description: Finish migrating "object copy" supporting routines into src/H5Ocopy. Clean up a few minor errors _en passant_ Tested on: FreeBSD/32 4.11 (sleipnir) Linux/32 2.4 (heping) Linux/64 2.4 (mir) --- src/H5O.c | 665 +------------------------------------------------------ src/H5Ocopy.c | 592 ++++++++++++++++++++++++++++++++++++++++++++++++- src/H5Opkg.h | 7 +- src/H5Oprivate.h | 11 +- src/H5SM.c | 2 +- 5 files changed, 608 insertions(+), 669 deletions(-) diff --git a/src/H5O.c b/src/H5O.c index bb4b917..dba50a6 100644 --- a/src/H5O.c +++ b/src/H5O.c @@ -38,12 +38,10 @@ #include "H5Fpkg.h" /* File access */ #include "H5FLprivate.h" /* Free lists */ #include "H5Iprivate.h" /* IDs */ -#include "H5Lprivate.h" /* Links */ #include "H5MFprivate.h" /* File memory management */ #include "H5MMprivate.h" /* Memory management */ #include "H5Opkg.h" /* Object headers */ #include "H5SMprivate.h" /* Shared object header messages */ -#include "H5Tprivate.h" /* Datatypes */ #ifdef H5_HAVE_GETTIMEOFDAY #include @@ -173,10 +171,6 @@ static herr_t H5O_iterate_real(const H5O_loc_t *loc, const H5O_msg_class_t *type H5AC_protect_t prot, hbool_t internal, H5O_mesg_operator_t op, void *op_data, hid_t dxpl_id); static const H5O_obj_class_t *H5O_obj_class(H5O_loc_t *loc, hid_t dxpl_id); static H5G_obj_t H5O_obj_type_real(H5O_t *oh); -static const H5O_obj_class_t *H5O_obj_class_real(H5O_t *oh); -static herr_t H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */, - hid_t dxpl_id, H5O_copy_t *cpy_info); -static herr_t H5O_copy_free_addrmap_cb(void *item, void *key, void *op_data); /*********************/ /* Package Variables */ @@ -4165,8 +4159,7 @@ H5O_is_shared(unsigned type_id, const void *mesg) *------------------------------------------------------------------------- */ herr_t -H5O_set_share(H5F_t *f, hid_t dxpl_id, H5O_shared_t *share, - unsigned type_id, void *mesg) +H5O_set_share(H5F_t *f, H5O_shared_t *share, unsigned type_id, void *mesg) { const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ herr_t ret_value; /* Return value */ @@ -4857,13 +4850,13 @@ done: * *------------------------------------------------------------------------- */ -static const H5O_obj_class_t * +const H5O_obj_class_t * H5O_obj_class_real(H5O_t *oh) { size_t i; /* Local index variable */ const H5O_obj_class_t *ret_value; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT(H5O_obj_class_real) + FUNC_ENTER_NOAPI(H5O_obj_class_real, NULL) /* Sanity check */ HDassert(oh); @@ -5083,591 +5076,6 @@ done: /*------------------------------------------------------------------------- - * Function: H5O_copy_header_real - * - * Purpose: Copy header object from one location to another using - * pre-copy, copy, and post-copy callbacks for each message - * type. - * - * The source header object is compressed into a single chunk - * (since we know how big it is) and any continuation messages - * are converted into NULL messages. - * - * By default, NULL messages are not copied. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Peter Cao - * May 30, 2005 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */, - hid_t dxpl_id, H5O_copy_t *cpy_info) -{ - H5O_addr_map_t *addr_map = NULL; /* Address mapping of object copied */ - H5O_t *oh_src = NULL; /* Object header for source object */ - H5O_t *oh_dst = NULL; /* Object header for destination object */ - unsigned chunkno = 0, mesgno = 0; - haddr_t addr_new = HADDR_UNDEF; - hbool_t *deleted = NULL; /* Array of flags indicating whether messages should be copied */ - size_t null_msgs; /* Number of NULL messages found in each loop */ - H5O_mesg_t *mesg_src; /* Message in source object header */ - H5O_mesg_t *mesg_dst; /* Message in source object header */ - const H5O_msg_class_t *copy_type; /* Type of message to use for copying */ - const H5O_obj_class_t *obj_class = NULL; /* Type of object we are copying */ - void *udata = NULL; /* User data for passing to message - callbacks */ - size_t dst_oh_size; /* Total size of the destination OH */ - uint8_t *current_pos; /* Current position in destination image */ - size_t msghdr_size; - herr_t ret_value = SUCCEED; - - FUNC_ENTER_NOAPI_NOINIT(H5O_copy_header_real) - - HDassert(oloc_src); - HDassert(oloc_src->file); - HDassert(H5F_addr_defined(oloc_src->addr)); - HDassert(oloc_dst->file); - HDassert(cpy_info); - - /* Get source object header */ - if(NULL == (oh_src = H5AC_protect(oloc_src->file, dxpl_id, H5AC_OHDR, oloc_src->addr, NULL, NULL, H5AC_READ))) - HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header") - - /* Get pointer to object class for this object */ - if(NULL == (obj_class = H5O_obj_class_real(oh_src))) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object type") - - /* Retrieve user data for particular type of object to copy */ - if(obj_class->get_copy_file_udata && - (NULL == (udata = (obj_class->get_copy_file_udata)()))) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to retrieve copy user data") - - /* Flush any dirty messages in source object header to update the header chunks */ - if(H5O_flush_msgs(oloc_src->file, oh_src) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object header messages") - - /* Allocate the destination object header and fill in header fields */ - if(NULL == (oh_dst = H5FL_MALLOC(H5O_t))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") - - /* Initialize header information */ - oh_dst->version = oh_src->version; - oh_dst->nlink = 0; - - /* Initialize size of chunk array. The destination always has only one - * chunk. - */ - oh_dst->alloc_nchunks = oh_dst->nchunks = 1; - - /* Allocate memory for the chunk array */ - if(NULL == (oh_dst->chunk = H5FL_SEQ_MALLOC(H5O_chunk_t, oh_dst->alloc_nchunks))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") - - /* Allocate memory for "deleted" array. This array marks the message in - * the source that shouldn't be copied to the destination. - */ - if(NULL == (deleted = HDmalloc(sizeof(hbool_t) * oh_src->nmesgs))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") - HDmemset(deleted, FALSE, sizeof(hbool_t) * oh_src->nmesgs); - - /* "pre copy" pass over messages, to gather information for actual message copy operation - * (for messages which depend on information from other messages) - * Keep track of how many NULL or deleted messages we find (or create) - */ - null_msgs = 0; - for(mesgno = 0; mesgno < oh_src->nmesgs; mesgno++) { - /* Set up convenience variables */ - mesg_src = &(oh_src->mesg[mesgno]); - mesg_dst = &(oh_dst->mesg[mesgno]); - - /* Sanity check */ - HDassert(!mesg_src->dirty); /* Should be cleared by earlier call to flush messages */ - - /* Check for shared message to operate on */ - if(mesg_src->flags & H5O_FLAG_SHARED) - copy_type = H5O_MSG_SHARED; - else - copy_type = mesg_src->type; - - /* Check for continuation message; these are converted to NULL - * messages because the destination OH will have only one chunk - */ - if(H5O_CONT_ID == mesg_src->type->id || H5O_NULL_ID == mesg_src->type->id) { - deleted[mesgno] = TRUE; - ++null_msgs; - copy_type = H5O_MSG_NULL; - } - HDassert(copy_type); - - if(copy_type->pre_copy_file ) { - /* - * Decode the message if necessary. If the message is shared then do - * a shared message, ignoring the message type. - */ - if(NULL == mesg_src->native) { - /* Decode the message if necessary */ - HDassert(copy_type->decode); - if(NULL == (mesg_src->native = (copy_type->decode)(oloc_src->file, dxpl_id, mesg_src->raw))) - HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "unable to decode a message") - } /* end if (NULL == mesg_src->native) */ - - /* Perform "pre copy" operation on message */ - if((copy_type->pre_copy_file)(oloc_src->file, mesg_src->type, mesg_src->native, &(deleted[mesgno]), cpy_info, udata) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to perform 'pre copy' operation on message") - - /* Check if the message should be deleted in the destination */ - if(deleted[mesgno]) { - /* Mark message as deleted */ - ++null_msgs; - } /* end if(deleted) */ - } /* end if(copy_type->pre_copy_file) */ - } /* end for */ - - /* Initialize size of message list. It may or may not include the NULL messages - * detected above. - */ - if(cpy_info->preserve_null) - oh_dst->alloc_nmesgs = oh_dst->nmesgs = oh_src->nmesgs; - else - oh_dst->alloc_nmesgs = oh_dst->nmesgs = (oh_src->nmesgs - null_msgs); - - /* Allocate memory for destination message array */ - if(oh_dst->alloc_nmesgs > 0) { - if(NULL == (oh_dst->mesg = H5FL_SEQ_CALLOC(H5O_mesg_t, oh_dst->alloc_nmesgs))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") - } - - /* "copy" pass over messages, to perform main message copying */ - null_msgs = 0; - for(mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) { - /* Skip any deleted or NULL messages in the source unless the - * preserve_null flag is set - */ - if(FALSE == cpy_info->preserve_null) { - while(deleted[mesgno + null_msgs]) { - ++null_msgs; - HDassert(mesgno + null_msgs < oh_src->nmesgs); - } - } - - /* Set up convenience variables */ - mesg_src = &(oh_src->mesg[mesgno + null_msgs]); - mesg_dst = &(oh_dst->mesg[mesgno]); - - /* Initialize on destination message */ - mesg_dst->chunkno = 0; - mesg_dst->dirty = FALSE; - mesg_dst->flags = mesg_src->flags; - mesg_dst->native = NULL; - mesg_dst->raw = NULL; - mesg_dst->raw_size = mesg_src->raw_size; - mesg_dst->type = mesg_src->type; - - /* If we're preserving deleted messages, set their types to 'NULL' - * in the destination. - */ - if(cpy_info->preserve_null && deleted[mesgno]) { - mesg_dst->type = H5O_MSG_NULL; - } - - /* Check for shared message to operate on */ - /* (Use destination message, in case the message has been removed (i.e - * converted to a nil message) in the destination -QAK) - */ - if(mesg_dst->flags & H5O_FLAG_SHARED) - copy_type = H5O_MSG_SHARED; - else - copy_type = mesg_dst->type; - HDassert(copy_type); - - /* copy this message into destination file */ - if(copy_type->copy_file) { - /* - * Decode the message if necessary. If the message is shared then do - * a shared message, ignoring the message type. - */ - if(NULL == mesg_src->native) { - /* Decode the message if necessary */ - HDassert(copy_type->decode); - if(NULL == (mesg_src->native = (copy_type->decode)(oloc_src->file, dxpl_id, mesg_src->raw))) - HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "unable to decode a message") - } /* end if (NULL == mesg_src->native) */ - - /* Copy the source message */ - if((mesg_dst->native = H5O_copy_mesg_file(copy_type, mesg_dst->type, - oloc_src->file, mesg_src->native, oloc_dst->file, dxpl_id, - cpy_info, udata)) == NULL) - HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object header message") - - /* Mark the message in the destination as dirty, so it'll get encoded when the object header is flushed */ - mesg_dst->dirty = TRUE; - } /* end if (mesg_src->type->copy_file) */ - } /* end of mesgno loop */ - - - /* Allocate the destination header and copy any messages that didn't have - * copy callbacks. They get copied directly from the source image to the - * destination image. - */ - - /* Calculate how big the destination object header will be on disk. - * This isn't necessarily the same size as the original. - */ - dst_oh_size = H5O_SIZEOF_HDR_OH(oh_dst); - - /* Add space for messages. */ - for(mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) { - dst_oh_size += H5O_SIZEOF_MSGHDR_OH(oh_dst); - dst_oh_size += H5O_ALIGN_OH(oh_dst, oh_dst->mesg[mesgno].raw_size); - } - - /* Allocate space for chunk in destination file */ - if(HADDR_UNDEF == (oh_dst->chunk[0].addr = H5MF_alloc(oloc_dst->file, H5FD_MEM_OHDR, dxpl_id, (hsize_t)dst_oh_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for object header") - addr_new = oh_dst->chunk[0].addr; - - /* Create memory image for the new chunk */ - if(NULL == (oh_dst->chunk[0].image = H5FL_BLK_MALLOC(chunk_image, dst_oh_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") - - /* Set dest. chunk information */ - oh_dst->chunk[0].dirty = TRUE; - oh_dst->chunk[0].size = dst_oh_size; - oh_dst->chunk[0].gap = 0; - - /* Set up raw pointers and copy messages that didn't need special - * treatment. This has to happen after the destination header has been - * allocated. - */ - HDassert(H5O_SIZEOF_HDR_OH(oh_src) == H5O_SIZEOF_HDR_OH(oh_dst)); - HDassert(H5O_SIZEOF_MSGHDR_OH(oh_src) == H5O_SIZEOF_MSGHDR_OH(oh_dst)); - msghdr_size = H5O_SIZEOF_MSGHDR_OH(oh_src); - - current_pos = oh_dst->chunk[0].image; - - /* Copy the message header. Most of this will be overwritten when - * the header is flushed to disk, but later versions have a - * magic number that isn't. - */ - HDmemcpy(current_pos, oh_src->chunk[0].image, - H5O_SIZEOF_HDR_OH(oh_dst) - H5O_SIZEOF_CHKSUM_OH(oh_dst)); - current_pos += H5O_SIZEOF_HDR_OH(oh_dst) - H5O_SIZEOF_CHKSUM_OH(oh_dst); - - /* JAMES: include this in loop above? Doesn't take deleted messages - * into account - */ - /* Copy each message that wasn't dirtied above */ - null_msgs = 0; - for(mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) { - /* Skip any deleted or NULL messages in the source unless the - * preserve_null flag is set - */ - if(FALSE == cpy_info->preserve_null) { - while(deleted[mesgno + null_msgs]) { - ++null_msgs; - HDassert(mesgno + null_msgs < oh_src->nmesgs); - } - } - - /* Set up convenience variables */ - mesg_src = &(oh_src->mesg[mesgno + null_msgs]); - mesg_dst = &(oh_dst->mesg[mesgno]); - - if(! mesg_dst->dirty) { - /* Copy the message header plus the message's raw data. */ - HDmemcpy(current_pos, mesg_src->raw - msghdr_size, - msghdr_size + mesg_src->raw_size); - } - mesg_dst->raw = current_pos + msghdr_size; - current_pos += mesg_dst->raw_size + msghdr_size; - } - - /* Make sure we filled the chunk, except for room at the end for a checksum */ - HDassert(current_pos + H5O_SIZEOF_CHKSUM_OH(oh_dst) == dst_oh_size + oh_dst->chunk[0].image); - - /* Set the dest. object location to the first chunk address */ - HDassert(H5F_addr_defined(addr_new)); - oloc_dst->addr = addr_new; - - /* Allocate space for the address mapping of the object copied */ - if(NULL == (addr_map = H5FL_MALLOC(H5O_addr_map_t))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") - - /* Insert the address mapping for the new object into the copied list */ - /* (Do this here, because "post copy" possibly checks it) */ - addr_map->src_addr = oloc_src->addr; - addr_map->dst_addr = oloc_dst->addr; - addr_map->is_locked = TRUE; /* We've locked the object currently */ - addr_map->inc_ref_count = 0; /* Start with no additional ref counts to add */ - - if(H5SL_insert(cpy_info->map_list, addr_map, &(addr_map->src_addr)) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object into skip list") - - /* "post copy" loop over messages, to fix up any messages which require a complete - * object header for destination object - */ - null_msgs = 0; - for(mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) { - /* Skip any deleted or NULL messages in the source unless the - * preserve_null flag is set - */ - if(FALSE == cpy_info->preserve_null) { - while(deleted[mesgno + null_msgs]) { - ++null_msgs; - HDassert(mesgno + null_msgs < oh_src->nmesgs); - } - } - - /* Set up convenience variables */ - mesg_src = &(oh_src->mesg[mesgno + null_msgs]); - mesg_dst = &(oh_dst->mesg[mesgno]); - - /* Check for shared message to operate on */ - /* (Use destination message, in case the message has been removed (i.e - * converted to a nil message) in the destination -QAK) - */ - if(mesg_dst->flags & H5O_FLAG_SHARED) - copy_type = H5O_MSG_SHARED; - else - copy_type = mesg_dst->type; - HDassert(copy_type); - - if(copy_type->post_copy_file && mesg_src->native) { - /* Sanity check destination message */ - HDassert(mesg_dst->type == mesg_src->type); - HDassert(mesg_dst->native); - - /* Perform "post copy" operation on message */ - if((copy_type->post_copy_file)(oloc_src, mesg_src->native, oloc_dst, - mesg_dst->native, dxpl_id, cpy_info) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to perform 'post copy' operation on message") - } /* end if */ - } /* end for */ - - /* Indicate that the destination address will no longer be locked */ - addr_map->is_locked = FALSE; - - /* Increment object header's reference count, if any descendents have created links to link to this object */ - if(addr_map->inc_ref_count) { - H5_CHECK_OVERFLOW(addr_map->inc_ref_count, hsize_t, int); - oh_dst->nlink += (int)addr_map->inc_ref_count; - } /* end if */ - - /* Insert destination object header in cache */ - if(H5AC_set(oloc_dst->file, dxpl_id, H5AC_OHDR, oloc_dst->addr, oh_dst, H5AC__DIRTIED_FLAG) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to cache object header") - -done: - /* Free deleted array */ - if(deleted) { - HDfree(deleted); - } - - /* Release pointer to source object header and its derived objects */ - if(oh_src != NULL) { - /* Unprotect the source object header */ - if(H5AC_unprotect(oloc_src->file, dxpl_id, H5AC_OHDR, oloc_src->addr, oh_src, H5AC__NO_FLAGS_SET) < 0) - HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header") - } /* end if */ - - /* Release pointer to destination object header */ - if(ret_value < 0 && oh_dst) { - if(H5O_dest(oloc_dst->file, oh_dst) < 0) - HDONE_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header data") - } /* end if */ - - /* Release user data for particular type of object to copy */ - if(udata) { - HDassert(obj_class); - HDassert(obj_class->free_copy_file_udata); - (obj_class->free_copy_file_udata)(udata); - } /* end if */ - - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5O_copy_header_real() */ - - -/*------------------------------------------------------------------------- - * 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_addr_map_t *addr_map; /* Address mapping of object copied */ - 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_dst); - HDassert(oloc_dst->file); - HDassert(cpy_info); - - /* Look up the address of the object to copy in the skip list */ - addr_map = (H5O_addr_map_t *)H5SL_search(cpy_info->map_list, &(oloc_src->addr)); - - /* 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) < 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; - - /* 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) -{ - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_copy_free_addrmap_cb) - - HDassert(item); - - /* Release the 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 - * - *------------------------------------------------------------------------- - */ -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(H5O_copy_header, FAIL) - - 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_HADDR, 0.5, (size_t)16)) == 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) < 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_mesg_hash * * Purpose: Returns a hash value for an object header message. @@ -5688,7 +5096,7 @@ H5O_mesg_hash(unsigned type_id, H5F_t *f, const void *mesg) uint32_t hash; uint32_t ret_value; - FUNC_ENTER_NOAPI(H5O_mesg_hash, FAIL) + FUNC_ENTER_NOAPI(H5O_mesg_hash, H5O_HASH_UNDEF) /* Check args */ HDassert(type_id < NELMTS(H5O_msg_class_g)); @@ -5697,17 +5105,17 @@ H5O_mesg_hash(unsigned type_id, H5F_t *f, const void *mesg) /* Find out the size of buffer needed */ if((buf_size = H5O_raw_size(type_id, f, mesg)) <= 0) - HGOTO_ERROR(H5E_OHDR, H5E_BADSIZE, FAIL, "can't find message size"); + HGOTO_ERROR(H5E_OHDR, H5E_BADSIZE, H5O_HASH_UNDEF, "can't find message size"); /* JAMES: revisit this! Some messages don't use as much space as they say * they need. Quincey may have fixed this. */ if((buf = HDmalloc(buf_size)) == NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate buffer for message"); + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, H5O_HASH_UNDEF, "can't allocate buffer for message"); HDmemset(buf, 0, buf_size); if(H5O_encode(f, buf, mesg, type_id) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "can't encode OH message"); + HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, H5O_HASH_UNDEF, "can't encode OH message"); /* * Compute the hash value for this message. type_id is used here to @@ -5724,70 +5132,13 @@ H5O_mesg_hash(unsigned type_id, H5F_t *f, const void *mesg) hash = (uint32_t) 1; ret_value = hash; + done: if(buf) HDfree(buf); FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_mesg_hash() */ - -/*------------------------------------------------------------------------- - * 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)) < 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 */ - 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() */ - - - #ifdef H5O_DEBUG /*------------------------------------------------------------------------- diff --git a/src/H5Ocopy.c b/src/H5Ocopy.c index a26dde2..a312b5a 100644 --- a/src/H5Ocopy.c +++ b/src/H5Ocopy.c @@ -35,9 +35,10 @@ #include "H5private.h" /* Generic Functions */ #include "H5Eprivate.h" /* Error handling */ #include "H5FLprivate.h" /* Free lists */ -#include "H5HGprivate.h" /* Global Heaps */ #include "H5Iprivate.h" /* IDs */ +#include "H5HGprivate.h" /* Global Heaps */ #include "H5Lprivate.h" /* Links */ +#include "H5MFprivate.h" /* File memory management */ #include "H5MMprivate.h" /* Memory management */ #include "H5Opkg.h" /* Object headers */ #include "H5Pprivate.h" /* Property lists */ @@ -61,6 +62,11 @@ /* Local Prototypes */ /********************/ +static herr_t H5O_copy_free_addrmap_cb(void *item, void *key, void *op_data); +static herr_t H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */, + hid_t dxpl_id, H5O_copy_t *cpy_info); +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); 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); static herr_t H5O_copy_obj_by_ref(H5O_loc_t *src_oloc, hid_t dxpl_id, @@ -258,6 +264,590 @@ done: /*------------------------------------------------------------------------- + * Function: H5O_copy_header_real + * + * Purpose: Copy header object from one location to another using + * pre-copy, copy, and post-copy callbacks for each message + * type. + * + * The source header object is compressed into a single chunk + * (since we know how big it is) and any continuation messages + * are converted into NULL messages. + * + * By default, NULL messages are not copied. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Peter Cao + * May 30, 2005 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */, + hid_t dxpl_id, H5O_copy_t *cpy_info) +{ + H5O_addr_map_t *addr_map = NULL; /* Address mapping of object copied */ + H5O_t *oh_src = NULL; /* Object header for source object */ + H5O_t *oh_dst = NULL; /* Object header for destination object */ + unsigned mesgno = 0; + haddr_t addr_new = HADDR_UNDEF; + hbool_t *deleted = NULL; /* Array of flags indicating whether messages should be copied */ + size_t null_msgs; /* Number of NULL messages found in each loop */ + H5O_mesg_t *mesg_src; /* Message in source object header */ + H5O_mesg_t *mesg_dst; /* Message in source object header */ + const H5O_msg_class_t *copy_type; /* Type of message to use for copying */ + const H5O_obj_class_t *obj_class = NULL; /* Type of object we are copying */ + void *udata = NULL; /* User data for passing to message callbacks */ + size_t dst_oh_size; /* Total size of the destination OH */ + uint8_t *current_pos; /* Current position in destination image */ + size_t msghdr_size; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT(H5O_copy_header_real) + + HDassert(oloc_src); + HDassert(oloc_src->file); + HDassert(H5F_addr_defined(oloc_src->addr)); + HDassert(oloc_dst->file); + HDassert(cpy_info); + + /* Get source object header */ + if(NULL == (oh_src = H5AC_protect(oloc_src->file, dxpl_id, H5AC_OHDR, oloc_src->addr, NULL, NULL, H5AC_READ))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header") + + /* Get pointer to object class for this object */ + if(NULL == (obj_class = H5O_obj_class_real(oh_src))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object type") + + /* Retrieve user data for particular type of object to copy */ + if(obj_class->get_copy_file_udata && + (NULL == (udata = (obj_class->get_copy_file_udata)()))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to retrieve copy user data") + + /* Flush any dirty messages in source object header to update the header chunks */ + if(H5O_flush_msgs(oloc_src->file, oh_src) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object header messages") + + /* Allocate the destination object header and fill in header fields */ + if(NULL == (oh_dst = H5FL_MALLOC(H5O_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + + /* Initialize header information */ + oh_dst->version = oh_src->version; + oh_dst->nlink = 0; + + /* Initialize size of chunk array. The destination always has only one + * chunk. + */ + oh_dst->alloc_nchunks = oh_dst->nchunks = 1; + + /* Allocate memory for the chunk array */ + if(NULL == (oh_dst->chunk = H5FL_SEQ_MALLOC(H5O_chunk_t, oh_dst->alloc_nchunks))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + + /* Allocate memory for "deleted" array. This array marks the message in + * the source that shouldn't be copied to the destination. + */ + if(NULL == (deleted = HDmalloc(sizeof(hbool_t) * oh_src->nmesgs))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + HDmemset(deleted, FALSE, sizeof(hbool_t) * oh_src->nmesgs); + + /* "pre copy" pass over messages, to gather information for actual message copy operation + * (for messages which depend on information from other messages) + * Keep track of how many NULL or deleted messages we find (or create) + */ + null_msgs = 0; + for(mesgno = 0; mesgno < oh_src->nmesgs; mesgno++) { + /* Set up convenience variables */ + mesg_src = &(oh_src->mesg[mesgno]); + mesg_dst = &(oh_dst->mesg[mesgno]); + + /* Sanity check */ + HDassert(!mesg_src->dirty); /* Should be cleared by earlier call to flush messages */ + + /* Check for shared message to operate on */ + if(mesg_src->flags & H5O_FLAG_SHARED) + copy_type = H5O_MSG_SHARED; + else + copy_type = mesg_src->type; + + /* Check for continuation message; these are converted to NULL + * messages because the destination OH will have only one chunk + */ + if(H5O_CONT_ID == mesg_src->type->id || H5O_NULL_ID == mesg_src->type->id) { + deleted[mesgno] = TRUE; + ++null_msgs; + copy_type = H5O_MSG_NULL; + } + HDassert(copy_type); + + if(copy_type->pre_copy_file ) { + /* + * Decode the message if necessary. If the message is shared then do + * a shared message, ignoring the message type. + */ + if(NULL == mesg_src->native) { + /* Decode the message if necessary */ + HDassert(copy_type->decode); + if(NULL == (mesg_src->native = (copy_type->decode)(oloc_src->file, dxpl_id, mesg_src->raw))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "unable to decode a message") + } /* end if (NULL == mesg_src->native) */ + + /* Perform "pre copy" operation on message */ + if((copy_type->pre_copy_file)(oloc_src->file, mesg_src->type, mesg_src->native, &(deleted[mesgno]), cpy_info, udata) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to perform 'pre copy' operation on message") + + /* Check if the message should be deleted in the destination */ + if(deleted[mesgno]) { + /* Mark message as deleted */ + ++null_msgs; + } /* end if(deleted) */ + } /* end if(copy_type->pre_copy_file) */ + } /* end for */ + + /* Initialize size of message list. It may or may not include the NULL messages + * detected above. + */ + if(cpy_info->preserve_null) + oh_dst->alloc_nmesgs = oh_dst->nmesgs = oh_src->nmesgs; + else + oh_dst->alloc_nmesgs = oh_dst->nmesgs = (oh_src->nmesgs - null_msgs); + + /* Allocate memory for destination message array */ + if(oh_dst->alloc_nmesgs > 0) { + if(NULL == (oh_dst->mesg = H5FL_SEQ_CALLOC(H5O_mesg_t, oh_dst->alloc_nmesgs))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + } + + /* "copy" pass over messages, to perform main message copying */ + null_msgs = 0; + for(mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) { + /* Skip any deleted or NULL messages in the source unless the + * preserve_null flag is set + */ + if(FALSE == cpy_info->preserve_null) { + while(deleted[mesgno + null_msgs]) { + ++null_msgs; + HDassert(mesgno + null_msgs < oh_src->nmesgs); + } + } + + /* Set up convenience variables */ + mesg_src = &(oh_src->mesg[mesgno + null_msgs]); + mesg_dst = &(oh_dst->mesg[mesgno]); + + /* Initialize on destination message */ + mesg_dst->chunkno = 0; + mesg_dst->dirty = FALSE; + mesg_dst->flags = mesg_src->flags; + mesg_dst->native = NULL; + mesg_dst->raw = NULL; + mesg_dst->raw_size = mesg_src->raw_size; + mesg_dst->type = mesg_src->type; + + /* If we're preserving deleted messages, set their types to 'NULL' + * in the destination. + */ + if(cpy_info->preserve_null && deleted[mesgno]) { + mesg_dst->type = H5O_MSG_NULL; + } + + /* Check for shared message to operate on */ + /* (Use destination message, in case the message has been removed (i.e + * converted to a nil message) in the destination -QAK) + */ + if(mesg_dst->flags & H5O_FLAG_SHARED) + copy_type = H5O_MSG_SHARED; + else + copy_type = mesg_dst->type; + HDassert(copy_type); + + /* copy this message into destination file */ + if(copy_type->copy_file) { + /* + * Decode the message if necessary. If the message is shared then do + * a shared message, ignoring the message type. + */ + if(NULL == mesg_src->native) { + /* Decode the message if necessary */ + HDassert(copy_type->decode); + if(NULL == (mesg_src->native = (copy_type->decode)(oloc_src->file, dxpl_id, mesg_src->raw))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "unable to decode a message") + } /* end if (NULL == mesg_src->native) */ + + /* Copy the source message */ + if((mesg_dst->native = H5O_copy_mesg_file(copy_type, mesg_dst->type, + oloc_src->file, mesg_src->native, oloc_dst->file, dxpl_id, + cpy_info, udata)) == NULL) + HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object header message") + + /* Mark the message in the destination as dirty, so it'll get encoded when the object header is flushed */ + mesg_dst->dirty = TRUE; + } /* end if (mesg_src->type->copy_file) */ + } /* end of mesgno loop */ + + + /* Allocate the destination header and copy any messages that didn't have + * copy callbacks. They get copied directly from the source image to the + * destination image. + */ + + /* Calculate how big the destination object header will be on disk. + * This isn't necessarily the same size as the original. + */ + dst_oh_size = H5O_SIZEOF_HDR_OH(oh_dst); + + /* Add space for messages. */ + for(mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) { + dst_oh_size += H5O_SIZEOF_MSGHDR_OH(oh_dst); + dst_oh_size += H5O_ALIGN_OH(oh_dst, oh_dst->mesg[mesgno].raw_size); + } + + /* Allocate space for chunk in destination file */ + if(HADDR_UNDEF == (oh_dst->chunk[0].addr = H5MF_alloc(oloc_dst->file, H5FD_MEM_OHDR, dxpl_id, (hsize_t)dst_oh_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for object header") + addr_new = oh_dst->chunk[0].addr; + + /* Create memory image for the new chunk */ + if(NULL == (oh_dst->chunk[0].image = H5FL_BLK_MALLOC(chunk_image, dst_oh_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + + /* Set dest. chunk information */ + oh_dst->chunk[0].dirty = TRUE; + oh_dst->chunk[0].size = dst_oh_size; + oh_dst->chunk[0].gap = 0; + + /* Set up raw pointers and copy messages that didn't need special + * treatment. This has to happen after the destination header has been + * allocated. + */ + HDassert(H5O_SIZEOF_HDR_OH(oh_src) == H5O_SIZEOF_HDR_OH(oh_dst)); + HDassert(H5O_SIZEOF_MSGHDR_OH(oh_src) == H5O_SIZEOF_MSGHDR_OH(oh_dst)); + msghdr_size = H5O_SIZEOF_MSGHDR_OH(oh_src); + + current_pos = oh_dst->chunk[0].image; + + /* Copy the message header. Most of this will be overwritten when + * the header is flushed to disk, but later versions have a + * magic number that isn't. + */ + HDmemcpy(current_pos, oh_src->chunk[0].image, + (size_t)(H5O_SIZEOF_HDR_OH(oh_dst) - H5O_SIZEOF_CHKSUM_OH(oh_dst))); + current_pos += H5O_SIZEOF_HDR_OH(oh_dst) - H5O_SIZEOF_CHKSUM_OH(oh_dst); + + /* JAMES: include this in loop above? Doesn't take deleted messages + * into account + */ + /* Copy each message that wasn't dirtied above */ + null_msgs = 0; + for(mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) { + /* Skip any deleted or NULL messages in the source unless the + * preserve_null flag is set + */ + if(FALSE == cpy_info->preserve_null) { + while(deleted[mesgno + null_msgs]) { + ++null_msgs; + HDassert(mesgno + null_msgs < oh_src->nmesgs); + } + } + + /* Set up convenience variables */ + mesg_src = &(oh_src->mesg[mesgno + null_msgs]); + mesg_dst = &(oh_dst->mesg[mesgno]); + + if(! mesg_dst->dirty) { + /* Copy the message header plus the message's raw data. */ + HDmemcpy(current_pos, mesg_src->raw - msghdr_size, + msghdr_size + mesg_src->raw_size); + } + mesg_dst->raw = current_pos + msghdr_size; + current_pos += mesg_dst->raw_size + msghdr_size; + } + + /* Make sure we filled the chunk, except for room at the end for a checksum */ + HDassert(current_pos + H5O_SIZEOF_CHKSUM_OH(oh_dst) == dst_oh_size + oh_dst->chunk[0].image); + + /* Set the dest. object location to the first chunk address */ + HDassert(H5F_addr_defined(addr_new)); + oloc_dst->addr = addr_new; + + /* Allocate space for the address mapping of the object copied */ + if(NULL == (addr_map = H5FL_MALLOC(H5O_addr_map_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + + /* Insert the address mapping for the new object into the copied list */ + /* (Do this here, because "post copy" possibly checks it) */ + addr_map->src_addr = oloc_src->addr; + addr_map->dst_addr = oloc_dst->addr; + addr_map->is_locked = TRUE; /* We've locked the object currently */ + addr_map->inc_ref_count = 0; /* Start with no additional ref counts to add */ + + if(H5SL_insert(cpy_info->map_list, addr_map, &(addr_map->src_addr)) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object into skip list") + + /* "post copy" loop over messages, to fix up any messages which require a complete + * object header for destination object + */ + null_msgs = 0; + for(mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) { + /* Skip any deleted or NULL messages in the source unless the + * preserve_null flag is set + */ + if(FALSE == cpy_info->preserve_null) { + while(deleted[mesgno + null_msgs]) { + ++null_msgs; + HDassert(mesgno + null_msgs < oh_src->nmesgs); + } + } + + /* Set up convenience variables */ + mesg_src = &(oh_src->mesg[mesgno + null_msgs]); + mesg_dst = &(oh_dst->mesg[mesgno]); + + /* Check for shared message to operate on */ + /* (Use destination message, in case the message has been removed (i.e + * converted to a nil message) in the destination -QAK) + */ + if(mesg_dst->flags & H5O_FLAG_SHARED) + copy_type = H5O_MSG_SHARED; + else + copy_type = mesg_dst->type; + HDassert(copy_type); + + if(copy_type->post_copy_file && mesg_src->native) { + /* Sanity check destination message */ + HDassert(mesg_dst->type == mesg_src->type); + HDassert(mesg_dst->native); + + /* Perform "post copy" operation on message */ + if((copy_type->post_copy_file)(oloc_src, mesg_src->native, oloc_dst, + mesg_dst->native, dxpl_id, cpy_info) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to perform 'post copy' operation on message") + } /* end if */ + } /* end for */ + + /* Indicate that the destination address will no longer be locked */ + addr_map->is_locked = FALSE; + + /* Increment object header's reference count, if any descendents have created links to link to this object */ + if(addr_map->inc_ref_count) { + H5_CHECK_OVERFLOW(addr_map->inc_ref_count, hsize_t, int); + oh_dst->nlink += (int)addr_map->inc_ref_count; + } /* end if */ + + /* Insert destination object header in cache */ + if(H5AC_set(oloc_dst->file, dxpl_id, H5AC_OHDR, oloc_dst->addr, oh_dst, H5AC__DIRTIED_FLAG) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to cache object header") + +done: + /* Free deleted array */ + if(deleted) { + HDfree(deleted); + } + + /* Release pointer to source object header and its derived objects */ + if(oh_src != NULL) { + /* Unprotect the source object header */ + if(H5AC_unprotect(oloc_src->file, dxpl_id, H5AC_OHDR, oloc_src->addr, oh_src, H5AC__NO_FLAGS_SET) < 0) + HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header") + } /* end if */ + + /* Release pointer to destination object header */ + if(ret_value < 0 && oh_dst) { + if(H5O_dest(oloc_dst->file, oh_dst) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header data") + } /* end if */ + + /* Release user data for particular type of object to copy */ + if(udata) { + HDassert(obj_class); + HDassert(obj_class->free_copy_file_udata); + (obj_class->free_copy_file_udata)(udata); + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_copy_header_real() */ + + +/*------------------------------------------------------------------------- + * 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_addr_map_t *addr_map; /* Address mapping of object copied */ + 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_dst); + HDassert(oloc_dst->file); + HDassert(cpy_info); + + /* Look up the address of the object to copy in the skip list */ + addr_map = (H5O_addr_map_t *)H5SL_search(cpy_info->map_list, &(oloc_src->addr)); + + /* 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) < 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; + + /* 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) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_copy_free_addrmap_cb) + + HDassert(item); + + /* Release the 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_HADDR, 0.5, (size_t)16)) == 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) < 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 diff --git a/src/H5Opkg.h b/src/H5Opkg.h index a0812c9..1f50eeb 100644 --- a/src/H5Opkg.h +++ b/src/H5Opkg.h @@ -343,13 +343,14 @@ H5_DLL void * H5O_read_real(const H5O_loc_t *loc, const H5O_msg_class_t *type, int sequence, void *mesg, hid_t dxpl_id); H5_DLL herr_t H5O_free_mesg(H5O_mesg_t *mesg); H5_DLL void * H5O_free_real(const H5O_msg_class_t *type, void *mesg); +H5_DLL void * H5O_copy_mesg_file(const H5O_msg_class_t *copy_type, + const H5O_msg_class_t *mesg_type, H5F_t *file_src, void *mesg_src, + H5F_t *file_dst, hid_t dxpl_id, H5O_copy_t *cpy_info, void *udata); +H5_DLL const H5O_obj_class_t *H5O_obj_class_real(H5O_t *oh); #ifdef H5O_DEBUG H5_DLL herr_t H5O_assert(const H5O_t *oh); #endif /* H5O_DEBUG */ H5_DLL herr_t H5O_debug_real(H5F_t *f, hid_t dxpl_id, H5O_t *oh, haddr_t addr, FILE *stream, int indent, int fwidth); -H5_DLL void * H5O_copy_mesg_file(const H5O_msg_class_t *copy_type, - const H5O_msg_class_t *mesg_type, H5F_t *file_src, void *mesg_src, - H5F_t *file_dst, hid_t dxpl_id, H5O_copy_t *cpy_info, void *udata); /* Shared object operators */ H5_DLL void * H5O_shared_read(H5F_t *f, hid_t dxpl_id, H5O_shared_t *shared, diff --git a/src/H5Oprivate.h b/src/H5Oprivate.h index 30ea804..97cb16c 100644 --- a/src/H5Oprivate.h +++ b/src/H5Oprivate.h @@ -32,9 +32,8 @@ /* Public headers needed by this file */ #include "H5Dpublic.h" /* Dataset functions */ -#include "H5Lpublic.h" /* Link functions */ +#include "H5Lpublic.h" /* Link functions */ #include "H5Spublic.h" /* Dataspace functions */ -#include "H5Lpublic.h" /* Link functions */ /* Private headers needed by this file */ #include "H5Fprivate.h" /* File access */ @@ -82,7 +81,7 @@ typedef uint64_t H5SM_fheap_id_t; /* Hash value constants */ /* JAMES: undefined hash value may not be great */ #define H5O_HASH_SIZE 32 -#define H5O_HASH_UNDEF FAIL +#define H5O_HASH_UNDEF ((uint32_t)FAIL) /* ========= Object Copy properties ============ */ #define H5O_CPY_OPTION_NAME "copy object" /* Copy options */ @@ -414,15 +413,13 @@ H5_DLL size_t H5O_mesg_size(unsigned type_id, const H5F_t *f, const void *mesg, H5_DLL herr_t H5O_get_share(unsigned type_id, H5F_t *f, const void *mesg, H5O_shared_t *share); H5_DLL herr_t H5O_delete(H5F_t *f, hid_t dxpl_id, haddr_t addr); H5_DLL htri_t H5O_is_shared(unsigned type_id, const void *mesg); -H5_DLL herr_t H5O_set_share(H5F_t *f, hid_t dxpl_id, H5O_shared_t *share, - unsigned type_id, void *mesg); +H5_DLL herr_t H5O_set_share(H5F_t *f, H5O_shared_t *share, unsigned type_id, + void *mesg); H5_DLL herr_t H5O_reset_share(H5F_t *f, unsigned type_id, void *mesg); H5_DLL herr_t H5O_get_info(H5O_loc_t *loc, H5O_stat_t *ostat, hid_t dxpl_id); H5_DLL herr_t H5O_iterate(const H5O_loc_t *loc, unsigned type_id, H5O_operator_t op, void *op_data, hid_t dxpl_id); H5_DLL H5G_obj_t H5O_obj_type(H5O_loc_t *loc, hid_t dxpl_id); -H5_DLL herr_t H5O_copy_header(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */, - hid_t dxpl_id, unsigned cpy_option); H5_DLL 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); H5_DLL herr_t H5O_debug_id(unsigned type_id, H5F_t *f, hid_t dxpl_id, const void *mesg, FILE *stream, int indent, int fwidth); diff --git a/src/H5SM.c b/src/H5SM.c index c17dd16..79d0c05 100755 --- a/src/H5SM.c +++ b/src/H5SM.c @@ -714,7 +714,7 @@ H5SM_write_mesg(H5F_t *f, hid_t dxpl_id, H5SM_index_header_t *header, } /* Change the original message passed in to reflect that it's now shared */ - if(H5O_set_share(f, dxpl_id, &shared, type_id, mesg) < 0) + if(H5O_set_share(f, &shared, type_id, mesg) < 0) HGOTO_ERROR (H5E_OHDR, H5E_BADMESG, FAIL, "unable to set sharing information") done: -- cgit v0.12