diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/H5O.c | 1774 | ||||
-rw-r--r-- | src/H5Oalloc.c | 1489 | ||||
-rw-r--r-- | src/H5Odbg.c | 417 | ||||
-rw-r--r-- | src/H5Opkg.h | 12 | ||||
-rw-r--r-- | src/H5Oprivate.h | 8 | ||||
-rw-r--r-- | src/H5Pfcpl.c | 2 | ||||
-rwxr-xr-x | src/Makefile.am | 6 | ||||
-rw-r--r-- | src/Makefile.in | 10 |
8 files changed, 1937 insertions, 1781 deletions
@@ -51,8 +51,6 @@ /* Local Macros */ /****************/ -#define H5O_MIN_SIZE 32 /*min obj header data size */ - /* Load native information for a message, if it's not already present */ /* (Only works for messages with decode callback) */ #define LOAD_NATIVE(F, DXPL, MSG, ERR) \ @@ -71,7 +69,6 @@ HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, ERR, "unable to decode message") \ } /* end if */ -/* Private typedefs */ /******************/ /* Local Typedefs */ @@ -138,28 +135,7 @@ static int H5O_append_real(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned * oh_flags_ptr); static herr_t H5O_remove_real(const H5O_loc_t *loc, const H5O_msg_class_t *type, int sequence, H5O_operator_t op, void *op_data, hbool_t adj_link, hid_t dxpl_id); -static herr_t H5O_eliminate_gap(H5O_t *oh, H5O_mesg_t *mesg, - uint8_t *new_gap_loc, size_t new_gap_size); -static herr_t H5O_add_gap(H5O_t *oh, unsigned chunkno, unsigned idx, - uint8_t *new_gap_loc, size_t new_gap_size); -static unsigned H5O_alloc(H5F_t *f, hid_t dxpl_id, H5O_t *oh, - const H5O_msg_class_t *type, size_t size, hbool_t * oh_dirtied_ptr); -static herr_t H5O_alloc_msgs(H5O_t *oh, size_t min_alloc); -static herr_t H5O_alloc_null(H5O_t *oh, unsigned null_idx, - const H5O_msg_class_t *new_type, void *new_native, size_t new_size); -static herr_t H5O_release_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *oh, - H5O_mesg_t *mesg, hbool_t delete_mesg, hbool_t adj_link); -static htri_t H5O_move_msgs_forward(H5O_t *oh); -static htri_t H5O_merge_null(H5O_t *oh); -static htri_t H5O_remove_empty_chunks(H5F_t *f, H5O_t *oh, hid_t dxpl_id); -static herr_t H5O_condense_header(H5F_t *f, H5O_t *oh, hid_t dxpl_id); -static htri_t H5O_alloc_extend_chunk(H5F_t *f, H5O_t *oh, - unsigned chunkno, size_t size, unsigned * msg_idx); -static unsigned H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, - size_t size); static herr_t H5O_delete_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh); -static herr_t H5O_delete_mesg(H5F_t *f, hid_t dxpl_id, H5O_mesg_t *mesg, - hbool_t adj_link); static unsigned H5O_new_mesg(H5F_t *f, H5O_t *oh, unsigned *flags, const H5O_msg_class_t *orig_type, const void *orig_mesg, H5O_shared_t *sh_mesg, const H5O_msg_class_t **new_type, const void **new_mesg, hid_t dxpl_id, @@ -239,11 +215,6 @@ H5FL_BLK_DEFINE(chunk_image); /* Declare external the free list for time_t's */ H5FL_EXTERN(time_t); -/* Declare extern the free list for H5O_cont_t's */ -H5FL_EXTERN(H5O_cont_t); - -/* Declare a free list to manage the H5O_addr_map_t struct */ -H5FL_EXTERN(H5O_addr_map_t); /*------------------------------------------------------------------------- @@ -2568,1402 +2539,6 @@ done: /*------------------------------------------------------------------------- - * - * Function: H5O_alloc_msgs - * - * Purpose: Allocate more messages for a header - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Nov 21 2005 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5O_alloc_msgs(H5O_t *oh, size_t min_alloc) -{ - size_t old_alloc; /* Old number of messages allocated */ - size_t na; /* New number of messages allocated */ - H5O_mesg_t *new_mesg; /* Pointer to new message array */ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5O_alloc_msgs) - - /* check args */ - HDassert(oh); - - /* Initialize number of messages information */ - old_alloc = oh->alloc_nmesgs; - na = oh->alloc_nmesgs + MAX(oh->alloc_nmesgs, min_alloc); - - /* Attempt to allocate more memory */ - if(NULL == (new_mesg = H5FL_SEQ_REALLOC(H5O_mesg_t, oh->mesg, na))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") - - /* Update ohdr information */ - oh->alloc_nmesgs = na; - oh->mesg = new_mesg; - - /* Set new object header info to zeros */ - HDmemset(&oh->mesg[old_alloc], 0, (oh->alloc_nmesgs - old_alloc) * sizeof(H5O_mesg_t)); - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5O_alloc_msgs() */ - - -/*------------------------------------------------------------------------- - * - * Function: H5O_alloc_null - * - * Purpose: Allocate room for a new message from a null message - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Oct 22 2006 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5O_alloc_null(H5O_t *oh, unsigned null_idx, const H5O_msg_class_t *new_type, - void *new_native, size_t new_size) -{ - H5O_mesg_t *alloc_msg; /* Pointer to null message to allocate out of */ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5O_alloc_null) - - /* check args */ - HDassert(oh); - HDassert(new_type); - HDassert(new_size); - - /* Point to null message to allocate out of */ - alloc_msg = &oh->mesg[null_idx]; - - /* Check if there's a need to split the null message */ - if(alloc_msg->raw_size > new_size) { - /* Check for producing a gap in the chunk */ - if((alloc_msg->raw_size - new_size) < (size_t)H5O_SIZEOF_MSGHDR_OH(oh)) { - size_t gap_size = alloc_msg->raw_size - new_size; /* Size of gap produced */ - - /* Adjust the size of the null message being eliminated */ - alloc_msg->raw_size = new_size; - - /* Add the gap to the chunk */ - if(H5O_add_gap(oh, alloc_msg->chunkno, null_idx, alloc_msg->raw + alloc_msg->raw_size, gap_size) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, UFAIL, "can't insert gap in chunk") - } /* end if */ - else { - size_t new_mesg_size = new_size + H5O_SIZEOF_MSGHDR_OH(oh); /* Total size of newly allocated message */ - H5O_mesg_t *null_msg; /* Pointer to new null message */ - - /* Check if we need to extend message table to hold the new null message */ - if(oh->nmesgs >= oh->alloc_nmesgs) { - if(H5O_alloc_msgs(oh, (size_t)1) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "can't allocate more space for messages") - - /* "Retarget" 'alloc_msg' pointer into newly re-allocated array of messages */ - alloc_msg = &oh->mesg[null_idx]; - } /* end if */ - - /* Create new null message, with the tail of the previous null message */ - null_msg = &(oh->mesg[oh->nmesgs++]); - null_msg->type = H5O_MSG_NULL; - null_msg->dirty = TRUE; - null_msg->native = NULL; - null_msg->raw = alloc_msg->raw + new_mesg_size; - null_msg->raw_size = alloc_msg->raw_size - new_mesg_size; - null_msg->chunkno = alloc_msg->chunkno; - - /* Check for gap in new null message's chunk */ - if(oh->chunk[null_msg->chunkno].gap > 0) { - unsigned null_chunkno = null_msg->chunkno; /* Chunk w/gap */ - - /* Eliminate the gap in the chunk */ - if(H5O_eliminate_gap(oh, null_msg, - ((oh->chunk[null_chunkno].image + oh->chunk[null_chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[null_chunkno].gap)), - oh->chunk[null_chunkno].gap) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTREMOVE, UFAIL, "can't eliminate gap in chunk") - - /* Set the gap size to zero for the chunk */ - oh->chunk[null_chunkno].gap = 0; - } /* end if */ - - /* Set the size of the new "real" message */ - alloc_msg->raw_size = new_size; - } /* end else */ - } /* end if */ - - /* Initialize the new message */ - alloc_msg->type = new_type; - alloc_msg->dirty = TRUE; - alloc_msg->native = new_native; - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5O_alloc_null() */ - - -/*------------------------------------------------------------------------- - * - * Function: H5O_release_mesg - * - * Purpose: Convert a message into a null message - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Oct 22 2006 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5O_release_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5O_mesg_t *mesg, - hbool_t delete_mesg, hbool_t adj_link) -{ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5O_release_mesg) - - /* check args */ - HDassert(f); - HDassert(oh); - HDassert(mesg); - - /* Check if we should operate on the message */ - if(delete_mesg) { - /* Free any space referred to in the file from this message */ - if(H5O_delete_mesg(f, dxpl_id, mesg, adj_link) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to delete file space for object header message") - - /* Free any native information */ - H5O_free_mesg(mesg); - } /* end if */ - - /* Change message type to nil and zero it */ - mesg->type = H5O_MSG_NULL; - HDassert(mesg->raw + mesg->raw_size <= (oh->chunk[mesg->chunkno].image + oh->chunk[mesg->chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[mesg->chunkno].gap)); - HDmemset(mesg->raw, 0, mesg->raw_size); - - /* Clear message flags */ - mesg->flags = 0; - - /* Indicate that the message was modified */ - mesg->dirty = TRUE; - - /* Check if chunk has a gap currently */ - if(oh->chunk[mesg->chunkno].gap) { - /* Eliminate the gap in the chunk */ - if(H5O_eliminate_gap(oh, mesg, - ((oh->chunk[mesg->chunkno].image + oh->chunk[mesg->chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[mesg->chunkno].gap)), - oh->chunk[mesg->chunkno].gap) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTREMOVE, FAIL, "can't eliminate gap in chunk") - - /* Set the gap size to zero for the chunk */ - oh->chunk[mesg->chunkno].gap = 0; - } /* end if */ - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5O_release_mesg() */ - - -/*------------------------------------------------------------------------- - * - * Function: H5O_move_msgs_forward - * - * Purpose: Move messages toward first chunk - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Oct 17 2005 - * - *------------------------------------------------------------------------- - */ -static htri_t -H5O_move_msgs_forward(H5O_t *oh) -{ - hbool_t packed_msg; /* Flag to indicate that messages were packed */ - hbool_t did_packing = FALSE; /* Whether any messages were packed */ - htri_t ret_value; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5O_move_msgs_forward) - - /* check args */ - HDassert(oh); - - /* Loop until no messages packed */ - /* (Double loop is not very efficient, but it would be some extra work to - * add a list of messages to each chunk -QAK) - */ - do { - H5O_mesg_t *curr_msg; /* Pointer to current message to operate on */ - unsigned u; /* Local index variable */ - - /* Reset packed messages flag */ - packed_msg = FALSE; - - /* Scan through messages for messages that can be moved earlier in chunks */ - for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) { - if(H5O_NULL_ID == curr_msg->type->id) { - H5O_chunk_t *chunk; /* Pointer to chunk that null message is in */ - - /* Check if null message is not last in chunk */ - chunk = &(oh->chunk[curr_msg->chunkno]); - if((curr_msg->raw + curr_msg->raw_size) - != ((chunk->image + chunk->size) - (H5O_SIZEOF_CHKSUM_OH(oh) + chunk->gap))) { - H5O_mesg_t *nonnull_msg; /* Pointer to current message to operate on */ - unsigned v; /* Local index variable */ - - /* Loop over messages again, looking for the message in the chunk after the null message */ - for(v = 0, nonnull_msg = &oh->mesg[0]; v < oh->nmesgs; v++, nonnull_msg++) { - /* Locate message that is immediately after the null message */ - if((curr_msg->chunkno == nonnull_msg->chunkno) && - ((curr_msg->raw + curr_msg->raw_size) == (nonnull_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh)))) { - /* Don't swap messages if the second message is also a null message */ - /* (We'll merge them together later, in another routine) */ - if(H5O_NULL_ID != nonnull_msg->type->id) { - /* Copy raw data for non-null message to new location */ - HDmemmove(curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), - nonnull_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), nonnull_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh)); - - /* Adjust non-null message's offset in chunk */ - nonnull_msg->raw = curr_msg->raw; - - /* Adjust null message's offset in chunk */ - curr_msg->raw = nonnull_msg->raw + - nonnull_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh); - - /* Mark null message dirty */ - /* (since we need to re-encode its message header) */ - /* (also, marking this message dirty means we - * don't have to mark chunk as dirty) - */ - curr_msg->dirty = TRUE; - - /* Set the flag to indicate that the null message - * was packed - if its not at the end its chunk, - * we'll move it again on the next pass. - */ - packed_msg = TRUE; - } /* end if */ - - /* Break out of loop */ - break; - } /* end if */ - } /* end for */ - /* Should have been message after null message */ - HDassert(v < oh->nmesgs); - } /* end if */ - } /* end if */ - else { - H5O_mesg_t *null_msg; /* Pointer to current message to operate on */ - unsigned v; /* Local index variable */ - - /* Loop over messages again, looking for large enough null message in earlier chunk */ - for(v = 0, null_msg = &oh->mesg[0]; v < oh->nmesgs; v++, null_msg++) { - if(H5O_NULL_ID == null_msg->type->id && curr_msg->chunkno > null_msg->chunkno - && curr_msg->raw_size <= null_msg->raw_size) { - unsigned old_chunkno; /* Old message information */ - uint8_t *old_raw; - - /* Keep old information about non-null message */ - old_chunkno = curr_msg->chunkno; - old_raw = curr_msg->raw; - - /* Copy raw data for non-null message to new chunk */ - HDmemcpy(null_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), curr_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh)); - - /* Mark null message's chunk as dirty, since the raw data image changed */ - oh->chunk[null_msg->chunkno].dirty = TRUE; - - /* Point non-null message at null message's space */ - curr_msg->chunkno = null_msg->chunkno; - curr_msg->raw = null_msg->raw; - - /* Change information for null message */ - if(curr_msg->raw_size == null_msg->raw_size) { - /* Point null message at old non-null space */ - /* (Instead of freeing it and allocating new message) */ - null_msg->chunkno = old_chunkno; - null_msg->raw = old_raw; - - /* Mark null message dirty */ - null_msg->dirty = TRUE; - } /* end if */ - else { - unsigned new_null_msg; /* Message index for new null message */ - - /* Check if null message is large enough to still exist */ - if((null_msg->raw_size - curr_msg->raw_size) < (size_t)H5O_SIZEOF_MSGHDR_OH(oh)) { - size_t gap_size = null_msg->raw_size - curr_msg->raw_size; /* Size of gap produced */ - - /* Adjust the size of the null message being eliminated */ - null_msg->raw_size = curr_msg->raw_size; - - /* Add the gap to the chunk */ - if(H5O_add_gap(oh, null_msg->chunkno, v, null_msg->raw + null_msg->raw_size, gap_size) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert gap in chunk") - - /* Re-use message # for new null message taking place of non-null message */ - new_null_msg = v; - } /* end if */ - else { - /* Adjust null message's size & offset */ - null_msg->raw += curr_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh); - null_msg->raw_size -= curr_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh); - - /* Mark null message dirty */ - null_msg->dirty = TRUE; - - /* Create new null message for previous location of non-null message */ - if(oh->nmesgs >= oh->alloc_nmesgs) { - if(H5O_alloc_msgs(oh, (size_t)1) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages") - - /* "Retarget" 'curr_msg' pointer into newly re-allocated array of messages */ - curr_msg = &oh->mesg[u]; - } /* end if */ - - /* Get message # for new null message */ - new_null_msg = oh->nmesgs++; - } /* end else */ - - /* Initialize new null message to take over non-null message's location */ - oh->mesg[new_null_msg].type = H5O_MSG_NULL; - oh->mesg[new_null_msg].dirty = TRUE; - oh->mesg[new_null_msg].native = NULL; - oh->mesg[new_null_msg].raw = old_raw; - oh->mesg[new_null_msg].raw_size = curr_msg->raw_size; - oh->mesg[new_null_msg].chunkno = old_chunkno; - - /* Check for gap in new null message's chunk */ - if(oh->chunk[old_chunkno].gap > 0) { - /* Eliminate the gap in the chunk */ - if(H5O_eliminate_gap(oh, &oh->mesg[new_null_msg], - ((oh->chunk[old_chunkno].image + oh->chunk[old_chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[old_chunkno].gap)), - oh->chunk[old_chunkno].gap) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTREMOVE, FAIL, "can't eliminate gap in chunk") - - /* Set the gap size to zero for the chunk */ - oh->chunk[old_chunkno].gap = 0; - } /* end if */ - } /* end else */ - - /* Indicate that we packed messages */ - packed_msg = TRUE; - - /* Break out of loop */ - /* (If it's possible to move message to even earlier chunk - * we'll get it on the next pass - QAK) - */ - break; - } /* end if */ - } /* end for */ - - /* If we packed messages, get out of loop and start over */ - /* (Don't know if this has any benefit one way or the other -QAK) */ - if(packed_msg) - break; - } /* end else */ - } /* end for */ - - /* If we did any packing, remember that */ - if(packed_msg) - did_packing = TRUE; - } while(packed_msg); - - /* Set return value */ - ret_value = did_packing; - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5O_move_msgs_forward() */ - - -/*------------------------------------------------------------------------- - * - * Function: H5O_merge_null - * - * Purpose: Merge neighboring null messages in an object header - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Oct 10 2005 - * - *------------------------------------------------------------------------- - */ -static htri_t -H5O_merge_null(H5O_t *oh) -{ - hbool_t merged_msg; /* Flag to indicate that messages were merged */ - hbool_t did_merging = FALSE; /* Whether any messages were merged */ - htri_t ret_value; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_merge_null) - - /* check args */ - HDassert(oh != NULL); - - /* Loop until no messages merged */ - /* (Double loop is not very efficient, but it would be some extra work to add - * a list of messages to each chunk -QAK) - */ - do { - H5O_mesg_t *curr_msg; /* Pointer to current message to operate on */ - unsigned u; /* Local index variable */ - - /* Reset merged messages flag */ - merged_msg = FALSE; - - /* Scan messages for adjacent null messages & merge them */ - for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) { - if(H5O_NULL_ID == curr_msg->type->id) { - H5O_mesg_t *curr_msg2; /* Pointer to current message to operate on */ - unsigned v; /* Local index variable */ - - /* Should be no gaps in chunk with null message */ - HDassert(oh->chunk[curr_msg->chunkno].gap == 0); - - /* Loop over messages again, looking for null message in same chunk */ - for(v = 0, curr_msg2 = &oh->mesg[0]; v < oh->nmesgs; v++, curr_msg2++) { - if(u != v && H5O_NULL_ID == curr_msg2->type->id && curr_msg->chunkno == curr_msg2->chunkno) { - - /* Check for second message after first message */ - if((curr_msg->raw + curr_msg->raw_size) == (curr_msg2->raw - H5O_SIZEOF_MSGHDR_OH(oh))) { - /* Extend first null message length to cover second null message */ - curr_msg->raw_size += (H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg2->raw_size); - - /* Message has been merged */ - merged_msg = TRUE; - } /* end if */ - /* Check for second message before first message */ - else if((curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh)) == (curr_msg2->raw + curr_msg2->raw_size)) { - /* Adjust first message address and extend length to cover second message */ - curr_msg->raw -= (H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg2->raw_size); - curr_msg->raw_size += (H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg2->raw_size); - - /* Message has been merged */ - merged_msg = TRUE; - } /* end if */ - - /* Second message has been merged, delete it */ - if(merged_msg) { - /* Release any information/memory for second message */ - H5O_free_mesg(curr_msg2); - - /* Mark first message as dirty */ - curr_msg->dirty = TRUE; - - /* Remove second message from list of messages */ - if(v < (oh->nmesgs - 1)) - HDmemmove(&oh->mesg[v], &oh->mesg[v + 1], ((oh->nmesgs - 1) - v) * sizeof(H5O_mesg_t)); - - /* Decrement # of messages */ - /* (Don't bother reducing size of message array for now -QAK) */ - oh->nmesgs--; - - /* Get out of loop */ - break; - } /* end if */ - } /* end if */ - } /* end for */ - - /* Get out of loop if we merged messages */ - if(merged_msg) - break; - } /* end if */ - } /* end for */ - - /* If we did any merging, remember that */ - if(merged_msg) - did_merging = TRUE; - } while(merged_msg); - - /* Set return value */ - ret_value = did_merging; - - FUNC_LEAVE_NOAPI(ret_value) -} /* H5O_merge_null() */ - - -/*------------------------------------------------------------------------- - * - * Function: H5O_remove_empty_chunks - * - * Purpose: Attempt to eliminate empty chunks from object header. - * - * This examines a chunk to see if it's empty - * and removes it (and the continuation message that points to it) - * from the object header. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Oct 17 2005 - * - *------------------------------------------------------------------------- - */ -static htri_t -H5O_remove_empty_chunks(H5F_t *f, H5O_t *oh, hid_t dxpl_id) -{ - hbool_t deleted_chunk; /* Whether to a chunk was deleted */ - hbool_t did_deleting = FALSE; /* Whether any chunks were deleted */ - htri_t ret_value; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5O_remove_empty_chunks) - - /* check args */ - HDassert(oh != NULL); - - /* Loop until no chunks are freed */ - do { - H5O_mesg_t *null_msg; /* Pointer to null message found */ - H5O_mesg_t *cont_msg; /* Pointer to continuation message found */ - unsigned u, v; /* Local index variables */ - - /* Reset 'chunk deleted' flag */ - deleted_chunk = FALSE; - - /* Scan messages for null messages that fill an entire chunk */ - for(u = 0, null_msg = &oh->mesg[0]; u < oh->nmesgs; u++, null_msg++) { - /* If a null message takes up an entire object header chunk (and - * its not the "base" chunk), delete that chunk from object header - */ - if(H5O_NULL_ID == null_msg->type->id && null_msg->chunkno > 0 && - (H5O_SIZEOF_MSGHDR_OH(oh) + null_msg->raw_size) - == (oh->chunk[null_msg->chunkno].size - H5O_SIZEOF_CHKHDR_OH(oh))) { - H5O_mesg_t *curr_msg; /* Pointer to current message to operate on */ - unsigned null_msg_no; /* Message # for null message */ - unsigned deleted_chunkno; /* Chunk # to delete */ - - /* Locate continuation message that points to chunk */ - for(v = 0, cont_msg = &oh->mesg[0]; v < oh->nmesgs; v++, cont_msg++) { - if(H5O_CONT_ID == cont_msg->type->id) { - /* Decode current continuation message if necessary */ - if(NULL == cont_msg->native) { - HDassert(H5O_MSG_CONT->decode); - cont_msg->native = (H5O_MSG_CONT->decode)(f, dxpl_id, cont_msg->raw); - if(NULL == cont_msg->native) - HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "unable to decode message") - } /* end if */ - - /* Check for correct chunk to delete */ - if(oh->chunk[null_msg->chunkno].addr == ((H5O_cont_t *)(cont_msg->native))->addr) - break; - } /* end if */ - } /* end for */ - /* Must be a continuation message that points to chunk containing null message */ - HDassert(v < oh->nmesgs); - HDassert(cont_msg); - - /* Initialize information about null message */ - null_msg_no = u; - deleted_chunkno = null_msg->chunkno; - - /* Convert continuation message into a null message */ - if(H5O_release_mesg(f, dxpl_id, oh, cont_msg, TRUE, TRUE) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to convert into null message") - - /* - * Remove chunk from object header's data structure - */ - - /* Free memory for chunk image */ - H5FL_BLK_FREE(chunk_image, oh->chunk[null_msg->chunkno].image); - - /* Remove chunk from list of chunks */ - if(null_msg->chunkno < (oh->nchunks - 1)) - HDmemmove(&oh->chunk[null_msg->chunkno], &oh->chunk[null_msg->chunkno + 1], ((oh->nchunks - 1) - null_msg->chunkno) * sizeof(H5O_chunk_t)); - - /* Decrement # of chunks */ - /* (Don't bother reducing size of chunk array for now -QAK) */ - oh->nchunks--; - - /* - * Delete null message (in empty chunk that was be freed) from list of messages - */ - - /* Release any information/memory for message */ - H5O_free_mesg(null_msg); - - /* Remove null message from list of messages */ - if(null_msg_no < (oh->nmesgs - 1)) - HDmemmove(&oh->mesg[null_msg_no], &oh->mesg[null_msg_no + 1], ((oh->nmesgs - 1) - null_msg_no) * sizeof(H5O_mesg_t)); - - /* Decrement # of messages */ - /* (Don't bother reducing size of message array for now -QAK) */ - oh->nmesgs--; - - /* Adjust chunk # for messages in chunks after deleted chunk */ - for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) { - HDassert(curr_msg->chunkno != deleted_chunkno); - if(curr_msg->chunkno > deleted_chunkno) - curr_msg->chunkno--; - } /* end for */ - - /* Found chunk to delete */ - deleted_chunk = TRUE; - break; - } /* end if */ - } /* end for */ - - /* If we deleted any chunks, remember that */ - if(deleted_chunk) - did_deleting = TRUE; - } while(deleted_chunk); - - /* Set return value */ - ret_value = did_deleting; - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5O_remove_empty_chunks() */ - - -/*------------------------------------------------------------------------- - * - * Function: H5O_condense_header - * - * Purpose: Attempt to eliminate empty chunks from object header. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Oct 4 2005 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5O_condense_header(H5F_t *f, H5O_t *oh, hid_t dxpl_id) -{ - hbool_t rescan_header; /* Whether to rescan header */ - htri_t result; /* Result from packing/merging/etc */ - herr_t ret_value = SUCCEED; /* return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5O_condense_header) - - /* check args */ - HDassert(oh != NULL); - - /* Loop until no changed to the object header messages & chunks */ - do { - /* Reset 'rescan chunks' flag */ - rescan_header = FALSE; - - /* Scan for messages that can be moved earlier in chunks */ - result = H5O_move_msgs_forward(oh); - if(result < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "can't move header messages forward") - if(result > 0) - rescan_header = TRUE; - - /* Scan for adjacent null messages & merge them */ - result = H5O_merge_null(oh); - if(result < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "can't pack null header messages") - if(result > 0) - rescan_header = TRUE; - - /* Scan for empty chunks to remove */ - result = H5O_remove_empty_chunks(f, oh, dxpl_id); - if(result < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "can't remove empty chunk") - if(result > 0) - rescan_header = TRUE; - } while(rescan_header); -#ifdef H5O_DEBUG -H5O_assert(oh); -#endif /* H5O_DEBUG */ - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5O_condense_header() */ - - -/*------------------------------------------------------------------------- - * - * Function: H5O_alloc_extend_chunk - * - * Purpose: Attempt to extend a chunk that is allocated on disk. - * - * If the extension is successful, and if the last message - * of the chunk is the null message, then that message will - * be extended with the chunk. Otherwise a new null message - * is created. - * - * f is the file in which the chunk will be written. It is - * included to ensure that there is enough space to extend - * this chunk. - * - * Return: TRUE: The chunk has been extended, and *msg_idx - * contains the message index for null message - * which is large enough to hold size bytes. - * - * FALSE: The chunk cannot be extended, and *msg_idx - * is undefined. - * - * FAIL: Some internal error has been detected. - * - * Programmer: John Mainzer -- 8/16/05 - * - *------------------------------------------------------------------------- - */ -static htri_t -H5O_alloc_extend_chunk(H5F_t *f, - H5O_t *oh, - unsigned chunkno, - size_t size, - unsigned * msg_idx) -{ - size_t delta; /* Change in chunk's size */ - size_t aligned_size = H5O_ALIGN_OH(oh, size); - uint8_t *old_image; /* Old address of chunk's image in memory */ - size_t old_size; /* Old size of chunk */ - htri_t tri_result; /* Result from checking if chunk can be extended */ - int extend_msg = -1;/* Index of null message to extend */ - unsigned u; /* Local index variable */ - htri_t ret_value = TRUE; /* return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5O_alloc_extend_chunk) - - /* check args */ - HDassert(f != NULL); - HDassert(oh != NULL); - HDassert(chunkno < oh->nchunks); - HDassert(size > 0); - HDassert(msg_idx != NULL); - HDassert(H5F_addr_defined(oh->chunk[chunkno].addr)); - - /* Test to see if the specified chunk ends with a null messages. - * If successful, set the index of the the null message in extend_msg. - */ - for(u = 0; u < oh->nmesgs; u++) { - /* Check for null message at end of proper chunk */ - /* (account for possible checksum at end of chunk) */ - if(oh->mesg[u].chunkno == chunkno && H5O_NULL_ID == oh->mesg[u].type->id && - ((oh->mesg[u].raw + oh->mesg[u].raw_size) - == ((oh->chunk[chunkno].image + oh->chunk[chunkno].size) - - (oh->chunk[chunkno].gap + H5O_SIZEOF_CHKSUM_OH(oh))))) { - - extend_msg = u; - break; - } /* end if */ - } /* end for */ - - /* If we can extend an existing null message, adjust the delta appropriately */ - if(extend_msg >= 0) { - HDassert(oh->chunk[chunkno].gap == 0); - delta = aligned_size - oh->mesg[extend_msg].raw_size; - } /* end if */ - else - delta = (aligned_size + H5O_SIZEOF_MSGHDR_OH(oh)) - oh->chunk[chunkno].gap; - delta = H5O_ALIGN_OH(oh, delta); - - /* Determine whether the chunk can be extended */ - tri_result = H5MF_can_extend(f, H5FD_MEM_OHDR, oh->chunk[chunkno].addr, - (hsize_t)(oh->chunk[chunkno].size), (hsize_t)delta); - if(tri_result == FALSE) /* can't extend -- we are done */ - HGOTO_DONE(FALSE) - else if(tri_result < 0) /* error */ - HGOTO_ERROR(H5E_RESOURCE, H5E_SYSTEM, FAIL, "can't tell if we can extend chunk") - - /* If we get this far, we should be able to extend the chunk */ - if(H5MF_extend(f, H5FD_MEM_OHDR, oh->chunk[chunkno].addr, (hsize_t)(oh->chunk[chunkno].size), (hsize_t)delta) < 0 ) - HGOTO_ERROR(H5E_RESOURCE, H5E_SYSTEM, FAIL, "can't extend chunk") - - /* If we can extend an existing null message, take care of that */ - if(extend_msg >= 0) { - /* Adjust message size of existing null message */ - oh->mesg[extend_msg].dirty = TRUE; - oh->mesg[extend_msg].raw_size += delta; - } /* end if */ - /* Create new null message for end of chunk */ - else { - /* Create a new null message */ - if(oh->nmesgs >= oh->alloc_nmesgs) - if(H5O_alloc_msgs(oh, (size_t)1) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages") - - /* Set extension message */ - extend_msg = oh->nmesgs++; - - /* Initialize new null message */ - oh->mesg[extend_msg].type = H5O_MSG_NULL; - oh->mesg[extend_msg].dirty = TRUE; - oh->mesg[extend_msg].native = NULL; - oh->mesg[extend_msg].raw = ((oh->chunk[chunkno].image + oh->chunk[chunkno].size) - - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[chunkno].gap)) - + H5O_SIZEOF_MSGHDR_OH(oh); - oh->mesg[extend_msg].raw_size = (delta + oh->chunk[chunkno].gap) - H5O_SIZEOF_MSGHDR_OH(oh); - oh->mesg[extend_msg].chunkno = chunkno; - } /* end else */ - - /* Allocate more memory space for chunk's image */ - old_image = oh->chunk[chunkno].image; - old_size = oh->chunk[chunkno].size; - oh->chunk[chunkno].size += delta; - oh->chunk[chunkno].image = H5FL_BLK_REALLOC(chunk_image, old_image, oh->chunk[chunkno].size); - oh->chunk[chunkno].gap = 0; - oh->chunk[chunkno].dirty = TRUE; - if(NULL == oh->chunk[chunkno].image) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") - - /* Wipe new space for chunk */ - HDmemset(oh->chunk[chunkno].image + old_size, 0, oh->chunk[chunkno].size - old_size); - - /* Spin through existing messages, adjusting them */ - for(u = 0; u < oh->nmesgs; u++) { - /* Adjust raw addresses for messages in this chunk to reflect new 'image' address */ - if(oh->mesg[u].chunkno == chunkno) - oh->mesg[u].raw = oh->chunk[chunkno].image + (oh->mesg[u].raw - old_image); - - /* Find continuation message which points to this chunk and adjust chunk's size */ - /* (Chunk 0 doesn't have a continuation message that points to it and - * it's size is directly encoded in the object header) */ - if(chunkno > 0 && (H5O_CONT_ID == oh->mesg[u].type->id) && - (((H5O_cont_t *)(oh->mesg[u].native))->chunkno == chunkno)) { - /* Adjust size of continuation message */ - HDassert(((H5O_cont_t *)(oh->mesg[u].native))->size == old_size); - ((H5O_cont_t *)(oh->mesg[u].native))->size = oh->chunk[chunkno].size; - - /* Flag continuation message as dirty */ - oh->mesg[u].dirty = TRUE; - } /* end if */ - } /* end for */ - - /* Set return value */ - *msg_idx = extend_msg; - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5O_alloc_extend_chunk() */ - - -/*------------------------------------------------------------------------- - * Function: H5O_alloc_new_chunk - * - * Purpose: Allocates a new chunk for the object header, including - * file space. - * - * One of the other chunks will get an object continuation - * message. If there isn't room in any other chunk for the - * object continuation message, then some message from - * another chunk is moved into this chunk to make room. - * - * SIZE need not be aligned. - * - * Return: Success: Index number of the null message for the - * new chunk. The null message will be at - * least SIZE bytes not counting the message - * ID or size fields. - * - * Failure: Negative - * - * Programmer: Robb Matzke - * matzke@llnl.gov - * Aug 7 1997 - * - *------------------------------------------------------------------------- - */ -static unsigned -H5O_alloc_new_chunk(H5F_t *f, - hid_t dxpl_id, - H5O_t *oh, - size_t size) -{ - size_t cont_size; /*continuation message size */ - int found_null = (-1); /*best fit null message */ - int found_attr = (-1); /*best fit attribute message */ - int found_link = (-1); /*best fit link message */ - int found_other = (-1); /*best fit other message */ - unsigned idx; /*message number */ - uint8_t *p = NULL; /*ptr into new chunk */ - H5O_cont_t *cont = NULL; /*native continuation message */ - unsigned chunkno; /* Chunk allocated */ - haddr_t new_chunk_addr; - unsigned u; /* Local index variable */ - unsigned ret_value; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5O_alloc_new_chunk) - - /* check args */ - HDassert(oh); - HDassert(size > 0); - size = H5O_ALIGN_OH(oh, size); - - /* - * Find the smallest null message that will hold an object - * continuation message. Failing that, find the smallest message - * that could be moved to make room for the continuation message. - * - * Don't ever move continuation message from one chunk to another. - * Prioritize link messages moving to later chunks, instead of - * more "important" messages. - * Avoid moving attributes when possible to preserve their - * ordering (although ordering is *not* guaranteed!). - * - */ - cont_size = H5O_ALIGN_OH(oh, H5F_SIZEOF_ADDR(f) + H5F_SIZEOF_SIZE(f)); - for(u = 0; u < oh->nmesgs; u++) { - int msg_id = oh->mesg[u].type->id; /* Temp. copy of message type ID */ - - if(H5O_NULL_ID == msg_id) { - if(cont_size == oh->mesg[u].raw_size) { - found_null = u; - break; - } else if(oh->mesg[u].raw_size >= cont_size && - (found_null < 0 || - oh->mesg[u].raw_size < oh->mesg[found_null].raw_size)) { - found_null = u; - } - } else if(H5O_CONT_ID == msg_id) { - /*don't consider continuation messages */ - } else if(H5O_ATTR_ID == msg_id) { - if(oh->mesg[u].raw_size >= cont_size && - (found_attr < 0 || - oh->mesg[u].raw_size < oh->mesg[found_attr].raw_size)) - found_attr = u; - } else if(H5O_LINK_ID == msg_id) { - if(oh->mesg[u].raw_size >= cont_size && - (found_link < 0 || - oh->mesg[u].raw_size < oh->mesg[found_link].raw_size)) - found_link = u; - } else { - if(oh->mesg[u].raw_size >= cont_size && - (found_other < 0 || - oh->mesg[u].raw_size < oh->mesg[found_other].raw_size)) - found_other = u; - } /* end else */ - } /* end for */ - HDassert(found_null >= 0 || found_attr >= 0 || found_link >= 0 || found_other >= 0); - - /* - * If we must move some other message to make room for the null - * message, then make sure the new chunk has enough room for that - * other message. - * - * Move link messages first, then other messages, and attributes - * only as a last resort. - * - */ - if(found_null < 0) { - if(found_link >= 0) - found_other = found_link; - - if(found_other < 0) - found_other = found_attr; - - HDassert(found_other >= 0); - size += H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other].raw_size; - } /* end if */ - - /* - * The total chunk size must include enough space for the checksum - * on the chunk and the continuation chunk magic #. (which are only present - * in later versions of the object header) - */ - size += H5O_SIZEOF_CHKHDR_OH(oh); - - /* - * The total chunk size must include the requested space plus enough - * for the message header. This must be at least some minimum and a - * multiple of the alignment size. - */ - size = MAX(H5O_MIN_SIZE, size + H5O_SIZEOF_MSGHDR_OH(oh)); - HDassert(size == H5O_ALIGN_OH(oh, size)); - - /* allocate space in file to hold the new chunk */ - new_chunk_addr = H5MF_alloc(f, H5FD_MEM_OHDR, dxpl_id, (hsize_t)size); - if(HADDR_UNDEF == new_chunk_addr) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "unable to allocate space for new chunk") - - /* - * Create the new chunk giving it a file address. - */ - if(oh->nchunks >= oh->alloc_nchunks) { - unsigned na = MAX(H5O_NCHUNKS, oh->alloc_nchunks * 2); /* Double # of chunks allocated */ - H5O_chunk_t *x = H5FL_SEQ_REALLOC(H5O_chunk_t, oh->chunk, (size_t)na); - - if(!x) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed") - oh->alloc_nchunks = na; - oh->chunk = x; - } /* end if */ - - chunkno = oh->nchunks++; - oh->chunk[chunkno].dirty = TRUE; - oh->chunk[chunkno].addr = new_chunk_addr; - oh->chunk[chunkno].size = size; - oh->chunk[chunkno].gap = 0; - if(NULL == (oh->chunk[chunkno].image = p = H5FL_BLK_CALLOC(chunk_image, size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed") - - /* If this is a later version of the object header format, put the magic - * # at the beginning of the chunk image. - */ - if(oh->version > H5O_VERSION_1) { - HDmemcpy(p, H5O_CHK_MAGIC, (size_t)H5O_SIZEOF_MAGIC); - p += H5O_SIZEOF_MAGIC; - } /* end if */ - - /* - * Make sure we have enough space for all possible new messages - * that could be generated below. - */ - if(oh->nmesgs + 3 > oh->alloc_nmesgs) - if(H5O_alloc_msgs(oh, (size_t)3) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "can't allocate more space for messages") - - /* Move message (that will be replaced with continuation message) - * to new chunk, if necessary. - */ - if(found_null < 0) { - H5O_mesg_t *null_msg; /* Pointer to new null message */ - - /* Create null message for space that message to copy currently occupies */ - found_null = oh->nmesgs++; - null_msg = &(oh->mesg[found_null]); - null_msg->type = H5O_MSG_NULL; - null_msg->dirty = TRUE; - null_msg->native = NULL; - null_msg->raw = oh->mesg[found_other].raw; - null_msg->raw_size = oh->mesg[found_other].raw_size; - null_msg->chunkno = oh->mesg[found_other].chunkno; - - /* Copy the message to move to its new location */ - /* (Chunk is already dirty, no need to mark it) */ - HDmemcpy(p, oh->mesg[found_other].raw - H5O_SIZEOF_MSGHDR_OH(oh), - oh->mesg[found_other].raw_size + H5O_SIZEOF_MSGHDR_OH(oh)); - - /* Switch message to point to new location */ - oh->mesg[found_other].raw = p + H5O_SIZEOF_MSGHDR_OH(oh); - oh->mesg[found_other].chunkno = chunkno; - - /* Account for copied message in new chunk */ - p += H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other].raw_size; - size -= H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other].raw_size; - } /* end if */ - HDassert(found_null >= 0); - - /* Create null message for [rest of] space in new chunk */ - /* (account for chunk's magic # & checksum) */ - idx = oh->nmesgs++; - oh->mesg[idx].type = H5O_MSG_NULL; - oh->mesg[idx].dirty = TRUE; - oh->mesg[idx].native = NULL; - oh->mesg[idx].raw = p + H5O_SIZEOF_MSGHDR_OH(oh); - oh->mesg[idx].raw_size = size - - (H5O_SIZEOF_CHKHDR_OH(oh) + H5O_SIZEOF_MSGHDR_OH(oh)); - oh->mesg[idx].chunkno = chunkno; - - /* Initialize the continuation information */ - if(NULL == (cont = H5FL_MALLOC(H5O_cont_t))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed") - cont->addr = oh->chunk[chunkno].addr; - cont->size = oh->chunk[chunkno].size; - cont->chunkno = chunkno; - - /* Split the null message and point at continuation message */ - if(H5O_alloc_null(oh, (unsigned)found_null, H5O_MSG_CONT, cont, cont_size) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, UFAIL, "can't split null message") - - /* Set return value */ - ret_value = idx; - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5O_alloc_new_chunk() */ - - -/*------------------------------------------------------------------------- - * Function: H5O_eliminate_gap - * - * Purpose: Eliminate a gap in a chunk with a null message - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Oct 17 2006 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5O_eliminate_gap(H5O_t *oh, H5O_mesg_t *mesg, uint8_t *gap_loc, size_t gap_size) -{ - uint8_t *move_start, *move_end; /* Pointers to area of messages to move */ - hbool_t null_before_gap; /* Flag whether the null message is before the gap or not */ - - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_eliminate_gap) - - /* check args */ - HDassert(oh); - HDassert(oh->version > H5O_VERSION_1); - HDassert(mesg); - HDassert(gap_loc); - HDassert(gap_size); - - /* Check if the null message is before or after the gap produced */ - null_before_gap = (hbool_t)(mesg->raw < gap_loc); - - /* Set up information about region of messages to move */ - if(null_before_gap) { - move_start = mesg->raw + mesg->raw_size; - move_end = gap_loc; - } /* end if */ - else { - move_start = gap_loc + gap_size; - move_end = mesg->raw - H5O_SIZEOF_MSGHDR_OH(oh); - } /* end else */ - - /* Check for messages between null message and gap */ - if(move_end > move_start) { - unsigned u; /* Local index variable */ - - /* Look for messages that need to move, to adjust raw pointers in chunk */ - for(u = 0; u < oh->nmesgs; u++) { - uint8_t *msg_start; /* Start of encoded message in chunk */ - - msg_start = oh->mesg[u].raw - H5O_SIZEOF_MSGHDR_OH(oh); - if(oh->mesg[u].chunkno == mesg->chunkno - && (msg_start >= move_start && msg_start < move_end)) { - /* Move message's raw pointer in appropriate direction */ - if(null_before_gap) - oh->mesg[u].raw += gap_size; - else - oh->mesg[u].raw -= gap_size; - } /* end if */ - } /* end for */ - - /* Slide raw message info in chunk image */ - if(null_before_gap) - /* Slide messages down */ - HDmemmove(move_start + gap_size, move_start, (size_t)(move_end - move_start)); - else { - /* Slide messages up */ - HDmemmove(move_start - gap_size, move_start, (size_t)(move_end - move_start)); - - /* Adjust start of null message */ - mesg->raw -= gap_size; - } /* end else */ - } /* end if */ - - /* Zero out addition to null message */ - HDmemset(mesg->raw + mesg->raw_size, 0, gap_size); - - /* Adjust size of null message */ - mesg->raw_size += gap_size; - - /* Mark null message as dirty */ - mesg->dirty = TRUE; - - FUNC_LEAVE_NOAPI(SUCCEED) -} /* H5O_eliminate_gap() */ - - -/*------------------------------------------------------------------------- - * Function: H5O_add_gap - * - * Purpose: Add a gap to a chunk - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Oct 17 2006 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5O_add_gap(H5O_t *oh, unsigned chunkno, unsigned idx, - uint8_t *new_gap_loc, size_t new_gap_size) -{ - hbool_t merged_with_null; /* Whether the gap was merged with a null message */ - unsigned u; /* Local index variable */ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5O_add_gap) - - /* check args */ - HDassert(oh); - HDassert(oh->version > H5O_VERSION_1); - HDassert(new_gap_loc); - HDassert(new_gap_size); - - /* Check for existing null message in chunk */ - merged_with_null = FALSE; - for(u = 0; u < oh->nmesgs && !merged_with_null; u++) { - /* Find a null message in the chunk with the new gap */ - /* (a null message that's not the one we are eliminating) */ - if(H5O_NULL_ID == oh->mesg[u].type->id && oh->mesg[u].chunkno == chunkno - && u != idx) { - /* Sanity check - chunks with null messages shouldn't have a gap */ - HDassert(oh->chunk[chunkno].gap == 0); - - /* Eliminate the gap in the chunk */ - if(H5O_eliminate_gap(oh, &oh->mesg[u], new_gap_loc, new_gap_size) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't eliminate gap in chunk") - - /* Set flag to indicate that the gap was handled */ - merged_with_null = TRUE; - } /* end if */ - } /* end for */ - - /* If we couldn't find a null message in the chunk, move the gap to the end */ - if(!merged_with_null) { - /* Adjust message offsets after new gap forward in chunk */ - for(u = 0; u < oh->nmesgs; u++) - if(oh->mesg[u].chunkno == chunkno && oh->mesg[u].raw > new_gap_loc) - oh->mesg[u].raw -= new_gap_size; - - /* Slide raw message info forward in chunk image */ - HDmemmove(new_gap_loc, new_gap_loc + new_gap_size, - (size_t)((oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM_OH(oh))) - (new_gap_loc + new_gap_size))); - - /* Add existing gap size to new gap size */ - new_gap_size += oh->chunk[chunkno].gap; - - /* Merging with existing gap will allow for a new null message */ - if(new_gap_size >= (size_t)H5O_SIZEOF_MSGHDR_OH(oh)) { - H5O_mesg_t *null_msg; /* Pointer to new null message */ - - /* Check if we need to extend message table to hold the new null message */ - if(oh->nmesgs >= oh->alloc_nmesgs) - if(H5O_alloc_msgs(oh, (size_t)1) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "can't allocate more space for messages") - - /* Increment new gap size */ - oh->chunk[chunkno].gap += new_gap_size; - - /* Create new null message, with the tail of the previous null message */ - null_msg = &(oh->mesg[oh->nmesgs++]); - null_msg->type = H5O_MSG_NULL; - null_msg->dirty = TRUE; - null_msg->native = NULL; - null_msg->raw_size = new_gap_size - H5O_SIZEOF_MSGHDR_OH(oh); - null_msg->raw = (oh->chunk[chunkno].image + oh->chunk[chunkno].size) - - (H5O_SIZEOF_CHKSUM_OH(oh) + null_msg->raw_size); - null_msg->chunkno = chunkno; - - /* Zero out new null message's raw data */ - if(null_msg->raw_size) - HDmemset(null_msg->raw, 0, null_msg->raw_size); - - /* Reset size of gap in chunk */ - oh->chunk[chunkno].gap = 0; - } /* end if */ - else - oh->chunk[chunkno].gap = new_gap_size; - } /* end if */ - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5O_add_gap() */ - - -/*------------------------------------------------------------------------- - * Function: H5O_alloc - * - * Purpose: Allocate enough space in the object header for this message. - * - * Return: Success: Index of message - * - * Failure: Negative - * - * Programmer: Robb Matzke - * matzke@llnl.gov - * Aug 6 1997 - * - *------------------------------------------------------------------------- - */ -static unsigned -H5O_alloc(H5F_t *f, - hid_t dxpl_id, - H5O_t *oh, - const H5O_msg_class_t *type, - size_t size, - unsigned * oh_flags_ptr) -{ - size_t aligned_size = H5O_ALIGN_OH(oh, size); - unsigned idx; /* Index of message which fits allocation */ - unsigned ret_value; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5O_alloc) - - /* check args */ - HDassert(oh); - HDassert(type); - HDassert(oh_flags_ptr); - - /* look for a null message which is large enough */ - for(idx = 0; idx < oh->nmesgs; idx++) - if(H5O_NULL_ID == oh->mesg[idx].type->id && oh->mesg[idx].raw_size >= aligned_size) - break; - - /* if we didn't find one, then allocate more header space */ - if(idx >= oh->nmesgs) { - unsigned chunkno; - - /* check to see if we can extend one of the chunks. If we can, - * do so. Otherwise, we will have to allocate a new chunk. - * - * Note that in this new version of this function, all chunks - * must have file space allocated to them. - */ - for(chunkno = 0; chunkno < oh->nchunks; chunkno++) { - htri_t tri_result; - - HDassert(H5F_addr_defined(oh->chunk[chunkno].addr)); - - tri_result = H5O_alloc_extend_chunk(f, oh, chunkno, size, &idx); - if(tri_result == TRUE) - break; - else if(tri_result == FALSE) - idx = UFAIL; - else - HGOTO_ERROR(H5E_OHDR, H5E_SYSTEM, UFAIL, "H5O_alloc_extend_chunk failed unexpectedly") - } /* end for */ - - /* If idx is still UFAIL, we were not able to extend a chunk, - * create a new one. - */ - if(idx == UFAIL) - if((idx = H5O_alloc_new_chunk(f, dxpl_id, oh, size)) == UFAIL) - HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, UFAIL, "unable to create a new object header data chunk") - } /* end if */ - - /* Split the null message and point at continuation message */ - if(H5O_alloc_null(oh, idx, type, NULL, aligned_size) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, UFAIL, "can't split null message") - - /* Mark the object header as modified */ - *oh_flags_ptr |= H5AC__DIRTIED_FLAG; - -#ifdef H5O_DEBUG -H5O_assert(oh); -#endif /* H5O_DEBUG */ - /* Set return value */ - ret_value = idx; - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5O_alloc() */ - - -/*------------------------------------------------------------------------- * Function: H5O_raw_size * * Purpose: Call the 'raw_size' method for a @@ -4341,13 +2916,13 @@ done: * *------------------------------------------------------------------------- */ -static herr_t +herr_t H5O_delete_mesg(H5F_t *f, hid_t dxpl_id, H5O_mesg_t *mesg, hbool_t adj_link) { const H5O_msg_class_t *type; /* Type of object to free */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT(H5O_delete_mesg) + FUNC_ENTER_NOAPI(H5O_delete_mesg, FAIL) /* Check args */ HDassert(f); @@ -4355,9 +2930,7 @@ H5O_delete_mesg(H5F_t *f, hid_t dxpl_id, H5O_mesg_t *mesg, hbool_t adj_link) /* Get the message to free's type */ if(mesg->flags & H5O_FLAG_SHARED) - { type = H5O_MSG_SHARED; - } else type = mesg->type; @@ -5139,346 +3712,3 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_mesg_hash() */ -#ifdef H5O_DEBUG - -/*------------------------------------------------------------------------- - * Function: H5O_assert - * - * Purpose: Sanity check the information for an object header data - * structure. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Oct 17 2006 - * - *------------------------------------------------------------------------- - */ -herr_t -H5O_assert(const H5O_t *oh) -{ - H5O_mesg_t *curr_msg; /* Pointer to current message to examine */ - H5O_mesg_t *tmp_msg; /* Pointer to temporary message to examine */ - unsigned u, v; /* Local index variables */ - - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_assert) - - /* Loop over all chunks in object header */ - for(u = 0; u < oh->nchunks; u++) { - /* Check for valid raw data image */ - HDassert(oh->chunk[u].image); - HDassert(oh->chunk[u].size > (size_t)H5O_SIZEOF_CHKHDR_OH(oh)); - - /* All chunks must be allocated on disk */ - HDassert(H5F_addr_defined(oh->chunk[u].addr)); - - /* Version specific checks */ - if(oh->version > H5O_VERSION_1) { - /* Make certain that the magic number is correct for each chunk */ - HDassert(!HDmemcmp(oh->chunk[u].image, (u == 0 ? H5O_HDR_MAGIC : H5O_CHK_MAGIC), H5O_SIZEOF_MAGIC)); - - /* Check for valid gap size */ - HDassert(oh->chunk[u].gap < (size_t)H5O_SIZEOF_MSGHDR_OH(oh)); - } /* end if */ - else - /* Gaps should never occur in version 1 of the format */ - HDassert(oh->chunk[u].gap == 0); - } /* end for */ - - /* Loop over all messages in object header */ - for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) { - /* Make certain that the message is in a valid chunk */ - HDassert(curr_msg->chunkno < oh->nchunks); - - /* Make certain null messages aren't in chunks with gaps */ - if(H5O_NULL_ID == curr_msg->type->id) - HDassert(oh->chunk[curr_msg->chunkno].gap == 0); - - /* Make certain that the message is completely in a chunk message area */ - HDassert(curr_msg->raw_size <= (oh->chunk[curr_msg->chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[curr_msg->chunkno].gap)); - if(curr_msg->chunkno == 0) - HDassert(curr_msg->raw >= oh->chunk[curr_msg->chunkno].image + (H5O_SIZEOF_HDR_OH(oh) - H5O_SIZEOF_CHKSUM_OH(oh))); - else - HDassert(curr_msg->raw >= oh->chunk[curr_msg->chunkno].image + (H5O_SIZEOF_CHKHDR_OH(oh) - H5O_SIZEOF_CHKSUM_OH(oh))); - HDassert(curr_msg->raw + curr_msg->raw_size <= (oh->chunk[curr_msg->chunkno].image + oh->chunk[curr_msg->chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[curr_msg->chunkno].gap)); - - /* Make certain that no other messages overlap this message */ - for(v = 0, tmp_msg = &oh->mesg[0]; v < oh->nmesgs; v++, tmp_msg++) { - if(u != v) - HDassert(!(tmp_msg->raw >= curr_msg->raw && tmp_msg->raw < (curr_msg->raw + curr_msg->raw_size))); - } /* end for */ - } /* end for */ - - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5O_assert() */ -#endif /* H5O_DEBUG */ - - -/*------------------------------------------------------------------------- - * Function: H5O_debug_id - * - * Purpose: Act as a proxy for calling the 'debug' method for a - * particular class of object header. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 13 2003 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -herr_t -H5O_debug_id(unsigned type_id, H5F_t *f, hid_t dxpl_id, const void *mesg, FILE *stream, int indent, int fwidth) -{ - const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ - herr_t ret_value; /* Return value */ - - FUNC_ENTER_NOAPI(H5O_debug_id,FAIL) - - /* Check args */ - HDassert(type_id < NELMTS(H5O_msg_class_g)); - type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ - HDassert(type); - HDassert(type->debug); - HDassert(f); - HDassert(mesg); - HDassert(stream); - HDassert(indent >= 0); - HDassert(fwidth >= 0); - - /* Call the debug method in the class */ - if((ret_value = (type->debug)(f, dxpl_id, mesg, stream, indent, fwidth)) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_BADTYPE, FAIL, "unable to debug message") - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5O_debug_id() */ - - -/*------------------------------------------------------------------------- - * Function: H5O_debug_real - * - * Purpose: Prints debugging info about an object header. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Robb Matzke - * matzke@llnl.gov - * Aug 6 1997 - * - *------------------------------------------------------------------------- - */ -herr_t -H5O_debug_real(H5F_t *f, hid_t dxpl_id, H5O_t *oh, haddr_t addr, FILE *stream, int indent, int fwidth) -{ - unsigned i, chunkno; - size_t mesg_total = 0, chunk_total = 0; - int *sequence; - void *(*decode)(H5F_t*, hid_t, const uint8_t*); - herr_t (*debug)(H5F_t*, hid_t, const void*, FILE*, int, int)=NULL; - herr_t ret_value = SUCCEED; - - FUNC_ENTER_NOAPI(H5O_debug_real, FAIL) - - /* check args */ - HDassert(f); - HDassert(oh); - HDassert(H5F_addr_defined(addr)); - HDassert(stream); - HDassert(indent >= 0); - HDassert(fwidth >= 0); - - /* debug */ - HDfprintf(stream, "%*sObject Header...\n", indent, ""); - - HDfprintf(stream, "%*s%-*s %t\n", indent, "", fwidth, - "Dirty:", - oh->cache_info.is_dirty); - HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth, - "Version:", - oh->version); - HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth, - "Header size (in bytes):", - (unsigned)H5O_SIZEOF_HDR_OH(oh)); - HDfprintf(stream, "%*s%-*s %d\n", indent, "", fwidth, - "Number of links:", - oh->nlink); - HDfprintf(stream, "%*s%-*s %Zu (%Zu)\n", indent, "", fwidth, - "Number of messages (allocated):", - oh->nmesgs, oh->alloc_nmesgs); - HDfprintf(stream, "%*s%-*s %Zu (%Zu)\n", indent, "", fwidth, - "Number of chunks (allocated):", - oh->nchunks, oh->alloc_nchunks); - - /* debug each chunk */ - for(i = 0, chunk_total = 0; i < oh->nchunks; i++) { - size_t chunk_size; - - chunk_total += oh->chunk[i].size; - HDfprintf(stream, "%*sChunk %d...\n", indent, "", i); - - HDfprintf(stream, "%*s%-*s %t\n", indent + 3, "", MAX(0, fwidth - 3), - "Dirty:", - oh->chunk[i].dirty); - - HDfprintf(stream, "%*s%-*s %a\n", indent + 3, "", MAX(0, fwidth - 3), - "Address:", - oh->chunk[i].addr); - - if(0 == i) { - if(H5F_addr_ne(oh->chunk[i].addr, addr)) - HDfprintf(stream, "*** WRONG ADDRESS!\n"); - chunk_size = oh->chunk[i].size - H5O_SIZEOF_HDR_OH(oh); - } /* end if */ - else - chunk_size = oh->chunk[i].size; - HDfprintf(stream, "%*s%-*s %Zu\n", indent + 3, "", MAX(0, fwidth - 3), - "Size in bytes:", - chunk_size); - - HDfprintf(stream, "%*s%-*s %Zu\n", indent + 3, "", MAX(0, fwidth - 3), - "Gap:", - oh->chunk[i].gap); - } /* end for */ - - /* debug each message */ - if(NULL == (sequence = H5MM_calloc(NELMTS(H5O_msg_class_g) * sizeof(int)))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") - for(i = 0, mesg_total = 0; i < oh->nmesgs; i++) { - mesg_total += H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[i].raw_size; - HDfprintf(stream, "%*sMessage %d...\n", indent, "", i); - - /* check for bad message id */ - if(oh->mesg[i].type->id >= (int)NELMTS(H5O_msg_class_g)) { - HDfprintf(stream, "*** BAD MESSAGE ID 0x%04x\n", - oh->mesg[i].type->id); - continue; - } /* end if */ - - /* message name and size */ - HDfprintf(stream, "%*s%-*s 0x%04x `%s' (%d)\n", - indent + 3, "", MAX(0, fwidth - 3), - "Message ID (sequence number):", - (unsigned) (oh->mesg[i].type->id), - oh->mesg[i].type->name, - sequence[oh->mesg[i].type->id]++); - HDfprintf (stream, "%*s%-*s %t\n", indent+3, "", MAX (0, fwidth-3), - "Dirty:", - oh->mesg[i].dirty); - HDfprintf (stream, "%*s%-*s %s\n", indent+3, "", MAX (0, fwidth-3), - "Shared:", - (oh->mesg[i].flags & H5O_FLAG_SHARED) ? "Yes" : "No"); - HDfprintf(stream, "%*s%-*s %s\n", indent + 3, "", MAX(0, fwidth - 3), - "Constant:", - (oh->mesg[i].flags & H5O_FLAG_CONSTANT) ? "Yes" : "No"); - if(oh->mesg[i].flags & ~H5O_FLAG_BITS) { - HDfprintf (stream, "%*s%-*s 0x%02x\n", indent+3,"",MAX(0,fwidth-3), - "*** ADDITIONAL UNKNOWN FLAGS --->", - oh->mesg[i].flags & ~H5O_FLAG_BITS); - } /* end if */ - HDfprintf(stream, "%*s%-*s %Zu bytes\n", indent+3, "", MAX(0,fwidth-3), - "Raw size in obj header:", - oh->mesg[i].raw_size); - HDfprintf(stream, "%*s%-*s %u\n", indent + 3, "", MAX(0, fwidth - 3), - "Chunk number:", - oh->mesg[i].chunkno); - chunkno = oh->mesg[i].chunkno; - if(chunkno >= oh->nchunks) - HDfprintf(stream, "*** BAD CHUNK NUMBER\n"); - HDfprintf(stream, "%*s%-*s %Zu\n", indent + 3, "", MAX(0, fwidth - 3), - "Raw data offset in chunk:", - (size_t)(oh->mesg[i].raw - oh->chunk[chunkno].image)); - - /* check the size */ - if((oh->mesg[i].raw + oh->mesg[i].raw_size > - oh->chunk[chunkno].image + oh->chunk[chunkno].size) || - (oh->mesg[i].raw < oh->chunk[chunkno].image)) - HDfprintf(stream, "*** BAD MESSAGE RAW ADDRESS\n"); - - /* decode the message */ - if(oh->mesg[i].flags & H5O_FLAG_SHARED) { - decode = H5O_MSG_SHARED->decode; - debug = H5O_MSG_SHARED->debug; - } else { - decode = oh->mesg[i].type->decode; - debug = oh->mesg[i].type->debug; - } /* end else */ - if(NULL==oh->mesg[i].native && decode) - oh->mesg[i].native = (decode)(f, dxpl_id, oh->mesg[i].raw); - if(NULL == oh->mesg[i].native) - debug = NULL; - - /* print the message */ - HDfprintf(stream, "%*s%-*s\n", indent + 3, "", MAX(0, fwidth - 3), - "Message Information:"); - if(debug) - (debug)(f, dxpl_id, oh->mesg[i].native, stream, indent + 6, MAX(0, fwidth - 6)); - else - HDfprintf(stream, "%*s<No info for this message>\n", indent + 6, ""); - - /* If the message is shared then also print the pointed-to message */ - if(oh->mesg[i].flags & H5O_FLAG_SHARED) { - H5O_shared_t *shared = (H5O_shared_t*)(oh->mesg[i].native); - void *mesg; - - mesg = H5O_shared_read(f, dxpl_id, shared, oh->mesg[i].type, NULL); - if(oh->mesg[i].type->debug) - (oh->mesg[i].type->debug)(f, dxpl_id, mesg, stream, indent + 3, MAX (0, fwidth - 3)); - H5O_free_real(oh->mesg[i].type, mesg); - } /* end if */ - } /* end for */ - sequence = H5MM_xfree(sequence); - - if(mesg_total != chunk_total) - HDfprintf(stream, "*** TOTAL SIZE DOES NOT MATCH ALLOCATED SIZE!\n"); - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5O_debug_real() */ - - -/*------------------------------------------------------------------------- - * Function: H5O_debug - * - * Purpose: Prints debugging info about an object header. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Robb Matzke - * matzke@llnl.gov - * Aug 6 1997 - * - *------------------------------------------------------------------------- - */ -herr_t -H5O_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, int fwidth) -{ - H5O_t *oh = NULL; - herr_t ret_value = SUCCEED; - - FUNC_ENTER_NOAPI(H5O_debug, FAIL) - - /* check args */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); - HDassert(stream); - HDassert(indent >= 0); - HDassert(fwidth >= 0); - - if(NULL == (oh = H5AC_protect(f, dxpl_id, H5AC_OHDR, addr, NULL, NULL, H5AC_READ))) - HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header") - - /* debug */ - H5O_debug_real(f, dxpl_id, oh, addr, stream, indent, fwidth); - -done: - if(oh && H5AC_unprotect(f, dxpl_id, H5AC_OHDR, addr, oh, H5AC__NO_FLAGS_SET) < 0) - HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header") - - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5O_debug() */ - diff --git a/src/H5Oalloc.c b/src/H5Oalloc.c new file mode 100644 index 0000000..3d728ce --- /dev/null +++ b/src/H5Oalloc.c @@ -0,0 +1,1489 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*------------------------------------------------------------------------- + * + * Created: H5Oalloc.c + * Nov 17 2006 + * Quincey Koziol <koziol@hdfgroup.org> + * + * Purpose: Object header allocation routines. + * + *------------------------------------------------------------------------- + */ + +/****************/ +/* Module Setup */ +/****************/ + +#define H5O_PACKAGE /*suppress error about including H5Opkg */ + +/***********/ +/* Headers */ +/***********/ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5FLprivate.h" /* Free lists */ +#include "H5MFprivate.h" /* File memory management */ +#include "H5Opkg.h" /* Object headers */ + +/****************/ +/* Local Macros */ +/****************/ + + +/******************/ +/* Local Typedefs */ +/******************/ + + +/********************/ +/* Package Typedefs */ +/********************/ + + +/********************/ +/* Local Prototypes */ +/********************/ + +static herr_t H5O_add_gap(H5O_t *oh, unsigned chunkno, unsigned idx, + uint8_t *new_gap_loc, size_t new_gap_size); +static herr_t H5O_eliminate_gap(H5O_t *oh, H5O_mesg_t *mesg, + uint8_t *new_gap_loc, size_t new_gap_size); +static herr_t H5O_alloc_null(H5O_t *oh, unsigned null_idx, + const H5O_msg_class_t *new_type, void *new_native, size_t new_size); +static herr_t H5O_alloc_msgs(H5O_t *oh, size_t min_alloc); +static htri_t H5O_alloc_extend_chunk(H5F_t *f, H5O_t *oh, unsigned chunkno, + size_t size, unsigned * msg_idx); +static unsigned H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, + size_t size); +static htri_t H5O_move_msgs_forward(H5O_t *oh); +static htri_t H5O_merge_null(H5O_t *oh); +static htri_t H5O_remove_empty_chunks(H5F_t *f, H5O_t *oh, hid_t dxpl_id); + + +/*********************/ +/* Package Variables */ +/*********************/ + +/* Declare extern the free list for H5O_cont_t's */ +H5FL_EXTERN(H5O_cont_t); + + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + + +/*******************/ +/* Local Variables */ +/*******************/ + + + +/*------------------------------------------------------------------------- + * Function: H5O_add_gap + * + * Purpose: Add a gap to a chunk + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Oct 17 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_add_gap(H5O_t *oh, unsigned chunkno, unsigned idx, + uint8_t *new_gap_loc, size_t new_gap_size) +{ + hbool_t merged_with_null; /* Whether the gap was merged with a null message */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5O_add_gap) + + /* check args */ + HDassert(oh); + HDassert(oh->version > H5O_VERSION_1); + HDassert(new_gap_loc); + HDassert(new_gap_size); + + /* Check for existing null message in chunk */ + merged_with_null = FALSE; + for(u = 0; u < oh->nmesgs && !merged_with_null; u++) { + /* Find a null message in the chunk with the new gap */ + /* (a null message that's not the one we are eliminating) */ + if(H5O_NULL_ID == oh->mesg[u].type->id && oh->mesg[u].chunkno == chunkno + && u != idx) { + /* Sanity check - chunks with null messages shouldn't have a gap */ + HDassert(oh->chunk[chunkno].gap == 0); + + /* Eliminate the gap in the chunk */ + if(H5O_eliminate_gap(oh, &oh->mesg[u], new_gap_loc, new_gap_size) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't eliminate gap in chunk") + + /* Set flag to indicate that the gap was handled */ + merged_with_null = TRUE; + } /* end if */ + } /* end for */ + + /* If we couldn't find a null message in the chunk, move the gap to the end */ + if(!merged_with_null) { + /* Adjust message offsets after new gap forward in chunk */ + for(u = 0; u < oh->nmesgs; u++) + if(oh->mesg[u].chunkno == chunkno && oh->mesg[u].raw > new_gap_loc) + oh->mesg[u].raw -= new_gap_size; + + /* Slide raw message info forward in chunk image */ + HDmemmove(new_gap_loc, new_gap_loc + new_gap_size, + (size_t)((oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM_OH(oh))) - (new_gap_loc + new_gap_size))); + + /* Add existing gap size to new gap size */ + new_gap_size += oh->chunk[chunkno].gap; + + /* Merging with existing gap will allow for a new null message */ + if(new_gap_size >= (size_t)H5O_SIZEOF_MSGHDR_OH(oh)) { + H5O_mesg_t *null_msg; /* Pointer to new null message */ + + /* Check if we need to extend message table to hold the new null message */ + if(oh->nmesgs >= oh->alloc_nmesgs) + if(H5O_alloc_msgs(oh, (size_t)1) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "can't allocate more space for messages") + + /* Increment new gap size */ + oh->chunk[chunkno].gap += new_gap_size; + + /* Create new null message, with the tail of the previous null message */ + null_msg = &(oh->mesg[oh->nmesgs++]); + null_msg->type = H5O_MSG_NULL; + null_msg->dirty = TRUE; + null_msg->native = NULL; + null_msg->raw_size = new_gap_size - H5O_SIZEOF_MSGHDR_OH(oh); + null_msg->raw = (oh->chunk[chunkno].image + oh->chunk[chunkno].size) + - (H5O_SIZEOF_CHKSUM_OH(oh) + null_msg->raw_size); + null_msg->chunkno = chunkno; + + /* Zero out new null message's raw data */ + if(null_msg->raw_size) + HDmemset(null_msg->raw, 0, null_msg->raw_size); + + /* Reset size of gap in chunk */ + oh->chunk[chunkno].gap = 0; + } /* end if */ + else + oh->chunk[chunkno].gap = new_gap_size; + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5O_add_gap() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_eliminate_gap + * + * Purpose: Eliminate a gap in a chunk with a null message + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Oct 17 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_eliminate_gap(H5O_t *oh, H5O_mesg_t *mesg, uint8_t *gap_loc, size_t gap_size) +{ + uint8_t *move_start, *move_end; /* Pointers to area of messages to move */ + hbool_t null_before_gap; /* Flag whether the null message is before the gap or not */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_eliminate_gap) + + /* check args */ + HDassert(oh); + HDassert(oh->version > H5O_VERSION_1); + HDassert(mesg); + HDassert(gap_loc); + HDassert(gap_size); + + /* Check if the null message is before or after the gap produced */ + null_before_gap = (hbool_t)(mesg->raw < gap_loc); + + /* Set up information about region of messages to move */ + if(null_before_gap) { + move_start = mesg->raw + mesg->raw_size; + move_end = gap_loc; + } /* end if */ + else { + move_start = gap_loc + gap_size; + move_end = mesg->raw - H5O_SIZEOF_MSGHDR_OH(oh); + } /* end else */ + + /* Check for messages between null message and gap */ + if(move_end > move_start) { + unsigned u; /* Local index variable */ + + /* Look for messages that need to move, to adjust raw pointers in chunk */ + for(u = 0; u < oh->nmesgs; u++) { + uint8_t *msg_start; /* Start of encoded message in chunk */ + + msg_start = oh->mesg[u].raw - H5O_SIZEOF_MSGHDR_OH(oh); + if(oh->mesg[u].chunkno == mesg->chunkno + && (msg_start >= move_start && msg_start < move_end)) { + /* Move message's raw pointer in appropriate direction */ + if(null_before_gap) + oh->mesg[u].raw += gap_size; + else + oh->mesg[u].raw -= gap_size; + } /* end if */ + } /* end for */ + + /* Slide raw message info in chunk image */ + if(null_before_gap) + /* Slide messages down */ + HDmemmove(move_start + gap_size, move_start, (size_t)(move_end - move_start)); + else { + /* Slide messages up */ + HDmemmove(move_start - gap_size, move_start, (size_t)(move_end - move_start)); + + /* Adjust start of null message */ + mesg->raw -= gap_size; + } /* end else */ + } /* end if */ + + /* Zero out addition to null message */ + HDmemset(mesg->raw + mesg->raw_size, 0, gap_size); + + /* Adjust size of null message */ + mesg->raw_size += gap_size; + + /* Mark null message as dirty */ + mesg->dirty = TRUE; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5O_eliminate_gap() */ + + +/*------------------------------------------------------------------------- + * + * Function: H5O_alloc_null + * + * Purpose: Allocate room for a new message from a null message + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Oct 22 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_alloc_null(H5O_t *oh, unsigned null_idx, const H5O_msg_class_t *new_type, + void *new_native, size_t new_size) +{ + H5O_mesg_t *alloc_msg; /* Pointer to null message to allocate out of */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5O_alloc_null) + + /* check args */ + HDassert(oh); + HDassert(new_type); + HDassert(new_size); + + /* Point to null message to allocate out of */ + alloc_msg = &oh->mesg[null_idx]; + + /* Check if there's a need to split the null message */ + if(alloc_msg->raw_size > new_size) { + /* Check for producing a gap in the chunk */ + if((alloc_msg->raw_size - new_size) < (size_t)H5O_SIZEOF_MSGHDR_OH(oh)) { + size_t gap_size = alloc_msg->raw_size - new_size; /* Size of gap produced */ + + /* Adjust the size of the null message being eliminated */ + alloc_msg->raw_size = new_size; + + /* Add the gap to the chunk */ + if(H5O_add_gap(oh, alloc_msg->chunkno, null_idx, alloc_msg->raw + alloc_msg->raw_size, gap_size) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, UFAIL, "can't insert gap in chunk") + } /* end if */ + else { + size_t new_mesg_size = new_size + H5O_SIZEOF_MSGHDR_OH(oh); /* Total size of newly allocated message */ + H5O_mesg_t *null_msg; /* Pointer to new null message */ + + /* Check if we need to extend message table to hold the new null message */ + if(oh->nmesgs >= oh->alloc_nmesgs) { + if(H5O_alloc_msgs(oh, (size_t)1) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "can't allocate more space for messages") + + /* "Retarget" 'alloc_msg' pointer into newly re-allocated array of messages */ + alloc_msg = &oh->mesg[null_idx]; + } /* end if */ + + /* Create new null message, with the tail of the previous null message */ + null_msg = &(oh->mesg[oh->nmesgs++]); + null_msg->type = H5O_MSG_NULL; + null_msg->dirty = TRUE; + null_msg->native = NULL; + null_msg->raw = alloc_msg->raw + new_mesg_size; + null_msg->raw_size = alloc_msg->raw_size - new_mesg_size; + null_msg->chunkno = alloc_msg->chunkno; + + /* Check for gap in new null message's chunk */ + if(oh->chunk[null_msg->chunkno].gap > 0) { + unsigned null_chunkno = null_msg->chunkno; /* Chunk w/gap */ + + /* Eliminate the gap in the chunk */ + if(H5O_eliminate_gap(oh, null_msg, + ((oh->chunk[null_chunkno].image + oh->chunk[null_chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[null_chunkno].gap)), + oh->chunk[null_chunkno].gap) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTREMOVE, UFAIL, "can't eliminate gap in chunk") + + /* Set the gap size to zero for the chunk */ + oh->chunk[null_chunkno].gap = 0; + } /* end if */ + + /* Set the size of the new "real" message */ + alloc_msg->raw_size = new_size; + } /* end else */ + } /* end if */ + + /* Initialize the new message */ + alloc_msg->type = new_type; + alloc_msg->dirty = TRUE; + alloc_msg->native = new_native; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5O_alloc_null() */ + + +/*------------------------------------------------------------------------- + * + * Function: H5O_alloc_msgs + * + * Purpose: Allocate more messages for a header + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * Nov 21 2005 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_alloc_msgs(H5O_t *oh, size_t min_alloc) +{ + size_t old_alloc; /* Old number of messages allocated */ + size_t na; /* New number of messages allocated */ + H5O_mesg_t *new_mesg; /* Pointer to new message array */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5O_alloc_msgs) + + /* check args */ + HDassert(oh); + + /* Initialize number of messages information */ + old_alloc = oh->alloc_nmesgs; + na = oh->alloc_nmesgs + MAX(oh->alloc_nmesgs, min_alloc); + + /* Attempt to allocate more memory */ + if(NULL == (new_mesg = H5FL_SEQ_REALLOC(H5O_mesg_t, oh->mesg, na))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + + /* Update ohdr information */ + oh->alloc_nmesgs = na; + oh->mesg = new_mesg; + + /* Set new object header info to zeros */ + HDmemset(&oh->mesg[old_alloc], 0, (oh->alloc_nmesgs - old_alloc) * sizeof(H5O_mesg_t)); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5O_alloc_msgs() */ + + +/*------------------------------------------------------------------------- + * + * Function: H5O_alloc_extend_chunk + * + * Purpose: Attempt to extend a chunk that is allocated on disk. + * + * If the extension is successful, and if the last message + * of the chunk is the null message, then that message will + * be extended with the chunk. Otherwise a new null message + * is created. + * + * f is the file in which the chunk will be written. It is + * included to ensure that there is enough space to extend + * this chunk. + * + * Return: TRUE: The chunk has been extended, and *msg_idx + * contains the message index for null message + * which is large enough to hold size bytes. + * + * FALSE: The chunk cannot be extended, and *msg_idx + * is undefined. + * + * FAIL: Some internal error has been detected. + * + * Programmer: John Mainzer -- 8/16/05 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5O_alloc_extend_chunk(H5F_t *f, + H5O_t *oh, + unsigned chunkno, + size_t size, + unsigned * msg_idx) +{ + size_t delta; /* Change in chunk's size */ + size_t aligned_size = H5O_ALIGN_OH(oh, size); + uint8_t *old_image; /* Old address of chunk's image in memory */ + size_t old_size; /* Old size of chunk */ + htri_t tri_result; /* Result from checking if chunk can be extended */ + int extend_msg = -1;/* Index of null message to extend */ + unsigned u; /* Local index variable */ + htri_t ret_value = TRUE; /* return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5O_alloc_extend_chunk) + + /* check args */ + HDassert(f != NULL); + HDassert(oh != NULL); + HDassert(chunkno < oh->nchunks); + HDassert(size > 0); + HDassert(msg_idx != NULL); + HDassert(H5F_addr_defined(oh->chunk[chunkno].addr)); + + /* Test to see if the specified chunk ends with a null messages. + * If successful, set the index of the the null message in extend_msg. + */ + for(u = 0; u < oh->nmesgs; u++) { + /* Check for null message at end of proper chunk */ + /* (account for possible checksum at end of chunk) */ + if(oh->mesg[u].chunkno == chunkno && H5O_NULL_ID == oh->mesg[u].type->id && + ((oh->mesg[u].raw + oh->mesg[u].raw_size) + == ((oh->chunk[chunkno].image + oh->chunk[chunkno].size) - + (oh->chunk[chunkno].gap + H5O_SIZEOF_CHKSUM_OH(oh))))) { + + extend_msg = u; + break; + } /* end if */ + } /* end for */ + + /* If we can extend an existing null message, adjust the delta appropriately */ + if(extend_msg >= 0) { + HDassert(oh->chunk[chunkno].gap == 0); + delta = aligned_size - oh->mesg[extend_msg].raw_size; + } /* end if */ + else + delta = (aligned_size + H5O_SIZEOF_MSGHDR_OH(oh)) - oh->chunk[chunkno].gap; + delta = H5O_ALIGN_OH(oh, delta); + + /* Determine whether the chunk can be extended */ + tri_result = H5MF_can_extend(f, H5FD_MEM_OHDR, oh->chunk[chunkno].addr, + (hsize_t)(oh->chunk[chunkno].size), (hsize_t)delta); + if(tri_result == FALSE) /* can't extend -- we are done */ + HGOTO_DONE(FALSE) + else if(tri_result < 0) /* error */ + HGOTO_ERROR(H5E_RESOURCE, H5E_SYSTEM, FAIL, "can't tell if we can extend chunk") + + /* If we get this far, we should be able to extend the chunk */ + if(H5MF_extend(f, H5FD_MEM_OHDR, oh->chunk[chunkno].addr, (hsize_t)(oh->chunk[chunkno].size), (hsize_t)delta) < 0 ) + HGOTO_ERROR(H5E_RESOURCE, H5E_SYSTEM, FAIL, "can't extend chunk") + + /* If we can extend an existing null message, take care of that */ + if(extend_msg >= 0) { + /* Adjust message size of existing null message */ + oh->mesg[extend_msg].dirty = TRUE; + oh->mesg[extend_msg].raw_size += delta; + } /* end if */ + /* Create new null message for end of chunk */ + else { + /* Create a new null message */ + if(oh->nmesgs >= oh->alloc_nmesgs) + if(H5O_alloc_msgs(oh, (size_t)1) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages") + + /* Set extension message */ + extend_msg = oh->nmesgs++; + + /* Initialize new null message */ + oh->mesg[extend_msg].type = H5O_MSG_NULL; + oh->mesg[extend_msg].dirty = TRUE; + oh->mesg[extend_msg].native = NULL; + oh->mesg[extend_msg].raw = ((oh->chunk[chunkno].image + oh->chunk[chunkno].size) + - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[chunkno].gap)) + + H5O_SIZEOF_MSGHDR_OH(oh); + oh->mesg[extend_msg].raw_size = (delta + oh->chunk[chunkno].gap) - H5O_SIZEOF_MSGHDR_OH(oh); + oh->mesg[extend_msg].chunkno = chunkno; + } /* end else */ + + /* Allocate more memory space for chunk's image */ + old_image = oh->chunk[chunkno].image; + old_size = oh->chunk[chunkno].size; + oh->chunk[chunkno].size += delta; + oh->chunk[chunkno].image = H5FL_BLK_REALLOC(chunk_image, old_image, oh->chunk[chunkno].size); + oh->chunk[chunkno].gap = 0; + oh->chunk[chunkno].dirty = TRUE; + if(NULL == oh->chunk[chunkno].image) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + + /* Wipe new space for chunk */ + HDmemset(oh->chunk[chunkno].image + old_size, 0, oh->chunk[chunkno].size - old_size); + + /* Spin through existing messages, adjusting them */ + for(u = 0; u < oh->nmesgs; u++) { + /* Adjust raw addresses for messages in this chunk to reflect new 'image' address */ + if(oh->mesg[u].chunkno == chunkno) + oh->mesg[u].raw = oh->chunk[chunkno].image + (oh->mesg[u].raw - old_image); + + /* Find continuation message which points to this chunk and adjust chunk's size */ + /* (Chunk 0 doesn't have a continuation message that points to it and + * it's size is directly encoded in the object header) */ + if(chunkno > 0 && (H5O_CONT_ID == oh->mesg[u].type->id) && + (((H5O_cont_t *)(oh->mesg[u].native))->chunkno == chunkno)) { + /* Adjust size of continuation message */ + HDassert(((H5O_cont_t *)(oh->mesg[u].native))->size == old_size); + ((H5O_cont_t *)(oh->mesg[u].native))->size = oh->chunk[chunkno].size; + + /* Flag continuation message as dirty */ + oh->mesg[u].dirty = TRUE; + } /* end if */ + } /* end for */ + + /* Set return value */ + *msg_idx = extend_msg; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5O_alloc_extend_chunk() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_alloc_new_chunk + * + * Purpose: Allocates a new chunk for the object header, including + * file space. + * + * One of the other chunks will get an object continuation + * message. If there isn't room in any other chunk for the + * object continuation message, then some message from + * another chunk is moved into this chunk to make room. + * + * SIZE need not be aligned. + * + * Return: Success: Index number of the null message for the + * new chunk. The null message will be at + * least SIZE bytes not counting the message + * ID or size fields. + * + * Failure: Negative + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Aug 7 1997 + * + *------------------------------------------------------------------------- + */ +static unsigned +H5O_alloc_new_chunk(H5F_t *f, + hid_t dxpl_id, + H5O_t *oh, + size_t size) +{ + size_t cont_size; /*continuation message size */ + int found_null = (-1); /*best fit null message */ + int found_attr = (-1); /*best fit attribute message */ + int found_link = (-1); /*best fit link message */ + int found_other = (-1); /*best fit other message */ + unsigned idx; /*message number */ + uint8_t *p = NULL; /*ptr into new chunk */ + H5O_cont_t *cont = NULL; /*native continuation message */ + unsigned chunkno; /* Chunk allocated */ + haddr_t new_chunk_addr; + unsigned u; /* Local index variable */ + unsigned ret_value; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5O_alloc_new_chunk) + + /* check args */ + HDassert(oh); + HDassert(size > 0); + size = H5O_ALIGN_OH(oh, size); + + /* + * Find the smallest null message that will hold an object + * continuation message. Failing that, find the smallest message + * that could be moved to make room for the continuation message. + * + * Don't ever move continuation message from one chunk to another. + * Prioritize link messages moving to later chunks, instead of + * more "important" messages. + * Avoid moving attributes when possible to preserve their + * ordering (although ordering is *not* guaranteed!). + * + */ + cont_size = H5O_ALIGN_OH(oh, H5F_SIZEOF_ADDR(f) + H5F_SIZEOF_SIZE(f)); + for(u = 0; u < oh->nmesgs; u++) { + int msg_id = oh->mesg[u].type->id; /* Temp. copy of message type ID */ + + if(H5O_NULL_ID == msg_id) { + if(cont_size == oh->mesg[u].raw_size) { + found_null = u; + break; + } else if(oh->mesg[u].raw_size >= cont_size && + (found_null < 0 || + oh->mesg[u].raw_size < oh->mesg[found_null].raw_size)) { + found_null = u; + } + } else if(H5O_CONT_ID == msg_id) { + /*don't consider continuation messages */ + } else if(H5O_ATTR_ID == msg_id) { + if(oh->mesg[u].raw_size >= cont_size && + (found_attr < 0 || + oh->mesg[u].raw_size < oh->mesg[found_attr].raw_size)) + found_attr = u; + } else if(H5O_LINK_ID == msg_id) { + if(oh->mesg[u].raw_size >= cont_size && + (found_link < 0 || + oh->mesg[u].raw_size < oh->mesg[found_link].raw_size)) + found_link = u; + } else { + if(oh->mesg[u].raw_size >= cont_size && + (found_other < 0 || + oh->mesg[u].raw_size < oh->mesg[found_other].raw_size)) + found_other = u; + } /* end else */ + } /* end for */ + HDassert(found_null >= 0 || found_attr >= 0 || found_link >= 0 || found_other >= 0); + + /* + * If we must move some other message to make room for the null + * message, then make sure the new chunk has enough room for that + * other message. + * + * Move link messages first, then other messages, and attributes + * only as a last resort. + * + */ + if(found_null < 0) { + if(found_link >= 0) + found_other = found_link; + + if(found_other < 0) + found_other = found_attr; + + HDassert(found_other >= 0); + size += H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other].raw_size; + } /* end if */ + + /* + * The total chunk size must include enough space for the checksum + * on the chunk and the continuation chunk magic #. (which are only present + * in later versions of the object header) + */ + size += H5O_SIZEOF_CHKHDR_OH(oh); + + /* + * The total chunk size must include the requested space plus enough + * for the message header. This must be at least some minimum and a + * multiple of the alignment size. + */ + size = MAX(H5O_MIN_SIZE, size + H5O_SIZEOF_MSGHDR_OH(oh)); + HDassert(size == H5O_ALIGN_OH(oh, size)); + + /* allocate space in file to hold the new chunk */ + new_chunk_addr = H5MF_alloc(f, H5FD_MEM_OHDR, dxpl_id, (hsize_t)size); + if(HADDR_UNDEF == new_chunk_addr) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "unable to allocate space for new chunk") + + /* + * Create the new chunk giving it a file address. + */ + if(oh->nchunks >= oh->alloc_nchunks) { + unsigned na = MAX(H5O_NCHUNKS, oh->alloc_nchunks * 2); /* Double # of chunks allocated */ + H5O_chunk_t *x = H5FL_SEQ_REALLOC(H5O_chunk_t, oh->chunk, (size_t)na); + + if(!x) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed") + oh->alloc_nchunks = na; + oh->chunk = x; + } /* end if */ + + chunkno = oh->nchunks++; + oh->chunk[chunkno].dirty = TRUE; + oh->chunk[chunkno].addr = new_chunk_addr; + oh->chunk[chunkno].size = size; + oh->chunk[chunkno].gap = 0; + if(NULL == (oh->chunk[chunkno].image = p = H5FL_BLK_CALLOC(chunk_image, size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed") + + /* If this is a later version of the object header format, put the magic + * # at the beginning of the chunk image. + */ + if(oh->version > H5O_VERSION_1) { + HDmemcpy(p, H5O_CHK_MAGIC, (size_t)H5O_SIZEOF_MAGIC); + p += H5O_SIZEOF_MAGIC; + } /* end if */ + + /* + * Make sure we have enough space for all possible new messages + * that could be generated below. + */ + if(oh->nmesgs + 3 > oh->alloc_nmesgs) + if(H5O_alloc_msgs(oh, (size_t)3) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "can't allocate more space for messages") + + /* Move message (that will be replaced with continuation message) + * to new chunk, if necessary. + */ + if(found_null < 0) { + H5O_mesg_t *null_msg; /* Pointer to new null message */ + + /* Create null message for space that message to copy currently occupies */ + found_null = oh->nmesgs++; + null_msg = &(oh->mesg[found_null]); + null_msg->type = H5O_MSG_NULL; + null_msg->dirty = TRUE; + null_msg->native = NULL; + null_msg->raw = oh->mesg[found_other].raw; + null_msg->raw_size = oh->mesg[found_other].raw_size; + null_msg->chunkno = oh->mesg[found_other].chunkno; + + /* Copy the message to move to its new location */ + /* (Chunk is already dirty, no need to mark it) */ + HDmemcpy(p, oh->mesg[found_other].raw - H5O_SIZEOF_MSGHDR_OH(oh), + oh->mesg[found_other].raw_size + H5O_SIZEOF_MSGHDR_OH(oh)); + + /* Switch message to point to new location */ + oh->mesg[found_other].raw = p + H5O_SIZEOF_MSGHDR_OH(oh); + oh->mesg[found_other].chunkno = chunkno; + + /* Account for copied message in new chunk */ + p += H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other].raw_size; + size -= H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other].raw_size; + } /* end if */ + HDassert(found_null >= 0); + + /* Create null message for [rest of] space in new chunk */ + /* (account for chunk's magic # & checksum) */ + idx = oh->nmesgs++; + oh->mesg[idx].type = H5O_MSG_NULL; + oh->mesg[idx].dirty = TRUE; + oh->mesg[idx].native = NULL; + oh->mesg[idx].raw = p + H5O_SIZEOF_MSGHDR_OH(oh); + oh->mesg[idx].raw_size = size - + (H5O_SIZEOF_CHKHDR_OH(oh) + H5O_SIZEOF_MSGHDR_OH(oh)); + oh->mesg[idx].chunkno = chunkno; + + /* Initialize the continuation information */ + if(NULL == (cont = H5FL_MALLOC(H5O_cont_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed") + cont->addr = oh->chunk[chunkno].addr; + cont->size = oh->chunk[chunkno].size; + cont->chunkno = chunkno; + + /* Split the null message and point at continuation message */ + if(H5O_alloc_null(oh, (unsigned)found_null, H5O_MSG_CONT, cont, cont_size) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, UFAIL, "can't split null message") + + /* Set return value */ + ret_value = idx; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5O_alloc_new_chunk() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_alloc + * + * Purpose: Allocate enough space in the object header for this message. + * + * Return: Success: Index of message + * + * Failure: Negative + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Aug 6 1997 + * + *------------------------------------------------------------------------- + */ +unsigned +H5O_alloc(H5F_t *f, + hid_t dxpl_id, + H5O_t *oh, + const H5O_msg_class_t *type, + size_t size, + unsigned * oh_flags_ptr) +{ + size_t aligned_size = H5O_ALIGN_OH(oh, size); + unsigned idx; /* Index of message which fits allocation */ + unsigned ret_value; /* Return value */ + + FUNC_ENTER_NOAPI(H5O_alloc, UFAIL) + + /* check args */ + HDassert(oh); + HDassert(type); + HDassert(oh_flags_ptr); + + /* look for a null message which is large enough */ + for(idx = 0; idx < oh->nmesgs; idx++) + if(H5O_NULL_ID == oh->mesg[idx].type->id && oh->mesg[idx].raw_size >= aligned_size) + break; + + /* if we didn't find one, then allocate more header space */ + if(idx >= oh->nmesgs) { + unsigned chunkno; + + /* check to see if we can extend one of the chunks. If we can, + * do so. Otherwise, we will have to allocate a new chunk. + * + * Note that in this new version of this function, all chunks + * must have file space allocated to them. + */ + for(chunkno = 0; chunkno < oh->nchunks; chunkno++) { + htri_t tri_result; + + HDassert(H5F_addr_defined(oh->chunk[chunkno].addr)); + + tri_result = H5O_alloc_extend_chunk(f, oh, chunkno, size, &idx); + if(tri_result == TRUE) + break; + else if(tri_result == FALSE) + idx = UFAIL; + else + HGOTO_ERROR(H5E_OHDR, H5E_SYSTEM, UFAIL, "H5O_alloc_extend_chunk failed unexpectedly") + } /* end for */ + + /* If idx is still UFAIL, we were not able to extend a chunk, + * create a new one. + */ + if(idx == UFAIL) + if((idx = H5O_alloc_new_chunk(f, dxpl_id, oh, size)) == UFAIL) + HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, UFAIL, "unable to create a new object header data chunk") + } /* end if */ + + /* Split the null message and point at continuation message */ + if(H5O_alloc_null(oh, idx, type, NULL, aligned_size) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, UFAIL, "can't split null message") + + /* Mark the object header as modified */ + *oh_flags_ptr |= H5AC__DIRTIED_FLAG; + +#ifdef H5O_DEBUG +H5O_assert(oh); +#endif /* H5O_DEBUG */ + /* Set return value */ + ret_value = idx; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5O_alloc() */ + + +/*------------------------------------------------------------------------- + * + * Function: H5O_release_mesg + * + * Purpose: Convert a message into a null message + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Oct 22 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5O_release_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5O_mesg_t *mesg, + hbool_t delete_mesg, hbool_t adj_link) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5O_release_mesg, FAIL) + + /* check args */ + HDassert(f); + HDassert(oh); + HDassert(mesg); + + /* Check if we should operate on the message */ + if(delete_mesg) { + /* Free any space referred to in the file from this message */ + if(H5O_delete_mesg(f, dxpl_id, mesg, adj_link) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to delete file space for object header message") + + /* Free any native information */ + H5O_free_mesg(mesg); + } /* end if */ + + /* Change message type to nil and zero it */ + mesg->type = H5O_MSG_NULL; + HDassert(mesg->raw + mesg->raw_size <= (oh->chunk[mesg->chunkno].image + oh->chunk[mesg->chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[mesg->chunkno].gap)); + HDmemset(mesg->raw, 0, mesg->raw_size); + + /* Clear message flags */ + mesg->flags = 0; + + /* Indicate that the message was modified */ + mesg->dirty = TRUE; + + /* Check if chunk has a gap currently */ + if(oh->chunk[mesg->chunkno].gap) { + /* Eliminate the gap in the chunk */ + if(H5O_eliminate_gap(oh, mesg, + ((oh->chunk[mesg->chunkno].image + oh->chunk[mesg->chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[mesg->chunkno].gap)), + oh->chunk[mesg->chunkno].gap) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTREMOVE, FAIL, "can't eliminate gap in chunk") + + /* Set the gap size to zero for the chunk */ + oh->chunk[mesg->chunkno].gap = 0; + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5O_release_mesg() */ + + +/*------------------------------------------------------------------------- + * + * Function: H5O_move_msgs_forward + * + * Purpose: Move messages toward first chunk + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * Oct 17 2005 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5O_move_msgs_forward(H5O_t *oh) +{ + hbool_t packed_msg; /* Flag to indicate that messages were packed */ + hbool_t did_packing = FALSE; /* Whether any messages were packed */ + htri_t ret_value; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5O_move_msgs_forward) + + /* check args */ + HDassert(oh); + + /* Loop until no messages packed */ + /* (Double loop is not very efficient, but it would be some extra work to + * add a list of messages to each chunk -QAK) + */ + do { + H5O_mesg_t *curr_msg; /* Pointer to current message to operate on */ + unsigned u; /* Local index variable */ + + /* Reset packed messages flag */ + packed_msg = FALSE; + + /* Scan through messages for messages that can be moved earlier in chunks */ + for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) { + if(H5O_NULL_ID == curr_msg->type->id) { + H5O_chunk_t *chunk; /* Pointer to chunk that null message is in */ + + /* Check if null message is not last in chunk */ + chunk = &(oh->chunk[curr_msg->chunkno]); + if((curr_msg->raw + curr_msg->raw_size) + != ((chunk->image + chunk->size) - (H5O_SIZEOF_CHKSUM_OH(oh) + chunk->gap))) { + H5O_mesg_t *nonnull_msg; /* Pointer to current message to operate on */ + unsigned v; /* Local index variable */ + + /* Loop over messages again, looking for the message in the chunk after the null message */ + for(v = 0, nonnull_msg = &oh->mesg[0]; v < oh->nmesgs; v++, nonnull_msg++) { + /* Locate message that is immediately after the null message */ + if((curr_msg->chunkno == nonnull_msg->chunkno) && + ((curr_msg->raw + curr_msg->raw_size) == (nonnull_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh)))) { + /* Don't swap messages if the second message is also a null message */ + /* (We'll merge them together later, in another routine) */ + if(H5O_NULL_ID != nonnull_msg->type->id) { + /* Copy raw data for non-null message to new location */ + HDmemmove(curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), + nonnull_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), nonnull_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh)); + + /* Adjust non-null message's offset in chunk */ + nonnull_msg->raw = curr_msg->raw; + + /* Adjust null message's offset in chunk */ + curr_msg->raw = nonnull_msg->raw + + nonnull_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh); + + /* Mark null message dirty */ + /* (since we need to re-encode its message header) */ + /* (also, marking this message dirty means we + * don't have to mark chunk as dirty) + */ + curr_msg->dirty = TRUE; + + /* Set the flag to indicate that the null message + * was packed - if its not at the end its chunk, + * we'll move it again on the next pass. + */ + packed_msg = TRUE; + } /* end if */ + + /* Break out of loop */ + break; + } /* end if */ + } /* end for */ + /* Should have been message after null message */ + HDassert(v < oh->nmesgs); + } /* end if */ + } /* end if */ + else { + H5O_mesg_t *null_msg; /* Pointer to current message to operate on */ + unsigned v; /* Local index variable */ + + /* Loop over messages again, looking for large enough null message in earlier chunk */ + for(v = 0, null_msg = &oh->mesg[0]; v < oh->nmesgs; v++, null_msg++) { + if(H5O_NULL_ID == null_msg->type->id && curr_msg->chunkno > null_msg->chunkno + && curr_msg->raw_size <= null_msg->raw_size) { + unsigned old_chunkno; /* Old message information */ + uint8_t *old_raw; + + /* Keep old information about non-null message */ + old_chunkno = curr_msg->chunkno; + old_raw = curr_msg->raw; + + /* Copy raw data for non-null message to new chunk */ + HDmemcpy(null_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), curr_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh)); + + /* Mark null message's chunk as dirty, since the raw data image changed */ + oh->chunk[null_msg->chunkno].dirty = TRUE; + + /* Point non-null message at null message's space */ + curr_msg->chunkno = null_msg->chunkno; + curr_msg->raw = null_msg->raw; + + /* Change information for null message */ + if(curr_msg->raw_size == null_msg->raw_size) { + /* Point null message at old non-null space */ + /* (Instead of freeing it and allocating new message) */ + null_msg->chunkno = old_chunkno; + null_msg->raw = old_raw; + + /* Mark null message dirty */ + null_msg->dirty = TRUE; + } /* end if */ + else { + unsigned new_null_msg; /* Message index for new null message */ + + /* Check if null message is large enough to still exist */ + if((null_msg->raw_size - curr_msg->raw_size) < (size_t)H5O_SIZEOF_MSGHDR_OH(oh)) { + size_t gap_size = null_msg->raw_size - curr_msg->raw_size; /* Size of gap produced */ + + /* Adjust the size of the null message being eliminated */ + null_msg->raw_size = curr_msg->raw_size; + + /* Add the gap to the chunk */ + if(H5O_add_gap(oh, null_msg->chunkno, v, null_msg->raw + null_msg->raw_size, gap_size) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert gap in chunk") + + /* Re-use message # for new null message taking place of non-null message */ + new_null_msg = v; + } /* end if */ + else { + /* Adjust null message's size & offset */ + null_msg->raw += curr_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh); + null_msg->raw_size -= curr_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh); + + /* Mark null message dirty */ + null_msg->dirty = TRUE; + + /* Create new null message for previous location of non-null message */ + if(oh->nmesgs >= oh->alloc_nmesgs) { + if(H5O_alloc_msgs(oh, (size_t)1) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages") + + /* "Retarget" 'curr_msg' pointer into newly re-allocated array of messages */ + curr_msg = &oh->mesg[u]; + } /* end if */ + + /* Get message # for new null message */ + new_null_msg = oh->nmesgs++; + } /* end else */ + + /* Initialize new null message to take over non-null message's location */ + oh->mesg[new_null_msg].type = H5O_MSG_NULL; + oh->mesg[new_null_msg].dirty = TRUE; + oh->mesg[new_null_msg].native = NULL; + oh->mesg[new_null_msg].raw = old_raw; + oh->mesg[new_null_msg].raw_size = curr_msg->raw_size; + oh->mesg[new_null_msg].chunkno = old_chunkno; + + /* Check for gap in new null message's chunk */ + if(oh->chunk[old_chunkno].gap > 0) { + /* Eliminate the gap in the chunk */ + if(H5O_eliminate_gap(oh, &oh->mesg[new_null_msg], + ((oh->chunk[old_chunkno].image + oh->chunk[old_chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[old_chunkno].gap)), + oh->chunk[old_chunkno].gap) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTREMOVE, FAIL, "can't eliminate gap in chunk") + + /* Set the gap size to zero for the chunk */ + oh->chunk[old_chunkno].gap = 0; + } /* end if */ + } /* end else */ + + /* Indicate that we packed messages */ + packed_msg = TRUE; + + /* Break out of loop */ + /* (If it's possible to move message to even earlier chunk + * we'll get it on the next pass - QAK) + */ + break; + } /* end if */ + } /* end for */ + + /* If we packed messages, get out of loop and start over */ + /* (Don't know if this has any benefit one way or the other -QAK) */ + if(packed_msg) + break; + } /* end else */ + } /* end for */ + + /* If we did any packing, remember that */ + if(packed_msg) + did_packing = TRUE; + } while(packed_msg); + + /* Set return value */ + ret_value = did_packing; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5O_move_msgs_forward() */ + + +/*------------------------------------------------------------------------- + * + * Function: H5O_merge_null + * + * Purpose: Merge neighboring null messages in an object header + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * Oct 10 2005 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5O_merge_null(H5O_t *oh) +{ + hbool_t merged_msg; /* Flag to indicate that messages were merged */ + hbool_t did_merging = FALSE; /* Whether any messages were merged */ + htri_t ret_value; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_merge_null) + + /* check args */ + HDassert(oh != NULL); + + /* Loop until no messages merged */ + /* (Double loop is not very efficient, but it would be some extra work to add + * a list of messages to each chunk -QAK) + */ + do { + H5O_mesg_t *curr_msg; /* Pointer to current message to operate on */ + unsigned u; /* Local index variable */ + + /* Reset merged messages flag */ + merged_msg = FALSE; + + /* Scan messages for adjacent null messages & merge them */ + for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) { + if(H5O_NULL_ID == curr_msg->type->id) { + H5O_mesg_t *curr_msg2; /* Pointer to current message to operate on */ + unsigned v; /* Local index variable */ + + /* Should be no gaps in chunk with null message */ + HDassert(oh->chunk[curr_msg->chunkno].gap == 0); + + /* Loop over messages again, looking for null message in same chunk */ + for(v = 0, curr_msg2 = &oh->mesg[0]; v < oh->nmesgs; v++, curr_msg2++) { + if(u != v && H5O_NULL_ID == curr_msg2->type->id && curr_msg->chunkno == curr_msg2->chunkno) { + + /* Check for second message after first message */ + if((curr_msg->raw + curr_msg->raw_size) == (curr_msg2->raw - H5O_SIZEOF_MSGHDR_OH(oh))) { + /* Extend first null message length to cover second null message */ + curr_msg->raw_size += (H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg2->raw_size); + + /* Message has been merged */ + merged_msg = TRUE; + } /* end if */ + /* Check for second message before first message */ + else if((curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh)) == (curr_msg2->raw + curr_msg2->raw_size)) { + /* Adjust first message address and extend length to cover second message */ + curr_msg->raw -= (H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg2->raw_size); + curr_msg->raw_size += (H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg2->raw_size); + + /* Message has been merged */ + merged_msg = TRUE; + } /* end if */ + + /* Second message has been merged, delete it */ + if(merged_msg) { + /* Release any information/memory for second message */ + H5O_free_mesg(curr_msg2); + + /* Mark first message as dirty */ + curr_msg->dirty = TRUE; + + /* Remove second message from list of messages */ + if(v < (oh->nmesgs - 1)) + HDmemmove(&oh->mesg[v], &oh->mesg[v + 1], ((oh->nmesgs - 1) - v) * sizeof(H5O_mesg_t)); + + /* Decrement # of messages */ + /* (Don't bother reducing size of message array for now -QAK) */ + oh->nmesgs--; + + /* Get out of loop */ + break; + } /* end if */ + } /* end if */ + } /* end for */ + + /* Get out of loop if we merged messages */ + if(merged_msg) + break; + } /* end if */ + } /* end for */ + + /* If we did any merging, remember that */ + if(merged_msg) + did_merging = TRUE; + } while(merged_msg); + + /* Set return value */ + ret_value = did_merging; + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5O_merge_null() */ + + +/*------------------------------------------------------------------------- + * + * Function: H5O_remove_empty_chunks + * + * Purpose: Attempt to eliminate empty chunks from object header. + * + * This examines a chunk to see if it's empty + * and removes it (and the continuation message that points to it) + * from the object header. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * Oct 17 2005 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5O_remove_empty_chunks(H5F_t *f, H5O_t *oh, hid_t dxpl_id) +{ + hbool_t deleted_chunk; /* Whether to a chunk was deleted */ + hbool_t did_deleting = FALSE; /* Whether any chunks were deleted */ + htri_t ret_value; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5O_remove_empty_chunks) + + /* check args */ + HDassert(oh != NULL); + + /* Loop until no chunks are freed */ + do { + H5O_mesg_t *null_msg; /* Pointer to null message found */ + H5O_mesg_t *cont_msg; /* Pointer to continuation message found */ + unsigned u, v; /* Local index variables */ + + /* Reset 'chunk deleted' flag */ + deleted_chunk = FALSE; + + /* Scan messages for null messages that fill an entire chunk */ + for(u = 0, null_msg = &oh->mesg[0]; u < oh->nmesgs; u++, null_msg++) { + /* If a null message takes up an entire object header chunk (and + * its not the "base" chunk), delete that chunk from object header + */ + if(H5O_NULL_ID == null_msg->type->id && null_msg->chunkno > 0 && + (H5O_SIZEOF_MSGHDR_OH(oh) + null_msg->raw_size) + == (oh->chunk[null_msg->chunkno].size - H5O_SIZEOF_CHKHDR_OH(oh))) { + H5O_mesg_t *curr_msg; /* Pointer to current message to operate on */ + unsigned null_msg_no; /* Message # for null message */ + unsigned deleted_chunkno; /* Chunk # to delete */ + + /* Locate continuation message that points to chunk */ + for(v = 0, cont_msg = &oh->mesg[0]; v < oh->nmesgs; v++, cont_msg++) { + if(H5O_CONT_ID == cont_msg->type->id) { + /* Decode current continuation message if necessary */ + if(NULL == cont_msg->native) { + HDassert(H5O_MSG_CONT->decode); + cont_msg->native = (H5O_MSG_CONT->decode)(f, dxpl_id, cont_msg->raw); + if(NULL == cont_msg->native) + HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "unable to decode message") + } /* end if */ + + /* Check for correct chunk to delete */ + if(oh->chunk[null_msg->chunkno].addr == ((H5O_cont_t *)(cont_msg->native))->addr) + break; + } /* end if */ + } /* end for */ + /* Must be a continuation message that points to chunk containing null message */ + HDassert(v < oh->nmesgs); + HDassert(cont_msg); + + /* Initialize information about null message */ + null_msg_no = u; + deleted_chunkno = null_msg->chunkno; + + /* Convert continuation message into a null message */ + if(H5O_release_mesg(f, dxpl_id, oh, cont_msg, TRUE, TRUE) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to convert into null message") + + /* + * Remove chunk from object header's data structure + */ + + /* Free memory for chunk image */ + H5FL_BLK_FREE(chunk_image, oh->chunk[null_msg->chunkno].image); + + /* Remove chunk from list of chunks */ + if(null_msg->chunkno < (oh->nchunks - 1)) + HDmemmove(&oh->chunk[null_msg->chunkno], &oh->chunk[null_msg->chunkno + 1], ((oh->nchunks - 1) - null_msg->chunkno) * sizeof(H5O_chunk_t)); + + /* Decrement # of chunks */ + /* (Don't bother reducing size of chunk array for now -QAK) */ + oh->nchunks--; + + /* + * Delete null message (in empty chunk that was be freed) from list of messages + */ + + /* Release any information/memory for message */ + H5O_free_mesg(null_msg); + + /* Remove null message from list of messages */ + if(null_msg_no < (oh->nmesgs - 1)) + HDmemmove(&oh->mesg[null_msg_no], &oh->mesg[null_msg_no + 1], ((oh->nmesgs - 1) - null_msg_no) * sizeof(H5O_mesg_t)); + + /* Decrement # of messages */ + /* (Don't bother reducing size of message array for now -QAK) */ + oh->nmesgs--; + + /* Adjust chunk # for messages in chunks after deleted chunk */ + for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) { + HDassert(curr_msg->chunkno != deleted_chunkno); + if(curr_msg->chunkno > deleted_chunkno) + curr_msg->chunkno--; + } /* end for */ + + /* Found chunk to delete */ + deleted_chunk = TRUE; + break; + } /* end if */ + } /* end for */ + + /* If we deleted any chunks, remember that */ + if(deleted_chunk) + did_deleting = TRUE; + } while(deleted_chunk); + + /* Set return value */ + ret_value = did_deleting; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5O_remove_empty_chunks() */ + + +/*------------------------------------------------------------------------- + * + * Function: H5O_condense_header + * + * Purpose: Attempt to eliminate empty chunks from object header. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * Oct 4 2005 + * + *------------------------------------------------------------------------- + */ +herr_t +H5O_condense_header(H5F_t *f, H5O_t *oh, hid_t dxpl_id) +{ + hbool_t rescan_header; /* Whether to rescan header */ + htri_t result; /* Result from packing/merging/etc */ + herr_t ret_value = SUCCEED; /* return value */ + + FUNC_ENTER_NOAPI(H5O_condense_header, FAIL) + + /* check args */ + HDassert(oh != NULL); + + /* Loop until no changed to the object header messages & chunks */ + do { + /* Reset 'rescan chunks' flag */ + rescan_header = FALSE; + + /* Scan for messages that can be moved earlier in chunks */ + result = H5O_move_msgs_forward(oh); + if(result < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "can't move header messages forward") + if(result > 0) + rescan_header = TRUE; + + /* Scan for adjacent null messages & merge them */ + result = H5O_merge_null(oh); + if(result < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "can't pack null header messages") + if(result > 0) + rescan_header = TRUE; + + /* Scan for empty chunks to remove */ + result = H5O_remove_empty_chunks(f, oh, dxpl_id); + if(result < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "can't remove empty chunk") + if(result > 0) + rescan_header = TRUE; + } while(rescan_header); +#ifdef H5O_DEBUG +H5O_assert(oh); +#endif /* H5O_DEBUG */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5O_condense_header() */ + diff --git a/src/H5Odbg.c b/src/H5Odbg.c new file mode 100644 index 0000000..72c6d93 --- /dev/null +++ b/src/H5Odbg.c @@ -0,0 +1,417 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*------------------------------------------------------------------------- + * + * Created: H5Odbg.c + * Nov 17 2006 + * Quincey Koziol <koziol@hdfgroup.org> + * + * Purpose: Object header debugging routines. + * + *------------------------------------------------------------------------- + */ + +/****************/ +/* Module Setup */ +/****************/ + +#define H5O_PACKAGE /*suppress error about including H5Opkg */ + +/***********/ +/* Headers */ +/***********/ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5MMprivate.h" /* Memory management */ +#include "H5Opkg.h" /* Object headers */ + +/****************/ +/* Local Macros */ +/****************/ + + +/******************/ +/* Local Typedefs */ +/******************/ + + +/********************/ +/* Package Typedefs */ +/********************/ + + +/********************/ +/* Local Prototypes */ +/********************/ + + +/*********************/ +/* Package Variables */ +/*********************/ + + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + + +/*******************/ +/* Local Variables */ +/*******************/ + + +#ifdef H5O_DEBUG + +/*------------------------------------------------------------------------- + * Function: H5O_assert + * + * Purpose: Sanity check the information for an object header data + * structure. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Oct 17 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5O_assert(const H5O_t *oh) +{ + H5O_mesg_t *curr_msg; /* Pointer to current message to examine */ + H5O_mesg_t *tmp_msg; /* Pointer to temporary message to examine */ + unsigned u, v; /* Local index variables */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_assert) + + /* Loop over all chunks in object header */ + for(u = 0; u < oh->nchunks; u++) { + /* Check for valid raw data image */ + HDassert(oh->chunk[u].image); + HDassert(oh->chunk[u].size > (size_t)H5O_SIZEOF_CHKHDR_OH(oh)); + + /* All chunks must be allocated on disk */ + HDassert(H5F_addr_defined(oh->chunk[u].addr)); + + /* Version specific checks */ + if(oh->version > H5O_VERSION_1) { + /* Make certain that the magic number is correct for each chunk */ + HDassert(!HDmemcmp(oh->chunk[u].image, (u == 0 ? H5O_HDR_MAGIC : H5O_CHK_MAGIC), H5O_SIZEOF_MAGIC)); + + /* Check for valid gap size */ + HDassert(oh->chunk[u].gap < (size_t)H5O_SIZEOF_MSGHDR_OH(oh)); + } /* end if */ + else + /* Gaps should never occur in version 1 of the format */ + HDassert(oh->chunk[u].gap == 0); + } /* end for */ + + /* Loop over all messages in object header */ + for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) { + /* Make certain that the message is in a valid chunk */ + HDassert(curr_msg->chunkno < oh->nchunks); + + /* Make certain null messages aren't in chunks with gaps */ + if(H5O_NULL_ID == curr_msg->type->id) + HDassert(oh->chunk[curr_msg->chunkno].gap == 0); + + /* Make certain that the message is completely in a chunk message area */ + HDassert(curr_msg->raw_size <= (oh->chunk[curr_msg->chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[curr_msg->chunkno].gap)); + if(curr_msg->chunkno == 0) + HDassert(curr_msg->raw >= oh->chunk[curr_msg->chunkno].image + (H5O_SIZEOF_HDR_OH(oh) - H5O_SIZEOF_CHKSUM_OH(oh))); + else + HDassert(curr_msg->raw >= oh->chunk[curr_msg->chunkno].image + (H5O_SIZEOF_CHKHDR_OH(oh) - H5O_SIZEOF_CHKSUM_OH(oh))); + HDassert(curr_msg->raw + curr_msg->raw_size <= (oh->chunk[curr_msg->chunkno].image + oh->chunk[curr_msg->chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[curr_msg->chunkno].gap)); + + /* Make certain that no other messages overlap this message */ + for(v = 0, tmp_msg = &oh->mesg[0]; v < oh->nmesgs; v++, tmp_msg++) { + if(u != v) + HDassert(!(tmp_msg->raw >= curr_msg->raw && tmp_msg->raw < (curr_msg->raw + curr_msg->raw_size))); + } /* end for */ + } /* end for */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5O_assert() */ +#endif /* H5O_DEBUG */ + + +/*------------------------------------------------------------------------- + * Function: H5O_debug_id + * + * Purpose: Act as a proxy for calling the 'debug' method for a + * particular class of object header. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * Feb 13 2003 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5O_debug_id(unsigned type_id, H5F_t *f, hid_t dxpl_id, const void *mesg, FILE *stream, int indent, int fwidth) +{ + const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ + herr_t ret_value; /* Return value */ + + FUNC_ENTER_NOAPI(H5O_debug_id,FAIL) + + /* Check args */ + HDassert(type_id < NELMTS(H5O_msg_class_g)); + type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ + HDassert(type); + HDassert(type->debug); + HDassert(f); + HDassert(mesg); + HDassert(stream); + HDassert(indent >= 0); + HDassert(fwidth >= 0); + + /* Call the debug method in the class */ + if((ret_value = (type->debug)(f, dxpl_id, mesg, stream, indent, fwidth)) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_BADTYPE, FAIL, "unable to debug message") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_debug_id() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_debug_real + * + * Purpose: Prints debugging info about an object header. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Aug 6 1997 + * + *------------------------------------------------------------------------- + */ +herr_t +H5O_debug_real(H5F_t *f, hid_t dxpl_id, H5O_t *oh, haddr_t addr, FILE *stream, int indent, int fwidth) +{ + unsigned i, chunkno; + size_t mesg_total = 0, chunk_total = 0; + int *sequence; + void *(*decode)(H5F_t*, hid_t, const uint8_t*); + herr_t (*debug)(H5F_t*, hid_t, const void*, FILE*, int, int)=NULL; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5O_debug_real, FAIL) + + /* check args */ + HDassert(f); + HDassert(oh); + HDassert(H5F_addr_defined(addr)); + HDassert(stream); + HDassert(indent >= 0); + HDassert(fwidth >= 0); + + /* debug */ + HDfprintf(stream, "%*sObject Header...\n", indent, ""); + + HDfprintf(stream, "%*s%-*s %t\n", indent, "", fwidth, + "Dirty:", + oh->cache_info.is_dirty); + HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth, + "Version:", + oh->version); + HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth, + "Header size (in bytes):", + (unsigned)H5O_SIZEOF_HDR_OH(oh)); + HDfprintf(stream, "%*s%-*s %d\n", indent, "", fwidth, + "Number of links:", + oh->nlink); + HDfprintf(stream, "%*s%-*s %Zu (%Zu)\n", indent, "", fwidth, + "Number of messages (allocated):", + oh->nmesgs, oh->alloc_nmesgs); + HDfprintf(stream, "%*s%-*s %Zu (%Zu)\n", indent, "", fwidth, + "Number of chunks (allocated):", + oh->nchunks, oh->alloc_nchunks); + + /* debug each chunk */ + for(i = 0, chunk_total = 0; i < oh->nchunks; i++) { + size_t chunk_size; + + chunk_total += oh->chunk[i].size; + HDfprintf(stream, "%*sChunk %d...\n", indent, "", i); + + HDfprintf(stream, "%*s%-*s %t\n", indent + 3, "", MAX(0, fwidth - 3), + "Dirty:", + oh->chunk[i].dirty); + + HDfprintf(stream, "%*s%-*s %a\n", indent + 3, "", MAX(0, fwidth - 3), + "Address:", + oh->chunk[i].addr); + + if(0 == i) { + if(H5F_addr_ne(oh->chunk[i].addr, addr)) + HDfprintf(stream, "*** WRONG ADDRESS!\n"); + chunk_size = oh->chunk[i].size - H5O_SIZEOF_HDR_OH(oh); + } /* end if */ + else + chunk_size = oh->chunk[i].size; + HDfprintf(stream, "%*s%-*s %Zu\n", indent + 3, "", MAX(0, fwidth - 3), + "Size in bytes:", + chunk_size); + + HDfprintf(stream, "%*s%-*s %Zu\n", indent + 3, "", MAX(0, fwidth - 3), + "Gap:", + oh->chunk[i].gap); + } /* end for */ + + /* debug each message */ + if(NULL == (sequence = H5MM_calloc(NELMTS(H5O_msg_class_g) * sizeof(int)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + for(i = 0, mesg_total = 0; i < oh->nmesgs; i++) { + mesg_total += H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[i].raw_size; + HDfprintf(stream, "%*sMessage %d...\n", indent, "", i); + + /* check for bad message id */ + if(oh->mesg[i].type->id >= (int)NELMTS(H5O_msg_class_g)) { + HDfprintf(stream, "*** BAD MESSAGE ID 0x%04x\n", + oh->mesg[i].type->id); + continue; + } /* end if */ + + /* message name and size */ + HDfprintf(stream, "%*s%-*s 0x%04x `%s' (%d)\n", + indent + 3, "", MAX(0, fwidth - 3), + "Message ID (sequence number):", + (unsigned) (oh->mesg[i].type->id), + oh->mesg[i].type->name, + sequence[oh->mesg[i].type->id]++); + HDfprintf (stream, "%*s%-*s %t\n", indent+3, "", MAX (0, fwidth-3), + "Dirty:", + oh->mesg[i].dirty); + HDfprintf (stream, "%*s%-*s %s\n", indent+3, "", MAX (0, fwidth-3), + "Shared:", + (oh->mesg[i].flags & H5O_FLAG_SHARED) ? "Yes" : "No"); + HDfprintf(stream, "%*s%-*s %s\n", indent + 3, "", MAX(0, fwidth - 3), + "Constant:", + (oh->mesg[i].flags & H5O_FLAG_CONSTANT) ? "Yes" : "No"); + if(oh->mesg[i].flags & ~H5O_FLAG_BITS) { + HDfprintf (stream, "%*s%-*s 0x%02x\n", indent+3,"",MAX(0,fwidth-3), + "*** ADDITIONAL UNKNOWN FLAGS --->", + oh->mesg[i].flags & ~H5O_FLAG_BITS); + } /* end if */ + HDfprintf(stream, "%*s%-*s %Zu bytes\n", indent+3, "", MAX(0,fwidth-3), + "Raw size in obj header:", + oh->mesg[i].raw_size); + HDfprintf(stream, "%*s%-*s %u\n", indent + 3, "", MAX(0, fwidth - 3), + "Chunk number:", + oh->mesg[i].chunkno); + chunkno = oh->mesg[i].chunkno; + if(chunkno >= oh->nchunks) + HDfprintf(stream, "*** BAD CHUNK NUMBER\n"); + HDfprintf(stream, "%*s%-*s %Zu\n", indent + 3, "", MAX(0, fwidth - 3), + "Raw data offset in chunk:", + (size_t)(oh->mesg[i].raw - oh->chunk[chunkno].image)); + + /* check the size */ + if((oh->mesg[i].raw + oh->mesg[i].raw_size > + oh->chunk[chunkno].image + oh->chunk[chunkno].size) || + (oh->mesg[i].raw < oh->chunk[chunkno].image)) + HDfprintf(stream, "*** BAD MESSAGE RAW ADDRESS\n"); + + /* decode the message */ + if(oh->mesg[i].flags & H5O_FLAG_SHARED) { + decode = H5O_MSG_SHARED->decode; + debug = H5O_MSG_SHARED->debug; + } else { + decode = oh->mesg[i].type->decode; + debug = oh->mesg[i].type->debug; + } /* end else */ + if(NULL==oh->mesg[i].native && decode) + oh->mesg[i].native = (decode)(f, dxpl_id, oh->mesg[i].raw); + if(NULL == oh->mesg[i].native) + debug = NULL; + + /* print the message */ + HDfprintf(stream, "%*s%-*s\n", indent + 3, "", MAX(0, fwidth - 3), + "Message Information:"); + if(debug) + (debug)(f, dxpl_id, oh->mesg[i].native, stream, indent + 6, MAX(0, fwidth - 6)); + else + HDfprintf(stream, "%*s<No info for this message>\n", indent + 6, ""); + + /* If the message is shared then also print the pointed-to message */ + if(oh->mesg[i].flags & H5O_FLAG_SHARED) { + H5O_shared_t *shared = (H5O_shared_t*)(oh->mesg[i].native); + void *mesg; + + mesg = H5O_shared_read(f, dxpl_id, shared, oh->mesg[i].type, NULL); + if(oh->mesg[i].type->debug) + (oh->mesg[i].type->debug)(f, dxpl_id, mesg, stream, indent + 3, MAX (0, fwidth - 3)); + H5O_free_real(oh->mesg[i].type, mesg); + } /* end if */ + } /* end for */ + sequence = H5MM_xfree(sequence); + + if(mesg_total != chunk_total) + HDfprintf(stream, "*** TOTAL SIZE DOES NOT MATCH ALLOCATED SIZE!\n"); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_debug_real() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_debug + * + * Purpose: Prints debugging info about an object header. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Aug 6 1997 + * + *------------------------------------------------------------------------- + */ +herr_t +H5O_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, int fwidth) +{ + H5O_t *oh = NULL; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5O_debug, FAIL) + + /* check args */ + HDassert(f); + HDassert(H5F_addr_defined(addr)); + HDassert(stream); + HDassert(indent >= 0); + HDassert(fwidth >= 0); + + if(NULL == (oh = H5AC_protect(f, dxpl_id, H5AC_OHDR, addr, NULL, NULL, H5AC_READ))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header") + + /* debug */ + H5O_debug_real(f, dxpl_id, oh, addr, stream, indent, fwidth); + +done: + if(oh && H5AC_unprotect(f, dxpl_id, H5AC_OHDR, addr, oh, H5AC__NO_FLAGS_SET) < 0) + HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header") + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_debug() */ + diff --git a/src/H5Opkg.h b/src/H5Opkg.h index 1f50eeb..074c902 100644 --- a/src/H5Opkg.h +++ b/src/H5Opkg.h @@ -28,6 +28,7 @@ /* Object header macros */ #define H5O_NMESGS 8 /*initial number of messages */ #define H5O_NCHUNKS 2 /*initial number of chunks */ +#define H5O_MIN_SIZE 32 /*min obj header data size */ /* Versions of object header structure */ @@ -341,12 +342,23 @@ H5_DLLVAR const H5O_obj_class_t H5O_OBJ_DATATYPE[1]; H5_DLL herr_t H5O_flush_msgs(H5F_t *f, H5O_t *oh); 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_delete_mesg(H5F_t *f, hid_t dxpl_id, H5O_mesg_t *mesg, + hbool_t adj_link); 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); + +/* Object header allocation routines */ +H5_DLL unsigned H5O_alloc(H5F_t *f, hid_t dxpl_id, H5O_t *oh, + const H5O_msg_class_t *type, size_t size, hbool_t * oh_dirtied_ptr); +H5_DLL herr_t H5O_condense_header(H5F_t *f, H5O_t *oh, hid_t dxpl_id); +H5_DLL herr_t H5O_release_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *oh, + H5O_mesg_t *mesg, hbool_t delete_mesg, hbool_t adj_link); + +/* Object header debugging routines */ #ifdef H5O_DEBUG H5_DLL herr_t H5O_assert(const H5O_t *oh); #endif /* H5O_DEBUG */ diff --git a/src/H5Oprivate.h b/src/H5Oprivate.h index 97cb16c..45c5eec 100644 --- a/src/H5Oprivate.h +++ b/src/H5Oprivate.h @@ -420,15 +420,19 @@ 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 uint32_t H5O_mesg_hash(unsigned type_id, H5F_t *f, const void *mesg); + +/* Object copying routines */ 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); H5_DLL 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); + +/* Debugging routines */ +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); H5_DLL herr_t H5O_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE * stream, int indent, int fwidth); -H5_DLL uint32_t H5O_mesg_hash(unsigned type_id, H5F_t *f, const void *mesg); /* * These functions operate on object locations diff --git a/src/H5Pfcpl.c b/src/H5Pfcpl.c index b4ba4b9..57c10bd 100644 --- a/src/H5Pfcpl.c +++ b/src/H5Pfcpl.c @@ -77,7 +77,7 @@ #define H5F_CRT_SHMSG_NINDEXES_DEF (0) #define H5F_CRT_SHMSG_INDEX_TYPES_SIZE sizeof(unsigned[H5SM_MAX_NUM_INDEXES]) #define H5F_CRT_SHMSG_INDEX_TYPES_DEF {0,0,0,0,0,0} -// JAMES #define H5F_CRT_SHMSG_INDEX_TYPES_DEF { H5O_MESG_FILL_FLAG |H5O_MESG_SDSPACE_FLAG,H5O_MESG_ATTR_FLAG, 0, H5O_MESG_DTYPE_FLAG,0,H5O_MESG_PLINE_FLAG} +/* JAMES #define H5F_CRT_SHMSG_INDEX_TYPES_DEF { H5O_MESG_FILL_FLAG |H5O_MESG_SDSPACE_FLAG,H5O_MESG_ATTR_FLAG, 0, H5O_MESG_DTYPE_FLAG,0,H5O_MESG_PLINE_FLAG} */ #define H5F_CRT_SHMSG_INDEX_MINSIZE_SIZE sizeof(unsigned[H5SM_MAX_NUM_INDEXES]) #define H5F_CRT_SHMSG_INDEX_MINSIZE_DEF {250,250,250,250,250,250} /* Definitions for shared object header list/btree phase change cutoffs */ diff --git a/src/Makefile.am b/src/Makefile.am index 25f3a73..98103da 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -57,8 +57,10 @@ libhdf5_la_SOURCES= H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \ H5HFhdr.c H5HFhuge.c H5HFiblock.c H5HFiter.c H5HFman.c H5HFsection.c \ H5HFspace.c H5HFstat.c H5HFtest.c H5HFtiny.c \ H5HG.c H5HGdbg.c H5HL.c H5HLdbg.c H5HP.c H5I.c H5MF.c H5MM.c \ - H5MP.c H5MPtest.c H5L.c H5Lexternal.c H5O.c H5Oattr.c H5Obogus.c H5Ocache.c \ - H5Ocont.c H5Ocopy.c H5Odtype.c H5Oefl.c H5Ofill.c H5Oginfo.c H5Olayout.c \ + H5MP.c H5MPtest.c H5L.c H5Lexternal.c H5O.c H5Oalloc.c H5Oattr.c \ + H5Obogus.c H5Ocache.c \ + H5Ocont.c H5Ocopy.c H5Odbg.c H5Odtype.c H5Oefl.c H5Ofill.c H5Oginfo.c \ + H5Olayout.c \ H5Olinfo.c H5Olink.c H5Omtime.c \ H5Oname.c H5Onull.c H5Opline.c H5Osdspace.c H5Oshared.c H5Ostab.c \ H5P.c H5Pacpl.c H5Pdcpl.c H5Pdxpl.c H5Pfapl.c H5Pfcpl.c H5Pfmpl.c \ diff --git a/src/Makefile.in b/src/Makefile.in index e13097a..c5bd0b1 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -98,8 +98,8 @@ am_libhdf5_la_OBJECTS = H5.lo H5checksum.lo H5dbg.lo H5system.lo \ H5HFiblock.lo H5HFiter.lo H5HFman.lo H5HFsection.lo \ H5HFspace.lo H5HFstat.lo H5HFtest.lo H5HFtiny.lo H5HG.lo \ H5HGdbg.lo H5HL.lo H5HLdbg.lo H5HP.lo H5I.lo H5MF.lo H5MM.lo \ - H5MP.lo H5MPtest.lo H5L.lo H5Lexternal.lo H5O.lo H5Oattr.lo \ - H5Obogus.lo H5Ocache.lo H5Ocont.lo H5Ocopy.lo H5Odtype.lo \ + H5MP.lo H5MPtest.lo H5L.lo H5Lexternal.lo H5O.lo H5Oalloc.lo H5Oattr.lo \ + H5Obogus.lo H5Ocache.lo H5Ocont.lo H5Ocopy.lo H5Odbg.lo H5Odtype.lo \ H5Oefl.lo H5Ofill.lo H5Oginfo.lo H5Olayout.lo H5Olinfo.lo \ H5Olink.lo H5Omtime.lo H5Oname.lo H5Onull.lo H5Opline.lo \ H5Osdspace.lo H5Oshared.lo H5Ostab.lo H5P.lo H5Pacpl.lo \ @@ -413,8 +413,8 @@ libhdf5_la_SOURCES = H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \ H5HFhdr.c H5HFhuge.c H5HFiblock.c H5HFiter.c H5HFman.c H5HFsection.c \ H5HFspace.c H5HFstat.c H5HFtest.c H5HFtiny.c \ H5HG.c H5HGdbg.c H5HL.c H5HLdbg.c H5HP.c H5I.c H5MF.c H5MM.c \ - H5MP.c H5MPtest.c H5L.c H5Lexternal.c H5O.c H5Oattr.c H5Obogus.c H5Ocache.c \ - H5Ocont.c H5Ocopy.c H5Odtype.c H5Oefl.c H5Ofill.c H5Oginfo.c H5Olayout.c \ + H5MP.c H5MPtest.c H5L.c H5Lexternal.c H5O.c H5Oalloc.c H5Oattr.c H5Obogus.c H5Ocache.c \ + H5Ocont.c H5Ocopy.c H5Odbg.c H5Odtype.c H5Oefl.c H5Ofill.c H5Oginfo.c H5Olayout.c \ H5Olinfo.c H5Olink.c H5Omtime.c \ H5Oname.c H5Onull.c H5Opline.c H5Osdspace.c H5Oshared.c H5Ostab.c \ H5P.c H5Pacpl.c H5Pdcpl.c H5Pdxpl.c H5Pfapl.c H5Pfcpl.c H5Pfmpl.c \ @@ -653,11 +653,13 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5MP.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5MPtest.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5O.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oalloc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oattr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Obogus.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ocache.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@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Odtype.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oefl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ofill.Plo@am__quote@ |