diff options
Diffstat (limited to 'src/H5Oalloc.c')
-rw-r--r-- | src/H5Oalloc.c | 486 |
1 files changed, 425 insertions, 61 deletions
diff --git a/src/H5Oalloc.c b/src/H5Oalloc.c index 29c057d..9cf50ad 100644 --- a/src/H5Oalloc.c +++ b/src/H5Oalloc.c @@ -64,13 +64,15 @@ 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 htri_t H5O_alloc_extend_chunk(H5F_t *f, H5O_t *oh, unsigned chunkno, - size_t size, unsigned * msg_idx); +static htri_t H5O_alloc_extend_chunk(H5F_t *f, hid_t dxpl_id, 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_move_cont(H5F_t *f, H5O_t *oh, unsigned cont_u, hid_t dxpl_id); +static htri_t H5O_move_msgs_forward(H5F_t *f, H5O_t *oh, hid_t dxpl_id); +static htri_t H5O_merge_null(H5F_t *f, H5O_t *oh, hid_t dxpl_id); static htri_t H5O_remove_empty_chunks(H5F_t *f, H5O_t *oh, hid_t dxpl_id); +static herr_t H5O_alloc_shrink_chunk(H5F_t *f, H5O_t *oh, hid_t dxpl_id, unsigned chunkno); /*********************/ @@ -148,7 +150,7 @@ H5O_add_gap(H5O_t *oh, unsigned chunkno, unsigned idx, 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, + 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 */ @@ -161,7 +163,7 @@ H5O_add_gap(H5O_t *oh, unsigned chunkno, unsigned idx, /* 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") + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages") /* Increment new gap size */ oh->chunk[chunkno].gap += new_gap_size; @@ -329,7 +331,7 @@ H5O_alloc_null(H5O_t *oh, unsigned null_idx, const H5O_msg_class_t *new_type, /* 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") + HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "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 */ @@ -338,7 +340,7 @@ H5O_alloc_null(H5O_t *oh, unsigned null_idx, const H5O_msg_class_t *new_type, /* 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") + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages") /* "Retarget" 'alloc_msg' pointer into newly re-allocated array of messages */ alloc_msg = &oh->mesg[null_idx]; @@ -363,7 +365,7 @@ H5O_alloc_null(H5O_t *oh, unsigned null_idx, const H5O_msg_class_t *new_type, 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") + HGOTO_ERROR(H5E_OHDR, H5E_CANTREMOVE, FAIL, "can't eliminate gap in chunk") /* Set the gap size to zero for the chunk */ oh->chunk[null_chunkno].gap = 0; @@ -462,14 +464,14 @@ done: *------------------------------------------------------------------------- */ static htri_t -H5O_alloc_extend_chunk(H5F_t *f, H5O_t *oh, unsigned chunkno, +H5O_alloc_extend_chunk(H5F_t *f, hid_t dxpl_id, 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 */ + htri_t extended; /* If chunk can be extended */ int extend_msg = -1;/* Index of null message to extend */ uint8_t new_size_flags = 0; /* New chunk #0 size flags */ hbool_t adjust_size_flags = FALSE; /* Whether to adjust the chunk #0 size flags */ @@ -537,16 +539,12 @@ H5O_alloc_extend_chunk(H5F_t *f, H5O_t *oh, unsigned chunkno, } /* end if */ /* Determine whether the chunk can be extended */ - tri_result = H5MF_can_extend(f, H5FD_MEM_OHDR, oh->chunk[chunkno].addr, + extended = H5MF_try_extend(f, dxpl_id, H5FD_MEM_OHDR, oh->chunk[chunkno].addr, (hsize_t)(oh->chunk[chunkno].size), (hsize_t)(delta + extra_prfx_size)); - if(tri_result == FALSE) /* can't extend -- we are done */ + if(extended < 0) /* error */ + HGOTO_ERROR(H5E_OHDR, H5E_CANTEXTEND, FAIL, "can't tell if we can extend chunk") + else if(extended == 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 + extra_prfx_size)) < 0 ) - HGOTO_ERROR(H5E_RESOURCE, H5E_SYSTEM, FAIL, "can't extend chunk") /* Adjust object header prefix flags */ if(adjust_size_flags) { @@ -675,6 +673,7 @@ H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size) H5O_mesg_t *curr_msg; /* Pointer to current message to operate on */ size_t cont_size; /*continuation message size */ + size_t multi_size = 0; /* Size of all the messages in the last chunk */ int found_null = (-1); /* Best fit null message */ alloc_info found_attr = {-1, 0, 0, 0, 0}; /* Best fit attribute message */ alloc_info found_other = {-1, 0, 0, 0, 0}; /* Best fit other message */ @@ -770,11 +769,15 @@ H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size) found_other.null_msgno = null_msgno; } /* end if */ } /* end else */ - } /* end if */ + } else if(found_null < 0 && found_attr.msgno < 0 && found_other.msgno < 0 && msg_chunkno == oh->nchunks - 1) + /* Keep track of the total size of smaller messages in the last + * chunk, in case we need to move more than 1 message. + */ + multi_size += curr_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh); } /* end else */ } /* end for */ - if(found_null < 0 && found_attr.msgno < 0 && found_other.msgno < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "unable to locate message to move") + if(found_null >= 0 || found_attr.msgno >= 0 || found_other.msgno >= 0) + multi_size = 0; /* * If we must move some other message to make room for the null @@ -783,14 +786,20 @@ H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size) * * Move other messages first, and attributes only as a last resort. * + * If all else fails, move every message in the last chunk. + * */ - if(found_null < 0) { - if(found_other.msgno < 0) - found_other = found_attr; + if(multi_size == 0) { + if(found_null < 0) { + if(found_other.msgno < 0) + found_other = found_attr; - HDassert(found_other.msgno >= 0); - size += H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other.msgno].raw_size; + HDassert(found_other.msgno >= 0); + size += H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other.msgno].raw_size; + } /* end if */ } /* end if */ + else + size += multi_size; /* * The total chunk size must include the requested space plus enough @@ -837,8 +846,8 @@ H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size) * # 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; + HDmemcpy(p, H5O_CHK_MAGIC, (size_t)H5_SIZEOF_MAGIC); + p += H5_SIZEOF_MAGIC; } /* end if */ /* @@ -849,10 +858,58 @@ H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size) 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) { + if(multi_size > 0) { + /* Move all non-null messages in the last chunk to the new chunk. This + * should be extremely rare so we don't care too much about minimizing + * the space used */ + H5O_mesg_t *null_msg; /* Pointer to new null message */ + + /* Copy each message to the new location */ + for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) + if(curr_msg->chunkno == chunkno - 1) { + if(curr_msg->type->id == H5O_NULL_ID) { + /* Delete the null message */ + if(u < oh->nmesgs - 1) + HDmemmove(curr_msg, curr_msg + 1, ((oh->nmesgs - 1) - u) * sizeof(H5O_mesg_t)); + oh->nmesgs--; + } else { + /* Copy the raw data */ + HDmemcpy(p, curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), + curr_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh)); + + /* Update the message info */ + curr_msg->chunkno = chunkno; + curr_msg->raw = p + H5O_SIZEOF_MSGHDR_OH(oh); + + /* Account for copied message in new chunk */ + p += H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg->raw_size; + size -= H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg->raw_size; + } /* end else */ + } /* end if */ + + /* Create a null message spanning the entire last chunk */ + 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->chunk[chunkno-1].image + + ((chunkno == 1) ? H5O_SIZEOF_HDR(oh) : H5O_SIZEOF_CHKHDR_OH(oh)) + - H5O_SIZEOF_CHKSUM_OH(oh) + H5O_SIZEOF_MSGHDR_OH(oh); + null_msg->raw_size = oh->chunk[chunkno-1].size + - ((chunkno == 1) ? H5O_SIZEOF_HDR(oh) : H5O_SIZEOF_CHKHDR_OH(oh)) + - H5O_SIZEOF_MSGHDR_OH(oh); + null_msg->chunkno = chunkno - 1; + + HDassert(null_msg->raw_size >= cont_size); + + /* Remove any gap in the chunk */ + oh->chunk[chunkno-1].gap = 0; + + } else if(found_null < 0) { + /* Move message (that will be replaced with continuation message) + * to new chunk, if necessary. + */ H5O_mesg_t *null_msg; /* Pointer to new null message */ /* Create null message for space that message to copy currently occupies */ @@ -996,13 +1053,13 @@ H5O_alloc(H5F_t *f, hid_t dxpl_id, H5O_t *oh, const H5O_msg_class_t *type, HDassert(H5F_addr_defined(oh->chunk[chunkno].addr)); - tri_result = H5O_alloc_extend_chunk(f, oh, chunkno, raw_size, &idx); + tri_result = H5O_alloc_extend_chunk(f, dxpl_id, oh, chunkno, raw_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") + HGOTO_ERROR(H5E_OHDR, H5E_CANTEXTEND, UFAIL, "H5O_alloc_extend_chunk failed unexpectedly") } /* end for */ /* If idx is still UFAIL, we were not able to extend a chunk, @@ -1080,7 +1137,7 @@ H5O_release_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5O_mesg_t *mesg, /* 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, + 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") @@ -1095,6 +1152,118 @@ done: /*------------------------------------------------------------------------- + * Function: H5O_move_cont + * + * Purpose: Check and move message(s) forward into a continuation message + * + * Return: Success: non-negative (TRUE/FALSE) + * Failure: negative + * + * Programmer: Vailin Choi + * Feb. 2009 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5O_move_cont(H5F_t *f, H5O_t *oh, unsigned cont_u, hid_t dxpl_id) +{ + unsigned v; /* local index variable */ + H5O_mesg_t *cont_msg; /* pointer to the continuation message */ + H5O_mesg_t *nonnull_msg; /* pointer to the current message to operate on */ + H5O_mesg_t *null_msg; /* pointer to the current message to operate on */ + size_t total_size=0; /* total size of nonnull messages in the chunk pointed to by cont message */ + size_t move_size=0; /* size of the message to be moved */ + uint8_t *move_start, *move_end; /* pointers to area of messages to move */ + size_t gap_size; /* size of gap produced */ + unsigned deleted_chunkno; /* Chunk # to delete */ + htri_t ret_value = FALSE; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5O_move_cont) + + /* Check arguments. */ + HDassert(f); + HDassert(oh); + + cont_msg = &oh->mesg[cont_u]; + H5O_LOAD_NATIVE(f, dxpl_id, 0, oh, cont_msg, FAIL) + deleted_chunkno = ((H5O_cont_t *)(cont_msg->native))->chunkno; + + /* proceed further only if continuation message is pointing to the last chunk */ + if(deleted_chunkno != (oh->nchunks - 1)) + HGOTO_DONE(FALSE) + + /* find size of all nonnull messages in the chunk pointed to by the continuation message */ + for(v = 0, nonnull_msg = &oh->mesg[0]; v < oh->nmesgs; v++, nonnull_msg++) + if(nonnull_msg->chunkno == deleted_chunkno && nonnull_msg->type->id != H5O_NULL_ID) { + HDassert(nonnull_msg->type->id != H5O_CONT_ID); + total_size += nonnull_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh); + } + + /* check if messages can fit into the continuation message */ + if(total_size && total_size <= (cont_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh))) { + + /* convert continuation message into a null message */ + if(H5O_release_mesg(f, dxpl_id, oh, cont_msg, TRUE) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to convert into null message") + + move_start = cont_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh); + move_end = cont_msg->raw + cont_msg->raw_size; + + /* move message(s) forward into continuation message */ + for(v = 0, nonnull_msg = &oh->mesg[0]; v < oh->nmesgs; v++, nonnull_msg++) + if(nonnull_msg->chunkno == deleted_chunkno && nonnull_msg->type->id != H5O_NULL_ID) { + move_size = nonnull_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh); + HDmemcpy(move_start, nonnull_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), move_size); + nonnull_msg->raw = move_start + H5O_SIZEOF_MSGHDR_OH(oh); + nonnull_msg->chunkno = cont_msg->chunkno; + nonnull_msg->dirty = TRUE; + move_start += move_size; + } + + HDassert(move_start <= move_end); + + /* check if there is space remaining in the continuation message */ + /* the remaining space can be gap or a null message */ + gap_size = move_end - move_start; + if(gap_size >= (size_t)H5O_SIZEOF_MSGHDR_OH(oh)) { + cont_msg->raw_size = gap_size - H5O_SIZEOF_MSGHDR_OH(oh); + cont_msg->raw = move_start + H5O_SIZEOF_MSGHDR_OH(oh); + cont_msg->dirty = TRUE; + } else { + if(gap_size && (H5O_add_gap(oh, cont_msg->chunkno, cont_u, move_start, gap_size) < 0)) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert gap in chunk") + /* Release any information/memory for continuation message */ + H5O_msg_free_mesg(cont_msg); + if(cont_u < (oh->nmesgs - 1)) + HDmemmove(&oh->mesg[cont_u], &oh->mesg[cont_u + 1], ((oh->nmesgs - 1) - cont_u) * sizeof(H5O_mesg_t)); + oh->nmesgs--; + } + + /* remove all null messages in deleted chunk from list of messages */ + /* Note: unsigned v wrapping around at the end */ + for (v = oh->nmesgs - 1, null_msg = &oh->mesg[v]; v < oh->nmesgs; v--, null_msg--) + if(null_msg->type->id == H5O_NULL_ID && null_msg->chunkno == deleted_chunkno) { + + /* Release any information/memory for message */ + H5O_msg_free_mesg(null_msg); + + if(v < (oh->nmesgs - 1)) + HDmemmove(&oh->mesg[v], &oh->mesg[v + 1], ((oh->nmesgs - 1) - v) * sizeof(H5O_mesg_t)); + oh->nmesgs--; + } /* end if */ + + (void)H5FL_BLK_FREE(chunk_image, oh->chunk[deleted_chunkno].image); + + oh->nchunks--; + ret_value = TRUE; + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5O_move_cont() */ + + +/*------------------------------------------------------------------------- * * Function: H5O_move_msgs_forward * @@ -1105,11 +1274,14 @@ done: * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Oct 17 2005 + * Modifications: + * Feb. 2009: Vailin Choi + * Add changes to move messages forward into "continuation" message * *------------------------------------------------------------------------- */ static htri_t -H5O_move_msgs_forward(H5O_t *oh) +H5O_move_msgs_forward(H5F_t *f, H5O_t *oh, hid_t dxpl_id) { hbool_t packed_msg; /* Flag to indicate that messages were packed */ hbool_t did_packing = FALSE; /* Whether any messages were packed */ @@ -1138,7 +1310,7 @@ H5O_move_msgs_forward(H5O_t *oh) /* Check if null message is not last in chunk */ chunk = &(oh->chunk[curr_msg->chunkno]); - if((curr_msg->raw + curr_msg->raw_size) + 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 */ @@ -1186,7 +1358,17 @@ H5O_move_msgs_forward(H5O_t *oh) } /* end if */ else { H5O_mesg_t *null_msg; /* Pointer to current message to operate on */ - unsigned v; /* Local index variable */ + unsigned v; /* Local index variable */ + htri_t status; + + if(H5O_CONT_ID == curr_msg->type->id) { + if((status = H5O_move_cont(f, oh, u, dxpl_id)) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "Error in moving messages into cont message") + else if(status > 0) { /* message(s) got moved into "continuation" message */ + packed_msg = TRUE; + break; + } + } /* 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++) { @@ -1222,7 +1404,7 @@ H5O_move_msgs_forward(H5O_t *oh) /* Check for gap in null message's chunk */ if(oh->chunk[old_chunkno].gap > 0) { /* Eliminate the gap in the chunk */ - if(H5O_eliminate_gap(oh, null_msg, + if(H5O_eliminate_gap(oh, 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") @@ -1282,7 +1464,7 @@ H5O_move_msgs_forward(H5O_t *oh) /* 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], + 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") @@ -1316,7 +1498,7 @@ H5O_move_msgs_forward(H5O_t *oh) } while(packed_msg); /* Set return value */ - ret_value = did_packing; + ret_value = (htri_t)did_packing; done: FUNC_LEAVE_NOAPI(ret_value) @@ -1338,13 +1520,13 @@ done: *------------------------------------------------------------------------- */ static htri_t -H5O_merge_null(H5O_t *oh) +H5O_merge_null(H5F_t *f, H5O_t *oh, hid_t dxpl_id) { 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) + FUNC_ENTER_NOAPI_NOINIT(H5O_merge_null) /* check args */ HDassert(oh != NULL); @@ -1407,6 +1589,11 @@ H5O_merge_null(H5O_t *oh) /* (Don't bother reducing size of message array for now -QAK) */ oh->nmesgs--; + /* If the merged message is too large, shrink the chunk */ + if(curr_msg->raw_size >= H5O_MESG_MAX_SIZE) + if(H5O_alloc_shrink_chunk(f, oh, dxpl_id, curr_msg->chunkno) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "unable to shrink chunk") + /* Get out of loop */ break; } /* end if */ @@ -1425,8 +1612,9 @@ H5O_merge_null(H5O_t *oh) } while(merged_msg); /* Set return value */ - ret_value = did_merging; + ret_value = (htri_t)did_merging; +done: FUNC_LEAVE_NOAPI(ret_value) } /* H5O_merge_null() */ @@ -1486,12 +1674,7 @@ H5O_remove_empty_chunks(H5F_t *f, H5O_t *oh, hid_t dxpl_id) 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, 0, cont_msg->raw); - if(NULL == cont_msg->native) - HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "unable to decode message") - } /* end if */ + H5O_LOAD_NATIVE(f, dxpl_id, 0, oh, cont_msg, FAIL) /* Check for correct chunk to delete */ if(oh->chunk[null_msg->chunkno].addr == ((H5O_cont_t *)(cont_msg->native))->addr) @@ -1515,7 +1698,7 @@ H5O_remove_empty_chunks(H5F_t *f, H5O_t *oh, hid_t dxpl_id) */ /* Free memory for chunk image */ - H5FL_BLK_FREE(chunk_image, oh->chunk[null_msg->chunkno].image); + (void)H5FL_BLK_FREE(chunk_image, oh->chunk[null_msg->chunkno].image); /* Remove chunk from list of chunks */ if(null_msg->chunkno < (oh->nchunks - 1)) @@ -1552,12 +1735,7 @@ H5O_remove_empty_chunks(H5F_t *f, H5O_t *oh, hid_t dxpl_id) /* Check for continuation message */ if(H5O_CONT_ID == curr_msg->type->id) { /* Decode current continuation message if necessary */ - if(NULL == curr_msg->native) { - HDassert(H5O_MSG_CONT->decode); - curr_msg->native = (H5O_MSG_CONT->decode)(f, dxpl_id, 0, curr_msg->raw); - if(NULL == curr_msg->native) - HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "unable to decode message") - } /* end if */ + H5O_LOAD_NATIVE(f, dxpl_id, 0, oh, curr_msg, FAIL) /* Check for pointer to chunk after deleted chunk */ if(((H5O_cont_t *)(curr_msg->native))->chunkno > deleted_chunkno) @@ -1577,7 +1755,7 @@ H5O_remove_empty_chunks(H5F_t *f, H5O_t *oh, hid_t dxpl_id) } while(deleted_chunk); /* Set return value */ - ret_value = did_deleting; + ret_value = (htri_t)did_deleting; done: FUNC_LEAVE_NOAPI(ret_value) @@ -1596,6 +1774,11 @@ done: * koziol@ncsa.uiuc.edu * Oct 4 2005 * + * Modifications: + * Feb. 2009: Vailin Choi + * Add 2 more parameters to H5O_move_msgs_forward() for moving + * messages forward into "continuation" message + * *------------------------------------------------------------------------- */ herr_t @@ -1616,14 +1799,14 @@ H5O_condense_header(H5F_t *f, H5O_t *oh, hid_t dxpl_id) rescan_header = FALSE; /* Scan for messages that can be moved earlier in chunks */ - result = H5O_move_msgs_forward(oh); + result = H5O_move_msgs_forward(f, oh, dxpl_id); 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); + result = H5O_merge_null(f, oh, dxpl_id); if(result < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "can't pack null header messages") if(result > 0) @@ -1644,3 +1827,184 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* H5O_condense_header() */ + +/*------------------------------------------------------------------------- + * + * Function: H5O_alloc_shrink_chunk + * + * Purpose: Shrinks a chunk, removing all null messages and any gap. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Neil Fortner + * nfortne2@hdfgroup.org + * Oct 20 2008 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_alloc_shrink_chunk(H5F_t *f, + H5O_t *oh, + hid_t dxpl_id, + unsigned chunkno) +{ + H5O_chunk_t *chunk = &oh->chunk[chunkno]; /* Chunk to shrink */ + H5O_mesg_t *curr_msg; + uint8_t *old_image = chunk->image; /* Old address of chunk's image in memory */ + size_t old_size = chunk->size; /* Old size of chunk */ + size_t new_size = chunk->size - chunk->gap; /* Size of shrunk chunk */ + size_t total_msg_size; /* Size of the messages in this chunk */ + size_t min_chunk_size = H5O_ALIGN_OH(oh, H5O_MIN_SIZE); /* Minimum chunk size */ + size_t sizeof_chksum = H5O_SIZEOF_CHKSUM_OH(oh); /* Size of chunk checksum */ + size_t sizeof_msghdr = H5O_SIZEOF_MSGHDR_OH(oh); /* Size of message header */ + uint8_t new_size_flags = 0; /* New chunk #0 size flags */ + hbool_t adjust_size_flags = FALSE; /* Whether to adjust the chunk #0 size flags */ + size_t less_prfx_size = 0; /* Bytes removed from object header prefix */ + herr_t ret_value = SUCCEED; /* Return value */ + unsigned u; /* Index */ + + FUNC_ENTER_NOAPI_NOINIT(H5O_alloc_shrink_chunk) + + /* check args */ + HDassert(f != NULL); + + /* Loop backwards to increase the chance of seeing more null messages at the + * end of the chunk. Note that we rely on unsigned u wrapping around at the + * end. + */ + for (u = oh->nmesgs - 1, curr_msg = &oh->mesg[u]; u < oh->nmesgs; u--, curr_msg--) { + if ((H5O_NULL_ID == curr_msg->type->id) && (chunkno == curr_msg->chunkno)) { + size_t shrink_size = curr_msg->raw_size + sizeof_msghdr; /* Amount to shrink the chunk by */ + + /* If the current message is not at the end of the chunk, copy the + * data after it (except the checksum). + */ + if (curr_msg->raw + curr_msg->raw_size + < old_image + new_size - sizeof_chksum) { + unsigned v; /* Index */ + H5O_mesg_t *curr_msg2; + uint8_t *src = curr_msg->raw + curr_msg->raw_size; /* Source location */ + + /* Slide down the raw data */ + HDmemmove(curr_msg->raw - sizeof_msghdr, src, + (size_t)(old_image + new_size - sizeof_chksum - src)); + + /* Update the raw data pointers for messages after this one */ + for (v = 0, curr_msg2 = &oh->mesg[0]; v < oh->nmesgs; v++, curr_msg2++) + if ((chunkno == curr_msg2->chunkno) && (curr_msg2->raw > curr_msg->raw)) + curr_msg2->raw -= shrink_size; + } /* end if */ + + /* Adjust the new chunk size */ + new_size -= shrink_size; + + /* Release any information/memory for the message */ + H5O_msg_free_mesg(curr_msg); + + /* Remove the deleted null message from list of messages */ + if (u < (oh->nmesgs - 1)) + HDmemmove(&oh->mesg[u], &oh->mesg[u+1], ((oh->nmesgs - 1) - u) * sizeof(H5O_mesg_t)); + + /* Decrement # of messages */ + /* (Don't bother reducing size of message array for now) */ + oh->nmesgs--; + } /* end if */ + } /* end for */ + + /* Check if the chunk is too small, extend if necessary */ + total_msg_size = new_size - (chunkno == 0 ? H5O_SIZEOF_HDR(oh) : H5O_SIZEOF_CHKHDR_OH(oh)); + if(total_msg_size < min_chunk_size) { + HDassert(oh->alloc_nmesgs > oh->nmesgs); + oh->nmesgs++; + + /* Initialize new null message to make the chunk large enough */ + oh->mesg[oh->nmesgs].type = H5O_MSG_NULL; + oh->mesg[oh->nmesgs].dirty = TRUE; + oh->mesg[oh->nmesgs].native = NULL; + oh->mesg[oh->nmesgs].raw = old_image + new_size + sizeof_msghdr - sizeof_chksum; + oh->mesg[oh->nmesgs].raw_size = MAX(H5O_ALIGN_OH(oh, min_chunk_size - total_msg_size), + sizeof_msghdr) - sizeof_msghdr; + oh->mesg[oh->nmesgs].chunkno = chunkno; + + /* update the new chunk size */ + new_size += oh->mesg[oh->nmesgs].raw_size + sizeof_msghdr; + } + + /* Check for changing the chunk #0 data size enough to need adjusting the flags */ + if(oh->version > H5O_VERSION_1 && chunkno == 0) { + uint64_t chunk0_newsize = new_size - H5O_SIZEOF_HDR(oh); /* New size of chunk 0's data */ + size_t orig_prfx_size = 1 << (oh->flags & H5O_HDR_CHUNK0_SIZE); /* Original prefix size */ + + /* Check for moving to a 1-byte size encoding */ + if (orig_prfx_size > 1 && chunk0_newsize <= 255) { + less_prfx_size = orig_prfx_size - 1; + new_size_flags = H5O_HDR_CHUNK0_1; + adjust_size_flags = TRUE; + } /* end if */ + /* Check for moving to a 2-byte size encoding */ + else if (orig_prfx_size > 2 && chunk0_newsize <= 65535) { + less_prfx_size = orig_prfx_size - 2; + new_size_flags = H5O_HDR_CHUNK0_2; + adjust_size_flags = TRUE; + } /* end if */ + /* Check for moving to a 4-byte size encoding */ + else if (orig_prfx_size > 4 && chunk0_newsize <= 4294967295) { + less_prfx_size = orig_prfx_size - 4; + new_size_flags = H5O_HDR_CHUNK0_4; + adjust_size_flags = TRUE; + } /* end if */ + } /* end if */ + + if(adjust_size_flags) { + /* Adjust object header prefix flags */ + oh->flags &= ~H5O_HDR_CHUNK0_SIZE; + oh->flags |= new_size_flags; + + /* Slide chunk 0 data down */ + HDmemmove(chunk->image + H5O_SIZEOF_HDR(oh) - sizeof_chksum, + chunk->image + H5O_SIZEOF_HDR(oh) - sizeof_chksum + less_prfx_size, + new_size - H5O_SIZEOF_HDR(oh)); + + /* Adjust chunk size */ + new_size -= less_prfx_size; + } /* end if */ + + /* Allocate less memory space for chunk's image */ + chunk->size = new_size; + chunk->image = H5FL_BLK_REALLOC(chunk_image, old_image, chunk->size); + chunk->gap = 0; + chunk->dirty = TRUE; + if (NULL == oh->chunk[chunkno].image) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + + /* Spin through existing messages, adjusting them */ + for (u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) { + if (adjust_size_flags || (chunk->image != old_image)) + /* Adjust raw addresses for messages in this chunk to reflect new 'image' address */ + if (curr_msg->chunkno == chunkno) + curr_msg->raw = chunk->image - less_prfx_size + (curr_msg->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 + * its size is directly encoded in the object header) */ + if (chunkno > 0 && (H5O_CONT_ID == curr_msg->type->id) && + (((H5O_cont_t *)(curr_msg->native))->chunkno == chunkno)) { + /* Adjust size of continuation message */ + HDassert(((H5O_cont_t *)(curr_msg->native))->size == old_size); + ((H5O_cont_t *)(curr_msg->native))->size = chunk->size; + + /* Flag continuation message as dirty */ + curr_msg->dirty = TRUE; + } /* end if */ + } /* end for */ + + HDassert(new_size <= old_size); + + /* Free the unused space in the file */ + if (H5MF_xfree(f, H5FD_MEM_OHDR, dxpl_id, chunk->addr + new_size, (hsize_t)(old_size - new_size)) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to shrink object header chunk") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5O_alloc_shrink_chunk() */ + |