summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MANIFEST2
-rw-r--r--src/H5O.c1774
-rw-r--r--src/H5Oalloc.c1489
-rw-r--r--src/H5Odbg.c417
-rw-r--r--src/H5Opkg.h12
-rw-r--r--src/H5Oprivate.h8
-rw-r--r--src/H5Pfcpl.c2
-rwxr-xr-xsrc/Makefile.am6
-rw-r--r--src/Makefile.in10
-rw-r--r--test/tsohm.c4
10 files changed, 1941 insertions, 1783 deletions
diff --git a/MANIFEST b/MANIFEST
index e13ee25..1b01ea9 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -569,11 +569,13 @@
./src/H5MPprivate.h
./src/H5MPtest.c
./src/H5O.c
+./src/H5Oalloc.c
./src/H5Oattr.c
./src/H5Obogus.c
./src/H5Ocache.c
./src/H5Ocont.c
./src/H5Ocopy.c
+./src/H5Odbg.c
./src/H5Odtype.c
./src/H5Oefl.c
./src/H5Ofill.c
diff --git a/src/H5O.c b/src/H5O.c
index dba50a6..365ddfb 100644
--- a/src/H5O.c
+++ b/src/H5O.c
@@ -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@
diff --git a/test/tsohm.c b/test/tsohm.c
index 6eda3e3..d158ff0 100644
--- a/test/tsohm.c
+++ b/test/tsohm.c
@@ -58,8 +58,8 @@ static void check_fcpl_values(hid_t fcpl_id, const unsigned nindexes_in,
{
unsigned num_indexes;
unsigned index_flags, min_mesg_size;
- size_t list_size, btree_size;
- unsigned x;
+ unsigned list_size, btree_size;
+ unsigned x;
herr_t ret;
/* Verify number of indexes is set to default */