[svn-r12771] Description:

More fixes to make the I/O & memory operations more efficient when loading
& flushing object header chunks.

    Add in concept of a chunk having a "gap" at the end - unused space that is
not large enough to hold a full null message that describes it.

    Clean up formatting a bit.

    Latest version of object header format not enabled yet, still working on a
few bugs...

Tested on:
    Linux/32 2.6 (chicago)
    Linux/64 2.6 (chicago2)
This commit is contained in:
Quincey Koziol 2006-10-17 15:36:15 -05:00
parent f7a8a14bfd
commit 3a2bcc84ac
4 changed files with 453 additions and 151 deletions

373
src/H5O.c
View File

@ -90,8 +90,8 @@ typedef struct {
} H5O_iter_ud1_t;
/* Typedef for "internal library" iteration operations */
typedef herr_t (*H5O_lib_operator_t)(H5O_mesg_t *mesg/*in,out*/, unsigned idx,
unsigned * oh_flags_ptr, void *operator_data/*in,out*/);
typedef herr_t (*H5O_lib_operator_t)(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/,
unsigned idx, unsigned * oh_flags_ptr, void *operator_data/*in,out*/);
/* Some syntactic sugar to make the compiler happy with two different kinds of iterator callbacks */
typedef union {
@ -147,6 +147,10 @@ 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, unsigned chunkno, unsigned idx,
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);
@ -746,7 +750,7 @@ H5O_new(H5F_t *f, hid_t dxpl_id, size_t chunk_size, H5O_loc_t *loc/*out*/,
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
/* Initialize rudimentary information object object header */
oh->version = H5O_VERSION_1;
oh->version = H5F_USE_LATEST_FORMAT(f) ? H5O_VERSION_LATEST : H5O_VERSION_1;
oh->nlink = 0;
/* Compute total size of initial object header */
@ -754,8 +758,7 @@ H5O_new(H5F_t *f, hid_t dxpl_id, size_t chunk_size, H5O_loc_t *loc/*out*/,
oh_size = H5O_SIZEOF_HDR_OH(oh) + chunk_size;
/* Create the chunk list */
oh->nchunks = 1;
oh->alloc_nchunks = H5O_NCHUNKS;
oh->nchunks = oh->alloc_nchunks = 1;
if(NULL == (oh->chunk = H5FL_SEQ_MALLOC(H5O_chunk_t, (size_t)oh->alloc_nchunks)))
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
@ -763,6 +766,7 @@ H5O_new(H5F_t *f, hid_t dxpl_id, size_t chunk_size, H5O_loc_t *loc/*out*/,
oh->chunk[0].dirty = TRUE;
oh->chunk[0].addr = loc->addr;
oh->chunk[0].size = oh_size;
oh->chunk[0].gap = 0;
/* Allocate enough space for the first chunk */
/* (including space for serializing the object header prefix */
@ -2445,8 +2449,8 @@ done:
*-------------------------------------------------------------------------
*/
static herr_t
H5O_remove_cb(H5O_mesg_t *mesg/*in,out*/, unsigned idx, unsigned * oh_flags_ptr,
void *_udata/*in,out*/)
H5O_remove_cb(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/, unsigned idx,
unsigned * oh_flags_ptr, void *_udata/*in,out*/)
{
H5O_iter_ud1_t *udata = (H5O_iter_ud1_t *)_udata; /* Operator user data */
htri_t try_remove = FALSE; /* Whether to try removing a message */
@ -2475,9 +2479,8 @@ H5O_remove_cb(H5O_mesg_t *mesg/*in,out*/, unsigned idx, unsigned * oh_flags_ptr,
* Keep track of how many times we failed trying to remove constant
* messages.
*/
if(mesg->flags & H5O_FLAG_CONSTANT) {
if(mesg->flags & H5O_FLAG_CONSTANT)
udata->nfailed++;
} /* end if */
else {
/* Free any space referred to in the file from this message */
if(H5O_delete_mesg(udata->f, udata->dxpl_id, mesg, udata->adj_link) < 0)
@ -2488,11 +2491,27 @@ H5O_remove_cb(H5O_mesg_t *mesg/*in,out*/, unsigned idx, unsigned * oh_flags_ptr,
/* Change message type to nil and zero it */
mesg->type = H5O_MSG_NULL;
#ifdef QAK
HDfprintf(stderr, "%s: oh->version = %u\n", FUNC, oh->version);
HDfprintf(stderr, "%s: mesg->raw_size = %Zu\n", FUNC, mesg->raw_size);
#endif /* QAK */
HDmemset(mesg->raw, 0, mesg->raw_size);
/* 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->chunkno, idx,
((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, H5O_ITER_ERROR, "can't insert eliminate in chunk")
/* Set the gap size to zero for the chunk */
oh->chunk[mesg->chunkno].gap = 0;
} /* end if */
/* Indicate that the object header was modified */
*oh_flags_ptr |= H5AC__DIRTIED_FLAG;
} /* end else */
@ -2542,7 +2561,8 @@ H5O_remove_real(const H5O_loc_t *loc, const H5O_msg_class_t *type, int sequence,
HDassert(loc->file);
HDassert(type);
if (0==(loc->file->intent & H5F_ACC_RDWR))
/* Make certain we are allowed to modify the file */
if(0 == (loc->file->intent & H5F_ACC_RDWR))
HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "no write intent on file")
/* Set up iterator operator data */
@ -2659,7 +2679,8 @@ H5O_move_msgs_forward(H5F_t *f, H5O_t *oh, hid_t dxpl_id)
/* Check if null message is not last in chunk */
chunk = &(oh->chunk[curr_msg->chunkno]);
if((curr_msg->raw + curr_msg->raw_size + H5O_SIZEOF_CHKSUM_OH(oh)) != (chunk->image + chunk->size)) {
if((curr_msg->raw + curr_msg->raw_size)
!= ((chunk->image + chunk->size) - (H5O_SIZEOF_CHKSUM_OH(oh) + chunk->gap))) {
H5O_mesg_t *nonnull_msg; /* Pointer to current message to operate on */
unsigned v; /* Local index variable */
@ -2749,18 +2770,46 @@ H5O_move_msgs_forward(H5F_t *f, H5O_t *oh, hid_t dxpl_id)
/* Mark non-null message dirty */
curr_msg->dirty = TRUE;
/* 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);
/* Check if null message is large enough to still exist */
if(null_msg->raw_size - curr_msg->raw_size < H5O_SIZEOF_MSGHDR_OH(oh)) {
size_t gap_size = null_msg->raw_size - curr_msg->raw_size; /* Size of gap produced */
/* Mark null message dirty */
null_msg->dirty = TRUE;
/* Adjust the size of the null message being eliminated */
null_msg->raw_size -= gap_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")
/*
* Delete null message from list of messages
*/
/* Release any information/memory for message */
H5O_free_mesg(null_msg);
null_msg = NULL;
/* Remove null 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--;
} /* 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;
} /* end else */
/* Create new null message for previous location of non-null message */
if(oh->nmesgs >= oh->alloc_nmesgs) {
if(H5O_alloc_msgs(oh, (size_t)0) < 0)
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")
} /* end if */
/* Get message # for new message */
new_null_msg = oh->nmesgs++;
@ -2772,6 +2821,18 @@ H5O_move_msgs_forward(H5F_t *f, H5O_t *oh, hid_t dxpl_id)
oh->mesg[new_null_msg].raw = old_raw;
oh->mesg[new_null_msg].raw_size = old_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, old_chunkno, 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 insert eliminate 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 */
@ -2848,6 +2909,9 @@ H5O_merge_null(H5O_t *oh)
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) {
@ -2955,7 +3019,8 @@ H5O_remove_empty_chunks(H5F_t *f, H5O_t *oh, hid_t dxpl_id)
* 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 + H5O_SIZEOF_CHKHDR_OH(oh)) == oh->chunk[null_msg->chunkno].size) {
(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 */
@ -3177,7 +3242,9 @@ H5O_alloc_extend_chunk(H5F_t *f,
/* 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 + H5O_SIZEOF_CHKSUM_OH(oh)) == oh->chunk[chunkno].image + oh->chunk[chunkno].size)) {
((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;
@ -3185,10 +3252,12 @@ H5O_alloc_extend_chunk(H5F_t *f,
} /* end for */
/* If we can extend an existing null message, adjust the delta appropriately */
if(extend_msg >= 0)
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);
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 */
@ -3214,7 +3283,7 @@ H5O_alloc_extend_chunk(H5F_t *f,
else {
/* Create a new null message */
if(oh->nmesgs >= oh->alloc_nmesgs)
if(H5O_alloc_msgs(oh, (size_t)0) < 0)
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 */
@ -3224,9 +3293,10 @@ H5O_alloc_extend_chunk(H5F_t *f,
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_MSGHDR_OH(oh);
oh->mesg[extend_msg].raw_size = delta - H5O_SIZEOF_MSGHDR_OH(oh);
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 */
@ -3235,6 +3305,7 @@ H5O_alloc_extend_chunk(H5F_t *f,
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")
@ -3421,6 +3492,7 @@ H5O_alloc_new_chunk(H5F_t *f,
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")
@ -3514,6 +3586,190 @@ 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, unsigned chunkno, unsigned idx,
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 */
unsigned u; /* Local index variable */
FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_eliminate_gap)
/* check args */
HDassert(oh);
HDassert(oh->version > H5O_VERSION_1);
HDassert(gap_loc);
HDassert(gap_size);
/* Check if the null message is before or after the gap produced */
null_before_gap = (hbool_t)(oh->mesg[idx].raw < gap_loc);
/* Set up information about region of messages to move */
if(null_before_gap) {
move_start = oh->mesg[idx].raw + oh->mesg[idx].raw_size;
move_end = gap_loc;
} /* end if */
else {
move_start = gap_loc + gap_size;
move_end = oh->mesg[idx].raw - H5O_SIZEOF_MSGHDR_OH(oh);
} /* end else */
HDassert(move_end > move_start);
/* Look for other messages that will 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 == 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, move_start + gap_size, (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 */
oh->mesg[idx].raw -= gap_size;
} /* end else */
/* Zero out addition to null message */
HDmemset(oh->mesg[idx].raw + oh->mesg[idx].raw_size, 0, gap_size);
/* Adjust size of null message */
oh->mesg[idx].raw_size += gap_size;
/* Mark null message as dirty */
oh->mesg[idx].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, chunkno, 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 >= 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")
} /* end if */
/* 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
@ -3590,32 +3846,48 @@ H5O_alloc(H5F_t *f,
/* Set pointer to newly allocated message */
msg = &(oh->mesg[idx]);
/* do we need to split the null message? */
/* Do we need to split the existing null message? */
if(msg->raw_size > aligned_size) {
H5O_mesg_t *null_msg; /* Pointer to null message */
size_t mesg_size = aligned_size + H5O_SIZEOF_MSGHDR_OH(oh); /* Total size of newly allocated message */
HDassert(msg->raw_size - aligned_size >= H5O_SIZEOF_MSGHDR_OH(oh));
/* Check for producing a gap in the chunk */
if((msg->raw_size - aligned_size) < H5O_SIZEOF_MSGHDR_OH(oh)) {
size_t gap_size = msg->raw_size - aligned_size; /* Size of gap produced */
/* Check if we need to extend message table */
if(oh->nmesgs >= oh->alloc_nmesgs) {
if(H5O_alloc_msgs(oh, (size_t)0) < 0)
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "can't allocate more space for messages")
/* Adjust the size of the null message being eliminated */
msg->raw_size -= gap_size;
/* "Retarget" local 'msg' pointer into newly allocated array of messages */
msg = &oh->mesg[idx];
/* Add the gap to the chunk */
if(H5O_add_gap(oh, msg->chunkno, idx, msg->raw + msg->raw_size, gap_size) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, UFAIL, "can't insert gap in chunk")
} /* end if */
null_msg = &(oh->mesg[oh->nmesgs++]);
null_msg->type = H5O_MSG_NULL;
null_msg->dirty = TRUE;
null_msg->native = NULL;
null_msg->raw = msg->raw + mesg_size;
null_msg->raw_size = msg->raw_size - mesg_size;
null_msg->chunkno = msg->chunkno;
else {
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" local 'msg' pointer into newly re-allocated array of messages */
msg = &oh->mesg[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 = msg->raw + mesg_size;
null_msg->raw_size = msg->raw_size - mesg_size;
null_msg->chunkno = msg->chunkno;
} /* end else */
/* Set the size of the new "real" message */
msg->raw_size = aligned_size;
} /* end if */
/* initialize the new message */
/* Initialize the new message */
msg->type = type;
msg->dirty = TRUE;
msg->native = NULL;
@ -4180,7 +4452,7 @@ H5O_iterate_real(const H5O_loc_t *loc, const H5O_msg_class_t *type, H5AC_protect
/* Check for making an "internal" (i.e. within the H5O package) callback */
if(internal) {
/* Call the "internal" iterator callback */
if((ret_value = (op.lib_op)(idx_msg, sequence, &oh_flags, op_data)) != 0)
if((ret_value = (op.lib_op)(oh, idx_msg, sequence, &oh_flags, op_data)) != 0)
break;
} /* end if */
else {
@ -4206,6 +4478,10 @@ done:
HDassert(prot == H5AC_WRITE);
/* Try to condense object header info */
/* (Since this routine is invoked when a message is removed from
* an object header, the header will be condensed after each
* message removal)
*/
if(H5O_condense_header(loc->file, oh, dxpl_id) < 0)
HDONE_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "can't pack object header")
@ -4635,6 +4911,7 @@ H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */,
/* Set dest. chunk information */
oh_dst->chunk[chunkno].dirty = TRUE;
oh_dst->chunk[chunkno].size = chunk_size;
oh_dst->chunk[chunkno].gap = oh_src->chunk[chunkno].gap;
} /* end for */
@ -4715,7 +4992,7 @@ H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */,
/* (Use destination message, in case the message has been removed (i.e
* converted to a nil message) in the destination -QAK)
*/
if (mesg_dst->flags & H5O_FLAG_SHARED)
if(mesg_dst->flags & H5O_FLAG_SHARED)
copy_type = H5O_MSG_SHARED;
else
copy_type = mesg_dst->type;
@ -5317,6 +5594,10 @@ H5O_debug_real(H5F_t *f, hid_t dxpl_id, H5O_t *oh, haddr_t addr, FILE *stream, i
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 */

View File

@ -139,6 +139,13 @@ H5O_flush_msgs(H5F_t *f, H5O_t *oh)
*p++ = 0; /*reserved*/
*p++ = 0; /*reserved*/
} /* end for */
HDassert(p == curr_msg->raw);
#ifndef NDEBUG
/* Make certain that null messages aren't in chunks w/gaps */
if(H5O_NULL_ID == curr_msg->type->id)
HDassert(oh->chunk[curr_msg->chunkno].gap == 0);
#endif /* NDEBUG */
/* Encode the message itself */
if(curr_msg->native) {
@ -154,7 +161,7 @@ H5O_flush_msgs(H5F_t *f, H5O_t *oh)
HDassert(curr_msg->raw >= oh->chunk[curr_msg->chunkno].image);
HDassert(curr_msg->raw_size == H5O_ALIGN_OH(oh, curr_msg->raw_size));
HDassert(curr_msg->raw + curr_msg->raw_size <=
oh->chunk[curr_msg->chunkno].image + oh->chunk[curr_msg->chunkno].size);
oh->chunk[curr_msg->chunkno].image + (oh->chunk[curr_msg->chunkno].size - H5O_SIZEOF_CHKSUM_OH(oh)));
if(curr_msg->flags & H5O_FLAG_SHARED)
encode = H5O_MSG_SHARED->encode;
else
@ -162,6 +169,8 @@ H5O_flush_msgs(H5F_t *f, H5O_t *oh)
if((encode)(f, curr_msg->raw, curr_msg->native) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to encode object header message")
} /* end if */
/* Pass "modifiedness" from message to chunk */
curr_msg->dirty = FALSE;
oh->chunk[curr_msg->chunkno].dirty = TRUE;
} /* end if */
@ -208,7 +217,6 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
size_t chunk_size; /* Size of first chunk */
haddr_t abs_eoa; /* Absolute end of file address */
haddr_t rel_eoa; /* Relative end of file address */
uint32_t prefix_chksum = 0; /* Checksum of object header prefix */
H5O_t *ret_value; /* Return value */
FUNC_ENTER_NOAPI(H5O_load, NULL)
@ -275,10 +283,6 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
/* Determine object header prefix length */
prefix_size = (size_t)(p - read_buf);
/* Compute partial checksum, for later versions of the format */
if(oh->version > H5O_VERSION_1)
prefix_chksum = H5_checksum_lookup3(read_buf, prefix_size, 0);
/* Compute first chunk address */
chunk_addr = addr + (hsize_t)prefix_size;
@ -290,6 +294,10 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
/* Read each chunk from disk */
while(H5F_addr_defined(chunk_addr)) {
unsigned chunkno; /* Current chunk's index */
#ifndef NDEBUG
unsigned nullcnt; /* Count of null messages (for sanity checking gaps in chunks) */
#endif /* NDEBUG */
uint8_t *eom_ptr; /* Pointer to end of messages for a chunk */
/* Increase chunk array size, if necessary */
if(oh->nchunks >= oh->alloc_nchunks) {
@ -305,6 +313,7 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
/* Init the chunk data info */
chunkno = oh->nchunks++;
oh->chunk[chunkno].dirty = FALSE;
oh->chunk[chunkno].gap = 0;
if(chunkno == 0) {
/* First chunk's 'image' includes room for the object header prefix */
oh->chunk[0].addr = addr;
@ -354,7 +363,11 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
} /* end if */
/* Decode messages from this chunk */
while(p < (oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM_OH(oh)))) {
eom_ptr = oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM_OH(oh));
#ifndef NDEBUG
nullcnt = 0;
#endif /* NDEBUG */
while(p < eom_ptr) {
unsigned mesgno; /* Current message to operate on */
size_t mesg_size; /* Size of message read in */
unsigned id; /* ID (type) of current message */
@ -368,8 +381,10 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
if(oh->version == H5O_VERSION_1)
p += 3; /*reserved*/
/* Try to detect invalidly formatted object header messages */
if(p + mesg_size > oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM_OH(oh)))
/* Try to detect invalidly formatted object header message that
* extends past end of chunk.
*/
if(p + mesg_size > eom_ptr)
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "corrupt object header")
/* Skip header messages we don't know about */
@ -377,42 +392,58 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
if(id >= NELMTS(H5O_msg_class_g) || NULL == H5O_msg_class_g[id]) {
/* Increment skipped messages counter */
skipped_msgs++;
/* Advance decode pointer past message */
p += mesg_size;
/* Go get next message */
continue;
} /* end if */
/* Check for combining two adjacent 'null' messages */
if((H5F_get_intent(f) & H5F_ACC_RDWR) &&
H5O_NULL_ID == id && oh->nmesgs > 0 &&
H5O_NULL_ID == oh->mesg[oh->nmesgs - 1].type->id &&
oh->mesg[oh->nmesgs - 1].chunkno == chunkno) {
/* Combine adjacent null messages */
mesgno = oh->nmesgs - 1;
oh->mesg[mesgno].raw_size += H5O_SIZEOF_MSGHDR_OH(oh) + mesg_size;
oh->mesg[mesgno].dirty = TRUE;
merged_null_msgs++;
} /* end if */
else {
/* New message */
if(oh->nmesgs >= nmesgs)
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "corrupt object header - too many messages")
mesgno = oh->nmesgs++;
oh->mesg[mesgno].type = H5O_msg_class_g[id];
oh->mesg[mesgno].dirty = FALSE;
oh->mesg[mesgno].flags = flags;
oh->mesg[mesgno].native = NULL;
oh->mesg[mesgno].raw = p;
oh->mesg[mesgno].raw_size = mesg_size;
oh->mesg[mesgno].chunkno = chunkno;
} /* end else */
#ifndef NDEBUG
/* Increment count of null messages */
if(H5O_NULL_ID == id)
nullcnt++;
#endif /* NDEBUG */
/* Check for combining two adjacent 'null' messages */
if((H5F_get_intent(f) & H5F_ACC_RDWR) &&
H5O_NULL_ID == id && oh->nmesgs > 0 &&
H5O_NULL_ID == oh->mesg[oh->nmesgs - 1].type->id &&
oh->mesg[oh->nmesgs - 1].chunkno == chunkno) {
/* Combine adjacent null messages */
mesgno = oh->nmesgs - 1;
oh->mesg[mesgno].raw_size += H5O_SIZEOF_MSGHDR_OH(oh) + mesg_size;
oh->mesg[mesgno].dirty = TRUE;
merged_null_msgs++;
} /* end if */
else {
/* New message */
if(oh->nmesgs >= nmesgs)
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "corrupt object header - too many messages")
mesgno = oh->nmesgs++;
oh->mesg[mesgno].type = H5O_msg_class_g[id];
oh->mesg[mesgno].dirty = FALSE;
oh->mesg[mesgno].flags = flags;
oh->mesg[mesgno].native = NULL;
oh->mesg[mesgno].raw = p;
oh->mesg[mesgno].raw_size = mesg_size;
oh->mesg[mesgno].chunkno = chunkno;
} /* end else */
} /* end else */
/* Advance decode pointer past message */
p += mesg_size;
/* Check for 'gap' at end of chunk */
if((eom_ptr - p) > 0 && (eom_ptr - p) < H5O_SIZEOF_MSGHDR_OH(oh)) {
/* Gaps can only occur in later versions of the format */
HDassert(oh->version > H5O_VERSION_1);
/* Gaps should only occur in chunks with no null messages */
HDassert(nullcnt == 0);
/* Set gap information for chunk */
oh->chunk[chunkno].gap = (eom_ptr - p);
/* Increment location in chunk */
p += oh->chunk[chunkno].gap;
} /* end if */
} /* end while */
/* Check for correct checksum on chunks, in later versions of the format */
@ -423,11 +454,8 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
/* Metadata checksum */
UINT32DECODE(p, stored_chksum);
/* Compute checksum on entire header */
if(chunkno == 0)
computed_chksum = H5_checksum_metadata(oh->chunk[chunkno].image + prefix_size, chunk_size, prefix_chksum);
else
computed_chksum = H5_checksum_metadata(oh->chunk[chunkno].image, (chunk_size - H5O_SIZEOF_CHKSUM), 0);
/* Compute checksum on chunk */
computed_chksum = H5_checksum_metadata(oh->chunk[chunkno].image, (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM), 0);
/* Verify checksum */
if(stored_chksum != computed_chksum)
@ -509,10 +537,6 @@ H5O_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t UNUSED addr, H5O_t *
uint8_t *p; /* Pointer to object header prefix buffer */
unsigned u; /* Local index variable */
/* Encode any dirty messages */
if(H5O_flush_msgs(f, oh) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object header messages")
/* Point to raw data 'image' for first chunk, which has room for the prefix */
p = oh->chunk[0].image;
@ -521,13 +545,8 @@ H5O_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t UNUSED addr, H5O_t *
* on the entire block of memory needs to be updated if anything is
* modified */
if(oh->version > H5O_VERSION_1) {
size_t prefix_size; /* Length of object header prefix */
uint32_t prefix_chksum; /* Prefix checksum value */
uint32_t full_chksum; /* Full checksum value */
size_t raw_size; /* Size of raw data in first chunk */
/* Verify magic number */
HDassert(!HDmemcmp(oh->chunk[u].image, H5O_HDR_MAGIC, H5O_SIZEOF_MAGIC));
HDassert(!HDmemcmp(oh->chunk[0].image, H5O_HDR_MAGIC, H5O_SIZEOF_MAGIC));
p += H5O_SIZEOF_MAGIC;
/* Version */
@ -541,24 +560,6 @@ H5O_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t UNUSED addr, H5O_t *
/* Chunk size */
UINT32ENCODE(p, (oh->chunk[0].size - H5O_SIZEOF_HDR_OH(oh)));
/* Determine object header prefix length */
prefix_size = (size_t)(p - oh->chunk[0].image);
/* Compute partial checksum for later */
/* (checksum performed in this odd way in order to accomodate
* reading in the header & first chunk in reasonable way)
*/
prefix_chksum = H5_checksum_lookup3(oh->chunk[0].image, prefix_size, 0);
/* Finish full checksum, over chunk data */
raw_size = oh->chunk[0].size - H5O_SIZEOF_HDR_OH(oh);
full_chksum = H5_checksum_metadata(p, raw_size, prefix_chksum);
p += raw_size;
/* Metadata checksum */
UINT32ENCODE(p, full_chksum);
HDassert((size_t)(p - oh->chunk[0].image) == oh->chunk[0].size);
} /* end if */
else {
/* Version */
@ -578,26 +579,42 @@ H5O_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t UNUSED addr, H5O_t *
/* Zero to alignment */
HDmemset(p, 0, (size_t)(H5O_SIZEOF_HDR_OH(oh) - 12));
p += (size_t)(H5O_SIZEOF_HDR_OH(oh) - 12);
} /* end else */
HDassert((size_t)(p - oh->chunk[0].image) == (size_t)(H5O_SIZEOF_HDR_OH(oh) - H5O_SIZEOF_CHKSUM_OH(oh)));
/* Mark chunk 0 as dirty, since the object header prefix has been updated */
/* (this could be more sophisticated and track whether any prefix fields
* have been changed, which could save I/O accesses - QAK)
* have been changed, which could save I/O accesses if the
* messages in chunk 0 haven't changed - QAK)
*/
HDassert(H5F_addr_eq(addr, oh->chunk[0].addr));
oh->chunk[0].dirty = TRUE;
/* Encode any dirty messages */
if(H5O_flush_msgs(f, oh) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object header messages")
/* Write each chunk to disk, if it's dirty */
for(u = 0; u < oh->nchunks; u++) {
/* Sanity check - make certain the magic # is present */
/* Sanity checks */
if(oh->version > H5O_VERSION_1)
/* Make certain the magic # is present */
HDassert(!HDmemcmp(oh->chunk[u].image, (u == 0 ? H5O_HDR_MAGIC : H5O_CHK_MAGIC), H5O_SIZEOF_MAGIC));
else
/* Gaps should never occur in version 1 of the format */
HDassert(oh->chunk[u].gap == 0);
/* Write out chunk, if it's dirty */
if(oh->chunk[u].dirty) {
/* Compute checksum, for chunks > 0 & later versions of format */
if(u > 0 && oh->version > H5O_VERSION_1) {
uint32_t metadata_chksum; /* Computed metadata checksum value */
/* Extra work, for later versions of the format */
if(oh->version > H5O_VERSION_1) {
uint32_t metadata_chksum; /* Computed metadata checksum value */
/* Check for gap in chunk & zero it out */
if(oh->chunk[u].gap)
HDmemset((oh->chunk[u].image + oh->chunk[u].size) -
(H5O_SIZEOF_CHKSUM + oh->chunk[u].gap), 0, oh->chunk[u].gap);
/* Compute metadata checksum */
metadata_chksum = H5_checksum_metadata(oh->chunk[u].image, (oh->chunk[u].size - H5O_SIZEOF_CHKSUM), 0);
@ -704,28 +721,28 @@ H5O_clear(H5F_t *f, H5O_t *oh, hbool_t destroy)
unsigned u; /* Local index variable */
herr_t ret_value = SUCCEED;
FUNC_ENTER_NOAPI_NOINIT(H5O_clear);
FUNC_ENTER_NOAPI_NOINIT(H5O_clear)
/* check args */
assert(oh);
HDassert(oh);
/* Mark chunks as clean */
for (u = 0; u < oh->nchunks; u++)
oh->chunk[u].dirty=FALSE;
for(u = 0; u < oh->nchunks; u++)
oh->chunk[u].dirty = FALSE;
/* Mark messages as clean */
for (u = 0; u < oh->nmesgs; u++)
oh->mesg[u].dirty=FALSE;
for(u = 0; u < oh->nmesgs; u++)
oh->mesg[u].dirty = FALSE;
/* Mark whole header as clean */
oh->cache_info.is_dirty=FALSE;
oh->cache_info.is_dirty = FALSE;
if (destroy)
if (H5O_dest(f, oh) < 0)
if(destroy)
if(H5O_dest(f, oh) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header data")
done:
FUNC_LEAVE_NOAPI(ret_value);
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5O_clear() */
@ -755,11 +772,9 @@ H5O_size(const H5F_t UNUSED *f, const H5O_t *oh, size_t *size_ptr)
HDassert(oh);
HDassert(size_ptr);
/* Size of object header "prefix" */
size = H5O_SIZEOF_HDR_OH(oh);
/* Add sizes of all the chunks */
for(u = 0; u < oh->nchunks; u++)
/* (includes size of prefix, in chunk 0) */
for(u = 0, size = 0; u < oh->nchunks; u++)
size += oh->chunk[u].size;
*size_ptr = size;

View File

@ -94,25 +94,27 @@ H5O_cont_decode(H5F_t *f, hid_t UNUSED dxpl_id, const uint8_t *p)
H5O_cont_t *cont = NULL;
void *ret_value;
FUNC_ENTER_NOAPI_NOINIT(H5O_cont_decode);
FUNC_ENTER_NOAPI_NOINIT(H5O_cont_decode)
/* check args */
assert(f);
assert(p);
HDassert(f);
HDassert(p);
/* decode */
if (NULL==(cont = H5FL_MALLOC(H5O_cont_t)))
/* Allocate space for the message */
if(NULL == (cont = H5FL_MALLOC(H5O_cont_t)))
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
/* Decode */
H5F_addr_decode(f, &p, &(cont->addr));
H5F_DECODE_LENGTH(f, p, cont->size);
cont->chunkno=0;
cont->chunkno = 0;
/* Set return value */
ret_value=cont;
ret_value = cont;
done:
FUNC_LEAVE_NOAPI(ret_value);
}
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5O_cont_decode() */
/*-------------------------------------------------------------------------
@ -264,7 +266,7 @@ static void *
H5O_cont_copy_file(H5F_t UNUSED *file_src, void *mesg_src, H5F_t UNUSED *file_dst,
hid_t UNUSED dxpl_id, H5O_copy_t UNUSED *cpy_info, void *udata)
{
H5O_cont_t *cont_src = (H5O_cont_t *) mesg_src;
H5O_cont_t *cont_src = (H5O_cont_t *)mesg_src;
H5O_chunk_t *chunk = (H5O_chunk_t *)udata;
H5O_cont_t *cont_dst = NULL;
void *ret_value; /* Return value */
@ -273,13 +275,15 @@ H5O_cont_copy_file(H5F_t UNUSED *file_src, void *mesg_src, H5F_t UNUSED *file_ds
/* check args */
HDassert(cont_src);
HDassert(file_dst);
/* Allocate space for the destination cont */
if(NULL == (cont_dst = H5FL_MALLOC(H5O_cont_t)))
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
HDmemcpy(cont_dst, cont_src, sizeof(H5O_cont_t));
/* Shallow copy all the fields */
*cont_dst = *cont_src;
/* Update the destination address to point to correct address in dest. file */
cont_dst->addr = chunk[cont_src->chunkno].addr;
/* Set return value */

View File

@ -107,7 +107,8 @@
3) /*reserved */ \
: \
(2 + /*message type */ \
2) /*sizeof message data */ \
2 + /*sizeof message data */ \
1) /*flags */ \
)
#define H5O_SIZEOF_MSGHDR_OH(O) \
H5O_SIZEOF_MSGHDR_VERS((O)->version)
@ -174,6 +175,7 @@ typedef struct H5O_chunk_t {
hbool_t dirty; /*dirty flag */
haddr_t addr; /*chunk file address */
size_t size; /*chunk size */
size_t gap; /*space at end of chunk too small for null message */
uint8_t *image; /*image of file */
} H5O_chunk_t;