summaryrefslogtreecommitdiffstats
path: root/src/H5O.c
diff options
context:
space:
mode:
authorJohn Mainzer <mainzer@hdfgroup.org>2005-09-27 05:20:11 (GMT)
committerJohn Mainzer <mainzer@hdfgroup.org>2005-09-27 05:20:11 (GMT)
commitc100b0bf2639c03579ce1b2c4013b36c6f40350b (patch)
tree5c3b2834af1206110243886f357857900a8b108e /src/H5O.c
parentf9fc749ca218a878dbea4022ba1c2fb527f7822c (diff)
downloadhdf5-c100b0bf2639c03579ce1b2c4013b36c6f40350b.zip
hdf5-c100b0bf2639c03579ce1b2c4013b36c6f40350b.tar.gz
hdf5-c100b0bf2639c03579ce1b2c4013b36c6f40350b.tar.bz2
[svn-r11470] Purpose:
Repair synchronization bug in the metadata cache in PHDF5 Also repair numerous other bugs that surfaced in testing the bug fix. Description: While operations modifying metadata must be collective, we allow independant reads. This allows metadata caches on different processes to adjust to different sizes, and to place the entries on their dirty lists in different orders. Since only process 0 actually writes metadata to disk (all other processes thought they did, but the writes were discarded on the theory that they had to be collective), this made it possible for another process to modify metadata, flush it, and then read it back in in its original form (pre-modification) form. The possibilities for file corruption should be obvious. Solution: Make the policy that only process 0 can write to file explicit, and visible to the metadata caches. Thus only process 0 may flush dirty entries -- all other caches must retain dirty entries until they are informed by process 0 that the entries are clean. Synchronization is handled by counting the bytes of dirty cache entries created, and then synching up between the caches whenever the sum exceeds an (eventually user specified) limit. Dirty metadata creation is consistent across all processes because all operations modifying metadata must be collective. This change uncovered may bugs which are repaired in this checkin. It also required modification of H5HL and H5O to allocate file space on insertion rather than on flush from cache. Platforms tested: H5committest, heping(parallel & serial) Misc. update:
Diffstat (limited to 'src/H5O.c')
-rw-r--r--src/H5O.c746
1 files changed, 500 insertions, 246 deletions
diff --git a/src/H5O.c b/src/H5O.c
index c1d8d46..81da26f 100644
--- a/src/H5O.c
+++ b/src/H5O.c
@@ -89,10 +89,12 @@ 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(H5G_entry_t *ent, const H5O_class_t *type,
int sequence, H5O_operator_t op, void *op_data, hbool_t adj_link, hid_t dxpl_id);
-static unsigned H5O_alloc(H5F_t *f, H5O_t *oh, const H5O_class_t *type,
- size_t size, unsigned * oh_flags_ptr);
-static unsigned H5O_alloc_extend_chunk(H5F_t *f, H5O_t *oh, unsigned chunkno, size_t size);
-static unsigned H5O_alloc_new_chunk(H5F_t *f, H5O_t *oh, size_t size);
+static unsigned H5O_alloc(H5F_t *f, hid_t dxpl_id, H5O_t *oh,
+ const H5O_class_t *type, size_t size, hbool_t * oh_dirtied_ptr);
+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);
@@ -582,8 +584,12 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
p += 3; /*reserved*/
/* Try to detect invalidly formatted object header messages */
- if (p + mesg_size > oh->chunk[chunkno].image + chunk_size)
- HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "corrupt object header");
+ if (p + mesg_size > oh->chunk[chunkno].image + chunk_size) {
+
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, \
+ "corrupt object header");
+ }
+
/* Skip header messages we don't know about */
/* (Usually from future versions of the library */
@@ -740,17 +746,12 @@ H5O_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5O_t *oh)
/* allocate file space for chunks that have none yet */
if (H5O_CONT_ID == curr_msg->type->id &&
!H5F_addr_defined(((H5O_cont_t *)(curr_msg->native))->addr)) {
- cont = (H5O_cont_t *) (curr_msg->native);
- assert(cont->chunkno < oh->nchunks);
- assert(!H5F_addr_defined(oh->chunk[cont->chunkno].addr));
- cont->size = oh->chunk[cont->chunkno].size;
-
- /* Free the space we'd reserved in the file to hold this chunk */
- H5MF_free_reserved(f, (hsize_t)cont->size);
-
- if (HADDR_UNDEF==(cont->addr=H5MF_alloc(f, H5FD_MEM_OHDR, dxpl_id, (hsize_t)cont->size)))
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate space for object header data");
- oh->chunk[cont->chunkno].addr = cont->addr;
+ /* We now allocate disk space on insertion, instead
+ * of on flush from the cache, so this case is now an
+ * error. -- JRM
+ */
+ HGOTO_ERROR(H5E_OHDR, H5E_SYSTEM, FAIL,
+ "File space for message not allocated!?!");
}
/*
@@ -1972,7 +1973,7 @@ H5O_modify_real(H5G_entry_t *ent, const H5O_class_t *type, int overwrite,
/* Update the modification time message if any */
if(update_flags&H5O_UPDATE_TIME)
- H5O_touch_oh(ent->file, oh, FALSE, &oh_flags);
+ H5O_touch_oh(ent->file, dxpl_id, oh, FALSE, &oh_flags);
/* Set return value */
ret_value = sequence;
@@ -2258,7 +2259,8 @@ H5O_new_mesg(H5F_t *f, H5O_t *oh, unsigned *flags, const H5O_class_t *orig_type,
HGOTO_ERROR (H5E_OHDR, H5E_CANTINIT, UFAIL, "object header message is too large (16k max)");
/* Allocate space in the object headed for the message */
- if ((ret_value = H5O_alloc(f, oh, orig_type, size, oh_flags_ptr)) == UFAIL)
+ if ((ret_value = H5O_alloc(f, dxpl_id, oh,
+ orig_type, size, oh_flags_ptr)) == UFAIL)
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, UFAIL, "unable to allocate space for message");
/* Increment any links in message */
@@ -2346,10 +2348,18 @@ done:
* In this case, that requires the addition of the oh_dirtied_ptr
* parameter to track whether *oh is dirty.
*
+ * John Mainzer, 8/20/05
+ * Added dxpl_id parameter needed by the revised version of
+ * H5O_alloc().
+ *
*-------------------------------------------------------------------------
*/
herr_t
-H5O_touch_oh(H5F_t *f, H5O_t *oh, hbool_t force, unsigned * oh_flags_ptr)
+H5O_touch_oh(H5F_t *f,
+ hid_t dxpl_id,
+ H5O_t *oh,
+ hbool_t force,
+ unsigned * oh_flags_ptr)
{
unsigned idx;
#ifdef H5_HAVE_GETTIMEOFDAY
@@ -2382,7 +2392,9 @@ H5O_touch_oh(H5F_t *f, H5O_t *oh, hbool_t force, unsigned * oh_flags_ptr)
if (!force)
HGOTO_DONE(SUCCEED); /*nothing to do*/
size = (H5O_MTIME_NEW->raw_size)(f, &now);
- if ((idx=H5O_alloc(f, oh, H5O_MTIME_NEW, size, oh_flags_ptr))==UFAIL)
+
+ if ((idx=H5O_alloc(f, dxpl_id, oh, H5O_MTIME_NEW,
+ size, oh_flags_ptr))==UFAIL)
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to allocate space for modification time message");
}
@@ -2442,7 +2454,7 @@ H5O_touch(H5G_entry_t *ent, hbool_t force, hid_t dxpl_id)
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header");
/* Create/Update the modification time message */
- if (H5O_touch_oh(ent->file, oh, force, &oh_flags)<0)
+ if (H5O_touch_oh(ent->file, dxpl_id, oh, force, &oh_flags)<0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to update object modificaton time");
done:
@@ -2473,10 +2485,13 @@ done:
* In this case, that requires the addition of the oh_dirtied_ptr
* parameter to track whether *oh is dirty.
*
+ * John Mainzer, 8/20/05
+ * Added dxpl_id parameter needed by call to H5O_alloc().
+ *
*-------------------------------------------------------------------------
*/
herr_t
-H5O_bogus_oh(H5F_t *f, H5O_t *oh, hbool_t * oh_flags_ptr)
+H5O_bogus_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh, hbool_t * oh_flags_ptr)
{
int idx;
size_t size;
@@ -2496,7 +2511,7 @@ H5O_bogus_oh(H5F_t *f, H5O_t *oh, hbool_t * oh_flags_ptr)
/* Create a new message */
if (idx==oh->nmesgs) {
size = (H5O_BOGUS->raw_size)(f, NULL);
- if ((idx=H5O_alloc(f, oh, H5O_BOGUS, size, oh_flags_ptr))<0)
+ if ((idx=H5O_alloc(f, dxpl_id, oh, H5O_BOGUS, size, oh_flags_ptr))<0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to allocate space for 'bogus' message");
/* Allocate the native message in memory */
@@ -2507,6 +2522,7 @@ H5O_bogus_oh(H5F_t *f, H5O_t *oh, hbool_t * oh_flags_ptr)
((H5O_bogus_t *)(oh->mesg[idx].native))->u = H5O_BOGUS_VALUE;
/* Mark the message and object header as dirty */
+ *oh_flags_ptr = TRUE;
oh->mesg[idx].dirty = TRUE;
oh->dirty = TRUE;
} /* end if */
@@ -2558,7 +2574,7 @@ H5O_bogus(H5G_entry_t *ent, hid_t dxpl_id)
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header");
/* Create the "bogus" message */
- if (H5O_bogus_oh(ent->file, oh, &oh_flags)<0)
+ if (H5O_bogus_oh(ent->file, dxpl_id, oh, &oh_flags)<0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to update object 'bogus' message");
done:
@@ -2816,71 +2832,115 @@ done:
} /* end H5O_remove_real() */
-/*-------------------------------------------------------------------------
- * Function: H5O_alloc_extend_chunk
+/*-------------------------------------------------------------------------
*
- * Purpose: Extends a chunk which hasn't been allocated on disk yet
- * to make the chunk large enough to contain a message whose
- * data size is exactly SIZE bytes (SIZE need not be aligned).
+ * Function: H5O_alloc_extend_chunk
*
- * 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.
+ * Purpose: Attempt to extend a chunk that is allocated on disk.
*
- * 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.
+ * 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.
*
- * Return: Success: Message index for null message which
- * is large enough to hold SIZE bytes.
+ * 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.
*
- * Failure: Negative
+ * 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.
*
- * Programmer: Robb Matzke
- * matzke@llnl.gov
- * Aug 7 1997
+ * FALSE: The chunk cannot be extended, and *msg_idx
+ * is undefined.
+ *
+ * FAIL: Some internal error has been detected.
+ *
+ * Programmer: John Mainzer -- 8/16/05
*
* Modifications:
- * Robb Matzke, 1999-08-26
- * If new memory is allocated as a multiple of some alignment
- * then we're careful to initialize the part of the new memory
- * from the end of the expected message to the end of the new
- * memory.
+ *
*-------------------------------------------------------------------------
*/
-static unsigned
-H5O_alloc_extend_chunk(H5F_t *f, H5O_t *oh, unsigned chunkno, size_t size)
+static htri_t
+H5O_alloc_extend_chunk(H5F_t *f,
+ H5O_t *oh,
+ unsigned chunkno,
+ size_t size,
+ unsigned * msg_idx)
{
- unsigned u;
- unsigned idx;
- size_t delta, old_size;
- size_t aligned_size = H5O_ALIGN(size);
- uint8_t *old_addr;
- unsigned ret_value;
+ unsigned u;
+ unsigned idx;
+ unsigned i;
+ size_t delta, old_size;
+ size_t aligned_size = H5O_ALIGN(size);
+ uint8_t *old_addr;
+ herr_t result;
+ htri_t tri_result;
+ htri_t ret_value; /* return value */
+ hbool_t cont_updated;
FUNC_ENTER_NOAPI_NOINIT(H5O_alloc_extend_chunk);
/* check args */
- assert(oh);
- assert(chunkno < oh->nchunks);
- assert(size > 0);
+ HDassert( f != NULL );
+ HDassert( oh != NULL );
+ HDassert( chunkno < oh->nchunks );
+ HDassert( size > 0 );
+ HDassert( msg_idx != NULL );
- if (H5F_addr_defined(oh->chunk[chunkno].addr))
- HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, UFAIL, "chunk is on disk");
+ if ( !H5F_addr_defined(oh->chunk[chunkno].addr) ) {
+
+ HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, FAIL, "chunk isn't on disk");
+ }
+
+ /* Test to see if the specified chunk ends with a null messages. If
+ * it does, try to extend the chunk and (thereby) the null message.
+ * If successful, return the index of the the null message in *msg_idx.
+ */
+ for ( idx = 0; idx < oh->nmesgs; idx++ )
+ {
+ if (oh->mesg[idx].chunkno==chunkno) {
- /* try to extend a null message */
- for (idx=0; idx<oh->nmesgs; idx++) {
- if (oh->mesg[idx].chunkno==chunkno) {
if (H5O_NULL_ID == oh->mesg[idx].type->id &&
(oh->mesg[idx].raw + oh->mesg[idx].raw_size ==
oh->chunk[chunkno].image + oh->chunk[chunkno].size)) {
- delta = MAX (H5O_MIN_SIZE, aligned_size - oh->mesg[idx].raw_size);
- assert (delta=H5O_ALIGN (delta));
+ delta = MAX(H5O_MIN_SIZE,
+ aligned_size - oh->mesg[idx].raw_size);
+
+ HDassert( delta == H5O_ALIGN(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 != TRUE ) { /* system error */
- /* Reserve space in the file to hold the increased chunk size */
- if( H5MF_reserve(f, (hsize_t)delta) < 0 )
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "unable to reserve space in file");
+ HGOTO_ERROR (H5E_RESOURCE, H5E_SYSTEM, FAIL, \
+ "H5MF_can_extend() failed");
+ }
+
+ /* if we get this far, we should be able to extend the chunk */
+ result = H5MF_extend(f, H5FD_MEM_OHDR,
+ oh->chunk[chunkno].addr,
+ (hsize_t)(oh->chunk[chunkno].size),
+ (hsize_t)delta);
+
+ if ( result < 0 ) { /* system error */
+
+ HGOTO_ERROR (H5E_RESOURCE, H5E_SYSTEM, FAIL, \
+ "H5MF_extend() failed.");
+ }
+
+
+ /* chunk size has been increased -- tidy up */
oh->mesg[idx].dirty = TRUE;
oh->mesg[idx].raw_size += delta;
@@ -2888,12 +2948,19 @@ H5O_alloc_extend_chunk(H5F_t *f, H5O_t *oh, unsigned chunkno, size_t size)
old_addr = oh->chunk[chunkno].image;
/* Be careful not to indroduce garbage */
- oh->chunk[chunkno].image = H5FL_BLK_REALLOC(chunk_image,old_addr,
- (oh->chunk[chunkno].size + delta));
- if (NULL==oh->chunk[chunkno].image)
- HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed");
+ oh->chunk[chunkno].image =
+ H5FL_BLK_REALLOC(chunk_image,old_addr,
+ (oh->chunk[chunkno].size + delta));
+
+ if ( NULL == oh->chunk[chunkno].image ) {
+
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, \
+ "memory allocation failed");
+ }
+
HDmemset(oh->chunk[chunkno].image + oh->chunk[chunkno].size,
0, delta);
+
oh->chunk[chunkno].size += delta;
/* adjust raw addresses for messages of this chunk */
@@ -2904,35 +2971,106 @@ H5O_alloc_extend_chunk(H5F_t *f, H5O_t *oh, unsigned chunkno, size_t size)
(oh->mesg[u].raw - old_addr);
}
}
- HGOTO_DONE(idx);
+
+ /* adjust the continuation message pointing to this chunk
+ * for the increase in chunk size.
+ *
+ * As best I understand the code, it is not necessarily an
+ * error if there is no continuation message pointing to a
+ * chunk -- for example, chunk 0 seems to be pointed to by
+ * the object header.
+ */
+ cont_updated = FALSE;
+ for ( i = 0; i < oh->nmesgs; i++ )
+ {
+ if ( ( H5O_CONT_ID == oh->mesg[i].type->id ) &&
+ ( ((H5O_cont_t *)(oh->mesg[i].native))->chunkno
+ == chunkno ) ) {
+
+ HDassert( ((H5O_cont_t *)(oh->mesg[i].native))->size
+ == oh->chunk[chunkno].size - delta );
+
+ ((H5O_cont_t *)(oh->mesg[i].native))->size =
+ oh->chunk[chunkno].size;
+
+ cont_updated = TRUE;
+
+ /* there should be at most one continuation message
+ * pointing to this chunk, so we can quit when we find
+ * and update it.
+ */
+ break;
+ }
+ }
+ HDassert( ( chunkno == 0 ) || ( cont_updated ) );
+
+ *msg_idx = idx;
+ HGOTO_DONE(TRUE);
}
} /* end if */
- }
+ } /* end for */
- /* Reserve space in the file */
+ /* if we get this far, the specified chunk does not end in a null message.
+ * Attempt to extend the chunk, and if successful, fill the new section
+ * of the chunk with a null messages.
+ */
+
+ /* compute space needed in the file */
delta = MAX(H5O_MIN_SIZE, aligned_size+H5O_SIZEOF_MSGHDR(f));
delta = H5O_ALIGN(delta);
- if( H5MF_reserve(f, (hsize_t)delta) < 0 )
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "unable to reserve space in file");
+ /* 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 != TRUE ) { /* system error */
+
+ HGOTO_ERROR(H5E_RESOURCE, H5E_SYSTEM, FAIL, "H5MF_can_extend() failed");
+ }
+
+ /* if we get this far, we should be able to extend the chunk */
+ result = H5MF_extend(f, H5FD_MEM_OHDR,
+ oh->chunk[chunkno].addr,
+ (hsize_t)(oh->chunk[chunkno].size),
+ (hsize_t)delta);
+
+ if ( result < 0 ) { /* system error */
+
+ HGOTO_ERROR(H5E_RESOURCE, H5E_SYSTEM, FAIL, \
+ "H5MF_extend() failed");
+ }
+
/* create a new null message */
- if (oh->nmesgs >= oh->alloc_nmesgs) {
+ if ( oh->nmesgs >= oh->alloc_nmesgs ) {
+
unsigned na = oh->alloc_nmesgs + H5O_NMESGS;
+
H5O_mesg_t *x = H5FL_SEQ_REALLOC (H5O_mesg_t, oh->mesg, (size_t)na);
- if (NULL==x)
- HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed");
+ if ( NULL == x ) {
+
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \
+ "memory allocation failed");
+ }
oh->alloc_nmesgs = na;
oh->mesg = x;
}
+
idx = oh->nmesgs++;
+
oh->mesg[idx].type = H5O_NULL;
oh->mesg[idx].dirty = TRUE;
oh->mesg[idx].native = NULL;
oh->mesg[idx].raw = oh->chunk[chunkno].image +
- oh->chunk[chunkno].size +
- H5O_SIZEOF_MSGHDR(f);
+ oh->chunk[chunkno].size +
+ H5O_SIZEOF_MSGHDR(f);
oh->mesg[idx].raw_size = delta - H5O_SIZEOF_MSGHDR(f);
oh->mesg[idx].chunkno = chunkno;
@@ -2940,74 +3078,125 @@ H5O_alloc_extend_chunk(H5F_t *f, H5O_t *oh, unsigned chunkno, size_t size)
old_size = oh->chunk[chunkno].size;
oh->chunk[chunkno].size += delta;
oh->chunk[chunkno].image = H5FL_BLK_REALLOC(chunk_image,old_addr,
- oh->chunk[chunkno].size);
- if (NULL==oh->chunk[chunkno].image)
- HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed");
+ oh->chunk[chunkno].size);
+ if (NULL==oh->chunk[chunkno].image) {
+
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \
+ "memory allocation failed");
+ }
+
HDmemset(oh->chunk[chunkno].image+old_size, 0,
oh->chunk[chunkno].size - old_size);
/* adjust raw addresses for messages of this chunk */
if (old_addr != oh->chunk[chunkno].image) {
- for (u = 0; u < oh->nmesgs; u++) {
- if (oh->mesg[u].chunkno == chunkno)
- oh->mesg[u].raw = oh->chunk[chunkno].image +
- (oh->mesg[u].raw - old_addr);
- }
+ for (u = 0; u < oh->nmesgs; u++) {
+ if (oh->mesg[u].chunkno == chunkno)
+ oh->mesg[u].raw = oh->chunk[chunkno].image +
+ (oh->mesg[u].raw - old_addr);
+ }
+ }
+
+ /* adjust the continuation message pointing to this chunk for the
+ * increase in chunk size.
+ *
+ * As best I understand the code, it is not necessarily an error
+ * if there is no continuation message pointing to a chunk -- for
+ * example, chunk 0 seems to be pointed to by the object header.
+ */
+ cont_updated = FALSE;
+ for ( i = 0; i < oh->nmesgs; i++ )
+ {
+ if ( ( H5O_CONT_ID == oh->mesg[i].type->id ) &&
+ ( ((H5O_cont_t *)(oh->mesg[i].native))->chunkno == chunkno ) ) {
+
+ HDassert( ((H5O_cont_t *)(oh->mesg[i].native))->size ==
+ oh->chunk[chunkno].size - delta );
+
+ ((H5O_cont_t *)(oh->mesg[i].native))->size =
+ oh->chunk[chunkno].size;
+
+ cont_updated = TRUE;
+
+ /* there should be at most one continuation message
+ * pointing to this chunk, so we can quit when we find
+ * and update it.
+ */
+ break;
+ }
}
+ HDassert( ( chunkno == 0 ) || ( cont_updated ) );
/* Set return value */
- ret_value=idx;
+ *msg_idx = idx;
+ ret_value = TRUE;
done:
+
FUNC_LEAVE_NOAPI(ret_value);
-}
+
+} /* H5O_alloc_extend_chunk() */
/*-------------------------------------------------------------------------
- * Function: H5O_alloc_new_chunk
+ * Function: H5O_alloc_new_chunk
*
- * Purpose: Allocates a new chunk for the object header but doen't
- * give the new chunk a file address yet. 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.
+ * Purpose: Allocates a new chunk for the object header, including
+ * file space.
*
- * SIZE need not be aligned.
+ * 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.
*
- * 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.
+ * SIZE need not be aligned.
*
- * Failure: Negative
+ * 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.
*
- * Programmer: Robb Matzke
- * matzke@llnl.gov
- * Aug 7 1997
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 7 1997
*
* Modifications:
*
+ * John Mainzer, 8/17/05
+ * Reworked function to allocate file space immediately,
+ * instead of just allocating core space (as it used to).
+ * This change was necessary, as we were allocating file
+ * space on metadata cache eviction, which need not be
+ * synchronized across all processes. As a result,
+ * different processes were allocating different file
+ * locations to the same chunk.
+ *
*-------------------------------------------------------------------------
*/
static unsigned
-H5O_alloc_new_chunk(H5F_t *f, H5O_t *oh, size_t size)
+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_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 */
- int chunkno;
- unsigned u;
- unsigned ret_value; /*return value */
+ size_t cont_size; /*continuation message size */
+ int found_null = (-1); /*best fit null 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 */
+ int chunkno;
+ unsigned u;
+ unsigned ret_value; /*return value */
+ haddr_t new_chunk_addr;
FUNC_ENTER_NOAPI_NOINIT(H5O_alloc_new_chunk);
/* check args */
- assert (oh);
- assert (size > 0);
+ HDassert (oh);
+ HDassert (size > 0);
size = H5O_ALIGN(size);
/*
@@ -3018,23 +3207,23 @@ H5O_alloc_new_chunk(H5F_t *f, H5O_t *oh, size_t size)
*/
cont_size = H5O_ALIGN (H5F_SIZEOF_ADDR(f) + H5F_SIZEOF_SIZE(f));
for (u=0; u<oh->nmesgs; u++) {
- if (H5O_NULL_ID == oh->mesg[u].type->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 == oh->mesg[u].type->id) {
- /*don't consider continuation messages */
- } 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;
- }
+ if (H5O_NULL_ID == oh->mesg[u].type->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 == oh->mesg[u].type->id) {
+ /*don't consider continuation messages */
+ } 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;
+ }
}
assert(found_null >= 0 || found_other >= 0);
@@ -3043,36 +3232,47 @@ H5O_alloc_new_chunk(H5F_t *f, H5O_t *oh, size_t size)
* message, then make sure the new chunk has enough room for that
* other message.
*/
- if (found_null < 0)
- size += H5O_SIZEOF_MSGHDR(f) + oh->mesg[found_other].raw_size;
+ if ( found_null < 0 ) {
+
+ size += H5O_SIZEOF_MSGHDR(f) + oh->mesg[found_other].raw_size;
+ }
/*
* The total chunk size must include the requested space plus enough
- * for the message header. This must be at least some minimum and a
+ * 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(f));
assert (size == H5O_ALIGN (size));
- /* Reserve space in the file to hold the new chunk */
- if( H5MF_reserve(f, (hsize_t)size) < 0 )
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "unable to reserve space in file for new chunk");
+ /* 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 without giving it a file address.
+ * Create the new chunk giving it a file address.
*/
- if (oh->nchunks >= oh->alloc_nchunks) {
+ if ( oh->nchunks >= oh->alloc_nchunks ) {
+
unsigned na = oh->alloc_nchunks + H5O_NCHUNKS;
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");
+ if ( !x ) {
+
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, \
+ "memory allocation failed");
+ }
oh->alloc_nchunks = na;
oh->chunk = x;
}
+
chunkno = oh->nchunks++;
oh->chunk[chunkno].dirty = TRUE;
- oh->chunk[chunkno].addr = HADDR_UNDEF;
+ oh->chunk[chunkno].addr = new_chunk_addr;
oh->chunk[chunkno].size = size;
if (NULL==(oh->chunk[chunkno].image = p = H5FL_BLK_CALLOC(chunk_image,size)))
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed");
@@ -3086,35 +3286,40 @@ H5O_alloc_new_chunk(H5F_t *f, H5O_t *oh, size_t size)
unsigned na = oh->alloc_nmesgs + MAX (H5O_NMESGS, 3);
H5O_mesg_t *x = H5FL_SEQ_REALLOC (H5O_mesg_t, oh->mesg, (size_t)na);
- if (!x)
- HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed");
+ if ( !x ) {
+
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, \
+ "memory allocation failed");
+ }
oh->alloc_nmesgs = na;
oh->mesg = x;
/* Set new object header info to zeros */
HDmemset(&oh->mesg[old_alloc], 0,
- (oh->alloc_nmesgs-old_alloc)*sizeof(H5O_mesg_t));
+ (oh->alloc_nmesgs-old_alloc)*sizeof(H5O_mesg_t));
}
/*
* Describe the messages of the new chunk.
*/
if (found_null < 0) {
- found_null = u = oh->nmesgs++;
- oh->mesg[u].type = H5O_NULL;
- oh->mesg[u].dirty = TRUE;
- oh->mesg[u].native = NULL;
- oh->mesg[u].raw = oh->mesg[found_other].raw;
- oh->mesg[u].raw_size = oh->mesg[found_other].raw_size;
- oh->mesg[u].chunkno = oh->mesg[found_other].chunkno;
-
- oh->mesg[found_other].dirty = TRUE;
+ found_null = u = oh->nmesgs++;
+ oh->mesg[u].type = H5O_NULL;
+ oh->mesg[u].dirty = TRUE;
+ oh->mesg[u].native = NULL;
+ oh->mesg[u].raw = oh->mesg[found_other].raw;
+ oh->mesg[u].raw_size = oh->mesg[found_other].raw_size;
+ oh->mesg[u].chunkno = oh->mesg[found_other].chunkno;
+
+ oh->mesg[found_other].dirty = TRUE;
/* Copy the message to the new location */
- HDmemcpy(p+H5O_SIZEOF_MSGHDR(f),oh->mesg[found_other].raw,oh->mesg[found_other].raw_size);
- oh->mesg[found_other].raw = p + H5O_SIZEOF_MSGHDR(f);
- oh->mesg[found_other].chunkno = chunkno;
- p += H5O_SIZEOF_MSGHDR(f) + oh->mesg[found_other].raw_size;
- size -= H5O_SIZEOF_MSGHDR(f) + oh->mesg[found_other].raw_size;
+ HDmemcpy(p + H5O_SIZEOF_MSGHDR(f),
+ oh->mesg[found_other].raw,
+ oh->mesg[found_other].raw_size);
+ oh->mesg[found_other].raw = p + H5O_SIZEOF_MSGHDR(f);
+ oh->mesg[found_other].chunkno = chunkno;
+ p += H5O_SIZEOF_MSGHDR(f) + oh->mesg[found_other].raw_size;
+ size -= H5O_SIZEOF_MSGHDR(f) + oh->mesg[found_other].raw_size;
}
idx = oh->nmesgs++;
oh->mesg[idx].type = H5O_NULL;
@@ -3130,19 +3335,19 @@ H5O_alloc_new_chunk(H5F_t *f, H5O_t *oh, size_t size)
* two null messages.
*/
if (oh->mesg[found_null].raw_size > cont_size) {
- u = oh->nmesgs++;
- oh->mesg[u].type = H5O_NULL;
- oh->mesg[u].dirty = TRUE;
- oh->mesg[u].native = NULL;
- oh->mesg[u].raw = oh->mesg[found_null].raw +
- cont_size +
- H5O_SIZEOF_MSGHDR(f);
- oh->mesg[u].raw_size = oh->mesg[found_null].raw_size -
- (cont_size + H5O_SIZEOF_MSGHDR(f));
- oh->mesg[u].chunkno = oh->mesg[found_null].chunkno;
-
- oh->mesg[found_null].dirty = TRUE;
- oh->mesg[found_null].raw_size = cont_size;
+ u = oh->nmesgs++;
+ oh->mesg[u].type = H5O_NULL;
+ oh->mesg[u].dirty = TRUE;
+ oh->mesg[u].native = NULL;
+ oh->mesg[u].raw = oh->mesg[found_null].raw +
+ cont_size +
+ H5O_SIZEOF_MSGHDR(f);
+ oh->mesg[u].raw_size = oh->mesg[found_null].raw_size -
+ (cont_size + H5O_SIZEOF_MSGHDR(f));
+ oh->mesg[u].chunkno = oh->mesg[found_null].chunkno;
+
+ oh->mesg[found_null].dirty = TRUE;
+ oh->mesg[found_null].raw_size = cont_size;
}
/*
@@ -3150,10 +3355,13 @@ H5O_alloc_new_chunk(H5F_t *f, H5O_t *oh, size_t size)
*/
oh->mesg[found_null].type = H5O_CONT;
oh->mesg[found_null].dirty = TRUE;
- if (NULL==(cont = H5FL_MALLOC(H5O_cont_t)))
- HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed");
- cont->addr = HADDR_UNDEF;
- cont->size = 0;
+ 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;
oh->mesg[found_null].native = cont;
@@ -3162,59 +3370,75 @@ H5O_alloc_new_chunk(H5F_t *f, H5O_t *oh, size_t size)
done:
FUNC_LEAVE_NOAPI(ret_value);
-}
+
+} /* H5O_alloc_new_chunk() */
/*-------------------------------------------------------------------------
- * Function: H5O_alloc
+ * Function: H5O_alloc
*
- * Purpose: Allocate enough space in the object header for this message.
+ * Purpose: Allocate enough space in the object header for this message.
*
- * Return: Success: Index of message
+ * Return: Success: Index of message
*
- * Failure: Negative
+ * Failure: Negative
*
- * Programmer: Robb Matzke
- * matzke@llnl.gov
- * Aug 6 1997
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 6 1997
*
* Modifications:
*
* John Mainzer, 6/7/05
* Modified function to use the new dirtied parameter to
- * H5AC_unprotect() instead of modfying the is_dirty field.
+ * H5AC_unprotect() instead of modfying the is_dirty field directly.
* In this case, that requires the addition of the oh_dirtied_ptr
* parameter to track whether *oh is dirty.
*
+ * John Mainzer, 8/19/05
+ * Reworked the function to allocate disk space immediately instead
+ * of waiting to cache eviction time. This is necessary since cache
+ * evictions need not be synchronized across the processes in the
+ * PHDF5 case.
+ *
+ * Note the use of a revised versions of H5O_alloc_new_chunk() and
+ * H5O_alloc_extend_chunk().
+ *
*-------------------------------------------------------------------------
*/
static unsigned
-H5O_alloc(H5F_t *f, H5O_t *oh, const H5O_class_t *type, size_t size, unsigned * oh_flags_ptr)
+H5O_alloc(H5F_t *f,
+ hid_t dxpl_id,
+ H5O_t *oh,
+ const H5O_class_t *type,
+ size_t size,
+ unsigned * oh_flags_ptr)
{
- unsigned idx;
+ unsigned idx = UFAIL;
H5O_mesg_t *msg; /* Pointer to newly allocated message */
- size_t aligned_size = H5O_ALIGN(size);
- unsigned ret_value; /* Return value */
+ size_t aligned_size = H5O_ALIGN(size);
+ htri_t tri_result;
+ unsigned ret_value; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5O_alloc);
/* check args */
- assert (oh);
- assert (type);
- assert (oh_flags_ptr);
+ 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 &&
+ if (H5O_NULL_ID == oh->mesg[idx].type->id &&
oh->mesg[idx].raw_size >= aligned_size)
- break;
+ break;
}
#ifdef LATER
/*
* Perhaps if we join adjacent null messages we could make one
* large enough... we leave this as an exercise for future
- * programmers :-) This isn't a high priority because when an
+ * programmers :-) This isn't a high priority because when an
* object header is read from disk the null messages are combined
* anyway.
*/
@@ -3222,63 +3446,92 @@ H5O_alloc(H5F_t *f, H5O_t *oh, const H5O_class_t *type, size_t size, unsigned *
/* if we didn't find one, then allocate more header space */
if (idx >= oh->nmesgs) {
- unsigned chunkno;
+ unsigned chunkno;
- /*
- * Look for a chunk which hasn't had disk space allocated yet
- * since we can just increase the size of that chunk.
- */
- for (chunkno = 0; chunkno < oh->nchunks; chunkno++) {
- if ((idx = H5O_alloc_extend_chunk(f, oh, chunkno, size)) != UFAIL) {
- break;
- }
- H5E_clear_stack(NULL);
- }
+ /* 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++ )
+ {
+ HDassert( H5F_addr_defined(oh->chunk[chunkno].addr) );
- /*
- * Create a new chunk
- */
- if (idx == UFAIL) {
- if ((idx = H5O_alloc_new_chunk(f, oh, size)) == UFAIL)
- HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, UFAIL, "unable to create a new object header data chunk");
- }
+ 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");
+ }
+ }
+
+ /* 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");
+ }
+ }
}
/* Set pointer to newly allocated message */
- msg=&oh->mesg[idx];
+ msg = &(oh->mesg[idx]);
/* do we need to split the 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(f); /* Total size of newly allocated message */
- assert(msg->raw_size - aligned_size >= H5O_SIZEOF_MSGHDR(f));
+ size_t mesg_size = aligned_size + H5O_SIZEOF_MSGHDR(f);
+ /* Total size of newly allocated message */
- if (oh->nmesgs >= oh->alloc_nmesgs) {
- int old_alloc=oh->alloc_nmesgs;
- unsigned na = oh->alloc_nmesgs + H5O_NMESGS;
- H5O_mesg_t *x = H5FL_SEQ_REALLOC (H5O_mesg_t, oh->mesg, (size_t)na);
+ HDassert( msg->raw_size - aligned_size >= H5O_SIZEOF_MSGHDR(f) );
- if (!x)
- HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed");
- oh->alloc_nmesgs = na;
- oh->mesg = x;
+ if (oh->nmesgs >= oh->alloc_nmesgs) {
+
+ int old_alloc=oh->alloc_nmesgs;
+ unsigned na = oh->alloc_nmesgs + H5O_NMESGS;
+ H5O_mesg_t *x = H5FL_SEQ_REALLOC(H5O_mesg_t, oh->mesg, (size_t)na);
- /* Set new object header info to zeros */
- HDmemset(&oh->mesg[old_alloc],0,
- (oh->alloc_nmesgs-old_alloc)*sizeof(H5O_mesg_t));
+ if (!x) {
- /* "Retarget" local 'msg' pointer into newly allocated array of messages */
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, \
+ "memory allocation failed");
+ }
+ oh->alloc_nmesgs = na;
+ oh->mesg = x;
+
+ /* Set new object header info to zeros */
+ HDmemset(&oh->mesg[old_alloc],0,
+ (oh->alloc_nmesgs-old_alloc)*sizeof(H5O_mesg_t));
+
+ /* "Retarget" local 'msg' pointer into newly allocated array
+ * of messages
+ */
msg=&oh->mesg[idx];
- }
- null_msg=&oh->mesg[oh->nmesgs++];
- null_msg->type = H5O_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;
- msg->raw_size = aligned_size;
+ }
+ null_msg = &(oh->mesg[oh->nmesgs++]);
+ null_msg->type = H5O_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;
+ msg->raw_size = aligned_size;
}
/* initialize the new message */
@@ -3289,11 +3542,12 @@ H5O_alloc(H5F_t *f, H5O_t *oh, const H5O_class_t *type, size_t size, unsigned *
*oh_flags_ptr |= H5AC__DIRTIED_FLAG;
/* Set return value */
- ret_value=idx;
+ ret_value = idx;
done:
FUNC_LEAVE_NOAPI(ret_value);
-}
+
+} /* H5O_alloc() */
#ifdef NOT_YET
@@ -3956,7 +4210,7 @@ H5O_iterate_real(const H5G_entry_t *ent, const H5O_class_t *type, H5AC_protect_t
if(oh_flags & H5AC__DIRTIED_FLAG) {
/* Shouldn't be able to modify object header if we don't have write access */
HDassert(prot == H5AC_WRITE);
- H5O_touch_oh(ent->file, oh, FALSE, &oh_flags);
+ H5O_touch_oh(ent->file, dxpl_id, oh, FALSE, &oh_flags);
} /* end if */
done: