diff options
Diffstat (limited to 'src/H5HL.c')
-rw-r--r-- | src/H5HL.c | 189 |
1 files changed, 150 insertions, 39 deletions
@@ -155,7 +155,6 @@ H5HL_create(H5F_t *f, hid_t dxpl_id, size_t size_hint, haddr_t *addr_p/*out*/) heap->addr = *addr_p + (hsize_t)sizeof_hdr; heap->disk_alloc = size_hint; heap->mem_alloc = size_hint; - heap->disk_resrv = 0; if (NULL==(heap->chunk = H5FL_BLK_CALLOC(heap_chunk,(sizeof_hdr + size_hint)))) HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed"); @@ -320,6 +319,20 @@ done: * * Modifications: * + * John Mainzer, 8/10/05 + * Reworked this function for a different role. + * + * It used to be called during cache eviction, where it + * attempted to size the disk space allocation for the + * actuall size of the heap. However, this causes problems + * in the parallel case, as the reuslting disk allocations + * may not be synchronized. + * + * It is now called from H5HL_remove(), where it is used to + * reduce heap size in response to an entry deletion. This + * means that the function should either do nothing, or + * reduce the size of the disk allocation. + * *------------------------------------------------------------------------- */ static herr_t @@ -331,19 +344,13 @@ H5HL_minimize_heap_space(H5F_t *f, hid_t dxpl_id, H5HL_t *heap) FUNC_ENTER_NOAPI(H5HL_minimize_heap_space, FAIL) /* check args */ - assert(f); - assert(heap); + HDassert( f ); + HDassert( heap ); + HDassert( heap->disk_alloc == heap->mem_alloc ); sizeof_hdr = H5HL_SIZEOF_HDR(f); /* cache H5HL header size for file */ /* - * When the heap is being flushed to disk, release the file space reserved - * for it. - */ - H5MF_free_reserved(f, (hsize_t)heap->disk_resrv); - heap->disk_resrv = 0; - - /* * Check to see if we can reduce the size of the heap in memory by * eliminating free blocks at the tail of the buffer before flushing the * buffer out. @@ -427,13 +434,15 @@ H5HL_minimize_heap_space(H5F_t *f, hid_t dxpl_id, H5HL_t *heap) } /* - * If the heap grew larger or smaller than disk storage then move the + * If the heap grew smaller than disk storage then move the * data segment of the heap to another contiguous block of disk * storage. */ if (heap->mem_alloc != heap->disk_alloc) { haddr_t old_addr = heap->addr, new_addr; + HDassert( heap->mem_alloc < heap->disk_alloc ); + /* Release old space on disk */ H5_CHECK_OVERFLOW(heap->disk_alloc, size_t, hsize_t); H5MF_xfree(f, H5FD_MEM_LHEAP, dxpl_id, old_addr, (hsize_t)heap->disk_alloc); @@ -453,7 +462,8 @@ H5HL_minimize_heap_space(H5F_t *f, hid_t dxpl_id, H5HL_t *heap) done: FUNC_LEAVE_NOAPI(ret_value) -} + +} /* H5HL_minimize_heap_space() */ /*------------------------------------------------------------------------- @@ -543,6 +553,13 @@ H5HL_serialize(H5F_t *f, H5HL_t *heap, uint8_t *buf) * * Bill Wendling, 2003-09-16 * Separated out the bit that serializes the heap. + * + * John Mainzer, 2005-08-10 + * Removed call to H5HL_minimize_heap_space(). It does disk space + * allocation, which can cause problems if done at flush time. + * Instead, disk space allocation/deallocation is now done at + * insert/remove time. + * *------------------------------------------------------------------------- */ static herr_t @@ -553,21 +570,18 @@ H5HL_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HL_t *heap) FUNC_ENTER_NOAPI(H5HL_flush, FAIL); /* check arguments */ - assert(f); - assert(H5F_addr_defined(addr)); - assert(heap); + HDassert( f ); + HDassert( H5F_addr_defined(addr) ); + HDassert( heap ); + HDassert( heap->disk_alloc == heap->mem_alloc ); if (heap->cache_info.is_dirty) { haddr_t hdr_end_addr; size_t sizeof_hdr = H5HL_SIZEOF_HDR(f); /* cache H5HL header size for file */ - /* Minimize the heap space size if possible */ - if (H5HL_minimize_heap_space(f, dxpl_id, heap) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to minimize local heap space") - /* Write the header */ if (H5HL_serialize(f, heap, heap->chunk) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTSERIALIZE, FAIL, "unable to serialize local heap") + HGOTO_ERROR(H5E_HEAP, H5E_CANTSERIALIZE, FAIL, "unable to serialize local heap") /* Copy buffer to disk */ hdr_end_addr = addr + (hsize_t)sizeof_hdr; @@ -951,6 +965,10 @@ H5HL_remove_free(H5HL_t *heap, H5HL_free_t *fl) * H5AC_unprotect() instead of manipulating the is_dirty * field of the cache info directly. * + * John Mainzer, 8/10/05 + * Modified code to allocate file space as needed, instead + * of allocating it on eviction. + * *------------------------------------------------------------------------- */ size_t @@ -959,10 +977,12 @@ H5HL_insert(H5F_t *f, hid_t dxpl_id, haddr_t addr, size_t buf_size, const void * H5HL_t *heap = NULL; unsigned heap_flags = H5AC__NO_FLAGS_SET; H5HL_free_t *fl = NULL, *max_fl = NULL; + htri_t tri_result; + herr_t result; size_t offset = 0; size_t need_size, old_size, need_more; + size_t new_disk_alloc; hbool_t found; - size_t disk_resrv; /* Amount of additional space to reserve in file */ size_t sizeof_hdr; /* Cache H5HL header size for file */ size_t ret_value; /* Return value */ @@ -1028,18 +1048,54 @@ H5HL_insert(H5F_t *f, hid_t dxpl_id, haddr_t addr, size_t buf_size, const void * if (found==FALSE) { need_more = MAX3(need_size, heap->mem_alloc, H5HL_SIZEOF_FREE(f)); - /* Reserve space in the file to hold the increased heap size - */ - if( heap->disk_resrv == heap->mem_alloc) - disk_resrv = need_more; - else - disk_resrv = heap->mem_alloc + need_more - heap->disk_resrv; + new_disk_alloc = heap->disk_alloc + need_more; + HDassert( heap->disk_alloc < new_disk_alloc ); + H5_CHECK_OVERFLOW(heap->disk_alloc, size_t, hsize_t); + H5_CHECK_OVERFLOW(new_disk_alloc, size_t, hsize_t); + + /* extend the current heap if we can... */ + tri_result = H5MF_can_extend(f, H5FD_MEM_LHEAP, heap->addr, + (hsize_t)(heap->disk_alloc), + (hsize_t)need_more); + if ( tri_result == TRUE ) { + + result = H5MF_extend(f, H5FD_MEM_LHEAP, heap->addr, + (hsize_t)(heap->disk_alloc), + (hsize_t)need_more); + if ( result < 0 ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, (size_t)(-1), \ + "can't extend heap on disk"); + } + + heap->disk_alloc = new_disk_alloc; + + } else { /* ...if we can't, allocate a new chunk & release the old */ + + haddr_t old_addr = heap->addr; + haddr_t new_addr; + + /* The new allocation may fail -- to avoid the possiblity of + * file corruption, allocate the new heap first, and then + * deallocate the old. + */ + + /* allocate new disk space for the heap */ + if ( (new_addr = H5MF_alloc(f, H5FD_MEM_LHEAP, dxpl_id, + (hsize_t)new_disk_alloc)) == HADDR_UNDEF ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, (size_t)(-1), \ + "unable to allocate file space for heap") + } - if( H5MF_reserve(f, (hsize_t)disk_resrv) < 0 ) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, (size_t)(-1), "unable to reserve space in file"); + /* Release old space on disk */ + H5MF_xfree(f, H5FD_MEM_LHEAP, dxpl_id, old_addr, + (hsize_t)heap->disk_alloc); + H5E_clear_stack(NULL); /* don't really care if the free failed */ - /* Update heap's record of how much space it has reserved */ - heap->disk_resrv += disk_resrv; + heap->addr = new_addr; + heap->disk_alloc = new_disk_alloc; + } if (max_fl && max_fl->offset + max_fl->size == heap->mem_alloc) { /* @@ -1117,7 +1173,8 @@ done: HDONE_ERROR(H5E_HEAP, H5E_PROTECT, (size_t)(-1), "unable to release object header"); FUNC_LEAVE_NOAPI(ret_value); -} + +} /* H5HL_insert() */ #ifdef NOT_YET @@ -1217,6 +1274,11 @@ done: * H5AC_unprotect() instead of manipulating the is_dirty * field of the cache info directly. * + * John Mainzer, 8/10/05 + * Modified code to attempt to decrease heap size if the + * entry removal results in a free list entry at the end + * of the heap that is at least half the size of the heap. + * *------------------------------------------------------------------------- */ herr_t @@ -1225,15 +1287,15 @@ H5HL_remove(H5F_t *f, hid_t dxpl_id, haddr_t addr, size_t offset, size_t size) H5HL_t *heap = NULL; unsigned heap_flags = H5AC__NO_FLAGS_SET; H5HL_free_t *fl = NULL, *fl2 = NULL; - herr_t ret_value=SUCCEED; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(H5HL_remove, FAIL); /* check arguments */ - assert(f); - assert(H5F_addr_defined(addr)); - assert(size > 0); - assert (offset==H5HL_ALIGN (offset)); + HDassert( f ); + HDassert( H5F_addr_defined(addr) ); + HDassert( size > 0 ); + HDassert( offset == H5HL_ALIGN(offset) ); if (0==(f->intent & H5F_ACC_RDWR)) HGOTO_ERROR (H5E_HEAP, H5E_WRITEERROR, FAIL, "no write intent on file"); @@ -1243,8 +1305,9 @@ H5HL_remove(H5F_t *f, hid_t dxpl_id, haddr_t addr, size_t offset, size_t size) if (NULL == (heap = H5AC_protect(f, dxpl_id, H5AC_LHEAP, addr, NULL, NULL, H5AC_WRITE))) HGOTO_ERROR(H5E_HEAP, H5E_PROTECT, FAIL, "unable to load heap"); - assert(offset < heap->mem_alloc); - assert(offset + size <= heap->mem_alloc); + HDassert( offset < heap->mem_alloc ); + HDassert( offset + size <= heap->mem_alloc ); + HDassert( heap->disk_alloc == heap->mem_alloc ); fl = heap->freelist; heap_flags |= H5AC__DIRTIED_FLAG; @@ -1268,10 +1331,29 @@ H5HL_remove(H5F_t *f, hid_t dxpl_id, haddr_t addr, size_t offset, size_t size) assert (fl->offset==H5HL_ALIGN (fl->offset)); assert (fl->size==H5HL_ALIGN (fl->size)); fl2 = H5HL_remove_free(heap, fl2); + if ( ( (fl->offset + fl->size) == heap->mem_alloc ) && + ( (2 * fl->size) > heap->mem_alloc ) ) { + + if ( H5HL_minimize_heap_space(f, dxpl_id, heap) != + SUCCEED ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, \ + "heap size minimization failed"); + } + } HGOTO_DONE(SUCCEED); } fl2 = fl2->next; } + if ( ( (fl->offset + fl->size) == heap->mem_alloc ) && + ( (2 * fl->size) > heap->mem_alloc ) ) { + + if ( H5HL_minimize_heap_space(f, dxpl_id, heap) != SUCCEED ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, \ + "heap size minimization failed"); + } + } HGOTO_DONE(SUCCEED); } else if (fl->offset + fl->size == offset) { @@ -1283,10 +1365,29 @@ H5HL_remove(H5F_t *f, hid_t dxpl_id, haddr_t addr, size_t offset, size_t size) fl->size += fl2->size; assert (fl->size==H5HL_ALIGN (fl->size)); fl2 = H5HL_remove_free(heap, fl2); + if ( ( (fl->offset + fl->size) == heap->mem_alloc ) && + ( (2 * fl->size) > heap->mem_alloc ) ) { + + if ( H5HL_minimize_heap_space(f, dxpl_id, heap) != + SUCCEED ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, \ + "heap size minimization failed"); + } + } HGOTO_DONE(SUCCEED); } fl2 = fl2->next; } + if ( ( (fl->offset + fl->size) == heap->mem_alloc ) && + ( (2 * fl->size) > heap->mem_alloc ) ) { + + if ( H5HL_minimize_heap_space(f, dxpl_id, heap) != SUCCEED ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, \ + "heap size minimization failed"); + } + } HGOTO_DONE(SUCCEED); } fl = fl->next; @@ -1321,6 +1422,16 @@ H5HL_remove(H5F_t *f, hid_t dxpl_id, haddr_t addr, size_t offset, size_t size) heap->freelist->prev = fl; heap->freelist = fl; + if ( ( (fl->offset + fl->size) == heap->mem_alloc ) && + ( (2 * fl->size) > heap->mem_alloc ) ) { + + if ( H5HL_minimize_heap_space(f, dxpl_id, heap) != SUCCEED ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, \ + "heap size minimization failed"); + } + } + done: if (heap && H5AC_unprotect(f, dxpl_id, H5AC_LHEAP, addr, heap, heap_flags) != SUCCEED) HDONE_ERROR(H5E_HEAP, H5E_PROTECT, FAIL, "unable to release object header"); |