From 1c14d3e96d8e4ab0b504ca98fdd3958c9cc451ea Mon Sep 17 00:00:00 2001 From: Mike McGreevy Date: Fri, 15 Oct 2010 14:59:07 -0500 Subject: [svn-r19618] Purpose: Bring metadata accumulator fixes and tests into 1.8 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 --- MANIFEST | 1 + src/H5F.c | 2 +- src/H5Faccum.c | 721 +++++++++++--------- src/H5Fio.c | 24 +- src/H5Fpkg.h | 8 +- test/CMakeLists.txt | 1 + test/Makefile.am | 4 +- test/Makefile.in | 53 +- test/accum.c | 1809 +++++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 2281 insertions(+), 342 deletions(-) create mode 100644 test/accum.c diff --git a/MANIFEST b/MANIFEST index 1ebf569..da8e50b 100644 --- a/MANIFEST +++ b/MANIFEST @@ -782,6 +782,7 @@ ./test/H5srcdir_str.h.in ./test/Makefile.am ./test/Makefile.in +./test/accum.c ./test/app_ref.c ./test/be_data.h5 ./test/be_extlink1.h5 diff --git a/src/H5F.c b/src/H5F.c index f27e4f2..a2715ce 100644 --- a/src/H5F.c +++ b/src/H5F.c @@ -1042,7 +1042,7 @@ H5F_dest(H5F_t *f, hid_t dxpl_id, hbool_t flush) } /* end if */ /* Destroy other components of the file */ - if(H5F_accum_reset(f, dxpl_id) < 0) + if(H5F_accum_reset(f, dxpl_id, TRUE) < 0) /* Push error, but keep going*/ HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "problems closing file") if(H5FO_dest(f) < 0) diff --git a/src/H5Faccum.c b/src/H5Faccum.c index 7e665ee..7dedb1b 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) { diff --git a/src/H5Fio.c b/src/H5Fio.c index 407f950..231c4c9 100644 --- a/src/H5Fio.c +++ b/src/H5Fio.c @@ -95,7 +95,6 @@ herr_t H5F_block_read(const H5F_t *f, H5FD_mem_t type, haddr_t addr, size_t size, hid_t dxpl_id, void *buf/*out*/) { - htri_t accumulated; /* Whether the data was accepted by the metadata accumulator */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(H5F_block_read, FAIL) @@ -108,14 +107,9 @@ H5F_block_read(const H5F_t *f, H5FD_mem_t type, haddr_t addr, size_t size, if(H5F_addr_le(f->shared->tmp_addr, (addr + size))) HGOTO_ERROR(H5E_IO, H5E_BADRANGE, FAIL, "attempting I/O in temporary file space") - /* Check if this I/O can be satisfied by the metadata accumulator */ - if((accumulated = H5F_accum_read(f, dxpl_id, type, addr, size, buf)) < 0) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "read from metadata accumulator failed") - else if(accumulated == FALSE) { - /* 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 */ + /* Pass through metadata accumulator layer */ + if(H5F_accum_read(f, dxpl_id, type, addr, size, buf) < 0) + HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "read through metadata accumulator failed") done: FUNC_LEAVE_NOAPI(ret_value) @@ -141,7 +135,6 @@ herr_t H5F_block_write(const H5F_t *f, H5FD_mem_t type, haddr_t addr, size_t size, hid_t dxpl_id, const void *buf) { - htri_t accumulated; /* Whether the data was accepted by the metadata accumulator */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(H5F_block_write, FAIL) @@ -158,14 +151,9 @@ HDfprintf(stderr, "%s: write to addr = %a, size = %Zu\n", FUNC, addr, size); if(H5F_addr_le(f->shared->tmp_addr, (addr + size))) HGOTO_ERROR(H5E_IO, H5E_BADRANGE, FAIL, "attempting I/O in temporary file space") - /* Check for accumulating metadata */ - if((accumulated = H5F_accum_write(f, dxpl_id, type, addr, size, buf)) < 0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "write to metadata accumulator failed") - else if(accumulated == FALSE) { - /* 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 */ + /* Pass through metadata accumulator layer */ + if(H5F_accum_write(f, dxpl_id, type, addr, size, buf) < 0) + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "write through metadata accumulator failed") done: FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5Fpkg.h b/src/H5Fpkg.h index 8a4a5f8..f10dc7e 100644 --- a/src/H5Fpkg.h +++ b/src/H5Fpkg.h @@ -310,14 +310,14 @@ H5_DLL herr_t H5F_super_ext_close(H5F_t *f, H5O_loc_t *ext_ptr, hid_t dxpl_id, hbool_t was_created); /* Metadata accumulator routines */ -H5_DLL htri_t H5F_accum_read(const H5F_t *f, hid_t dxpl_id, H5FD_mem_t type, +H5_DLL 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); -H5_DLL htri_t H5F_accum_write(const H5F_t *f, hid_t dxpl_id, H5FD_mem_t type, +H5_DLL 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); H5_DLL herr_t H5F_accum_free(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type, haddr_t addr, hsize_t size); -H5_DLL herr_t H5F_accum_flush(H5F_t *f, hid_t dxpl_id); -H5_DLL herr_t H5F_accum_reset(H5F_t *f, hid_t dxpl_id); +H5_DLL herr_t H5F_accum_flush(const H5F_t *f, hid_t dxpl_id); +H5_DLL herr_t H5F_accum_reset(const H5F_t *f, hid_t dxpl_id, hbool_t flush); /* Shared file list related routines */ H5_DLL herr_t H5F_sfile_add(H5F_file_t *shared); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f37d54b..2d53499 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -239,6 +239,7 @@ ADD_TEST ( ) SET (H5_TESTS + accum lheap ohdr stab diff --git a/test/Makefile.am b/test/Makefile.am index 9ef4fb3..b37ad53 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -37,7 +37,7 @@ SCRIPT_DEPEND = error_test$(EXEEXT) err_compat$(EXEEXT) # the library yet. Move them to the end so that their failure do not block # other current library code tests. TEST_PROG=testhdf5 lheap ohdr stab gheap cache cache_api \ - pool hyperslab istore bittests dt_arith \ + pool accum hyperslab istore bittests dt_arith \ dtypes dsets cmpd_dset filter_fail extend external objcopy links unlink \ big mtime fillval mount flush1 flush2 app_ref enum \ set_extent ttsafe \ @@ -103,7 +103,7 @@ flush2.chkexe_: flush1.chkexe_ # specifying a file prefix or low-level driver. Changing the file # prefix or low-level driver with environment variables will influence # the temporary file name in ways that the makefile is not aware of. -CHECK_CLEANFILES+=cmpd_dset.h5 compact_dataset.h5 dataset.h5 dset_offset.h5 \ +CHECK_CLEANFILES+=accum.h5 cmpd_dset.h5 compact_dataset.h5 dataset.h5 dset_offset.h5 \ max_compact_dataset.h5 simple.h5 set_local.h5 random_chunks.h5 \ huge_chunks.h5 chunk_cache.h5 big_chunk.h5 chunk_expand.h5 \ copy_dcpl_newfile.h5 extend.h5 istore.h5 extlinks*.h5 frspace.h5 links*.h5 \ diff --git a/test/Makefile.in b/test/Makefile.in index 09cd98d..0d996e7 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -77,12 +77,12 @@ am_libh5test_la_OBJECTS = h5test.lo testframe.lo cache_common.lo libh5test_la_OBJECTS = $(am_libh5test_la_OBJECTS) am__EXEEXT_1 = testhdf5$(EXEEXT) lheap$(EXEEXT) ohdr$(EXEEXT) \ stab$(EXEEXT) gheap$(EXEEXT) cache$(EXEEXT) cache_api$(EXEEXT) \ - pool$(EXEEXT) hyperslab$(EXEEXT) istore$(EXEEXT) \ - bittests$(EXEEXT) dt_arith$(EXEEXT) dtypes$(EXEEXT) \ - dsets$(EXEEXT) cmpd_dset$(EXEEXT) filter_fail$(EXEEXT) \ - extend$(EXEEXT) external$(EXEEXT) objcopy$(EXEEXT) \ - links$(EXEEXT) unlink$(EXEEXT) big$(EXEEXT) mtime$(EXEEXT) \ - fillval$(EXEEXT) mount$(EXEEXT) flush1$(EXEEXT) \ + pool$(EXEEXT) accum$(EXEEXT) hyperslab$(EXEEXT) \ + istore$(EXEEXT) bittests$(EXEEXT) dt_arith$(EXEEXT) \ + dtypes$(EXEEXT) dsets$(EXEEXT) cmpd_dset$(EXEEXT) \ + filter_fail$(EXEEXT) extend$(EXEEXT) external$(EXEEXT) \ + objcopy$(EXEEXT) links$(EXEEXT) unlink$(EXEEXT) big$(EXEEXT) \ + mtime$(EXEEXT) fillval$(EXEEXT) mount$(EXEEXT) flush1$(EXEEXT) \ flush2$(EXEEXT) app_ref$(EXEEXT) enum$(EXEEXT) \ set_extent$(EXEEXT) ttsafe$(EXEEXT) getname$(EXEEXT) \ vfd$(EXEEXT) ntypes$(EXEEXT) dangle$(EXEEXT) \ @@ -96,6 +96,10 @@ am__EXEEXT_2 = gen_bad_ohdr$(EXEEXT) gen_bogus$(EXEEXT) \ gen_nullspace$(EXEEXT) gen_udlinks$(EXEEXT) \ space_overflow$(EXEEXT) gen_sizes_lheap$(EXEEXT) PROGRAMS = $(noinst_PROGRAMS) +accum_SOURCES = accum.c +accum_OBJECTS = accum.$(OBJEXT) +accum_LDADD = $(LDADD) +accum_DEPENDENCIES = libh5test.la $(LIBHDF5) app_ref_SOURCES = app_ref.c app_ref_OBJECTS = app_ref.$(OBJEXT) app_ref_LDADD = $(LDADD) @@ -367,20 +371,7 @@ CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ -SOURCES = $(libh5test_la_SOURCES) app_ref.c big.c bittests.c btree2.c \ - cache.c cache_api.c cmpd_dset.c cross_read.c dangle.c dsets.c \ - dt_arith.c dtransform.c dtypes.c enum.c err_compat.c \ - error_test.c extend.c external.c fheap.c fillval.c \ - filter_fail.c flush1.c flush2.c freespace.c gen_bad_ohdr.c \ - gen_bogus.c gen_cross.c gen_deflate.c gen_filters.c gen_idx.c \ - gen_new_array.c gen_new_fill.c gen_new_group.c gen_new_mtime.c \ - gen_new_super.c gen_noencoder.c gen_nullspace.c \ - gen_sizes_lheap.c gen_udlinks.c getname.c gheap.c hyperslab.c \ - istore.c lheap.c links.c mf.c mount.c mtime.c ntypes.c \ - objcopy.c ohdr.c pool.c reserved.c set_extent.c \ - space_overflow.c stab.c tcheck_version.c $(testhdf5_SOURCES) \ - testmeta.c $(ttsafe_SOURCES) unlink.c vfd.c -DIST_SOURCES = $(libh5test_la_SOURCES) app_ref.c big.c bittests.c \ +SOURCES = $(libh5test_la_SOURCES) accum.c app_ref.c big.c bittests.c \ btree2.c cache.c cache_api.c cmpd_dset.c cross_read.c dangle.c \ dsets.c dt_arith.c dtransform.c dtypes.c enum.c err_compat.c \ error_test.c extend.c external.c fheap.c fillval.c \ @@ -393,6 +384,20 @@ DIST_SOURCES = $(libh5test_la_SOURCES) app_ref.c big.c bittests.c \ objcopy.c ohdr.c pool.c reserved.c set_extent.c \ space_overflow.c stab.c tcheck_version.c $(testhdf5_SOURCES) \ testmeta.c $(ttsafe_SOURCES) unlink.c vfd.c +DIST_SOURCES = $(libh5test_la_SOURCES) accum.c app_ref.c big.c \ + bittests.c btree2.c cache.c cache_api.c cmpd_dset.c \ + cross_read.c dangle.c dsets.c dt_arith.c dtransform.c dtypes.c \ + enum.c err_compat.c error_test.c extend.c external.c fheap.c \ + fillval.c filter_fail.c flush1.c flush2.c freespace.c \ + gen_bad_ohdr.c gen_bogus.c gen_cross.c gen_deflate.c \ + gen_filters.c gen_idx.c gen_new_array.c gen_new_fill.c \ + gen_new_group.c gen_new_mtime.c gen_new_super.c \ + gen_noencoder.c gen_nullspace.c gen_sizes_lheap.c \ + gen_udlinks.c getname.c gheap.c hyperslab.c istore.c lheap.c \ + links.c mf.c mount.c mtime.c ntypes.c objcopy.c ohdr.c pool.c \ + reserved.c set_extent.c space_overflow.c stab.c \ + tcheck_version.c $(testhdf5_SOURCES) testmeta.c \ + $(ttsafe_SOURCES) unlink.c vfd.c ETAGS = etags CTAGS = ctags am__tty_colors = \ @@ -673,7 +678,7 @@ TRACE = perl $(top_srcdir)/bin/trace # specifying a file prefix or low-level driver. Changing the file # prefix or low-level driver with environment variables will influence # the temporary file name in ways that the makefile is not aware of. -CHECK_CLEANFILES = *.chkexe *.chklog *.clog cmpd_dset.h5 \ +CHECK_CLEANFILES = *.chkexe *.chklog *.clog accum.h5 cmpd_dset.h5 \ compact_dataset.h5 dataset.h5 dset_offset.h5 \ max_compact_dataset.h5 simple.h5 set_local.h5 random_chunks.h5 \ huge_chunks.h5 chunk_cache.h5 big_chunk.h5 chunk_expand.h5 \ @@ -711,7 +716,7 @@ SCRIPT_DEPEND = error_test$(EXEEXT) err_compat$(EXEEXT) # the library yet. Move them to the end so that their failure do not block # other current library code tests. TEST_PROG = testhdf5 lheap ohdr stab gheap cache cache_api \ - pool hyperslab istore bittests dt_arith \ + pool accum hyperslab istore bittests dt_arith \ dtypes dsets cmpd_dset filter_fail extend external objcopy links unlink \ big mtime fillval mount flush1 flush2 app_ref enum \ set_extent ttsafe \ @@ -841,6 +846,9 @@ clean-noinstPROGRAMS: list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list +accum$(EXEEXT): $(accum_OBJECTS) $(accum_DEPENDENCIES) + @rm -f accum$(EXEEXT) + $(LINK) $(accum_OBJECTS) $(accum_LDADD) $(LIBS) app_ref$(EXEEXT): $(app_ref_OBJECTS) $(app_ref_DEPENDENCIES) @rm -f app_ref$(EXEEXT) $(LINK) $(app_ref_OBJECTS) $(app_ref_LDADD) $(LIBS) @@ -1034,6 +1042,7 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/accum.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app_ref.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/big.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bittests.Po@am__quote@ diff --git a/test/accum.c b/test/accum.c new file mode 100644 index 0000000..91d30c4 --- /dev/null +++ b/test/accum.c @@ -0,0 +1,1809 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* Programmer: Mike McGreevy + * October 7, 2010 + */ +#include "h5test.h" + +#define H5F_PACKAGE +#include "H5Fpkg.h" +#include "H5FDprivate.h" +#include "H5Iprivate.h" + +/* Filename */ +#define FILENAME "accum.h5" + +/* "big" I/O test values */ +#define BIG_BUF_SIZE (6 * 1024 * 1024) + +/* Random I/O test values */ +#define RANDOM_BUF_SIZE (1 * 1024 * 1024) +#define MAX_RANDOM_SEGMENTS (5 * 1024) +#define RAND_SEG_LEN (1024) +#define RANDOM_BASE_OFF (1024 * 1024) + +/* Make file global to all tests */ +H5F_t * f = NULL; + +/* Function Prototypes */ +unsigned test_write_read(void); +unsigned test_write_read_nonacc_front(void); +unsigned test_write_read_nonacc_end(void); +unsigned test_accum_overlap(void); +unsigned test_accum_overlap_clean(void); +unsigned test_accum_overlap_size(void); +unsigned test_accum_non_overlap_size(void); +unsigned test_accum_adjust(void); +unsigned test_read_after(void); +unsigned test_free(void); +unsigned test_big(void); +unsigned test_random_write(void); + +/* Helper Function Prototypes */ +void accum_printf(void); + +/* Private Test H5Faccum Function Wrappers */ +#define accum_write(a,s,b) H5F_block_write(f, H5FD_MEM_DEFAULT, (haddr_t)(a), (size_t)(s), H5AC_dxpl_id, (b)) +#define accum_read(a,s,b) H5F_block_read(f, H5FD_MEM_DEFAULT, (haddr_t)(a), (size_t)(s), H5AC_dxpl_id, (b)) +#define accum_free(a,s) H5F_accum_free(f, H5AC_dxpl_id, H5FD_MEM_DEFAULT, (haddr_t)(a), (hsize_t)(s)) +#define accum_flush() H5F_accum_flush(f, H5AC_dxpl_id) +#define accum_reset() H5F_accum_reset(f, H5AC_dxpl_id, TRUE) + +/* ================= */ +/* Main Test Routine */ +/* ================= */ + + +/*------------------------------------------------------------------------- + * Function: main + * + * Purpose: Test the metadata accumulator code + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Mike McGreevy + * October 7, 2010 + * + *------------------------------------------------------------------------- + */ +int +main(void) +{ + unsigned nerrors = 0; /* track errors */ + hid_t fid = -1; + + /* Test Setup */ + puts("Testing the metadata accumulator"); + + /* Create a test file */ + if((fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) FAIL_STACK_ERROR + + /* Get H5F_t * to internal file structure */ + if(NULL == (f = (H5F_t *)H5I_object(fid))) FAIL_STACK_ERROR + + /* We'll be writing lots of garbage data, so extend the + file a ways. 10MB should do. */ + if(H5FD_set_eoa(f->shared->lf, H5FD_MEM_DEFAULT, (haddr_t)(1024*1024*10)) < 0) FAIL_STACK_ERROR + + /* Reset metadata accumulator for the file */ + if(accum_reset() < 0) FAIL_STACK_ERROR + + /* Test Functions */ + nerrors += test_write_read(); + nerrors += test_write_read_nonacc_front(); + nerrors += test_write_read_nonacc_end(); + nerrors += test_accum_overlap(); + nerrors += test_accum_overlap_clean(); + nerrors += test_accum_overlap_size(); + nerrors += test_accum_non_overlap_size(); + nerrors += test_accum_adjust(); + nerrors += test_read_after(); + nerrors += test_free(); + nerrors += test_big(); + nerrors += test_random_write(); + + /* End of test code, close and delete file */ + if(H5Fclose(fid) < 0) TEST_ERROR + HDremove(FILENAME); + + if(nerrors) + goto error; + puts("All metadata accumulator tests passed."); + + return 0; + +error: + puts("*** TESTS FAILED ***"); + return 1; +} /* end main() */ + +/* ============================= */ +/* Individual Unit Test Routines */ +/* ============================= */ + + +/*------------------------------------------------------------------------- + * Function: test_write_read + * + * Purpose: Simple test to write to then read from metadata accumulator. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Mike McGreevy + * October 7, 2010 + * + *------------------------------------------------------------------------- + */ +unsigned +test_write_read(void) +{ + int i = 0; + int *write_buf, *read_buf; + + TESTING("simple write/read to/from metadata accumulator"); + + /* Allocate buffers */ + write_buf = (int *)HDmalloc(1024 * sizeof(int)); + HDassert(write_buf); + read_buf = (int *)HDcalloc(1024, sizeof(int)); + HDassert(read_buf); + + /* Fill buffer with data, zero out read buffer */ + for(i = 0; i < 1024; i++) + write_buf[i] = i + 1; + + /* Do a simple write/read/verify of data */ + /* Write 1KB at Address 0 */ + if(accum_write(0, 1024, write_buf) < 0) FAIL_STACK_ERROR; + if(accum_read(0, 1024, read_buf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(write_buf, read_buf, 1024) != 0) TEST_ERROR; + + if(accum_reset() < 0) FAIL_STACK_ERROR; + + PASSED(); + + /* Release memory */ + HDfree(write_buf); + HDfree(read_buf); + + return 0; + +error: + /* Release memory */ + HDfree(write_buf); + HDfree(read_buf); + + return 1; +} /* test_write_read */ + + +/*------------------------------------------------------------------------- + * Function: test_write_read_nonacc_front + * + * Purpose: Simple test to write to then read from before metadata accumulator. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Allen Byrne + * October 8, 2010 + * + *------------------------------------------------------------------------- + */ +unsigned +test_write_read_nonacc_front(void) +{ + int i = 0; + int *write_buf, *read_buf; + + TESTING("simple write/read to/from before metadata accumulator"); + + /* Allocate buffers */ + write_buf = (int *)HDmalloc(2048 * sizeof(int)); + HDassert(write_buf); + read_buf = (int *)HDcalloc(2048, sizeof(int)); + HDassert(read_buf); + + /* Fill buffer with data, zero out read buffer */ + for(i = 0; i < 2048; i++) + write_buf[i] = i + 1; + + /* Do a simple write/read/verify of data */ + /* Write 1KB at Address 0 */ + if(accum_write(0, 1024, write_buf) < 0) FAIL_STACK_ERROR; + if(accum_flush() < 0) FAIL_STACK_ERROR; + if(accum_reset() < 0) FAIL_STACK_ERROR; + if(accum_write(1024, 1024, write_buf) < 0) FAIL_STACK_ERROR; + if(accum_read(0, 1024, read_buf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(write_buf, read_buf, 1024) != 0) TEST_ERROR; + + if(accum_reset() < 0) FAIL_STACK_ERROR; + + PASSED(); + + /* Release memory */ + HDfree(write_buf); + HDfree(read_buf); + + return 0; + +error: + /* Release memory */ + HDfree(write_buf); + HDfree(read_buf); + + return 1; +} /* test_write_read */ + + +/*------------------------------------------------------------------------- + * Function: test_write_read_nonacc_end + * + * Purpose: Simple test to write to then read from after metadata accumulator. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Allen Byrne + * October 8, 2010 + * + *------------------------------------------------------------------------- + */ +unsigned +test_write_read_nonacc_end(void) +{ + int i = 0; + int *write_buf, *read_buf; + + TESTING("simple write/read to/from after metadata accumulator"); + + /* Allocate buffers */ + write_buf = (int *)HDmalloc(2048 * sizeof(int)); + HDassert(write_buf); + read_buf = (int *)HDcalloc(2048, sizeof(int)); + HDassert(read_buf); + + /* Fill buffer with data, zero out read buffer */ + for(i = 0; i < 2048; i++) + write_buf[i] = i + 1; + + /* Do a simple write/read/verify of data */ + /* Write 1KB at Address 0 */ + if(accum_write(1024, 1024, write_buf) < 0) FAIL_STACK_ERROR; + if(accum_flush() < 0) FAIL_STACK_ERROR; + if(accum_reset() < 0) FAIL_STACK_ERROR; + if(accum_write(0, 1024, write_buf) < 0) FAIL_STACK_ERROR; + if(accum_read(1024, 1024, read_buf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(write_buf, read_buf, 1024) != 0) TEST_ERROR; + + if(accum_reset() < 0) FAIL_STACK_ERROR; + + PASSED(); + + /* Release memory */ + HDfree(write_buf); + HDfree(read_buf); + + return 0; + +error: + /* Release memory */ + HDfree(write_buf); + HDfree(read_buf); + + return 1; +} /* test_write_read */ + + +/*------------------------------------------------------------------------- + * Function: test_free + * + * Purpose: Simple test to free metadata accumulator. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Raymond Lu + * October 8, 2010 + * + *------------------------------------------------------------------------- + */ +unsigned +test_free(void) +{ + int i = 0; + int32_t *wbuf = NULL; + int32_t *rbuf = NULL; + int32_t *expect = NULL; + + TESTING("simple freeing metadata accumulator"); + + /* Write and free the whole accumulator. */ + wbuf = (int32_t *)HDmalloc(256 * sizeof(int32_t)); + HDassert(wbuf); + rbuf = (int32_t *)HDmalloc(256 * sizeof(int32_t)); + HDassert(rbuf); + expect = (int32_t *)HDmalloc(256 * sizeof(int32_t)); + HDassert(expect); + + /* Fill buffer with data */ + for(i = 0; i < 256; i++) + wbuf[i] = (int32_t)(i + 1); + + if(accum_write(0, 256 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + + if(accum_free(0, 256 * sizeof(int32_t)) < 0) FAIL_STACK_ERROR; + + /* Free an empty accumulator */ + if(accum_free(0, 256 * 1024 * sizeof(int32_t)) < 0) FAIL_STACK_ERROR; + + /* Write second quarter of the accumulator */ + if(accum_write(64 * sizeof(int32_t), 64 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + + /* Free the second quarter of the accumulator, the requested area + * is bigger than the data region on the right side. */ + if(accum_free(64 * sizeof(int32_t), 65 * sizeof(int32_t)) < 0) FAIL_STACK_ERROR; + + + /* Write half of the accumulator. */ + if(accum_write(0, 128 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + + /* Free the first block of 4B */ + if(accum_free(0, sizeof(int32_t)) < 0) FAIL_STACK_ERROR; + + /* Check that the accumulator still contains the correct data */ + if(accum_read(1 * sizeof(int32_t), 127 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf + 1, rbuf, 127 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Free the block of 4B at 127*4B */ + if(accum_free(127 * sizeof(int32_t), sizeof(int32_t)) < 0) FAIL_STACK_ERROR; + + /* Check that the accumulator still contains the correct data */ + if(accum_read(1 * sizeof(int32_t), 126 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf + 1, rbuf, 126 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Free the block of 4B at 2*4B */ + if(accum_free(2 * sizeof(int32_t), sizeof(int32_t)) < 0) FAIL_STACK_ERROR; + + /* Check that the accumulator still contains the correct data */ + if(accum_read(1 * sizeof(int32_t), 1 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf + 1, rbuf, 1 * sizeof(int32_t)) != 0) TEST_ERROR; + if(accum_read(3 * sizeof(int32_t), 124 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf + 3, rbuf, 124 * sizeof(int32_t)) != 0) TEST_ERROR; + + + /* Test freeing section that overlaps the start of the accumulator and is + * entirely before dirty section */ + if(accum_write(64 * sizeof(int32_t), 128 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + HDmemcpy(expect + 64, wbuf, 128 * sizeof(int32_t)); + if(accum_flush() < 0) FAIL_STACK_ERROR; + if(accum_write(68 * sizeof(int32_t), 4 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + HDmemcpy(expect + 68, wbuf, 4 * sizeof(int32_t)); + if(accum_free(62 * sizeof(int32_t), 4 * sizeof(int32_t)) < 0) FAIL_STACK_ERROR; + + /* Check that the accumulator still contains the correct data */ + if(accum_read(66 * sizeof(int32_t), 126 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(expect + 66, rbuf, 126 * sizeof(int32_t)) != 0) TEST_ERROR; + + + /* Test freeing section that overlaps the start of the accumulator and + * completely contains dirty section */ + if(accum_write(64 * sizeof(int32_t), 128 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + HDmemcpy(expect + 64, wbuf, 128 * sizeof(int32_t)); + if(accum_flush() < 0) FAIL_STACK_ERROR; + if(accum_write(68 * sizeof(int32_t), 4 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + HDmemcpy(expect + 68, wbuf, 4 * sizeof(int32_t)); + if(accum_free(62 * sizeof(int32_t), 16 * sizeof(int32_t)) < 0) FAIL_STACK_ERROR; + + /* Check that the accumulator still contains the correct data */ + if(accum_read(78 * sizeof(int32_t), 114 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(expect + 78, rbuf, 114 * sizeof(int32_t)) != 0) TEST_ERROR; + + + /* Test freeing section completely contained in accumulator and is entirely + * before dirty section */ + if(accum_write(64 * sizeof(int32_t), 128 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + HDmemcpy(expect + 64, wbuf, 128 * sizeof(int32_t)); + if(accum_flush() < 0) FAIL_STACK_ERROR; + if(accum_write(72 * sizeof(int32_t), 4 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + HDmemcpy(expect + 72, wbuf, 4 * sizeof(int32_t)); + if(accum_free(66 * sizeof(int32_t), 4 * sizeof(int32_t)) < 0) FAIL_STACK_ERROR; + + /* Check that the accumulator still contains the correct data */ + if(accum_read(70 * sizeof(int32_t), 122 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(expect + 70, rbuf, 122 * sizeof(int32_t)) != 0) TEST_ERROR; + + + /* Test freeing section completely contained in accumulator, starts before + * dirty section, and ends in dirty section */ + if(accum_write(64 * sizeof(int32_t), 128 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + HDmemcpy(expect + 64, wbuf, 128 * sizeof(int32_t)); + if(accum_flush() < 0) FAIL_STACK_ERROR; + if(accum_write(72 * sizeof(int32_t), 4 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + HDmemcpy(expect + 72, wbuf, 4 * sizeof(int32_t)); + if(accum_free(70 * sizeof(int32_t), 4 * sizeof(int32_t)) < 0) FAIL_STACK_ERROR; + + /* Check that the accumulator still contains the correct data */ + if(accum_read(74 * sizeof(int32_t), 118 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(expect + 74, rbuf, 118 * sizeof(int32_t)) != 0) TEST_ERROR; + + + /* Test freeing section completely contained in accumulator and completely + * contains dirty section */ + if(accum_write(64 * sizeof(int32_t), 128 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + HDmemcpy(expect + 64, wbuf, 128 * sizeof(int32_t)); + if(accum_flush() < 0) FAIL_STACK_ERROR; + if(accum_write(72 * sizeof(int32_t), 4 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + HDmemcpy(expect + 72, wbuf, 4 * sizeof(int32_t)); + if(accum_free(70 * sizeof(int32_t), 8 * sizeof(int32_t)) < 0) FAIL_STACK_ERROR; + + /* Check that the accumulator still contains the correct data */ + if(accum_read(78 * sizeof(int32_t), 114 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(expect + 78, rbuf, 114 * sizeof(int32_t)) != 0) TEST_ERROR; + + + /* Test freeing section completely contained in accumulator, starts at start + * of dirty section, and ends in dirty section */ + if(accum_write(64 * sizeof(int32_t), 128 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + HDmemcpy(expect + 64, wbuf, 128 * sizeof(int32_t)); + if(accum_flush() < 0) FAIL_STACK_ERROR; + if(accum_write(72 * sizeof(int32_t), 8 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + HDmemcpy(expect + 72, wbuf, 8 * sizeof(int32_t)); + if(accum_free(72 * sizeof(int32_t), 4 * sizeof(int32_t)) < 0) FAIL_STACK_ERROR; + + /* Check that the accumulator still contains the correct data */ + if(accum_read(76 * sizeof(int32_t), 116 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(expect + 76, rbuf, 116 * sizeof(int32_t)) != 0) TEST_ERROR; + + HDfree(wbuf); + HDfree(rbuf); + HDfree(expect); + + if(accum_reset() < 0) FAIL_STACK_ERROR; + + PASSED(); + + return 0; + +error: + HDfree(wbuf); + HDfree(rbuf); + HDfree(expect); + + return 1; +} /* test_free */ + + +/*------------------------------------------------------------------------- + * Function: test_accum_overlap + * + * Purpose: This test will write a series of pieces of data + * to the accumulator with the goal of overlapping + * the writes in various different ways. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Mike McGreevy + * October 7, 2010 + * + *------------------------------------------------------------------------- + */ +unsigned +test_accum_overlap(void) +{ + int i = 0; + int32_t *wbuf, *rbuf; + + TESTING("overlapping write to metadata accumulator"); + + /* Allocate buffers */ + wbuf = (int32_t *)HDmalloc(4096 * sizeof(int32_t)); + HDassert(wbuf); + rbuf = (int32_t *)HDcalloc(4096, sizeof(int32_t)); + HDassert(rbuf); + + /* Case 1: No metadata in accumulator */ + /* Write 10 1's at address 40 */ + /* @0:| 1111111111| */ + /* Put some data in the accumulator initially */ + for(i = 0; i < 10; i++) + wbuf[i] = 1; + if(accum_write(40, 10 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(40, 10 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 10 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Case 2: End of new piece aligns with start of accumulated data */ + /* Write 5 2's at address 20 */ + /* @0:| 222221111111111| */ + for(i = 0; i < 5; i++) + wbuf[i] = 2; + if(accum_write(20, 5 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(20, 5 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 5 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Case 3: Start of new piece aligns with start of accumulated data */ + /* Write 3 3's at address 20 */ + /* @0:| 333221111111111| */ + for(i = 0; i < 3; i++) + wbuf[i] = 3; + if(accum_write(20, 3 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(20, 3 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 3 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Case 4: New piece overlaps start of accumulated data */ + /* Write 5 4's at address 8 */ + /* @0:| 444443221111111111| */ + for(i = 0; i < 5; i++) + wbuf[i] = 4; + if(accum_write(8, 5 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(8, 5 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 5 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Case 5: New piece completely within accumulated data */ + /* Write 4 5's at address 48 */ + /* @0:| 444443221155551111| */ + for(i = 0; i < 4; i++) + wbuf[i] = 5; + if(accum_write(48, 4 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(48, 4 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 4 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Case 6: End of new piece aligns with end of accumulated data */ + /* Write 3 6's at address 68 */ + /* @0:| 444443221155551666| */ + for(i = 0; i < 3; i++) + wbuf[i] = 6; + if(accum_write(68, 3 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(68, 3 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 3 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Case 7: New piece overlaps end of accumulated data */ + /* Write 5 7's at address 76 */ + /* @0:| 4444432211555516677777| */ + for(i = 0; i < 5; i++) + wbuf[i] = 7; + if(accum_write(76, 5 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(76, 5 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 5 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Case 8: Start of new piece aligns with end of accumulated data */ + /* Write 3 8's at address 96 */ + /* @0:| 4444432211555516677777888| */ + for(i = 0; i < 3; i++) + wbuf[i] = 8; + if(accum_write(96, 3 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(96, 3 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 3 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Set up expected data buffer and verify contents of + accumulator as constructed by cases 1-8, above */ + for(i = 0; i < 5; i++) + wbuf[i] = 4; + for(i = 5; i < 6; i++) + wbuf[i] = 3; + for(i = 6; i < 8; i++) + wbuf[i] = 2; + for(i = 8; i < 10; i++) + wbuf[i] = 1; + for(i = 10; i < 14; i++) + wbuf[i] = 5; + for(i = 14; i < 15; i++) + wbuf[i] = 1; + for(i = 15; i < 17; i++) + wbuf[i] = 6; + for(i = 17; i < 22; i++) + wbuf[i] = 7; + for(i = 22; i < 25; i++) + wbuf[i] = 8; + if(accum_read(8, 25 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 25 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Case 9: New piece completely before accumulated data */ + /* Write 1 9 at address 0 */ + /* @0:|9 4444432211555516677777888| */ + for(i = 0; i < 1; i++) + wbuf[i] = 9; + if(accum_write(0, 1 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(0, 1 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 1 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Case 10: New piece completely after accumulated data */ + /* Write 4 3's at address 116 */ + /* @0:|9 4444432211555516677777888 3333| */ + for(i = 0; i < 4; i++) + wbuf[i] = 3; + if(accum_write(116, 4 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(116, 4 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 4 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Case 11: New piece completely overlaps accumulated data */ + /* Write 6 4's at address 112 */ + /* @0:|9 4444432211555516677777888 444444| */ + for(i = 0; i < 6; i++) + wbuf[i] = 4; + if(accum_write(112, 6 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(112, 6 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 6 * sizeof(int32_t)) != 0) TEST_ERROR; + + if(accum_reset() < 0) FAIL_STACK_ERROR; + + PASSED(); + + /* Release memory */ + HDfree(wbuf); + HDfree(rbuf); + + return 0; + +error: + /* Release memory */ + HDfree(wbuf); + HDfree(rbuf); + + return 1; +} /* test_accum_overlap */ + + +/*------------------------------------------------------------------------- + * Function: test_accum_overlap_clean + * + * Purpose: This test will write a series of pieces of data + * to the accumulator with the goal of overlapping + * the writes in various different ways, with clean + * areas in the accumulator. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Neil Fortner + * October 8, 2010 + * + *------------------------------------------------------------------------- + */ +unsigned +test_accum_overlap_clean(void) +{ + int i = 0; + int32_t *wbuf, *rbuf; + + TESTING("overlapping write to partially clean metadata accumulator"); + + /* Allocate buffers */ + wbuf = (int32_t *)HDmalloc(4096 * sizeof(int32_t)); + HDassert(wbuf); + rbuf = (int32_t *)HDcalloc(4096, sizeof(int32_t)); + HDassert(rbuf); + + /* Case 1: No metadata in accumulator */ + /* Write 10 1's at address 40 */ + /* @0:| 1111111111| */ + /* Put some data in the accumulator initially */ + for(i = 0; i < 10; i++) + wbuf[i] = 1; + if(accum_write(40, 10 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(40, 10 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 10 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Case 2: End of new piece aligns with start of clean accumulated data */ + /* Write 5 2's at address 20 */ + /* @0:| 222221111111111| */ + if(accum_flush() < 0) FAIL_STACK_ERROR; + for(i = 0; i < 5; i++) + wbuf[i] = 2; + if(accum_write(20, 5 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(20, 5 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 5 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Case 3: Start of new piece aligns with start of accumulated data, + * completely encloses dirty section of accumulator */ + /* Write 6 3's at address 20 */ + /* @0:| 333333111111111| */ + for(i = 0; i < 6; i++) + wbuf[i] = 3; + if(accum_write(20, 6 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(20, 6 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 6 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Case 4: New piece completely within accumulated data, overlaps + * end of dirty section of accumulator */ + /* Write 2 4's at address 40 */ + /* @0:| 333334411111111| */ + for(i = 0; i < 2; i++) + wbuf[i] = 4; + if(accum_write(40, 2 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(40, 2 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 2 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Case 5: New piece completely within accumulated data, completely + * after dirty section of accumulator */ + /* Write 2 5's at address 52 */ + /* @0:| 333334415511111| */ + for(i = 0; i < 2; i++) + wbuf[i] = 5; + if(accum_write(52, 2 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(52, 2 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 2 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Case 6: New piece completely within clean accumulated data */ + /* Write 3 6's at address 44 */ + /* @0:| 333334666511111| */ + if(accum_flush() < 0) FAIL_STACK_ERROR; + for(i = 0; i < 3; i++) + wbuf[i] = 6; + if(accum_write(44, 3 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(44, 3 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 3 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Case 7: New piece overlaps start of clean accumulated data */ + /* Write 2 7's at address 16 */ + /* @0:| 7733334666511111| */ + if(accum_flush() < 0) FAIL_STACK_ERROR; + for(i = 0; i < 2; i++) + wbuf[i] = 7; + if(accum_write(16, 2 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(16, 2 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 2 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Case 8: New piece overlaps start of accumulated data, completely + * encloses dirty section of accumulator */ + /* Write 4 8's at address 12 */ + /* @0:| 88883334666511111| */ + for(i = 0; i < 4; i++) + wbuf[i] = 8; + if(accum_write(12, 4 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(12, 4 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 4 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Case 9: Start of new piece aligns with end of clean accumulated data */ + /* Write 3 9's at address 80 */ + /* @0:| 88883334666511111999| */ + if(accum_flush() < 0) FAIL_STACK_ERROR; + for(i = 0; i < 3; i++) + wbuf[i] = 9; + if(accum_write(80, 3 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(80, 3 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 3 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Case 10: New piece overlaps end of clean accumulated data */ + /* Write 3 2's at address 88 */ + /* @0:| 888833346665111119922| */ + if(accum_flush() < 0) FAIL_STACK_ERROR; + for(i = 0; i < 2; i++) + wbuf[i] = 2; + if(accum_write(88, 2 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(88, 2 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 2 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Case 11: New piece overlaps end of accumulated data, completely encloses + * dirty section of accumulator */ + /* Write 4 7's at address 84 */ + /* @0:| 8888333466651111197777| */ + for(i = 0; i < 4; i++) + wbuf[i] = 7; + if(accum_write(84, 4 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(84, 4 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 4 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Set up expected data buffer and verify contents of + accumulator as constructed by cases 1-11, above */ + for(i = 0; i < 4; i++) + wbuf[i] = 8; + for(i = 4; i < 7; i++) + wbuf[i] = 3; + for(i = 7; i < 8; i++) + wbuf[i] = 4; + for(i = 8; i < 11; i++) + wbuf[i] = 6; + for(i = 11; i < 12; i++) + wbuf[i] = 5; + for(i = 12; i < 17; i++) + wbuf[i] = 1; + for(i = 17; i < 18; i++) + wbuf[i] = 9; + for(i = 18; i < 22; i++) + wbuf[i] = 7; + if(accum_read(12, 22 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 22 * sizeof(int32_t)) != 0) TEST_ERROR; + + if(accum_reset() < 0) FAIL_STACK_ERROR; + + PASSED(); + + /* Release memory */ + HDfree(wbuf); + HDfree(rbuf); + + return 0; + +error: + /* Release memory */ + HDfree(wbuf); + HDfree(rbuf); + + return 1; +} /* test_accum_overlap_clean */ + + +/*------------------------------------------------------------------------- + * Function: test_accum_non_overlap_size + * + * Purpose: This test will write a series of pieces of data + * to the accumulator with the goal of not overlapping + * the writes with a data size larger then the accum size. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Allen Byrne + * October 8, 2010 + * + *------------------------------------------------------------------------- + */ +unsigned +test_accum_non_overlap_size(void) +{ + int i = 0; + int32_t *wbuf, *rbuf; + + TESTING("non-overlapping write to accumulator larger then accum_size"); + + /* Allocate buffers */ + wbuf = (int *)HDmalloc(4096 * sizeof(int32_t)); + HDassert(wbuf); + rbuf = (int *)HDcalloc(4096, sizeof(int32_t)); + HDassert(rbuf); + + /* Case 1: No metadata in accumulator */ + /* Write 10 1's at address 140 */ + /* @0:| 1111111111| */ + /* Put some data in the accumulator initially */ + for(i = 0; i < 10; i++) + wbuf[i] = 1; + if(accum_write(140, 10 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(140, 10 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 10 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Case 9: New piece completely before accumulated data */ + /* Write 20 9 at address 0 */ + /* @0:|9 1111111111| */ + for(i = 0; i < 20; i++) + wbuf[i] = 9; + if(accum_write(0, 20 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(0, 20 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 20 * sizeof(int32_t)) != 0) TEST_ERROR; + + if(accum_reset() < 0) FAIL_STACK_ERROR; + + PASSED(); + + /* Release memory */ + HDfree(wbuf); + HDfree(rbuf); + + return 0; + +error: + /* Release memory */ + HDfree(wbuf); + HDfree(rbuf); + + return 1; +} /* test_accum_non_overlap_size */ + +/*------------------------------------------------------------------------- + * Function: test_accum_overlap_size + * + * Purpose: This test will write a series of pieces of data + * to the accumulator with the goal of overlapping + * the writes with a data size completely overlapping + * the accumulator at both ends. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Allen Byrne + * October 8, 2010 + * + *------------------------------------------------------------------------- + */ +unsigned +test_accum_overlap_size(void) +{ + int i = 0; + int32_t *wbuf, *rbuf; + + TESTING("overlapping write to accumulator larger then accum_size"); + + /* Allocate buffers */ + wbuf = (int32_t *)HDmalloc(4096 * sizeof(int32_t)); + HDassert(wbuf); + rbuf = (int32_t *)HDcalloc(4096, sizeof(int32_t)); + HDassert(rbuf); + + /* Case 1: No metadata in accumulator */ + /* Write 10 1's at address 64 */ + /* @0:| 1111111111| */ + /* Put some data in the accumulator initially */ + for(i = 0; i < 10; i++) + wbuf[i] = 1; + if(accum_write(64, 10 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(64, 10 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 10 * sizeof(int32_t)) != 0) TEST_ERROR; + + /* Case 9: New piece completely before accumulated data */ + /* Write 72 9 at address 60 */ + /* @0:|9 1111111111| */ + for(i = 0; i < 72; i++) + wbuf[i] = 9; + if(accum_write(60, 72 * sizeof(int32_t), wbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(60, 72 * sizeof(int32_t), rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 72 * sizeof(int32_t)) != 0) TEST_ERROR; + + if(accum_reset() < 0) FAIL_STACK_ERROR; + + PASSED(); + + /* Release memory */ + HDfree(wbuf); + HDfree(rbuf); + + return 0; + +error: + /* Release memory */ + HDfree(wbuf); + HDfree(rbuf); + + return 1; +} /* test_accum_overlap_size */ + + +/*------------------------------------------------------------------------- + * Function: test_accum_adjust + * + * Purpose: This test examines the various ways the accumulator might + * adjust itself as a result of data appending or prepending + * to it. + * + * This test program covers all the code in H5F_accum_adjust, + * but NOT all possible paths through said code. It only covers + * six potential paths through the function. (Again, though, each + * piece of code within an if/else statement in H5F_accum_adjust is + * covered by one of the paths in this test function). Since there + * are a ridiculous number of total possible paths through this + * function due to its large number of embedded if/else statements, + * that's certainly a lot of different test cases to write by hand. + * (Though if someone comes across this code and has some free + * time, go for it). + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Mike McGreevy + * October 11, 2010 + * + *------------------------------------------------------------------------- + */ +unsigned +test_accum_adjust(void) +{ + int i = 0; + int s = 1048576; /* size of buffer */ + int32_t *wbuf, *rbuf; + + TESTING("accumulator adjustments after append/prepend of data"); + + /* Allocate buffers */ + wbuf = (int32_t *)HDmalloc((size_t)s * sizeof(int32_t)); + HDassert(wbuf); + rbuf = (int32_t *)HDcalloc((size_t)s, sizeof(int32_t)); + HDassert(rbuf); + + /* Fill up write buffer */ + for(i = 0; i < s; i++) + wbuf[i] = i + 1; + + /* ================================================================ */ + /* CASE 1: Prepending small block to large, fully dirty accumulator */ + /* ================================================================ */ + + /* Write data to the accumulator to fill it just under 1MB (max size), + * but not quite full. This will force the accumulator to, on subsequent + * writes, a) have to adjust since it's nearly full, and b) prevent + * an increase in size because it's already at it's maximum size */ + if(accum_write((1024 * 1024), (1024 * 1024) - 1, wbuf) < 0) FAIL_STACK_ERROR; + + /* Write a small (1KB) block that prepends to the front of the accumulator. */ + /* ==> Accumulator will need more buffer space */ + /* ==> Accumulator will try to resize, but see that it's getting too big */ + /* ==> Size of new block is less than half maximum size of accumulator */ + /* ==> New block is being prepended to accumulator */ + /* ==> Accumulator is dirty, it will be flushed. */ + /* ==> Dirty region overlaps region to eliminate from accumulator */ + if(accum_write((1024 * 1024) - 1024, 1024, wbuf) < 0) FAIL_STACK_ERROR; + + /* Read back and verify first write */ + if(accum_read((1024 * 1024), (1024 * 1024) - 1, rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, (1024 * 1024) - 1) != 0) TEST_ERROR; + + /* Read back and verify second write */ + if(accum_read((1024 * 1024) - 1024, 1024, rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 1024) != 0) TEST_ERROR; + + /* Reset accumulator for next case */ + if(accum_reset() < 0) FAIL_STACK_ERROR; + + /* ================================================================ */ + /* Case 2: Prepending large block to large, fully dirty accumulator */ + /* ================================================================ */ + + /* Write data to the accumulator to fill it just under 1MB (max size), + * but not quite full. This will force the accumulator to, on subsequent + * writes, a) have to adjust since it's nearly full, and b) prevent + * an increase in size because it's already at it's maximum size */ + if(accum_write((1024 * 1024), (1024 * 1024) - 1, wbuf) < 0) FAIL_STACK_ERROR; + + /* Write a large (just under 1MB) block to the front of the accumulator. */ + /* ==> Accumulator will need more buffer space */ + /* ==> Accumulator will try to resize, but see that it's getting too big */ + /* ==> Size of new block is larger than half maximum size of accumulator */ + /* ==> New block is being prepended to accumulator */ + /* ==> Accumulator is dirty, it will be flushed. */ + /* ==> Dirty region overlaps region to eliminate from accumulator */ + if(accum_write(5, (1024 * 1024) - 5, wbuf) < 0) FAIL_STACK_ERROR; + + /* Read back and verify both pieces of data */ + if(accum_read(1048576, 1048575, rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 1048576) != 0) TEST_ERROR; + + if(accum_read(5, 1048571, rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 1048571) != 0) TEST_ERROR; + + /* Reset accumulator for next case */ + if(accum_reset() < 0) FAIL_STACK_ERROR; + + /* ========================================================= */ + /* Case 3: Appending small block to large, clean accumulator */ + /* ========================================================= */ + + /* Write data to the accumulator to fill it just under 1MB (max size), + * but not quite full. This will force the accumulator to, on subsequent + * writes, a) have to adjust since it's nearly full, and b) prevent + * an increase in size because it's already at it's maximum size */ + if(accum_write(0, (1024 * 1024) - 1, wbuf) < 0) FAIL_STACK_ERROR; + + /* Flush the accumulator -- we want to test the case when + accumulator contains clean data */ + if(accum_flush() < 0) FAIL_STACK_ERROR + + /* Write a small (1KB) block to the end of the accumulator */ + /* ==> Accumulator will need more buffer space */ + /* ==> Accumulator will try to resize, but see that it's getting too big */ + /* ==> Size of new block is larger than half maximum size of accumulator */ + /* ==> New block being appended to accumulator */ + /* ==> Accumulator is NOT dirty */ + /* ==> Since we're appending, need to adjust location of accumulator */ + if(accum_write((1024 * 1024) - 1, 1024, wbuf) < 0) FAIL_STACK_ERROR; + + /* Write a piece of metadata outside current accumulator to force write + to disk */ + if(accum_write(0, 1, wbuf) < 0) FAIL_STACK_ERROR; + + /* Read in the piece we wrote to disk above, and then verify that + the data is as expected */ + if(accum_read((1024 * 1024) - 1, 1024, rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 1024) != 0) TEST_ERROR; + + /* Reset accumulator for next case */ + if(accum_reset() < 0) FAIL_STACK_ERROR; + + /* ==================================================================== */ + /* Case 4: Appending small block to large, partially dirty accumulator, */ + /* with existing dirty region NOT aligning with the new block */ + /* ==================================================================== */ + + /* Write data to the accumulator to fill it just under 1MB (max size), + * but not quite full. This will force the accumulator to, on subsequent + * writes, a) have to adjust since it's nearly full, and b) prevent + * an increase in size because it's already at it's maximum size */ + if(accum_write(0, (1024 * 1024) - 5, wbuf) < 0) FAIL_STACK_ERROR; + + /* Flush the accumulator to clean it */ + if(accum_flush() < 0) FAIL_STACK_ERROR + + /* write to part of the accumulator so just the start of it is dirty */ + if(accum_write(0, 5, wbuf) < 0) FAIL_STACK_ERROR; + + /* Write a small (~340KB) piece of data to the other end of the accumulator */ + /* ==> Accumulator will need more buffer space */ + /* ==> Accumulator will try to resize, but see that it's getting too big */ + /* ==> Size of new block is less than than half maximum size of accumulator */ + /* ==> New block being appended to accumulator */ + /* ==> We can slide the dirty region down, to accomodate the request */ + /* ==> Max Buffer Size - (dirty offset + adjust size) >= 2 * size) */ + /* ==> Need to adjust location of accumulator while appending */ + /* ==> Accumulator will need to be reallocated */ + if(accum_write(1048571, 349523, wbuf) < 0) FAIL_STACK_ERROR; + + /* Write a piece of metadata outside current accumulator to force write + to disk */ + if(accum_write(1398900, 1, wbuf) < 0) FAIL_STACK_ERROR; + + /* Read in the piece we wrote to disk above, and then verify that + the data is as expected */ + if(accum_read(1048571, 349523, rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 349523) != 0) TEST_ERROR; + + /* Reset accumulator for next case */ + if(accum_reset() < 0) FAIL_STACK_ERROR; + + /* ==================================================================== */ + /* Case 5: Appending small block to large, partially dirty accumulator, */ + /* with existing dirty region aligning with new block */ + /* ==================================================================== */ + + /* Write data to the accumulator to fill it just under max size (but not full) */ + if(accum_write(0, (1024 * 1024) - 5, wbuf) < 0) FAIL_STACK_ERROR; + + /* Flush the accumulator to clean it */ + if(accum_flush() < 0) FAIL_STACK_ERROR + + /* write to part of the accumulator so it's dirty, but not entirely dirty */ + /* (just the begging few bytes will be clean) */ + if(accum_write(10, (1024 * 1024) - 15, wbuf) < 0) FAIL_STACK_ERROR; + + /* Write a small piece of data to the dirty end of the accumulator */ + /* ==> Accumulator will need more buffer space */ + /* ==> Accumulator will try to resize, but see that it's getting too big */ + /* ==> Size of new block is less than than half maximum size of accumulator */ + /* ==> New block being appended to accumulator */ + /* ==> We can slide the dirty region down, to accomodate the request */ + /* ==> Max Buffer Size - (dirty offset + adjust size) < 2 * size) */ + /* ==> Need to adjust location of accumulator while appending */ + if(accum_write((1024 * 1024) - 5, 10, wbuf) < 0) FAIL_STACK_ERROR; + + /* Write a piece of metadata outside current accumulator to force write + to disk */ + if(accum_write(0, 1, wbuf) < 0) FAIL_STACK_ERROR; + + /* Read in the piece we wrote to disk above, and then verify that + the data is as expected */ + if(accum_read((1024 * 1024) - 5, 10, rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 10) != 0) TEST_ERROR; + + /* Reset accumulator for next case */ + if(accum_reset() < 0) FAIL_STACK_ERROR; + + /* ================================================================= */ + /* Case 6: Appending small block to large, fully dirty accumulator */ + /* ================================================================= */ + + /* Write data to the accumulator to fill it just under 1MB (max size), + * but not quite full. This will force the accumulator to, on subsequent + * writes, a) have to adjust since it's nearly full, and b) prevent + * an increase in size because it's already at it's maximum size */ + if(accum_write(0, (1024 * 1024) - 5, wbuf) < 0) FAIL_STACK_ERROR; + + /* Write a small (~340KB) piece of data to the end of the accumulator */ + /* ==> Accumulator will need more buffer space */ + /* ==> Accumulator will try to resize, but see that it's getting too big */ + /* ==> Size of new block is less than than half maximum size of accumulator */ + /* ==> New block being appended to accumulator */ + /* ==> We cannot slide dirty region down, it's all dirty */ + /* ==> Dirty region overlaps region to eliminate from accumulator */ + /* ==> Need to adjust location of accumulator while appending */ + if(accum_write(1048571, 349523, wbuf) < 0) FAIL_STACK_ERROR; + + /* Write a piece of metadata outside current accumulator to force write + to disk */ + if(accum_write(1398900, 1, wbuf) < 0) FAIL_STACK_ERROR; + + /* Read in the piece we wrote to disk above, and then verify that + the data is as expected */ + if(accum_read(1048571, 349523, rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 349523) != 0) TEST_ERROR; + + if(accum_reset() < 0) FAIL_STACK_ERROR; + + PASSED(); + + /* Release memory */ + HDfree(wbuf); + HDfree(rbuf); + + return 0; + +error: + /* Release memory */ + HDfree(wbuf); + HDfree(rbuf); + + return 1; +} /* test_accum_adjust */ + + +/*------------------------------------------------------------------------- + * Function: test_read_after + * + * Purpose: This test will verify the case when metadata is read partly + * from the accumulator and partly from disk. The test will + * write a block of data at address 512, force the data to be + * written to disk, write new data partially overlapping the + * original block from below, then read data at address 512. + * The data read should be partly new and partly original. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Larry Knox + * October 8, 2010 + * + *------------------------------------------------------------------------- + */ +unsigned +test_read_after(void) +{ + int i = 0; + int s = 128; /* size of buffer */ + int32_t *wbuf, *rbuf; + + TESTING("reading data from both accumulator and disk"); + + /* Allocate buffers */ + wbuf = (int32_t *)HDmalloc((size_t)s * sizeof(int32_t)); + HDassert(wbuf); + rbuf = (int32_t *)HDcalloc((size_t)s, sizeof(int32_t)); + HDassert(rbuf); + + /* Fill up write buffer with 1s */ + for(i = 0; i < s; i++) + wbuf[i] = 1; + + /* Write data to the accumulator to fill it. */ + if(accum_write(512, 512, wbuf) < 0) FAIL_STACK_ERROR; + + /* Write a piece of metadata outside current accumulator to force write + to disk */ + if(accum_write(0, 1, wbuf) < 0) FAIL_STACK_ERROR; + + /* Fill up write buffer with 2s */ + for(i = 0; i < s; i++) + wbuf[i] = 2; + + /* Write a block of 2s of the original size that will overlap the lower half + of the original block */ + if(accum_write(256, 512, wbuf) < 0) FAIL_STACK_ERROR; + + /* Read 128 bytes at the original address, and then */ + if(accum_read(512, 512, rbuf) < 0) FAIL_STACK_ERROR; + + /* Set the second half of wbuf back to 1s */ + for(i = 64; i < s; i++) + wbuf[i] = 1; + + /* Read in the piece we wrote to disk above, and then verify that + the data is as expected */ + if(accum_read(512, 512, rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf, rbuf, 128) != 0) TEST_ERROR; + + if(accum_reset() < 0) FAIL_STACK_ERROR; + + PASSED(); + + /* Release memory */ + HDfree(wbuf); + HDfree(rbuf); + + return 0; + +error: + /* Release memory */ + HDfree(wbuf); + HDfree(rbuf); + + return 1; +} /* end test_read_after */ + + +/*------------------------------------------------------------------------- + * Function: test_big + * + * Purpose: This test exercises writing large pieces of metadata to the + * file. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Quincey Koziol + * October 12, 2010 + * + *------------------------------------------------------------------------- + */ +unsigned +test_big(void) +{ + uint8_t *wbuf, *wbuf2, *rbuf, *zbuf; /* Buffers for reading & writing, etc */ + unsigned u; /* Local index variable */ + + /* Allocate space for the write & read buffers */ + wbuf = (uint8_t *)HDmalloc(BIG_BUF_SIZE); + HDassert(wbuf); + wbuf2 = (uint8_t *)HDmalloc(BIG_BUF_SIZE); + HDassert(wbuf2); + rbuf = (uint8_t *)HDcalloc(BIG_BUF_SIZE + 1536, 1); + HDassert(rbuf); + zbuf = (uint8_t *)HDcalloc(BIG_BUF_SIZE + 1536, 1); + HDassert(zbuf); + + /* Initialize write buffers */ + for(u = 0; u < BIG_BUF_SIZE; u++) { + wbuf[u] = (uint8_t)u; + wbuf2[u] = (uint8_t)(u + 1); + } /* end for */ + + TESTING("large metadata I/O operations"); + + /* Write large data segment to file */ + if(accum_write(0, BIG_BUF_SIZE, wbuf) < 0) FAIL_STACK_ERROR; + + /* Read entire segment back from file */ + if(accum_read(0, BIG_BUF_SIZE, rbuf) < 0) FAIL_STACK_ERROR; + + /* Verify data read */ + if(HDmemcmp(wbuf, rbuf, BIG_BUF_SIZE) != 0) TEST_ERROR; + + + /* Reset data in file back to zeros & reset the read buffer */ + if(accum_write(0, BIG_BUF_SIZE, zbuf) < 0) FAIL_STACK_ERROR; + HDmemset(rbuf, 0, BIG_BUF_SIZE); + if(accum_reset() < 0) FAIL_STACK_ERROR; + + + /* Write small section to middle of accumulator */ + if(accum_write(1024, 1024, wbuf) < 0) FAIL_STACK_ERROR; + + /* Read entire segment back from file */ + /* (Read covers entire dirty region) */ + if(accum_read(0, BIG_BUF_SIZE, rbuf) < 0) FAIL_STACK_ERROR; + + /* Verify data read */ + if(HDmemcmp(zbuf, rbuf, 1024) != 0) TEST_ERROR; + if(HDmemcmp(wbuf, rbuf + 1024, 1024) != 0) TEST_ERROR; + if(HDmemcmp(zbuf, rbuf + 2048, (BIG_BUF_SIZE - 2048)) != 0) TEST_ERROR; + + + /* Reset data in file back to zeros & reset the read buffer */ + if(accum_write(1024, 1024, zbuf) < 0) FAIL_STACK_ERROR; + HDmemset(rbuf, 0, BIG_BUF_SIZE); + if(accum_reset() < 0) FAIL_STACK_ERROR; + + + /* Write small section to overlap with end of "big" region */ + if(accum_write(BIG_BUF_SIZE - 512, 1024, wbuf) < 0) FAIL_STACK_ERROR; + + /* Read entire segment back from file */ + /* (Read covers bottom half of dirty region) */ + if(accum_read(0, BIG_BUF_SIZE, rbuf) < 0) FAIL_STACK_ERROR; + + /* Verify data read */ + if(HDmemcmp(zbuf, rbuf, (BIG_BUF_SIZE - 512)) != 0) TEST_ERROR; + if(HDmemcmp(wbuf, rbuf + (BIG_BUF_SIZE - 512), 512) != 0) TEST_ERROR; + + + /* Reset data in file back to zeros & reset the read buffer */ + if(accum_write(BIG_BUF_SIZE - 512, 1024, zbuf) < 0) FAIL_STACK_ERROR; + HDmemset(rbuf, 0, BIG_BUF_SIZE); + if(accum_reset() < 0) FAIL_STACK_ERROR; + + + /* Write small section to overlap with beginning of "big" region */ + if(accum_write(0, 1024, wbuf) < 0) FAIL_STACK_ERROR; + + /* Read entire segment back from file */ + /* (Read covers bottom half of dirty region) */ + if(accum_read(512, BIG_BUF_SIZE, rbuf) < 0) FAIL_STACK_ERROR; + + /* Verify data read */ + if(HDmemcmp(wbuf + 512, rbuf, 512) != 0) TEST_ERROR; + if(HDmemcmp(zbuf, rbuf + 512, (BIG_BUF_SIZE - 512)) != 0) TEST_ERROR; + + + /* Reset data in file back to zeros & reset the read buffer */ + if(accum_write(0, 1024, zbuf) < 0) FAIL_STACK_ERROR; + HDmemset(rbuf, 0, BIG_BUF_SIZE); + if(accum_reset() < 0) FAIL_STACK_ERROR; + + + /* Write small section to middle of accumulator */ + /* (With write buffer #1) */ + if(accum_write(1024, 1024, wbuf) < 0) FAIL_STACK_ERROR; + + /* Write entire segment to from file */ + /* (With write buffer #2) */ + /* (Write covers entire dirty region) */ + if(accum_write(0, BIG_BUF_SIZE, wbuf2) < 0) FAIL_STACK_ERROR; + + /* Read entire segment back from file */ + if(accum_read(0, BIG_BUF_SIZE, rbuf) < 0) FAIL_STACK_ERROR; + + /* Verify data read */ + if(HDmemcmp(wbuf2, rbuf, BIG_BUF_SIZE) != 0) TEST_ERROR; + + + /* Reset data in file back to zeros & reset the read buffer */ + if(accum_write(0, BIG_BUF_SIZE, zbuf) < 0) FAIL_STACK_ERROR; + HDmemset(rbuf, 0, BIG_BUF_SIZE); + if(accum_reset() < 0) FAIL_STACK_ERROR; + + + /* Write small section to overlap with end of "big" region */ + /* (With write buffer #1) */ + if(accum_write(BIG_BUF_SIZE - 512, 1024, wbuf) < 0) FAIL_STACK_ERROR; + + /* Write entire segment to from file */ + /* (With write buffer #2) */ + /* (Read covers bottom half of dirty region) */ + if(accum_write(0, BIG_BUF_SIZE, wbuf2) < 0) FAIL_STACK_ERROR; + + /* Read both segments back from file */ + if(accum_read(0, BIG_BUF_SIZE + 512, rbuf) < 0) FAIL_STACK_ERROR; + + /* Verify data read */ + if(HDmemcmp(wbuf2, rbuf, BIG_BUF_SIZE) != 0) TEST_ERROR; + if(HDmemcmp(wbuf + 512, rbuf + BIG_BUF_SIZE, 512) != 0) TEST_ERROR; + + + /* Reset data in file back to zeros & reset the read buffer */ + if(accum_write(0, BIG_BUF_SIZE + 512, zbuf) < 0) FAIL_STACK_ERROR; + HDmemset(rbuf, 0, BIG_BUF_SIZE + 512); + if(accum_reset() < 0) FAIL_STACK_ERROR; + + + /* Write small section to be past "big" region */ + /* (With write buffer #1) */ + if(accum_write(BIG_BUF_SIZE + 512, 1024, wbuf) < 0) FAIL_STACK_ERROR; + + /* Read section before "big" region */ + /* (To enlarge accumulator, to it will intersect with big write) */ + if(accum_read(BIG_BUF_SIZE - 512, 1024, rbuf) < 0) FAIL_STACK_ERROR; + + /* Write entire segment to from file */ + /* (With write buffer #2) */ + /* (Doesn't overlap with small section) */ + if(accum_write(0, BIG_BUF_SIZE, wbuf2) < 0) FAIL_STACK_ERROR; + + /* Read both segments & gap back from file */ + if(accum_read(0, BIG_BUF_SIZE + 1024, rbuf) < 0) FAIL_STACK_ERROR; + + /* Verify data read */ + if(HDmemcmp(wbuf2, rbuf, BIG_BUF_SIZE) != 0) TEST_ERROR; + if(HDmemcmp(zbuf, rbuf + BIG_BUF_SIZE, 512) != 0) TEST_ERROR; + if(HDmemcmp(wbuf, rbuf + BIG_BUF_SIZE + 512, 512) != 0) TEST_ERROR; + + + /* Reset data in file back to zeros & reset the read buffer */ + if(accum_write(0, BIG_BUF_SIZE + 1536, zbuf) < 0) FAIL_STACK_ERROR; + HDmemset(rbuf, 0, BIG_BUF_SIZE + 1024); + if(accum_reset() < 0) FAIL_STACK_ERROR; + + + /* Write small section to be past "big" region */ + /* (With write buffer #1) */ + if(accum_write(BIG_BUF_SIZE + 512, 1024, wbuf) < 0) FAIL_STACK_ERROR; + + /* Read section before "big" region */ + /* (To enlarge accumulator, so it will intersect with big write) */ + if(accum_read(BIG_BUF_SIZE - 512, 1024, rbuf) < 0) FAIL_STACK_ERROR; + if(accum_read(BIG_BUF_SIZE + 1536, 1024, rbuf) < 0) FAIL_STACK_ERROR; + + /* Write entire segment to from file */ + /* (With write buffer #2) */ + /* (Overwriting dirty region, but not invalidating entire accumulator) */ + if(accum_write(1536, BIG_BUF_SIZE, wbuf2) < 0) FAIL_STACK_ERROR; + + /* Read both segments & gap back from file */ + if(accum_read(0, BIG_BUF_SIZE + 1536, rbuf) < 0) FAIL_STACK_ERROR; + + /* Verify data read */ + if(HDmemcmp(zbuf, rbuf, 1536) != 0) TEST_ERROR; + if(HDmemcmp(wbuf2, rbuf + 1536, BIG_BUF_SIZE) != 0) TEST_ERROR; + + + /* Reset data in file back to zeros & reset the read buffer */ + if(accum_write(1536, BIG_BUF_SIZE, zbuf) < 0) FAIL_STACK_ERROR; + HDmemset(rbuf, 0, BIG_BUF_SIZE + 1536); + if(accum_reset() < 0) FAIL_STACK_ERROR; + + + /* Write small section before "big" region */ + /* (With write buffer #1) */ + if(accum_write(1024, 1024, wbuf) < 0) FAIL_STACK_ERROR; + + /* Read section before "big" region */ + /* (To enlarge accumulator, so it will intersect with big write) */ + if(accum_read(0, 1024, rbuf) < 0) FAIL_STACK_ERROR; + + /* Write entire segment to from file */ + /* (With write buffer #2) */ + /* (Overwriting dirty region, but not invalidating entire accumulator) */ + if(accum_write(512, BIG_BUF_SIZE, wbuf2) < 0) FAIL_STACK_ERROR; + + /* Read both segments & gap back from file */ + if(accum_read(0, BIG_BUF_SIZE + 512, rbuf) < 0) FAIL_STACK_ERROR; + + /* Verify data read */ + if(HDmemcmp(zbuf, rbuf, 512) != 0) TEST_ERROR; + if(HDmemcmp(wbuf2, rbuf + 512, BIG_BUF_SIZE) != 0) TEST_ERROR; + + + /* Reset data in file back to zeros & reset the read buffer */ + if(accum_write(512, BIG_BUF_SIZE, zbuf) < 0) FAIL_STACK_ERROR; + HDmemset(rbuf, 0, BIG_BUF_SIZE + 512); + if(accum_reset() < 0) FAIL_STACK_ERROR; + + + /* Write small section before "big" region */ + /* (With write buffer #1) */ + if(accum_write(0, 1024, wbuf) < 0) FAIL_STACK_ERROR; + + /* Read section before "big" region */ + /* (To enlarge accumulator, so it will intersect with big write) */ + if(accum_read(1024, 1024, rbuf) < 0) FAIL_STACK_ERROR; + + /* Write entire segment to from file */ + /* (With write buffer #2) */ + /* (Avoiding dirty region, and not invalidating entire accumulator) */ + if(accum_write(1536, BIG_BUF_SIZE, wbuf2) < 0) FAIL_STACK_ERROR; + + /* Read both segments & gap back from file */ + if(accum_read(0, BIG_BUF_SIZE + 1536, rbuf) < 0) FAIL_STACK_ERROR; + + /* Verify data read */ + if(HDmemcmp(wbuf, rbuf, 1024) != 0) TEST_ERROR; + if(HDmemcmp(zbuf, rbuf + 1024, 512) != 0) TEST_ERROR; + if(HDmemcmp(wbuf2, rbuf + 1536, BIG_BUF_SIZE) != 0) TEST_ERROR; + + + /* Reset data in file back to zeros & reset the read buffer */ + if(accum_write(0, BIG_BUF_SIZE + 1536, zbuf) < 0) FAIL_STACK_ERROR; + HDmemset(rbuf, 0, BIG_BUF_SIZE + 1536); + if(accum_reset() < 0) FAIL_STACK_ERROR; + + + /* Write small section before "big" region */ + /* (With write buffer #1) */ + if(accum_write(0, 1024, wbuf) < 0) FAIL_STACK_ERROR; + + /* Read section before "big" region */ + /* (To enlarge accumulator, so it will intersect with big write) */ + if(accum_read(1024, 1024, rbuf) < 0) FAIL_STACK_ERROR; + + /* Write entire segment to from file */ + /* (With write buffer #2) */ + /* (Partially overwriting dirty region, and not invalidating entire accumulator) */ + if(accum_write(512, BIG_BUF_SIZE, wbuf2) < 0) FAIL_STACK_ERROR; + + /* Read both segments back from file */ + if(accum_read(0, BIG_BUF_SIZE + 512, rbuf) < 0) FAIL_STACK_ERROR; + + /* Verify data read */ + if(HDmemcmp(wbuf, rbuf, 512) != 0) TEST_ERROR; + if(HDmemcmp(wbuf2, rbuf + 512, BIG_BUF_SIZE) != 0) TEST_ERROR; + + + if(accum_reset() < 0) FAIL_STACK_ERROR; + + PASSED(); + + /* Release memory */ + HDfree(wbuf); + HDfree(wbuf2); + HDfree(rbuf); + HDfree(zbuf); + + return 0; + +error: + HDfree(wbuf); + HDfree(wbuf2); + HDfree(rbuf); + HDfree(zbuf); + + return 1; +} /* end test_random_write() */ + + +/*------------------------------------------------------------------------- + * Function: test_random_write + * + * Purpose: This test writes random pieces of data to the file and + * then reads it all back. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Quincey Koziol + * October 11, 2010 + * + *------------------------------------------------------------------------- + */ +unsigned +test_random_write(void) +{ + uint8_t *wbuf, *rbuf; /* Buffers for reading & writing */ + unsigned long seed = 0; /* Random # seed */ + size_t *off; /* Offset of buffer segments to write */ + size_t *len; /* Size of buffer segments to write */ + size_t cur_off; /* Current offset */ + size_t nsegments; /* Number of segments to write */ + size_t swap; /* Position to swap with */ + unsigned u; /* Local index variable */ + + /* Allocate space for the write & read buffers */ + wbuf = (uint8_t *)malloc(RANDOM_BUF_SIZE); + HDassert(wbuf); + rbuf = (uint8_t *)calloc(RANDOM_BUF_SIZE, 1); + HDassert(rbuf); + + /* Initialize write buffer */ + for(u = 0; u < RANDOM_BUF_SIZE; u++) + wbuf[u] = (uint8_t)u; + + TESTING("random writes to accumulator"); + + /* Choose random # seed */ + seed = (unsigned long)HDtime(NULL); +#ifdef QAK +/* seed = (unsigned long)1155438845; */ +HDfprintf(stderr, "Random # seed was: %lu\n", seed); +#endif /* QAK */ + HDsrandom(seed); + + /* Allocate space for the segment length buffer */ + off = (size_t *)malloc(MAX_RANDOM_SEGMENTS * sizeof(size_t)); + HDassert(off); + len = (size_t *)malloc(MAX_RANDOM_SEGMENTS * sizeof(size_t)); + HDassert(len); + + /* Randomly choose lengths of segments */ + cur_off = 0; + for(u = 0; u < MAX_RANDOM_SEGMENTS; ) { + size_t length = 0; /* Length of current segment */ + + /* Choose random length of segment, allowing for variance */ + do { + length += (size_t)(HDrandom() % RAND_SEG_LEN) + 1; + } while((HDrandom() & 256) >= 128); /* end while */ + + /* Check for going off end of buffer */ + if((cur_off + length) > RANDOM_BUF_SIZE) + length = RANDOM_BUF_SIZE - cur_off; + + /* Set offset & length of segment */ + off[u] = cur_off; + len[u] = length; + + /* Advance array offset */ + u++; + + /* Advance current offset */ + cur_off += length; + + /* If we've used up entire buffer before hitting limit of segments, get out */ + if(cur_off >= RANDOM_BUF_SIZE) + break; + } /* end for */ + nsegments = u; + + /* Increase length of last segment, if it doesn't reach end of buffer */ + if(nsegments < MAX_RANDOM_SEGMENTS) + len[nsegments - 1] = RANDOM_BUF_SIZE - off[nsegments - 1]; + + /* Shuffle order of segments, to randomize positions to write */ + for(u = 0; u < nsegments; u++) { + size_t tmp; /* Temporary holder for offset & length values */ + + /* Choose value within next few elements to to swap with */ + swap = ((size_t)HDrandom() % 8) + u; + if(swap >= nsegments) + swap = nsegments - 1; + + /* Swap values */ + tmp = off[u]; off[u] = off[swap]; off[swap] = tmp; + tmp = len[u]; len[u] = len[swap]; len[swap] = tmp; + } /* end for */ + + /* Write data segments to file */ + for(u = 0; u < nsegments; u++) { + if(accum_write(RANDOM_BASE_OFF + off[u], len[u], wbuf + off[u]) < 0) FAIL_STACK_ERROR; + + /* Verify individual reads */ + if(accum_read(RANDOM_BASE_OFF + off[u], len[u], rbuf) < 0) FAIL_STACK_ERROR; + if(HDmemcmp(wbuf + off[u], rbuf, len[u]) != 0) TEST_ERROR; + } /* end for */ + + /* Read entire region back from file */ + if(accum_read(RANDOM_BASE_OFF, RANDOM_BUF_SIZE, rbuf) < 0) FAIL_STACK_ERROR; + + /* Verify data read back in */ + if(HDmemcmp(wbuf, rbuf, RANDOM_BUF_SIZE) != 0) TEST_ERROR; + + if(accum_reset() < 0) FAIL_STACK_ERROR; + + PASSED(); + + /* Release memory */ + HDfree(wbuf); + HDfree(rbuf); + HDfree(off); + HDfree(len); + + return 0; + +error: + /* Release memory */ + HDfree(wbuf); + HDfree(rbuf); + HDfree(off); + HDfree(len); + + HDfprintf(stderr, "Random # seed was: %lu\n", seed); + return 1; +} /* end test_random_write() */ + + +/*------------------------------------------------------------------------- + * Function: accum_printf + * + * Purpose: Debug function to print some stats about the accumulator + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Mike McGreevy + * October 7, 2010 + * + *------------------------------------------------------------------------- + */ +void +accum_printf(void) +{ + H5F_meta_accum_t * accum = &f->shared->accum; + + printf("\n"); + printf("Current contents of accumulator:\n"); + if (accum->alloc_size == 0) { + printf("=====================================================\n"); + printf(" No accumulator allocated.\n"); + printf("=====================================================\n"); + } else { + printf("=====================================================\n"); + printf(" accumulator allocated size == %lu\n", (unsigned long)accum->alloc_size); + printf(" accumulated data size == %lu\n", (unsigned long)accum->size); + printf(" accumulator dirty? == %d\n", accum->dirty); + printf("=====================================================\n"); + printf(" start of accumulated data, loc = %llu\n", accum->loc); + if (accum->dirty) printf(" start of dirty region, loc = %llu\n", accum->loc + accum->dirty_off); + if (accum->dirty) printf(" end of dirty region, loc = %llu\n", accum->loc + accum->dirty_off + accum->dirty_len); + printf(" end of accumulated data, loc = %llu\n", accum->loc + accum->size); + printf(" end of accumulator allocation, loc = %llu\n", accum->loc + accum->alloc_size); + printf("=====================================================\n"); + } + printf("\n\n"); +} /* accum_printf() */ + -- cgit v0.12