diff options
author | Mike McGreevy <mamcgree@hdfgroup.org> | 2010-10-15 19:16:41 (GMT) |
---|---|---|
committer | Mike McGreevy <mamcgree@hdfgroup.org> | 2010-10-15 19:16:41 (GMT) |
commit | c002883bcc008a4274433ed8e8275669c09dcfe6 (patch) | |
tree | c2290aca7bed508bd952eb29ef04fb0adc9642f2 /src/H5Faccum.c | |
parent | 9f6fb53aa6941dbc67e40f47c8e27a12255cd123 (diff) | |
download | hdf5-c002883bcc008a4274433ed8e8275669c09dcfe6.zip hdf5-c002883bcc008a4274433ed8e8275669c09dcfe6.tar.gz hdf5-c002883bcc008a4274433ed8e8275669c09dcfe6.tar.bz2 |
[svn-r19617] Purpose:
Merge accum_tests branch back to the trunk.
Description:
Changes consist of addition of tests for H5Faccum.c source code,
as well as some fixes that address some discovered bugs in the
metadata accumulator on several corner cases.
Tested:
h5committested
Diffstat (limited to 'src/H5Faccum.c')
-rw-r--r-- | src/H5Faccum.c | 721 |
1 files changed, 426 insertions, 295 deletions
diff --git a/src/H5Faccum.c b/src/H5Faccum.c index 600c3f3..6c9eb67 100644 --- a/src/H5Faccum.c +++ b/src/H5Faccum.c @@ -111,11 +111,11 @@ H5FL_BLK_DEFINE_STATIC(meta_accum); * *------------------------------------------------------------------------- */ -htri_t +herr_t H5F_accum_read(const H5F_t *f, hid_t dxpl_id, H5FD_mem_t type, haddr_t addr, size_t size, void *buf/*out*/) { - htri_t ret_value = FALSE; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(H5F_accum_read, FAIL) @@ -124,90 +124,135 @@ H5F_accum_read(const H5F_t *f, hid_t dxpl_id, H5FD_mem_t type, haddr_t addr, HDassert(buf); /* Check if this information is in the metadata accumulator */ - if((f->shared->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) && type != H5FD_MEM_DRAW - && size < H5F_ACCUM_MAX_SIZE) { - /* Sanity check */ - HDassert(!f->shared->accum.buf || (f->shared->accum.alloc_size >= f->shared->accum.size)); - - /* Current read adjoins or overlaps with metadata accumulator */ - if(H5F_addr_overlap(addr, size, f->shared->accum.loc, f->shared->accum.size) - || ((addr + size) == f->shared->accum.loc) - || (f->shared->accum.loc + f->shared->accum.size) == addr) { - size_t amount_before; /* Amount to read before current accumulator */ - haddr_t new_addr; /* New address of the accumulator buffer */ - size_t new_size; /* New size of the accumulator buffer */ - - /* Compute new values for accumulator */ - new_addr = MIN(addr, f->shared->accum.loc); - new_size = (size_t)(MAX((addr + size), (f->shared->accum.loc + f->shared->accum.size)) - - new_addr); - - /* Check if we need more buffer space */ - if(new_size > f->shared->accum.alloc_size) { - size_t new_alloc_size; /* New size of accumulator */ - - /* Adjust the buffer size to be a power of 2 that is large enough to hold data */ - new_alloc_size = (size_t)1 << (1 + H5V_log2_gen((uint64_t)(new_size - 1))); - - /* Reallocate the metadata accumulator buffer */ - if(NULL == (f->shared->accum.buf = H5FL_BLK_REALLOC(meta_accum, f->shared->accum.buf, new_alloc_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer") - - /* Note the new buffer size */ - f->shared->accum.alloc_size = new_alloc_size; + if((f->shared->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) && type != H5FD_MEM_DRAW) { + if(size < H5F_ACCUM_MAX_SIZE) { + /* Sanity check */ + HDassert(!f->shared->accum.buf || (f->shared->accum.alloc_size >= f->shared->accum.size)); + + /* Current read adjoins or overlaps with metadata accumulator */ + if(H5F_addr_overlap(addr, size, f->shared->accum.loc, f->shared->accum.size) + || ((addr + size) == f->shared->accum.loc) + || (f->shared->accum.loc + f->shared->accum.size) == addr) { + size_t amount_before; /* Amount to read before current accumulator */ + haddr_t new_addr; /* New address of the accumulator buffer */ + size_t new_size; /* New size of the accumulator buffer */ + + /* Compute new values for accumulator */ + new_addr = MIN(addr, f->shared->accum.loc); + new_size = (size_t)(MAX((addr + size), (f->shared->accum.loc + f->shared->accum.size)) + - new_addr); + + /* Check if we need more buffer space */ + if(new_size > f->shared->accum.alloc_size) { + size_t new_alloc_size; /* New size of accumulator */ + + /* Adjust the buffer size to be a power of 2 that is large enough to hold data */ + new_alloc_size = (size_t)1 << (1 + H5V_log2_gen((uint64_t)(new_size - 1))); + + /* Reallocate the metadata accumulator buffer */ + if(NULL == (f->shared->accum.buf = H5FL_BLK_REALLOC(meta_accum, f->shared->accum.buf, new_alloc_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer") + + /* Note the new buffer size */ + f->shared->accum.alloc_size = new_alloc_size; #ifdef H5_CLEAR_MEMORY -HDmemset(f->shared->accum.buf + f->shared->accum.size, 0, (f->shared->accum.alloc_size - f->shared->accum.size)); + HDmemset(f->shared->accum.buf + f->shared->accum.size, 0, (f->shared->accum.alloc_size - f->shared->accum.size)); #endif /* H5_CLEAR_MEMORY */ - } /* end if */ + } /* end if */ - /* Read the part before the metadata accumulator */ - if(addr < f->shared->accum.loc) { - /* Set the amount to read */ - H5_ASSIGN_OVERFLOW(amount_before, (f->shared->accum.loc - addr), hsize_t, size_t); + /* Read the part before the metadata accumulator */ + if(addr < f->shared->accum.loc) { + /* Set the amount to read */ + H5_ASSIGN_OVERFLOW(amount_before, (f->shared->accum.loc - addr), hsize_t, size_t); - /* Make room for the metadata to read in */ - HDmemmove(f->shared->accum.buf + amount_before, f->shared->accum.buf, f->shared->accum.size); + /* Make room for the metadata to read in */ + HDmemmove(f->shared->accum.buf + amount_before, f->shared->accum.buf, f->shared->accum.size); - /* Adjust dirty region tracking info, if present */ - if(f->shared->accum.dirty) - f->shared->accum.dirty_off += amount_before; + /* Adjust dirty region tracking info, if present */ + if(f->shared->accum.dirty) + f->shared->accum.dirty_off += amount_before; - /* Dispatch to driver */ - if(H5FD_read(f->shared->lf, dxpl_id, type, addr, amount_before, f->shared->accum.buf) < 0) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "driver read request failed") - } /* end if */ - else - amount_before = 0; + /* Dispatch to driver */ + if(H5FD_read(f->shared->lf, dxpl_id, type, addr, amount_before, f->shared->accum.buf) < 0) + HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "driver read request failed") + } /* end if */ + else + amount_before = 0; - /* Read the part after the metadata accumulator */ - if((addr + size) > (f->shared->accum.loc + f->shared->accum.size)) { - size_t amount_after; /* Amount to read at a time */ + /* Read the part after the metadata accumulator */ + if((addr + size) > (f->shared->accum.loc + f->shared->accum.size)) { + size_t amount_after; /* Amount to read at a time */ - /* Set the amount to read */ - H5_ASSIGN_OVERFLOW(amount_after, ((addr + size) - (f->shared->accum.loc + f->shared->accum.size)), hsize_t, size_t); + /* Set the amount to read */ + H5_ASSIGN_OVERFLOW(amount_after, ((addr + size) - (f->shared->accum.loc + f->shared->accum.size)), hsize_t, size_t); - /* Dispatch to driver */ - if(H5FD_read(f->shared->lf, dxpl_id, type, (f->shared->accum.loc + f->shared->accum.size), amount_after, (f->shared->accum.buf + f->shared->accum.size + amount_before)) < 0) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "driver read request failed") - } /* end if */ + /* Dispatch to driver */ + if(H5FD_read(f->shared->lf, dxpl_id, type, (f->shared->accum.loc + f->shared->accum.size), amount_after, (f->shared->accum.buf + f->shared->accum.size + amount_before)) < 0) + HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "driver read request failed") + } /* end if */ - /* Copy the data out of the buffer */ - HDmemcpy(buf, f->shared->accum.buf + (addr - new_addr), size); + /* Copy the data out of the buffer */ + HDmemcpy(buf, f->shared->accum.buf + (addr - new_addr), size); - /* Adjust the accumulator address & size */ - f->shared->accum.loc = new_addr; - f->shared->accum.size = new_size; + /* Adjust the accumulator address & size */ + f->shared->accum.loc = new_addr; + f->shared->accum.size = new_size; + } /* end if */ + /* Current read doesn't overlap with metadata accumulator, read it from file */ + else { + /* Dispatch to driver */ + if(H5FD_read(f->shared->lf, dxpl_id, type, addr, size, buf) < 0) + HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "driver read request failed") + } /* end else */ } /* end if */ - /* Current read doesn't overlap with metadata accumulator, read it from file */ else { - /* Dispatch to driver */ + /* Read the data */ if(H5FD_read(f->shared->lf, dxpl_id, type, addr, size, buf) < 0) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "driver read request failed") - } /* end else */ - /* Indicate success */ - HGOTO_DONE(TRUE); + /* Check for overlap w/dirty accumulator */ + /* (Note that this could be improved by updating the non-dirty + * information in the accumulator with [some of] the information + * just read in. -QAK) + */ + if(f->shared->accum.dirty && + H5F_addr_overlap(addr, size, f->shared->accum.loc + f->shared->accum.dirty_off, f->shared->accum.dirty_len)) { + haddr_t dirty_loc = f->shared->accum.loc + f->shared->accum.dirty_off; /* File offset of dirty information */ + size_t buf_off; /* Offset of dirty region in buffer */ + size_t dirty_off; /* Offset within dirty region */ + size_t overlap_size; /* Size of overlap with dirty region */ + + /* Check for read starting before beginning dirty region */ + if(H5F_addr_le(addr, dirty_loc)) { + /* Compute offset of dirty region within buffer */ + buf_off = (size_t)(dirty_loc - addr); + + /* Compute offset within dirty region */ + dirty_off = 0; + + /* Check for read ending within dirty region */ + if(H5F_addr_le(addr + size, dirty_loc + f->shared->accum.dirty_len)) + overlap_size = (size_t)((addr + size) - buf_off); + else /* Access covers whole dirty region */ + overlap_size = f->shared->accum.dirty_len; + } /* end if */ + else { /* Read starts after beginning of dirty region */ + /* Compute dirty offset within buffer and overlap size */ + buf_off = 0; + dirty_off = (size_t)(addr - dirty_loc); + overlap_size = (size_t)((dirty_loc + f->shared->accum.dirty_len) - addr); + } /* end else */ + + /* Copy the dirty region to buffer */ + HDmemcpy((unsigned char *)buf + buf_off, (unsigned char *)f->shared->accum.buf + f->shared->accum.dirty_off + dirty_off, overlap_size); + } /* end if */ + } /* end else */ } /* end if */ + else { + /* Read the data */ + if(H5FD_read(f->shared->lf, dxpl_id, type, addr, size, buf) < 0) + HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "driver read request failed") + } /* end else */ done: FUNC_LEAVE_NOAPI(ret_value) @@ -355,8 +400,8 @@ done: /*------------------------------------------------------------------------- * Function: H5F_accum_write * - * Purpose: Attempts to read some data from the metadata accumulator for - * a file into a buffer. + * Purpose: Attempts to write some data to the metadata accumulator for + * a file from a buffer. * * Return: Non-negative on success/Negative on failure * @@ -366,11 +411,11 @@ done: * *------------------------------------------------------------------------- */ -htri_t +herr_t H5F_accum_write(const H5F_t *f, hid_t dxpl_id, H5FD_mem_t type, haddr_t addr, size_t size, const void *buf) { - htri_t ret_value = FALSE; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(H5F_accum_write, FAIL) @@ -380,248 +425,284 @@ H5F_accum_write(const H5F_t *f, hid_t dxpl_id, H5FD_mem_t type, haddr_t addr, HDassert(buf); /* Check for accumulating metadata */ - if((f->shared->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) && type != H5FD_MEM_DRAW - && size < H5F_ACCUM_MAX_SIZE) { - /* Sanity check */ - HDassert(!f->shared->accum.buf || (f->shared->accum.alloc_size >= f->shared->accum.size)); - - /* Check if there is already metadata in the accumulator */ - if(f->shared->accum.size > 0) { - /* Check if the new metadata adjoins the beginning of the current accumulator */ - if((addr + size) == f->shared->accum.loc) { - /* Check if we need to adjust accumulator size */ - if(H5F_accum_adjust(&f->shared->accum, f->shared->lf, dxpl_id, H5F_ACCUM_PREPEND, size) < 0) - HGOTO_ERROR(H5E_IO, H5E_CANTRESIZE, FAIL, "can't adjust metadata accumulator") - - /* Move the existing metadata to the proper location */ - HDmemmove(f->shared->accum.buf + size, f->shared->accum.buf, f->shared->accum.size); - - /* Copy the new metadata at the front */ - HDmemcpy(f->shared->accum.buf, buf, size); - - /* Set the new size & location of the metadata accumulator */ - f->shared->accum.loc = addr; - f->shared->accum.size += size; - - /* Adjust the dirty region and mark accumulator dirty */ - if(f->shared->accum.dirty) - f->shared->accum.dirty_len = size + f->shared->accum.dirty_off - + f->shared->accum.dirty_len; - else { - f->shared->accum.dirty_len = size; - f->shared->accum.dirty = TRUE; - } /* end else */ - f->shared->accum.dirty_off = 0; - } /* end if */ - /* Check if the new metadata adjoins the end of the current accumulator */ - else if(addr == (f->shared->accum.loc + f->shared->accum.size)) { - /* Check if we need to adjust accumulator size */ - if(H5F_accum_adjust(&f->shared->accum, f->shared->lf, dxpl_id, H5F_ACCUM_APPEND, size) < 0) - HGOTO_ERROR(H5E_IO, H5E_CANTRESIZE, FAIL, "can't adjust metadata accumulator") + if((f->shared->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) && type != H5FD_MEM_DRAW) { + if(size < H5F_ACCUM_MAX_SIZE) { + /* Sanity check */ + HDassert(!f->shared->accum.buf || (f->shared->accum.alloc_size >= f->shared->accum.size)); + + /* Check if there is already metadata in the accumulator */ + if(f->shared->accum.size > 0) { + /* Check if the new metadata adjoins the beginning of the current accumulator */ + if((addr + size) == f->shared->accum.loc) { + /* Check if we need to adjust accumulator size */ + if(H5F_accum_adjust(&f->shared->accum, f->shared->lf, dxpl_id, H5F_ACCUM_PREPEND, size) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTRESIZE, FAIL, "can't adjust metadata accumulator") - /* Copy the new metadata to the end */ - HDmemcpy(f->shared->accum.buf + f->shared->accum.size, buf, size); + /* Move the existing metadata to the proper location */ + HDmemmove(f->shared->accum.buf + size, f->shared->accum.buf, f->shared->accum.size); - /* Adjust the dirty region and mark accumulator dirty */ - if(f->shared->accum.dirty) - f->shared->accum.dirty_len = size + (f->shared->accum.size - - f->shared->accum.dirty_off); - else { - f->shared->accum.dirty_off = f->shared->accum.size; - f->shared->accum.dirty_len = size; - f->shared->accum.dirty = TRUE; - } /* end else */ + /* Copy the new metadata at the front */ + HDmemcpy(f->shared->accum.buf, buf, size); - /* Set the new size of the metadata accumulator */ - f->shared->accum.size += size; - } /* end if */ - /* Check if the piece of metadata being written overlaps the metadata accumulator */ - else if(H5F_addr_overlap(addr, size, f->shared->accum.loc, f->shared->accum.size)) { - size_t add_size; /* New size of the accumulator buffer */ + /* Set the new size & location of the metadata accumulator */ + f->shared->accum.loc = addr; + f->shared->accum.size += size; - /* Check if the new metadata is entirely within the current accumulator */ - if(addr >= f->shared->accum.loc && (addr + size) <= (f->shared->accum.loc + f->shared->accum.size)) { - size_t dirty_off = (size_t)(addr - f->shared->accum.loc); + /* Adjust the dirty region and mark accumulator dirty */ + if(f->shared->accum.dirty) + f->shared->accum.dirty_len = size + f->shared->accum.dirty_off + + f->shared->accum.dirty_len; + else { + f->shared->accum.dirty_len = size; + f->shared->accum.dirty = TRUE; + } /* end else */ + f->shared->accum.dirty_off = 0; + } /* end if */ + /* Check if the new metadata adjoins the end of the current accumulator */ + else if(addr == (f->shared->accum.loc + f->shared->accum.size)) { + /* Check if we need to adjust accumulator size */ + if(H5F_accum_adjust(&f->shared->accum, f->shared->lf, dxpl_id, H5F_ACCUM_APPEND, size) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTRESIZE, FAIL, "can't adjust metadata accumulator") - /* Copy the new metadata to the proper location within the accumulator */ - HDmemcpy(f->shared->accum.buf + dirty_off, buf, size); + /* Copy the new metadata to the end */ + HDmemcpy(f->shared->accum.buf + f->shared->accum.size, buf, size); /* Adjust the dirty region and mark accumulator dirty */ - if(f->shared->accum.dirty) { - /* Check for new metadata starting before current dirty region */ - if(dirty_off <= f->shared->accum.dirty_off) { - if((dirty_off + size) <= (f->shared->accum.dirty_off + f->shared->accum.dirty_len)) - f->shared->accum.dirty_len = (f->shared->accum.dirty_off + f->shared->accum.dirty_len) - dirty_off; - else - f->shared->accum.dirty_len = size; - f->shared->accum.dirty_off = dirty_off; - } /* end if */ - else { - if((dirty_off + size) <= (f->shared->accum.dirty_off + f->shared->accum.dirty_len)) - ; /* f->shared->accum.dirty_len doesn't change */ - else - f->shared->accum.dirty_len = (dirty_off + size) - f->shared->accum.dirty_off; - } /* end else */ - } /* end if */ + if(f->shared->accum.dirty) + f->shared->accum.dirty_len = size + (f->shared->accum.size - + f->shared->accum.dirty_off); else { - f->shared->accum.dirty_off = dirty_off; + f->shared->accum.dirty_off = f->shared->accum.size; f->shared->accum.dirty_len = size; f->shared->accum.dirty = TRUE; } /* end else */ + + /* Set the new size of the metadata accumulator */ + f->shared->accum.size += size; } /* end if */ - /* Check if the new metadata overlaps the beginning of the current accumulator */ - else if(addr < f->shared->accum.loc && (addr + size) <= (f->shared->accum.loc + f->shared->accum.size)) { - size_t old_offset; /* Offset of old data within the accumulator buffer */ + /* Check if the piece of metadata being written overlaps the metadata accumulator */ + else if(H5F_addr_overlap(addr, size, f->shared->accum.loc, f->shared->accum.size)) { + size_t add_size; /* New size of the accumulator buffer */ + + /* Check if the new metadata is entirely within the current accumulator */ + if(addr >= f->shared->accum.loc && (addr + size) <= (f->shared->accum.loc + f->shared->accum.size)) { + size_t dirty_off = (size_t)(addr - f->shared->accum.loc); + + /* Copy the new metadata to the proper location within the accumulator */ + HDmemcpy(f->shared->accum.buf + dirty_off, buf, size); + + /* Adjust the dirty region and mark accumulator dirty */ + if(f->shared->accum.dirty) { + /* Check for new metadata starting before current dirty region */ + if(dirty_off <= f->shared->accum.dirty_off) { + if((dirty_off + size) <= (f->shared->accum.dirty_off + f->shared->accum.dirty_len)) + f->shared->accum.dirty_len = (f->shared->accum.dirty_off + f->shared->accum.dirty_len) - dirty_off; + else + f->shared->accum.dirty_len = size; + f->shared->accum.dirty_off = dirty_off; + } /* end if */ + else { + if((dirty_off + size) <= (f->shared->accum.dirty_off + f->shared->accum.dirty_len)) + ; /* f->shared->accum.dirty_len doesn't change */ + else + f->shared->accum.dirty_len = (dirty_off + size) - f->shared->accum.dirty_off; + } /* end else */ + } /* end if */ + else { + f->shared->accum.dirty_off = dirty_off; + f->shared->accum.dirty_len = size; + f->shared->accum.dirty = TRUE; + } /* end else */ + } /* end if */ + /* Check if the new metadata overlaps the beginning of the current accumulator */ + else if(addr < f->shared->accum.loc && (addr + size) <= (f->shared->accum.loc + f->shared->accum.size)) { + size_t old_offset; /* Offset of old data within the accumulator buffer */ - /* Calculate the amount we will need to add to the accumulator size, based on the amount of overlap */ - H5_ASSIGN_OVERFLOW(add_size, (f->shared->accum.loc - addr), hsize_t, size_t); + /* Calculate the amount we will need to add to the accumulator size, based on the amount of overlap */ + H5_ASSIGN_OVERFLOW(add_size, (f->shared->accum.loc - addr), hsize_t, size_t); - /* Check if we need to adjust accumulator size */ - if(H5F_accum_adjust(&f->shared->accum, f->shared->lf, dxpl_id, H5F_ACCUM_PREPEND, add_size) < 0) - HGOTO_ERROR(H5E_IO, H5E_CANTRESIZE, FAIL, "can't adjust metadata accumulator") + /* Check if we need to adjust accumulator size */ + if(H5F_accum_adjust(&f->shared->accum, f->shared->lf, dxpl_id, H5F_ACCUM_PREPEND, add_size) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTRESIZE, FAIL, "can't adjust metadata accumulator") - /* Calculate the proper offset of the existing metadata */ - H5_ASSIGN_OVERFLOW(old_offset, (addr + size) - f->shared->accum.loc, hsize_t, size_t); + /* Calculate the proper offset of the existing metadata */ + H5_ASSIGN_OVERFLOW(old_offset, (addr + size) - f->shared->accum.loc, hsize_t, size_t); - /* Move the existing metadata to the proper location */ - HDmemmove(f->shared->accum.buf + size, f->shared->accum.buf + old_offset, (f->shared->accum.size - old_offset)); + /* Move the existing metadata to the proper location */ + HDmemmove(f->shared->accum.buf + size, f->shared->accum.buf + old_offset, (f->shared->accum.size - old_offset)); - /* Copy the new metadata at the front */ - HDmemcpy(f->shared->accum.buf, buf, size); + /* Copy the new metadata at the front */ + HDmemcpy(f->shared->accum.buf, buf, size); - /* Set the new size & location of the metadata accumulator */ - f->shared->accum.loc = addr; - f->shared->accum.size += add_size; + /* Set the new size & location of the metadata accumulator */ + f->shared->accum.loc = addr; + f->shared->accum.size += add_size; - /* Adjust the dirty region and mark accumulator dirty */ - if(f->shared->accum.dirty) { - size_t curr_dirty_end = add_size + f->shared->accum.dirty_off + f->shared->accum.dirty_len; + /* Adjust the dirty region and mark accumulator dirty */ + if(f->shared->accum.dirty) { + size_t curr_dirty_end = add_size + f->shared->accum.dirty_off + f->shared->accum.dirty_len; - f->shared->accum.dirty_off = 0; - if(size <= curr_dirty_end) - f->shared->accum.dirty_len = curr_dirty_end; - else + f->shared->accum.dirty_off = 0; + if(size <= curr_dirty_end) + f->shared->accum.dirty_len = curr_dirty_end; + else + f->shared->accum.dirty_len = size; + } /* end if */ + else { + f->shared->accum.dirty_off = 0; f->shared->accum.dirty_len = size; + f->shared->accum.dirty = TRUE; + } /* end else */ } /* end if */ - else { - f->shared->accum.dirty_off = 0; - f->shared->accum.dirty_len = size; - f->shared->accum.dirty = TRUE; - } /* end else */ - } /* end if */ - /* Check if the new metadata overlaps the end of the current accumulator */ - else if(addr >= f->shared->accum.loc && (addr + size) > (f->shared->accum.loc + f->shared->accum.size)) { - size_t dirty_off = (size_t)(addr - f->shared->accum.loc); + /* Check if the new metadata overlaps the end of the current accumulator */ + else if(addr >= f->shared->accum.loc && (addr + size) > (f->shared->accum.loc + f->shared->accum.size)) { + size_t dirty_off; /* Offset of dirty region */ - /* Calculate the amount we will need to add to the accumulator size, based on the amount of overlap */ - H5_ASSIGN_OVERFLOW(add_size, (addr + size) - (f->shared->accum.loc + f->shared->accum.size), hsize_t, size_t); + /* Calculate the amount we will need to add to the accumulator size, based on the amount of overlap */ + H5_ASSIGN_OVERFLOW(add_size, (addr + size) - (f->shared->accum.loc + f->shared->accum.size), hsize_t, size_t); - /* Check if we need to adjust accumulator size */ - if(H5F_accum_adjust(&f->shared->accum, f->shared->lf, dxpl_id, H5F_ACCUM_APPEND, add_size) < 0) - HGOTO_ERROR(H5E_IO, H5E_CANTRESIZE, FAIL, "can't adjust metadata accumulator") + /* Check if we need to adjust accumulator size */ + if(H5F_accum_adjust(&f->shared->accum, f->shared->lf, dxpl_id, H5F_ACCUM_APPEND, add_size) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTRESIZE, FAIL, "can't adjust metadata accumulator") - /* Copy the new metadata to the end */ - HDmemcpy(f->shared->accum.buf + dirty_off, buf, size); + /* Compute offset of dirty region (after adjusting accumulator) */ + dirty_off = (size_t)(addr - f->shared->accum.loc); - /* Set the new size of the metadata accumulator */ - f->shared->accum.size += add_size; + /* Copy the new metadata to the end */ + HDmemcpy(f->shared->accum.buf + dirty_off, buf, size); - /* Adjust the dirty region and mark accumulator dirty */ - if(f->shared->accum.dirty) { - /* Check for new metadata starting before current dirty region */ - if(dirty_off <= f->shared->accum.dirty_off) { - f->shared->accum.dirty_off = dirty_off; - f->shared->accum.dirty_len = size; + /* Set the new size of the metadata accumulator */ + f->shared->accum.size += add_size; + + /* Adjust the dirty region and mark accumulator dirty */ + if(f->shared->accum.dirty) { + /* Check for new metadata starting before current dirty region */ + if(dirty_off <= f->shared->accum.dirty_off) { + f->shared->accum.dirty_off = dirty_off; + f->shared->accum.dirty_len = size; + } /* end if */ + else { + f->shared->accum.dirty_len = (dirty_off + size) - f->shared->accum.dirty_off; + } /* end else */ } /* end if */ else { - f->shared->accum.dirty_len = (dirty_off + size) - f->shared->accum.dirty_off; + f->shared->accum.dirty_off = dirty_off; + f->shared->accum.dirty_len = size; + f->shared->accum.dirty = TRUE; } /* end else */ } /* end if */ + /* New metadata overlaps both ends of the current accumulator */ else { - f->shared->accum.dirty_off = dirty_off; + /* Check if we need more buffer space */ + if(size > f->shared->accum.alloc_size) { + size_t new_alloc_size; /* New size of accumulator */ + + /* Adjust the buffer size to be a power of 2 that is large enough to hold data */ + new_alloc_size = (size_t)1 << (1 + H5V_log2_gen((uint64_t)(size - 1))); + + /* Reallocate the metadata accumulator buffer */ + if(NULL == (f->shared->accum.buf = H5FL_BLK_REALLOC(meta_accum, f->shared->accum.buf, new_alloc_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer") + + /* Note the new buffer size */ + f->shared->accum.alloc_size = new_alloc_size; +#ifdef H5_CLEAR_MEMORY +HDmemset(f->shared->accum.buf + size, 0, (f->shared->accum.alloc_size - size)); +#endif /* H5_CLEAR_MEMORY */ + } /* end if */ + + /* Copy the new metadata to the buffer */ + HDmemcpy(f->shared->accum.buf, buf, size); + + /* Set the new size & location of the metadata accumulator */ + f->shared->accum.loc = addr; + f->shared->accum.size = size; + + /* Adjust the dirty region and mark accumulator dirty */ + f->shared->accum.dirty_off = 0; f->shared->accum.dirty_len = size; f->shared->accum.dirty = TRUE; } /* end else */ } /* end if */ - /* New metadata overlaps both ends of the current accumulator */ + /* New piece of metadata doesn't adjoin or overlap the existing accumulator */ else { - /* Check if we need more buffer space */ + /* Write out the existing metadata accumulator, with dispatch to driver */ + if(f->shared->accum.dirty) { + if(H5FD_write(f->shared->lf, dxpl_id, H5FD_MEM_DEFAULT, f->shared->accum.loc + f->shared->accum.dirty_off, f->shared->accum.dirty_len, f->shared->accum.buf + f->shared->accum.dirty_off) < 0) + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed") + + /* Reset accumulator dirty flag */ + f->shared->accum.dirty = FALSE; + } /* end if */ + + /* Cache the new piece of metadata */ + /* Check if we need to resize the buffer */ if(size > f->shared->accum.alloc_size) { - size_t new_alloc_size; /* New size of accumulator */ + size_t new_size; /* New size of accumulator */ /* Adjust the buffer size to be a power of 2 that is large enough to hold data */ - new_alloc_size = (size_t)1 << (1 + H5V_log2_gen((uint64_t)(size - 1))); + new_size = (size_t)1 << (1 + H5V_log2_gen((uint64_t)(size - 1))); - /* Reallocate the metadata accumulator buffer */ - if(NULL == (f->shared->accum.buf = H5FL_BLK_REALLOC(meta_accum, f->shared->accum.buf, new_alloc_size))) + /* Grow the metadata accumulator buffer */ + if(NULL == (f->shared->accum.buf = H5FL_BLK_REALLOC(meta_accum, f->shared->accum.buf, new_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer") /* Note the new buffer size */ - f->shared->accum.alloc_size = new_alloc_size; + f->shared->accum.alloc_size = new_size; #ifdef H5_CLEAR_MEMORY -HDmemset(f->shared->accum.buf + size, 0, (f->shared->accum.alloc_size - size)); +{ +size_t clear_size = MAX(f->shared->accum.size, size); +HDmemset(f->shared->accum.buf + clear_size, 0, (f->shared->accum.alloc_size - clear_size)); +} #endif /* H5_CLEAR_MEMORY */ } /* end if */ + else { + /* Check if we should shrink the accumulator buffer */ + if(size < (f->shared->accum.alloc_size / H5F_ACCUM_THROTTLE) && + f->shared->accum.alloc_size > H5F_ACCUM_THRESHOLD) { + size_t tmp_size = (f->shared->accum.alloc_size / H5F_ACCUM_THROTTLE); /* New size of accumulator buffer */ - /* Copy the new metadata to the buffer */ - HDmemcpy(f->shared->accum.buf, buf, size); + /* Shrink the accumulator buffer */ + if(NULL == (f->shared->accum.buf = H5FL_BLK_REALLOC(meta_accum, f->shared->accum.buf, tmp_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer") - /* Set the new size & location of the metadata accumulator */ + /* Note the new buffer size */ + f->shared->accum.alloc_size = tmp_size; + } /* end if */ + } /* end else */ + + /* Update the metadata accumulator information */ f->shared->accum.loc = addr; f->shared->accum.size = size; + /* Store the piece of metadata in the accumulator */ + HDmemcpy(f->shared->accum.buf, buf, size); + /* Adjust the dirty region and mark accumulator dirty */ f->shared->accum.dirty_off = 0; f->shared->accum.dirty_len = size; f->shared->accum.dirty = TRUE; } /* end else */ } /* end if */ - /* New piece of metadata doesn't adjoin or overlap the existing accumulator */ + /* No metadata in the accumulator, grab this piece and keep it */ else { - /* Write out the existing metadata accumulator, with dispatch to driver */ - if(f->shared->accum.dirty) { - if(H5FD_write(f->shared->lf, dxpl_id, H5FD_MEM_DEFAULT, f->shared->accum.loc + f->shared->accum.dirty_off, f->shared->accum.dirty_len, f->shared->accum.buf + f->shared->accum.dirty_off) < 0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed") - - /* Reset accumulator dirty flag */ - f->shared->accum.dirty = FALSE; - } /* end if */ - - /* Cache the new piece of metadata */ - /* Check if we need to resize the buffer */ + /* Check if we need to reallocate the buffer */ if(size > f->shared->accum.alloc_size) { size_t new_size; /* New size of accumulator */ /* Adjust the buffer size to be a power of 2 that is large enough to hold data */ new_size = (size_t)1 << (1 + H5V_log2_gen((uint64_t)(size - 1))); - /* Grow the metadata accumulator buffer */ + /* Reallocate the metadata accumulator buffer */ if(NULL == (f->shared->accum.buf = H5FL_BLK_REALLOC(meta_accum, f->shared->accum.buf, new_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer") /* Note the new buffer size */ f->shared->accum.alloc_size = new_size; #ifdef H5_CLEAR_MEMORY -{ -size_t clear_size = MAX(f->shared->accum.size, size); -HDmemset(f->shared->accum.buf + clear_size, 0, (f->shared->accum.alloc_size - clear_size)); -} +HDmemset(f->shared->accum.buf + size, 0, (f->shared->accum.alloc_size - size)); #endif /* H5_CLEAR_MEMORY */ } /* end if */ - else { - /* Check if we should shrink the accumulator buffer */ - if(size < (f->shared->accum.alloc_size / H5F_ACCUM_THROTTLE) && - f->shared->accum.alloc_size > H5F_ACCUM_THRESHOLD) { - size_t tmp_size = (f->shared->accum.alloc_size / H5F_ACCUM_THROTTLE); /* New size of accumulator buffer */ - - /* Shrink the accumulator buffer */ - if(NULL == (f->shared->accum.buf = H5FL_BLK_REALLOC(meta_accum, f->shared->accum.buf, tmp_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer") - - /* Note the new buffer size */ - f->shared->accum.alloc_size = tmp_size; - } /* end if */ - } /* end else */ /* Update the metadata accumulator information */ f->shared->accum.loc = addr; @@ -636,42 +717,96 @@ HDmemset(f->shared->accum.buf + clear_size, 0, (f->shared->accum.alloc_size - cl f->shared->accum.dirty = TRUE; } /* end else */ } /* end if */ - /* No metadata in the accumulator, grab this piece and keep it */ else { - /* Check if we need to reallocate the buffer */ - if(size > f->shared->accum.alloc_size) { - size_t new_size; /* New size of accumulator */ + /* Write the data */ + if(H5FD_write(f->shared->lf, dxpl_id, type, addr, size, buf) < 0) + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed") + + /* Check for overlap w/accumulator */ + /* (Note that this could be improved by updating the accumulator + * with [some of] the information just read in. -QAK) + */ + if(H5F_addr_overlap(addr, size, f->shared->accum.loc, f->shared->accum.size)) { + /* Check for write starting before beginning of accumulator */ + if(H5F_addr_le(addr, f->shared->accum.loc)) { + /* Check for write ending within accumulator */ + if(H5F_addr_le(addr + size, f->shared->accum.loc + f->shared->accum.size)) { + size_t overlap_size; /* Size of overlapping region */ + + /* Compute overlap size */ + overlap_size = (size_t)((addr + size) - f->shared->accum.loc); + + /* Check for dirty region */ + if(f->shared->accum.dirty) { + haddr_t dirty_start = f->shared->accum.loc + f->shared->accum.dirty_off; /* File address of start of dirty region */ + haddr_t dirty_end = dirty_start + f->shared->accum.dirty_len; /* File address of end of dirty region */ + + /* Check if entire dirty region is overwritten */ + if(H5F_addr_le(dirty_end, addr + size)) { + f->shared->accum.dirty = FALSE; + f->shared->accum.dirty_len = 0; + } /* end if */ + else { + /* Check for dirty region falling after write */ + if(H5F_addr_le(addr + size, dirty_start)) + f->shared->accum.dirty_off = overlap_size; + else { /* Dirty region overlaps w/written region */ + f->shared->accum.dirty_off = 0; + f->shared->accum.dirty_len -= (size_t)((addr + size) - dirty_start); + } /* end else */ + } /* end if */ + } /* end if */ - /* Adjust the buffer size to be a power of 2 that is large enough to hold data */ - new_size = (size_t)1 << (1 + H5V_log2_gen((uint64_t)(size - 1))); + /* Trim bottom of accumulator off */ + f->shared->accum.loc += overlap_size; + f->shared->accum.size -= overlap_size; + HDmemmove(f->shared->accum.buf, f->shared->accum.buf + overlap_size, f->shared->accum.size); + } /* end if */ + else { /* Access covers whole accumulator */ + /* Reset accumulator, but don't flush */ + if(H5F_accum_reset(f, dxpl_id, FALSE) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTRESET, FAIL, "can't reset accumulator") + } /* end else */ + } /* end if */ + else { /* Write starts after beginning of accumulator */ + size_t overlap_size; /* Size of overlapping region */ - /* Reallocate the metadata accumulator buffer */ - if(NULL == (f->shared->accum.buf = H5FL_BLK_REALLOC(meta_accum, f->shared->accum.buf, new_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer") + /* Sanity check */ + HDassert(H5F_addr_gt(addr + size, f->shared->accum.loc + f->shared->accum.size)); - /* Note the new buffer size */ - f->shared->accum.alloc_size = new_size; -#ifdef H5_CLEAR_MEMORY -HDmemset(f->shared->accum.buf + size, 0, (f->shared->accum.alloc_size - size)); -#endif /* H5_CLEAR_MEMORY */ - } /* end if */ + /* Compute overlap size */ + overlap_size = (size_t)((f->shared->accum.loc + f->shared->accum.size) - addr); - /* Update the metadata accumulator information */ - f->shared->accum.loc = addr; - f->shared->accum.size = size; + /* Check for dirty region */ + if(f->shared->accum.dirty) { + haddr_t dirty_start = f->shared->accum.loc + f->shared->accum.dirty_off; /* File address of start of dirty region */ + haddr_t dirty_end = dirty_start + f->shared->accum.dirty_len; /* File address of end of dirty region */ - /* Store the piece of metadata in the accumulator */ - HDmemcpy(f->shared->accum.buf, buf, size); + /* Check if entire dirty region is overwritten */ + if(H5F_addr_ge(dirty_start, addr)) { + f->shared->accum.dirty = FALSE; + f->shared->accum.dirty_len = 0; + } /* end if */ + else { + /* Check for dirty region falling before write */ + if(H5F_addr_le(dirty_end, addr)) + ; /* noop */ + else /* Dirty region overlaps w/written region */ + f->shared->accum.dirty_len = (size_t)(addr - dirty_start); + } /* end if */ + } /* end if */ - /* Adjust the dirty region and mark accumulator dirty */ - f->shared->accum.dirty_off = 0; - f->shared->accum.dirty_len = size; - f->shared->accum.dirty = TRUE; + /* Trim top of accumulator off */ + f->shared->accum.size -= overlap_size; + } /* end else */ + } /* end if */ } /* end else */ - - /* Indicate success */ - HGOTO_DONE(TRUE); } /* end if */ + else { + /* Write the data */ + if(H5FD_write(f->shared->lf, dxpl_id, type, addr, size, buf) < 0) + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed") + } /* end else */ done: FUNC_LEAVE_NOAPI(ret_value) @@ -778,22 +913,20 @@ H5F_accum_free(H5F_t *f, hid_t dxpl_id, H5FD_mem_t UNUSED type, haddr_t addr, HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed") } /* end if */ /* Block to free overlaps with some/all of dirty region */ - else { + /* Check for unfreed dirty region to write */ + else if(H5F_addr_lt(tail_addr, dirty_end)) { size_t write_size; + size_t dirty_delta; write_size = (size_t)(dirty_end - tail_addr); + dirty_delta = f->shared->accum.dirty_len - write_size; - /* Check for unfreed dirty region to write */ - if(write_size > 0) { - size_t dirty_delta; - - dirty_delta = f->shared->accum.dirty_len - write_size; + HDassert(write_size > 0); - /* Write out the unfreed dirty region of the accumulator */ - if(H5FD_write(f->shared->lf, dxpl_id, H5FD_MEM_DEFAULT, dirty_start + dirty_delta, write_size, f->shared->accum.buf + f->shared->accum.dirty_off + dirty_delta) < 0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed") - } /* end if */ - } /* end else */ + /* Write out the unfreed dirty region of the accumulator */ + if(H5FD_write(f->shared->lf, dxpl_id, H5FD_MEM_DEFAULT, dirty_start + dirty_delta, write_size, f->shared->accum.buf + f->shared->accum.dirty_off + dirty_delta) < 0) + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed") + } /* end if */ /* Reset dirty flag */ f->shared->accum.dirty = FALSE; @@ -803,19 +936,16 @@ H5F_accum_free(H5F_t *f, hid_t dxpl_id, H5FD_mem_t UNUSED type, haddr_t addr, /* Check if block to free ends before end of dirty region */ if(H5F_addr_lt(tail_addr, dirty_end)) { size_t write_size; + size_t dirty_delta; write_size = (size_t)(dirty_end - tail_addr); + dirty_delta = f->shared->accum.dirty_len - write_size; - /* Check for unfreed dirty region to write */ - if(write_size > 0) { - size_t dirty_delta; + HDassert(write_size > 0); - dirty_delta = f->shared->accum.dirty_len - write_size; - - /* Write out the unfreed end of the dirty region of the accumulator */ - if(H5FD_write(f->shared->lf, dxpl_id, H5FD_MEM_DEFAULT, dirty_start + dirty_delta, write_size, f->shared->accum.buf + f->shared->accum.dirty_off + dirty_delta) < 0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed") - } /* end if */ + /* Write out the unfreed end of the dirty region of the accumulator */ + if(H5FD_write(f->shared->lf, dxpl_id, H5FD_MEM_DEFAULT, dirty_start + dirty_delta, write_size, f->shared->accum.buf + f->shared->accum.dirty_off + dirty_delta) < 0) + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed") } /* end if */ /* Check for block to free beginning at same location as dirty region */ @@ -825,7 +955,7 @@ H5F_accum_free(H5F_t *f, hid_t dxpl_id, H5FD_mem_t UNUSED type, haddr_t addr, } /* end if */ /* Block to free eliminates end of dirty region */ else { - f->shared->accum.dirty_len = (addr - dirty_start); + f->shared->accum.dirty_len = (size_t)(addr - dirty_start); } /* end else */ } /* end else */ @@ -855,7 +985,7 @@ done: *------------------------------------------------------------------------- */ herr_t -H5F_accum_flush(H5F_t *f, hid_t dxpl_id) +H5F_accum_flush(const H5F_t *f, hid_t dxpl_id) { herr_t ret_value = SUCCEED; /* Return value */ @@ -893,7 +1023,7 @@ done: *------------------------------------------------------------------------- */ herr_t -H5F_accum_reset(H5F_t *f, hid_t dxpl_id) +H5F_accum_reset(const H5F_t *f, hid_t dxpl_id, hbool_t flush) { herr_t ret_value = SUCCEED; /* Return value */ @@ -902,9 +1032,10 @@ H5F_accum_reset(H5F_t *f, hid_t dxpl_id) HDassert(f); HDassert(f->shared); - /* Flush any dirty data in accumulator */ - if(H5F_accum_flush(f, dxpl_id) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "can't flush metadata accumulator") + /* Flush any dirty data in accumulator, if requested */ + if(flush) + if(H5F_accum_flush(f, dxpl_id) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "can't flush metadata accumulator") /* Check if we need to reset the metadata accumulator information */ if(f->shared->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) { |