diff options
Diffstat (limited to 'src/H5MF.c')
-rw-r--r-- | src/H5MF.c | 797 |
1 files changed, 661 insertions, 136 deletions
@@ -29,6 +29,7 @@ /****************/ #define H5F_PACKAGE /*suppress error about including H5Fpkg */ +#define H5MF_PACKAGE /*suppress error about including H5MFpkg */ /***********/ @@ -37,18 +38,33 @@ #include "H5private.h" /* Generic Functions */ #include "H5Eprivate.h" /* Error handling */ #include "H5Fpkg.h" /* File access */ -#include "H5MFprivate.h" /* File memory management */ +#include "H5MFpkg.h" /* File memory management */ +#include "H5Vprivate.h" /* Vectors and arrays */ /****************/ /* Local Macros */ /****************/ +#define H5MF_FSPACE_SHRINK 80 /* Percent of "normal" size to shrink serialized free space size */ +#define H5MF_FSPACE_EXPAND 120 /* Percent of "normal" size to expand serialized free space size */ + +/* Map an allocation request type to a free list */ +#define H5MF_ALLOC_TO_FS_TYPE(F, T) ((H5FD_MEM_DEFAULT == (F)->shared->fs_type_map[T]) \ + ? (T) : (F)->shared->fs_type_map[T]) + /******************/ /* Local Typedefs */ /******************/ +/* Enum for kind of free space section+aggregator merging allowed for a file */ +typedef enum { + H5MF_AGGR_MERGE_SEPARATE, /* Everything in separate free list */ + H5MF_AGGR_MERGE_DICHOTOMY, /* Metadata in one free list and raw data in another */ + H5MF_AGGR_MERGE_TOGETHER /* Metadata & raw data in one free list */ +} H5MF_aggr_merge_t; + /********************/ /* Package Typedefs */ @@ -58,7 +74,6 @@ /********************/ /* Local Prototypes */ /********************/ -static hbool_t H5MF_alloc_overflow(H5F_t *f, hsize_t size); /*********************/ @@ -77,6 +92,177 @@ static hbool_t H5MF_alloc_overflow(H5F_t *f, hsize_t size); /*------------------------------------------------------------------------- + * Function: H5MF_init_merge_flags + * + * Purpose: Initialize the free space section+aggregator merge flags + * for the file. + * + * Return: SUCCEED/FAIL + * + * Programmer: Quincey Koziol + * Friday, February 1, 2008 + * + *------------------------------------------------------------------------- + */ +herr_t +H5MF_init_merge_flags(H5F_t *f) +{ + H5MF_aggr_merge_t mapping_type; /* Type of free list mapping */ + H5FD_mem_t type; /* Memory type for iteration */ + hbool_t all_same; /* Whether all the types map to the same value */ + + FUNC_ENTER_NOAPI_NOFUNC(H5MF_init_merge_flags) + + /* check args */ + HDassert(f); + HDassert(f->shared); + HDassert(f->shared->lf); + + /* Iterate over all the free space types to determine if sections of that type + * can merge with the metadata or small 'raw' data aggregator + */ + all_same = TRUE; + for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) + /* Check for any different type mappings */ + if(f->shared->fs_type_map[type] != f->shared->fs_type_map[H5FD_MEM_DEFAULT]) { + all_same = FALSE; + break; + } /* end if */ + + /* Check for all allocation types mapping to the same free list type */ + if(all_same) { + if(f->shared->fs_type_map[H5FD_MEM_DEFAULT] == H5FD_MEM_DEFAULT) + mapping_type = H5MF_AGGR_MERGE_SEPARATE; + else + mapping_type = H5MF_AGGR_MERGE_TOGETHER; + } /* end if */ + else { + /* Check for raw data mapping into same list as metadata */ + if(f->shared->fs_type_map[H5FD_MEM_DRAW] == f->shared->fs_type_map[H5FD_MEM_SUPER]) + mapping_type = H5MF_AGGR_MERGE_SEPARATE; + else { + hbool_t all_metadata_same; /* Whether all metadata go in same free list */ + + /* One or more allocation type don't map to the same free list type */ + /* Check if all the metadata allocation types map to the same type */ + all_metadata_same = TRUE; + for(type = H5FD_MEM_SUPER; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) + /* Skip checking raw data free list mapping */ + if(type != H5FD_MEM_DRAW) { + /* Check for any different type mappings */ + if(f->shared->fs_type_map[type] != f->shared->fs_type_map[H5FD_MEM_SUPER]) { + all_metadata_same = FALSE; + break; + } /* end if */ + } /* end if */ + + /* Check for all metadata on same free list */ + if(all_metadata_same) + mapping_type = H5MF_AGGR_MERGE_DICHOTOMY; + else + mapping_type = H5MF_AGGR_MERGE_SEPARATE; + } /* end else */ + } /* end else */ + + /* Based on mapping type, initialize merging flags for each free list type */ + switch(mapping_type) { + case H5MF_AGGR_MERGE_SEPARATE: + HDmemset(f->shared->fs_aggr_merge, 0, sizeof(f->shared->fs_aggr_merge)); + break; + + case H5MF_AGGR_MERGE_DICHOTOMY: + HDmemset(f->shared->fs_aggr_merge, H5F_FS_MERGE_METADATA, sizeof(f->shared->fs_aggr_merge)); + f->shared->fs_aggr_merge[H5FD_MEM_DRAW] = H5F_FS_MERGE_RAWDATA; + break; + + case H5MF_AGGR_MERGE_TOGETHER: + HDmemset(f->shared->fs_aggr_merge, (H5F_FS_MERGE_METADATA | H5F_FS_MERGE_RAWDATA), sizeof(f->shared->fs_aggr_merge)); + break; + } /* end switch */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5MF_init_merge_flags() */ + + +/*------------------------------------------------------------------------- + * Function: H5MF_alloc_start + * + * Purpose: "Start up" free space for file - open existing free space + * structure if one exists, otherwise create a new free space + * structure + * + * Return: Success: non-negative + * Failure: negative + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Jan 8 2008 + * + * Modifications: + * Vailin Choi, July 29th, 2008 + * Pass values of alignment and threshold to FS_create() for handling alignment + * + *------------------------------------------------------------------------- + */ +herr_t +H5MF_alloc_start(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type, hbool_t may_create) +{ + const H5FS_section_class_t *classes[] = { /* Free space section classes implemented for file */ + H5MF_FSPACE_SECT_CLS_SIMPLE}; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5MF_alloc_start) + + /* + * Check arguments. + */ + HDassert(f); + HDassert(f->shared); + + /* Check for creating free space info for the file */ + if(H5F_addr_defined(f->shared->fs_addr[type])) { + /* Open an existing free space structure for the file */ + HDassert(f->shared->fs_state[type] == H5F_FS_STATE_CLOSED); + if(NULL == (f->shared->fs_man[type] = H5FS_open(f, dxpl_id, f->shared->fs_addr[type], + NELMTS(classes), classes, f, f->shared->alignment, f->shared->threshold))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space info") + } /* end if */ + else { + /* Check if we are allowed to create the free space manager */ + if(may_create) { + H5FS_create_t fs_create; /* Free space creation parameters */ + + /* Set the free space creation parameters */ + fs_create.client = H5FS_CLIENT_FILE_ID; + fs_create.shrink_percent = H5MF_FSPACE_SHRINK; + fs_create.expand_percent = H5MF_FSPACE_EXPAND; + fs_create.max_sect_addr = 1 + H5V_log2_gen((uint64_t)f->shared->maxaddr); + fs_create.max_sect_size = f->shared->maxaddr; + + /* Create the free space structure for the heap */ + HDassert(f->shared->fs_state[type] == H5F_FS_STATE_CLOSED); +#ifdef LATER + if(NULL == (f->shared->fs_man[type] = H5FS_create(f, dxpl_id, &f->shared->fs_addr[type], + &fs_create, NELMTS(classes), classes, f, f->shared->alignment, f->shared->threshold))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space info") +#else /* LATER */ + if(NULL == (f->shared->fs_man[type] = H5FS_create(f, dxpl_id, NULL, + &fs_create, NELMTS(classes), classes, f, f->shared->alignment, f->shared->threshold))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space info") +#endif /* LATER */ + } /* end if */ + } /* end else */ + + /* Set the state for the free space manager to "open", if it is now */ + if(f->shared->fs_man[type]) + f->shared->fs_state[type] = H5F_FS_STATE_OPEN; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5MF_alloc_start() */ + + +/*------------------------------------------------------------------------- * Function: H5MF_alloc * * Purpose: Allocate SIZE bytes of file memory and return the relative @@ -94,31 +280,105 @@ static hbool_t H5MF_alloc_overflow(H5F_t *f, hsize_t size); *------------------------------------------------------------------------- */ haddr_t -H5MF_alloc(H5F_t *f, H5FD_mem_t type, hid_t dxpl_id, hsize_t size) +H5MF_alloc(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, hsize_t size) { - haddr_t ret_value; + H5FD_mem_t fs_type; /* Free space type (mapped from allocation type) */ + haddr_t ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5MF_alloc, HADDR_UNDEF) +#ifdef H5MF_ALLOC_DEBUG +HDfprintf(stderr, "%s: alloc_type = %u, size = %Hu\n", FUNC, (unsigned)alloc_type, size); +#endif /* H5MF_ALLOC_DEBUG */ /* check arguments */ HDassert(f); HDassert(size > 0); - /* Fail if we don't have write access */ - if(0 == (f->intent & H5F_ACC_RDWR)) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, HADDR_UNDEF, "file is read-only") - - /* Allocate space from the virtual file layer */ - if(HADDR_UNDEF == (ret_value = H5FD_alloc(f->shared->lf, type, dxpl_id, size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, HADDR_UNDEF, "file allocation failed") - - /* Convert absolute file address to relative file address */ - HDassert(ret_value >= f->shared->base_addr); - - /* Set return value */ - ret_value -= f->shared->base_addr; + /* Get free space type from allocation type */ + fs_type = H5MF_ALLOC_TO_FS_TYPE(f, alloc_type); + + /* Check if the free space manager for the file has been initialized */ + if(!f->shared->fs_man[fs_type]) + if(H5MF_alloc_start(f, dxpl_id, fs_type, FALSE) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, HADDR_UNDEF, "can't initialize file free space") + + /* Search for large enough space in the free space manager */ + if(f->shared->fs_man[fs_type]) { + H5MF_free_section_t *node; /* Free space section pointer */ + htri_t node_found = FALSE; /* Whether an existing free list node was found */ + + /* Try to get a section from the free space manager */ + if((node_found = H5FS_sect_find(f, dxpl_id, f->shared->fs_man[fs_type], size, (H5FS_section_info_t **)&node)) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "error locating free space in file") +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: Check 1.5, node_found = %t\n", FUNC, node_found); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + + /* Check for actually finding section */ + if(node_found) { + /* Sanity check */ + HDassert(node); + + /* Retrieve return value */ + ret_value = node->sect_info.addr; + + /* Check for eliminating the section */ + if(node->sect_info.size == size) { +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: Check 1.6, freeing node\n", FUNC); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + /* Free section node */ + if(H5MF_sect_simple_free((H5FS_section_info_t *)node) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, HADDR_UNDEF, "can't free simple section node") + } /* end if */ + else { + H5MF_sect_ud_t udata; /* User data for callback */ + + /* Adjust information for section */ + node->sect_info.addr += size; + node->sect_info.size -= size; + + /* Construct user data for callbacks */ + udata.f = f; + udata.dxpl_id = dxpl_id; + udata.alloc_type = alloc_type; + udata.allow_sect_absorb = TRUE; + +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: Check 1.7, re-adding node, node->sect_info.size = %Hu\n", FUNC, node->sect_info.size); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + /* Re-insert section node into file's free space */ + if(H5FS_sect_add(f, dxpl_id, f->shared->fs_man[fs_type], (H5FS_section_info_t *)node, H5FS_ADD_RETURNED_SPACE, &udata) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, HADDR_UNDEF, "can't re-add section to file free space") + } /* end else */ + + /* Leave now */ + HGOTO_DONE(ret_value) + } /* end if */ + } /* end if */ +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: Check 2.0\n", FUNC); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + + /* Couldn't find anything from the free space manager, go allocate some */ + if(alloc_type != H5FD_MEM_DRAW) { + /* Handle metadata differently from "raw" data */ + if(HADDR_UNDEF == (ret_value = H5MF_aggr_alloc(f, dxpl_id, &(f->shared->meta_aggr), &(f->shared->sdata_aggr), alloc_type, size))) + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate metadata") + } /* end if */ + else { + /* Allocate "raw" data */ + if(HADDR_UNDEF == (ret_value = H5MF_aggr_alloc(f, dxpl_id, &(f->shared->sdata_aggr), &(f->shared->meta_aggr), alloc_type, size))) + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate raw data") + } /* end else */ done: +#ifdef H5MF_ALLOC_DEBUG +HDfprintf(stderr, "%s: Leaving: ret_value = %a, size = %Hu\n", FUNC, ret_value, size); +#endif /* H5MF_ALLOC_DEBUG */ +#ifdef H5MF_ALLOC_DEBUG_DUMP +H5MF_sects_dump(f, dxpl_id, stderr); +#endif /* H5MF_ALLOC_DEBUG_DUMP */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5MF_alloc() */ @@ -138,193 +398,458 @@ done: *------------------------------------------------------------------------- */ herr_t -H5MF_xfree(H5F_t *f, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, hsize_t size) +H5MF_xfree(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, haddr_t addr, + hsize_t size) { - herr_t ret_value = SUCCEED; /* Return value */ + H5MF_free_section_t *node = NULL; /* Free space section pointer */ + H5MF_sect_ud_t udata; /* User data for callback */ + H5FD_mem_t fs_type; /* Free space type (mapped from allocation type) */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOFUNC(H5MF_xfree) + FUNC_ENTER_NOAPI(H5MF_xfree, FAIL) +#ifdef H5MF_ALLOC_DEBUG +HDfprintf(stderr, "%s: Entering - alloc_type = %u, addr = %a, size = %Hu\n", FUNC, (unsigned)alloc_type, addr, size); +#endif /* H5MF_ALLOC_DEBUG */ /* check arguments */ HDassert(f); if(!H5F_addr_defined(addr) || 0 == size) HGOTO_DONE(SUCCEED); - HDassert(addr != 0); - - /* Convert relative address to absolute address */ - addr += f->shared->base_addr; - - /* Allow virtual file layer to free block */ - if(H5FD_free(f->shared->lf, type, dxpl_id, addr, size) < 0) { -#ifdef H5MF_DEBUG - if(H5DEBUG(MF)) - fprintf(H5DEBUG(MF), "H5MF_free: lost %lu bytes of file storage\n", (unsigned long)size); -#endif + HDassert(addr != 0); /* Can't deallocate the superblock :-) */ + + /* Check if the space to free intersects with the file's metadata accumulator */ + if(H5F_accum_free(f, dxpl_id, alloc_type, addr, size) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't check free space intersection w/metadata accumulator") + + /* Get free space type from allocation type */ + fs_type = H5MF_ALLOC_TO_FS_TYPE(f, alloc_type); +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: fs_type = %u\n", FUNC, (unsigned)fs_type); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + + /* Check if the free space manager for the file has been initialized */ + if(!f->shared->fs_man[fs_type]) { + /* If there's no free space manager for objects of this type, + * see if we can avoid creating one by checking if the freed + * space is at the end of the file + */ +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: f->shared->fs_addr[%u] = %a\n", FUNC, (unsigned)fs_type, f->shared->fs_addr[fs_type]); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + if(!H5F_addr_defined(f->shared->fs_addr[fs_type])) { + htri_t status; /* "can absorb" status for section into */ + +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: Trying to avoid starting up free space manager\n", FUNC); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + /* Try to shrink the file or absorb the block into a block aggregator */ + if((status = H5MF_try_shrink(f, alloc_type, dxpl_id, addr, size)) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTMERGE, FAIL, "can't check for absorbing block") + else if(status > 0) + /* Indicate success */ + HGOTO_DONE(SUCCEED) + } /* end if */ + + /* If we are deleting the free space manager, leave now, to avoid + * [re-]starting it. + * + * Note: this drops the space to free on the floor... + * + */ + if(f->shared->fs_state[fs_type] == H5F_FS_STATE_DELETING) +{ +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: dropping addr = %a, size = %Hu, on the floor!\n", FUNC, addr, size); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + HGOTO_DONE(SUCCEED) +} + + /* There's either already a free space manager, or the freed + * space isn't at the end of the file, so start up (or create) + * the file space manager + */ + if(H5MF_alloc_start(f, dxpl_id, fs_type, TRUE) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space") } /* end if */ + HDassert(f->shared->fs_man[fs_type]); + + /* Create free space section for block */ + if(NULL == (node = H5MF_sect_simple_new(addr, size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space section") + + /* Construct user data for callbacks */ + udata.f = f; + udata.dxpl_id = dxpl_id; + udata.alloc_type = alloc_type; + udata.allow_sect_absorb = TRUE; + + /* Add to the free space for the file */ +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: Before H5FS_sect_add()\n", FUNC); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + if(H5FS_sect_add(f, dxpl_id, f->shared->fs_man[fs_type], (H5FS_section_info_t *)node, H5FS_ADD_RETURNED_SPACE, &udata) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't add section to file free space") +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: After H5FS_sect_add()\n", FUNC); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + node = NULL; done: + if(ret_value < 0 && node) + /* On error, free section node allocated */ + if(H5MF_sect_simple_free((H5FS_section_info_t *)node) < 0) + HDONE_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node") + +#ifdef H5MF_ALLOC_DEBUG +HDfprintf(stderr, "%s: Leaving, ret_value = %d\n", FUNC, ret_value); +#endif /* H5MF_ALLOC_DEBUG */ +#ifdef H5MF_ALLOC_DEBUG_DUMP +H5MF_sects_dump(f, dxpl_id, stderr); +#endif /* H5MF_ALLOC_DEBUG_DUMP */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5MF_xfree() */ /*------------------------------------------------------------------------- - * Function: H5MF_realloc + * Function: H5MF_try_extend * - * Purpose: Changes the size of an allocated chunk, possibly moving it to - * a new address. The chunk to change is at address OLD_ADDR - * and is exactly OLD_SIZE bytes (if these are H5F_ADDR_UNDEF - * and zero then this function acts like H5MF_alloc). The new - * size will be NEW_SIZE and its address is the return value (if - * NEW_SIZE is zero then this function acts like H5MF_free and - * an undefined address is returned). + * Purpose: Extend a block in the file if possible. * - * If the new size is less than the old size then the new - * address will be the same as the old address (except for the - * special case where the new size is zero). - * - * If the new size is more than the old size then most likely a - * new address will be returned. However, under certain - * circumstances the library may return the same address. - * - * Return: Success: The relative file address of the new block. - * Failure: HADDR_UNDEF + * Return: Success: TRUE(1) - Block was extended + * FALSE(0) - Block could not be extended + * Failure: FAIL * - * Programmer: Robb Matzke - * Thursday, April 16, 1998 + * Programmer: Quincey Koziol + * Friday, June 11, 2004 * *------------------------------------------------------------------------- */ -haddr_t -H5MF_realloc(H5F_t *f, H5FD_mem_t type, hid_t dxpl_id, haddr_t old_addr, hsize_t old_size, - hsize_t new_size) +htri_t +H5MF_try_extend(H5F_t *f, hid_t dxpl_id, H5FD_mem_t alloc_type, haddr_t addr, + hsize_t size, hsize_t extra_requested) { - haddr_t ret_value; - - FUNC_ENTER_NOAPI(H5MF_realloc, HADDR_UNDEF) - - /* Convert old relative address to absolute address */ - old_addr += f->shared->base_addr; - - /* Reallocate memory from the virtual file layer */ - ret_value = H5FD_realloc(f->shared->lf, type, dxpl_id, old_addr, old_size, new_size); - if(HADDR_UNDEF == ret_value) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, HADDR_UNDEF, "unable to allocate new file memory") - - /* Convert return value to relative address */ - HDassert(ret_value >= f->shared->base_addr); + haddr_t end; /* End of block to extend */ + htri_t ret_value; /* Return value */ - /* Set return value */ - ret_value -= f->shared->base_addr; + FUNC_ENTER_NOAPI(H5MF_try_extend, FAIL) +#ifdef H5MF_ALLOC_DEBUG +HDfprintf(stderr, "%s: Entering: alloc_type = %u, addr = %a, size = %Hu, extra_requested = %Hu\n", FUNC, (unsigned)alloc_type, addr, size, extra_requested); +#endif /* H5MF_ALLOC_DEBUG */ + + /* Compute end of block to extend */ + end = addr + size; + + /* Check if the block is exactly at the end of the file */ + if((ret_value = H5FD_try_extend(f->shared->lf, alloc_type, end, extra_requested)) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL, "error extending file") + else if(ret_value == FALSE) { + H5F_blk_aggr_t *aggr; /* Aggregator to use */ + + /* Check for test block able to extend aggregation block */ + aggr = (alloc_type == H5FD_MEM_DRAW) ? &(f->shared->sdata_aggr) : &(f->shared->meta_aggr); + if((ret_value = H5MF_aggr_try_extend(f, aggr, alloc_type, end, extra_requested)) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL, "error extending aggregation block") + else if(ret_value == FALSE) { + H5FD_mem_t fs_type; /* Free space type (mapped from allocation type) */ + + /* Get free space type from allocation type */ + fs_type = H5MF_ALLOC_TO_FS_TYPE(f, alloc_type); + + /* Check if the free space for the file has been initialized */ + if(!f->shared->fs_man[fs_type]) + if(H5MF_alloc_start(f, dxpl_id, fs_type, FALSE) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space") + + /* Check for test block able to block in free space manager */ + if(f->shared->fs_man[fs_type]) + if((ret_value = H5FS_sect_try_extend(f, dxpl_id, f->shared->fs_man[fs_type], addr, size, extra_requested)) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL, "error extending block in free space manager") + } /* end if */ + } /* end if */ done: +#ifdef H5MF_ALLOC_DEBUG +HDfprintf(stderr, "%s: Leaving: ret_value = %t\n", FUNC, ret_value); +#endif /* H5MF_ALLOC_DEBUG */ +#ifdef H5MF_ALLOC_DEBUG_DUMP +H5MF_sects_dump(f, dxpl_id, stderr); +#endif /* H5MF_ALLOC_DEBUG_DUMP */ FUNC_LEAVE_NOAPI(ret_value) -} /* end H5MF_realloc() */ +} /* end H5MF_try_extend() */ /*------------------------------------------------------------------------- - * Function: H5MF_alloc_overflow + * Function: H5MF_get_freespace * - * Purpose: Checks if an allocation of file space would cause an overflow. - * F is the file whose space is being allocated, SIZE is the amount - * of space needed. + * Purpose: Retrieve the amount of free space in a file. * - * Return: FALSE if no overflow would result - * TRUE if overflow would result (the allocation should not be allowed) + * Return: Success: Amount of free space in file + * Failure: Negative * - * Programmer: James Laird - * Nat Furrer - * Tuesday, June 1, 2004 + * Programmer: Quincey Koziol + * Monday, October 6, 2003 * *------------------------------------------------------------------------- */ -static hbool_t -H5MF_alloc_overflow(H5F_t *f, hsize_t size) +hssize_t +H5MF_get_freespace(H5F_t *f, hid_t dxpl_id) { - haddr_t eoa; /* End-of-allocation in the file */ - haddr_t space_avail; /* Unallocated space still available in file */ - hbool_t ret_value; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5MF_alloc_overflow) - - /* Start with the current end of the file's address. */ - eoa = H5F_get_eoa(f); - HDassert(H5F_addr_defined(eoa)); - - /* Subtract EOA from the file's maximum address to get the actual amount of - * addressable space left in the file. - */ - HDassert(f->shared->maxaddr >= eoa); - space_avail = (hsize_t)(f->shared->maxaddr - eoa); + haddr_t eoa; /* End of allocated space in the file */ + haddr_t ma_addr = HADDR_UNDEF; /* Base "metadata aggregator" address */ + hsize_t ma_size = 0; /* Size of "metadata aggregator" */ + haddr_t sda_addr = HADDR_UNDEF; /* Base "small data aggregator" address */ + hsize_t sda_size = 0; /* Size of "small data aggregator" */ + hsize_t tot_fs_size = 0; /* Amount of all free space managed */ + H5FD_mem_t type; /* Memory type for iteration */ + hssize_t ret_value; /* Return value */ + + FUNC_ENTER_NOAPI(H5MF_get_freespace, FAIL) + + /* check args */ + HDassert(f); + HDassert(f->shared); + HDassert(f->shared->lf); + + /* Retrieve the 'eoa' for the file */ + if(HADDR_UNDEF == (eoa = H5FD_get_eoa(f->shared->lf, H5FD_MEM_DEFAULT))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed") + + /* Retrieve metadata aggregator info, if available */ + H5MF_aggr_query(f, &(f->shared->meta_aggr), &ma_addr, &ma_size); + + /* Retrieve 'small data' aggregator info, if available */ + H5MF_aggr_query(f, &(f->shared->sdata_aggr), &sda_addr, &sda_size); + + /* Iterate over all the free space types that have managers and get each free list's space */ + for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) { + hsize_t type_fs_size = 0; /* Amount of free space managed for each type */ + + /* Check if the free space for the file has been initialized */ + if(!f->shared->fs_man[type]) + if(H5MF_alloc_start(f, dxpl_id, type, FALSE) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space") + + /* Retrieve free space size from free space manager */ + if(f->shared->fs_man[type]) + if((ret_value = H5FS_sect_stats(f->shared->fs_man[type], &type_fs_size, NULL)) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query free space stats") + + /* Increment total free space for types */ + tot_fs_size += type_fs_size; + } /* end for */ + + /* Start computing value to return */ + ret_value = tot_fs_size; + + /* Check for aggregating metadata allocations */ + if(ma_size > 0) { + /* Add in the reserved space for metadata to the available free space */ + /* (if it's not at the tail of the file) */ + if(H5F_addr_ne(ma_addr + ma_size, eoa)) + ret_value += ma_size; + } /* end if */ - /* Ensure that there's enough room left in the file for something of this size */ - if(size > space_avail) - ret_value = TRUE; - else - ret_value = FALSE; + /* Check for aggregating small data allocations */ + if(sda_size > 0) { + /* Add in the reserved space for metadata to the available free space */ + /* (if it's not at the tail of the file) */ + if(H5F_addr_ne(sda_addr + sda_size, eoa)) + ret_value += sda_size; + } /* end if */ +done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5MF_alloc_overflow() */ +} /* end H5MF_get_freespace() */ /*------------------------------------------------------------------------- - * Function: H5MF_can_extend + * Function: H5MF_can_shrink * - * Purpose: Check if a block in the file can be extended. + * Purpose: Try to shrink the size of a file with a block or absorb it + * into a block aggregator. * - * Return: Success: TRUE(1)/FALSE(0) - * Failure: FAIL + * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * Friday, June 11, 2004 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Feb 14 2008 * *------------------------------------------------------------------------- */ htri_t -H5MF_can_extend(H5F_t *f, H5FD_mem_t type, haddr_t addr, hsize_t size, hsize_t extra_requested) +H5MF_try_shrink(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, haddr_t addr, + hsize_t size) { - htri_t ret_value; /* Return value */ + H5MF_free_section_t *node = NULL; /* Free space section pointer */ + H5MF_sect_ud_t udata; /* User data for callback */ + htri_t ret_value; /* Return value */ - FUNC_ENTER_NOAPI(H5MF_can_extend, FAIL) + FUNC_ENTER_NOAPI(H5MF_try_shrink, FAIL) +#ifdef H5MF_ALLOC_DEBUG +HDfprintf(stderr, "%s: Entering - alloc_type = %u, addr = %a, size = %Hu\n", FUNC, (unsigned)alloc_type, addr, size); +#endif /* H5MF_ALLOC_DEBUG */ - /* Convert old relative address to absolute address */ - addr += H5F_BASE_ADDR(f); + /* check arguments */ + HDassert(f); + HDassert(H5F_addr_defined(addr)); + HDassert(size > 0); - /* Pass the request down to the virtual file layer */ - if((ret_value = H5FD_can_extend(f->shared->lf, type, addr, size, extra_requested)) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate new file memory"); + /* Create free space section for block */ + if(NULL == (node = H5MF_sect_simple_new(addr, size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space section") + + /* Construct user data for callbacks */ + udata.f = f; + udata.dxpl_id = dxpl_id; + udata.alloc_type = alloc_type; + udata.allow_sect_absorb = FALSE; /* Force section to be absorbed into aggregator */ + + /* Call the "can shrink" callback for the section */ + if((ret_value = H5MF_sect_simple_can_shrink((const H5FS_section_info_t *)node, &udata)) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL, "can't check if section can shrink container") + else if(ret_value > 0) { + /* Shrink or absorb the section */ + if(H5MF_sect_simple_shrink((H5FS_section_info_t **)&node, &udata) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink container") + } /* end if */ done: + /* Free section node allocated */ + if(node && H5MF_sect_simple_free((H5FS_section_info_t *)node) < 0) + HDONE_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node") + +#ifdef H5MF_ALLOC_DEBUG +HDfprintf(stderr, "%s: Leaving, ret_value = %d\n", FUNC, ret_value); +#endif /* H5MF_ALLOC_DEBUG */ FUNC_LEAVE_NOAPI(ret_value) -} /* end H5MF_can_extend() */ +} /* end H5MF_try_shrink() */ /*------------------------------------------------------------------------- - * Function: H5MF_extend + * Function: H5MF_close * - * Purpose: Extend a block in the file. + * Purpose: Close the free space tracker(s) for a file * - * Return: Success: Non-negative - * Failure: Negative + * Return: SUCCEED/FAIL * - * Programmer: Quincey Koziol - * Saturday, June 12, 2004 + * Programmer: Quincey Koziol + * Tuesday, January 22, 2008 * *------------------------------------------------------------------------- */ herr_t -H5MF_extend(H5F_t *f, H5FD_mem_t type, haddr_t addr, hsize_t size, hsize_t extra_requested) +H5MF_close(H5F_t *f, hid_t dxpl_id) { - herr_t ret_value; /* Return value */ - - FUNC_ENTER_NOAPI(H5MF_extend, FAIL) - - /* Convert relative address to absolute address */ - addr += H5F_BASE_ADDR(f); - - /* Pass the request down to the virtual file layer */ - if((ret_value = H5FD_extend(f->shared->lf, type, addr, size, extra_requested)) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate new file memory") + H5FD_mem_t type; /* Memory type for iteration */ + H5F_blk_aggr_t *first_aggr; /* First aggregator to reset */ + H5F_blk_aggr_t *second_aggr; /* Second aggregator to reset */ + haddr_t ma_addr = HADDR_UNDEF; /* Base "metadata aggregator" address */ + hsize_t ma_size = 0; /* Size of "metadata aggregator" */ + haddr_t sda_addr = HADDR_UNDEF; /* Base "small data aggregator" address */ + hsize_t sda_size = 0; /* Size of "small data aggregator" */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5MF_close, FAIL) +#ifdef H5MF_ALLOC_DEBUG +HDfprintf(stderr, "%s: Entering\n", FUNC); +#endif /* H5MF_ALLOC_DEBUG */ + + /* check args */ + HDassert(f); + HDassert(f->shared); + HDassert(f->shared->lf); + + /* Iterate over all the free space types that have managers and get each free list's space */ + for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) { +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: Check 1.0 - f->shared->fs_man[%u] = %p, f->shared->fs_addr[%u] = %a\n", FUNC, (unsigned)type, f->shared->fs_man[type], (unsigned)type, f->shared->fs_addr[type]); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + /* If the free space manager for this type is open, close it */ + if(f->shared->fs_man[type]) { +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: Before closing free space manager\n", FUNC); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + if(H5FS_close(f, dxpl_id, f->shared->fs_man[type]) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release free space info") + f->shared->fs_man[type] = NULL; + f->shared->fs_state[type] = H5F_FS_STATE_CLOSED; + } /* end if */ +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: Check 2.0 - f->shared->fs_man[%u] = %p, f->shared->fs_addr[%u] = %a\n", FUNC, (unsigned)type, f->shared->fs_man[type], (unsigned)type, f->shared->fs_addr[type]); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + + /* If there is free space manager info for this type, delete it */ + /* (XXX: Make this optional when free space for a file can be persistant) */ + if(H5F_addr_defined(f->shared->fs_addr[type])) { + haddr_t tmp_fs_addr; /* Temporary holder for free space manager address */ + + /* Put address into temporary variable and reset it */ + /* (Avoids loopback in file space freeing routine) */ + tmp_fs_addr = f->shared->fs_addr[type]; + f->shared->fs_addr[type] = HADDR_UNDEF; + + /* Shift to "deleting" state, to make certain we don't track any + * file space freed as a result of deleting the free space manager. + */ + f->shared->fs_state[type] = H5F_FS_STATE_DELETING; + +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: Before deleting free space manager\n", FUNC); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + /* Delete free space manager for this type */ + if(H5FS_delete(f, dxpl_id, tmp_fs_addr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "can't delete free space manager") + + /* Shift [back] to closed state */ + HDassert(f->shared->fs_state[type] == H5F_FS_STATE_DELETING); + f->shared->fs_state[type] = H5F_FS_STATE_CLOSED; + + /* Sanity check that the free space manager for this type wasn't started up again */ + HDassert(!H5F_addr_defined(f->shared->fs_addr[type])); + } /* end if */ + } /* end for */ + + /* Retrieve metadata aggregator info, if available */ + H5MF_aggr_query(f, &(f->shared->meta_aggr), &ma_addr, &ma_size); +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: ma_addr = %a, ma_size = %Hu, end of ma = %a\n", FUNC, ma_addr, ma_size, (haddr_t)((ma_addr + ma_size) - 1)); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + + /* Retrieve 'small data' aggregator info, if available */ + H5MF_aggr_query(f, &(f->shared->sdata_aggr), &sda_addr, &sda_size); +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: sda_addr = %a, sda_size = %Hu, end of sda = %a\n", FUNC, sda_addr, sda_size, (haddr_t)((sda_addr + sda_size) - 1)); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + + /* Make certain we release the aggregator that's later in the file first */ + /* (so the file shrinks properly) */ + if(H5F_addr_defined(ma_addr) && H5F_addr_defined(sda_addr)) { + if(H5F_addr_lt(ma_addr, sda_addr)) { + first_aggr = &(f->shared->sdata_aggr); + second_aggr = &(f->shared->meta_aggr); + } /* end if */ + else { + first_aggr = &(f->shared->meta_aggr); + second_aggr = &(f->shared->sdata_aggr); + } /* end else */ + } /* end if */ + else { + first_aggr = &(f->shared->meta_aggr); + second_aggr = &(f->shared->sdata_aggr); + } /* end else */ + + /* Release the unused portion of the metadata and "small data" blocks back + * to the free lists in the file. + */ + if(H5MF_aggr_reset(f, dxpl_id, first_aggr) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't reset metadata block") + if(H5MF_aggr_reset(f, dxpl_id, second_aggr) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't reset 'small data' block") done: +#ifdef H5MF_ALLOC_DEBUG +HDfprintf(stderr, "%s: Leaving\n", FUNC); +#endif /* H5MF_ALLOC_DEBUG */ FUNC_LEAVE_NOAPI(ret_value) -} /* end H5MF_extend() */ +} /* end H5MF_close() */ |