diff options
author | Quincey Koziol <koziol@hdfgroup.org> | 2006-05-22 16:43:45 (GMT) |
---|---|---|
committer | Quincey Koziol <koziol@hdfgroup.org> | 2006-05-22 16:43:45 (GMT) |
commit | 5d2bddcd0654b9f1ad548799e6828780a30b506c (patch) | |
tree | af3981ebdedc3e92aff186ca1b06a67de197c7f2 /src/H5FS.c | |
parent | 4d3390afd97c82f91165677877469ee0911288c6 (diff) | |
download | hdf5-5d2bddcd0654b9f1ad548799e6828780a30b506c.zip hdf5-5d2bddcd0654b9f1ad548799e6828780a30b506c.tar.gz hdf5-5d2bddcd0654b9f1ad548799e6828780a30b506c.tar.bz2 |
[svn-r12362] Purpose:
Code checkpoint
Description:
Update fractal heap code to allow objects to be deleted
Fix bugs in fractal heap object insertion
Improve free space manager code to allow sections to be merged and
shrink the container
Another try at making the Windows compilers happy...
Platforms tested:
FreeBSD 4.11 (sleipnir)
Mac OS X.4/PPC (amazon)
Linux 2.4 (chicago & heping)
Solaris 2.9 (shanti)
AIX 5.? (copper) w/parallel
Diffstat (limited to 'src/H5FS.c')
-rw-r--r-- | src/H5FS.c | 1031 |
1 files changed, 775 insertions, 256 deletions
@@ -115,13 +115,12 @@ struct H5FS_t { unsigned sect_prefix_size; /* Size of the section serialization prefix (in bytes) */ unsigned sect_off_size; /* Size of a section offset (in bytes) */ unsigned sect_len_size; /* Size of a section length (in bytes) */ - hbool_t using_bins; /* Flag to indicate that all nodes are in the bins */ hbool_t dirty; /* Space information is dirty */ /* Memory data structures (not stored directly) */ H5FS_section_class_t *sect_cls; /* Array of section classes for this free list */ H5FS_section_info_t *single; /* Section information when free list has only one free section */ - H5SL_operator_t node_free_op; /* Callback for freeing nodes when free list is destroyed */ + H5SL_t *merge_list; /* Skip list to hold sections for detecting merges */ H5FS_bin_t *bins; /* Array of lists of lists of free sections */ }; @@ -132,6 +131,7 @@ struct H5FS_t { static herr_t H5FS_open_add(H5FS_t *fspace); static herr_t H5FS_open_remove(H5FS_t *fspace); static herr_t H5FS_init(H5FS_t *fspace); +static herr_t H5FS_sect_free_cb(void *item, void *key, void *op_data); static herr_t H5FS_node_free_cb(void *item, void *key, void *op_data); static herr_t H5FS_sect_increase(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace); static herr_t H5FS_sect_decrease(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace); @@ -311,7 +311,7 @@ H5FS_open_remove(H5FS_t *fspace) /* Remove the free space manager from the list of open managers */ if(NULL == H5SL_remove(H5FS_open_g, &fspace->addr)) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTDELETE, FAIL, "can't remove free space manager from skip list") + HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL, "can't remove free space manager from skip list") done: FUNC_LEAVE_NOAPI(ret_value) @@ -343,7 +343,7 @@ H5FS_init(H5FS_t *fspace) /* Initialize free space memory structures */ fspace->single = NULL; fspace->bins = NULL; - fspace->using_bins = FALSE; + fspace->merge_list = NULL; fspace->serial_size = 0; fspace->size_count = 0; @@ -367,8 +367,7 @@ H5FS_init(H5FS_t *fspace) */ H5FS_t * H5FS_create(H5F_t *f, hid_t dxpl_id, haddr_t *fs_addr, const H5FS_create_t *fs_create, - H5SL_operator_t node_free_op, size_t nclasses, - H5FS_section_class_t *classes, const void *cls_init_udata) + size_t nclasses, H5FS_section_class_t *classes, const void *cls_init_udata) { H5FS_t *fspace = NULL; /* New free space structure */ H5FS_hdr_t *fs_hdr = NULL; /* New free space header */ @@ -391,14 +390,13 @@ H5FS_create(H5F_t *f, hid_t dxpl_id, haddr_t *fs_addr, const H5FS_create_t *fs_c HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for free space free list") /* Set immutable free list parameters */ - fspace->node_free_op = node_free_op; fspace->sect_cls = classes; /* Initialize the section classes for this free space list */ for(u = 0; u < nclasses; u++) { /* Call the class initialization routine, if there is one */ - if(fspace->sect_cls[u].init) - if((fspace->sect_cls[u].init)(&fspace->sect_cls[u], cls_init_udata) < 0) + if(fspace->sect_cls[u].init_cls) + if((fspace->sect_cls[u].init_cls)(&fspace->sect_cls[u], cls_init_udata) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, NULL, "unable to initialize section class") } /* end for */ @@ -421,14 +419,8 @@ H5FS_create(H5F_t *f, hid_t dxpl_id, haddr_t *fs_addr, const H5FS_create_t *fs_c fs_hdr->expand_percent = fs_create->expand_percent; fs_hdr->max_sect_addr = fs_create->max_sect_addr; fs_hdr->max_sect_size = fs_create->max_sect_size; - - /* Allocate space for the free space sections */ - fs_hdr->alloc_sect_size = H5FS_SECT_SIZE_DEFAULT; -#ifdef QAK -HDfprintf(stderr, "%s: fs_hdr->alloc_sect_size = %Hu\n", FUNC, fs_hdr->alloc_sect_size); -#endif /* QAK */ - if(HADDR_UNDEF == (fs_hdr->sect_addr = H5MF_alloc(f, H5FD_MEM_FSPACE_SECTS, dxpl_id, fs_hdr->alloc_sect_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "file allocation failed for free space sections") + fs_hdr->alloc_sect_size = 0; + fs_hdr->sect_addr = HADDR_UNDEF; /* Cache the new free space header */ if(H5AC_set(f, dxpl_id, H5AC_FSPACE_HDR, fspace->addr, fs_hdr, H5AC__NO_FLAGS_SET) < 0) @@ -502,8 +494,8 @@ done: *------------------------------------------------------------------------- */ H5FS_t * -H5FS_open(H5F_t *f, hid_t dxpl_id, haddr_t fs_addr, H5SL_operator_t node_free_op, - size_t nclasses, H5FS_section_class_t *classes, const void *cls_init_udata) +H5FS_open(H5F_t *f, hid_t dxpl_id, haddr_t fs_addr, size_t nclasses, + H5FS_section_class_t *classes, const void *cls_init_udata) { H5FS_hdr_t *fs_hdr = NULL; /* Free space header loaded from file */ H5FS_t *fspace = NULL; /* New free space structure */ @@ -539,15 +531,14 @@ HDfprintf(stderr, "%s: Opening free space manager\n", FUNC); /* Set immutable free list parameters */ fspace->addr = fs_addr; - fspace->node_free_op = node_free_op; HDassert(fspace->hdr->nclasses == nclasses); fspace->sect_cls = classes; /* Initialize the section classes for this free space list */ for(u = 0; u < nclasses; u++) { /* Call the class initialization routine, if there is one */ - if(fspace->sect_cls[u].init) - if((fspace->sect_cls[u].init)(&fspace->sect_cls[u], cls_init_udata) < 0) + if(fspace->sect_cls[u].init_cls) + if((fspace->sect_cls[u].init_cls)(&fspace->sect_cls[u], cls_init_udata) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, NULL, "unable to initialize section class") } /* end for */ @@ -565,9 +556,16 @@ HDfprintf(stderr, "%s: fspace->sect_off_size = %u, fspace->sect_len_size = %u\n" /* The free space is clean, currently */ fspace->dirty = FALSE; - /* Go get all the sections */ - if(H5FS_deserialize_bins(f, dxpl_id, fspace) < 0) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTDECODE, NULL, "can't deserialize sections") + /* Go get all the sections, if there are any */ +#ifdef QAK +HDfprintf(stderr, "%s: fspace->hdr->sect_addr = %a\n", FUNC, fspace->hdr->sect_addr); +#endif /* QAK */ + if(fspace->hdr->sect_count > 0) { + HDassert(H5F_addr_defined(fspace->hdr->sect_addr)); + HDassert(fspace->hdr->sect_size > 0); + if(H5FS_deserialize_bins(f, dxpl_id, fspace) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTDECODE, NULL, "can't deserialize sections") + } /* end if */ /* Add the free space manager to the list of open free space managers */ if(H5FS_open_add(fspace) < 0) @@ -605,7 +603,6 @@ done: static herr_t H5FS_sect_increase(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace) { - hsize_t new_size; /* New size of space for serialized sections */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5FS_sect_increase) @@ -621,35 +618,6 @@ H5FS_sect_increase(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace) /* Update the free space sections' serialized size */ fspace->hdr->sect_size = H5FS_serialize_size(fspace); -#ifdef QAK -HDfprintf(stderr, "%s: fspace->hdr->sect_size = %Hu\n", FUNC, fspace->hdr->sect_size); -HDfprintf(stderr, "%s: fspace->hdr->alloc_sect_size = %Hu\n", FUNC, fspace->hdr->alloc_sect_size); -#endif /* QAK */ - if(fspace->hdr->sect_size > fspace->hdr->alloc_sect_size) { -/* Currently, the old block data is "thrown away" after the space is reallocated, -* so avoid data copy in H5MF_realloc() call by just free'ing the space and -* allocating new space. -* -* This also keeps the file smaller, by freeing the space and then -* allocating new space, instead of vice versa (in H5MF_realloc). -* -* QAK - 5/ 8/2006 -*/ - /* Free previous indirect block disk space */ - if(H5MF_xfree(f, H5FD_MEM_FSPACE_SECTS, dxpl_id, fspace->hdr->sect_addr, (hsize_t)fspace->hdr->alloc_sect_size)<0) - HGOTO_ERROR(H5E_STORAGE, H5E_CANTFREE, FAIL, "unable to free free space sections") - - /* Compute new size */ - new_size = fspace->hdr->alloc_sect_size; - while(new_size < fspace->hdr->sect_size) - new_size *= (float)fspace->hdr->expand_percent / (float)100.0; - fspace->hdr->alloc_sect_size = new_size; - - /* Allocate space for the new indirect block on disk */ - if(HADDR_UNDEF == (fspace->hdr->sect_addr = H5MF_alloc(f, H5FD_MEM_FSPACE_SECTS, dxpl_id, (hsize_t)fspace->hdr->alloc_sect_size))) - HGOTO_ERROR(H5E_STORAGE, H5E_NOSPACE, FAIL, "file allocation failed for free space sections") - } /* end if */ - done: FUNC_LEAVE_NOAPI(ret_value) } /* H5FS_sect_increase() */ @@ -673,8 +641,6 @@ done: static herr_t H5FS_sect_decrease(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace) { - hsize_t decrease_threshold; /* Size threshold for decreasing serialized section size */ - hsize_t new_size; /* New size of space for serialized sections */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5FS_sect_decrease) @@ -684,64 +650,304 @@ H5FS_sect_decrease(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace) HDassert(fspace); HDassert(fspace->hdr); - /* Decrement # of sections on free space list */ + /* Decrement total # of sections in free space manager */ fspace->hdr->sect_count--; -/* XXX: Should check for only one section in bins & convert to single section */ - /* Drop back to using a "single" node when the bins are empty. */ - if(fspace->hdr->sect_count == 0) - fspace->using_bins = FALSE; + /* Drop back to using a "single" node when there's only one section */ + if(fspace->hdr->sect_count == 1) { + H5FS_node_t *fspace_node; /* Free list size node */ + H5FS_section_info_t *sect; /* Section to move to 'single' info */ + unsigned bin; /* Bin with node */ + unsigned u; /* Local index variable */ + + /* Sanity check */ + HDassert(fspace->single == NULL); + HDassert(fspace->size_count == 1); + + /* Search for the bin with the node */ + for(u = 0; u < fspace->nbins; u++) + if(fspace->bins[u].sect_count) { + HDassert(fspace->bins[u].sect_count == 1); + bin = u; + break; + } /* end if */ + +#ifndef NDEBUG + /* Sanity check rest of bins */ + for(u++ ; u < fspace->nbins; u++) + HDassert(fspace->bins[u].sect_count == 0); +#endif /* NDEBUG */ + + /* Sanity check section size count for bin */ + HDassert(H5SL_count(fspace->bins[bin].bin_list) == 1); + HDassert(fspace->bins[bin].sect_count == 1); + + /* Remove the free space section size node from the bin list */ + if(NULL == (fspace_node = H5SL_remove_first(fspace->bins[bin].bin_list))) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL, "can't remove free space section size node from skip list") + + /* Decrement # of section sizes in bin */ + fspace->bins[bin].sect_count = 0; + + /* Make certain there's only one section of this size */ + HDassert(H5SL_count(fspace_node->sect_list) == 1); + + /* Remove the free space section from the section size list */ + if(NULL == (sect = H5SL_remove_first(fspace_node->sect_list))) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL, "can't remove free space section from skip list") + + /* Destroy skip list for size tracking node */ + if(H5SL_close(fspace_node->sect_list) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTCLOSEOBJ, FAIL, "can't destroy size tracking node's skip list") + + /* Release free space list node */ + H5FL_FREE(H5FS_node_t, fspace_node); + + /* Capture single section's information */ + fspace->single = sect; + } /* end if */ /* Update the free space sections' serialized size */ - fspace->hdr->sect_size = H5FS_serialize_size(fspace); + if(fspace->hdr->sect_count > 0) + fspace->hdr->sect_size = H5FS_serialize_size(fspace); + else + fspace->hdr->sect_size = 0; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5FS_sect_decrease() */ + + +/*------------------------------------------------------------------------- + * Function: H5FS_remove_size_node + * + * Purpose: Remove a section size node from size tracking data structures for + * a free space manager + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Wednesday, May 17, 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FS_size_node_decr(H5FS_t *fspace, H5FS_node_t *fspace_node, unsigned bin) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5FS_size_node_decr) + + /* Check arguments. */ + HDassert(fspace); + HDassert(fspace_node); + + /* Check for no more nodes on list of that size */ + if(H5SL_count(fspace_node->sect_list) == 0) { + H5FS_node_t *tmp_fspace_node; /* Free space list size node */ + + /* Remove size tracking list from bin */ + tmp_fspace_node = H5SL_remove(fspace->bins[bin].bin_list, &fspace_node->sect_size); + if(tmp_fspace_node == NULL || tmp_fspace_node != fspace_node) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL, "can't remove free space node from skip list") - /* Compute the threshold for decreasing the sections' serialized size */ - decrease_threshold = (fspace->hdr->alloc_sect_size * (float)fspace->hdr->shrink_percent) / (float)100.0; + /* Destroy skip list for size tracking node */ + if(H5SL_close(fspace_node->sect_list) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTCLOSEOBJ, FAIL, "can't destroy size tracking node's skip list") + /* Release free space list node */ + H5FL_FREE(H5FS_node_t, fspace_node); + + /* Decrement number of section sizes */ + fspace->size_count--; + } /* end if */ + + /* Decrement the # of sections in this bin */ + /* (Different from the # of items in the bin's skiplist, since each node on + * the bin's skiplist is also a skiplist...) + */ + fspace->bins[bin].sect_count--; #ifdef QAK -HDfprintf(stderr, "%s: fspace->hdr->sect_size = %Hu\n", FUNC, fspace->hdr->sect_size); -HDfprintf(stderr, "%s: fspace->hdr->alloc_sect_size = %Hu\n", FUNC, fspace->hdr->alloc_sect_size); +HDfprintf(stderr, "%s: fspace->bins[%u].sect_count = %Zu\n", FUNC, bin, fspace->bins[bin].sect_count); #endif /* QAK */ - if(fspace->hdr->alloc_sect_size > H5FS_SECT_SIZE_DEFAULT && - fspace->hdr->sect_size < decrease_threshold) { -/* Currently, the old block data is "thrown away" after the space is reallocated, -* so avoid data copy in H5MF_realloc() call by just free'ing the space and -* allocating new space. -* -* This also keeps the file smaller, by freeing the space and then -* allocating new space, instead of vice versa (in H5MF_realloc). -* -* QAK - 5/ 8/2006 -*/ - /* Free previous indirect block disk space */ - if(H5MF_xfree(f, H5FD_MEM_FSPACE_SECTS, dxpl_id, fspace->hdr->sect_addr, (hsize_t)fspace->hdr->alloc_sect_size)<0) - HGOTO_ERROR(H5E_STORAGE, H5E_CANTFREE, FAIL, "unable to free free space sections") - - /* Compute new size */ - while(fspace->hdr->sect_size < decrease_threshold) { - new_size = decrease_threshold; - - decrease_threshold *= (float)fspace->hdr->shrink_percent / (float)100.0; - } /* end while */ - if(new_size < H5FS_SECT_SIZE_DEFAULT) - new_size = H5FS_SECT_SIZE_DEFAULT; - fspace->hdr->alloc_sect_size = new_size; - - /* Allocate space for the new indirect block on disk */ - if(HADDR_UNDEF == (fspace->hdr->sect_addr = H5MF_alloc(f, H5FD_MEM_FSPACE_SECTS, dxpl_id, (hsize_t)fspace->hdr->alloc_sect_size))) - HGOTO_ERROR(H5E_STORAGE, H5E_NOSPACE, FAIL, "file allocation failed for free space sections") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5FS_size_node_decr() */ + + +/*------------------------------------------------------------------------- + * Function: H5FS_sect_unlink_size + * + * Purpose: Remove a section node from size tracking data structures for + * a free space manager + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Wednesday, May 17, 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FS_sect_unlink_size(H5FS_t *fspace, H5FS_section_info_t *sect) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5FS_sect_unlink_size) + + /* Check arguments. */ + HDassert(fspace); + HDassert(sect); + + /* Check for only a single section */ + if(fspace->single) { + /* Verify that single section is correct */ + if(H5F_addr_ne(fspace->single->addr, sect->addr)) + HGOTO_ERROR(H5E_FSPACE, H5E_NOTFOUND, FAIL, "can't remove single section") + + /* Reset 'single' section pointer */ + fspace->single = NULL; + + /* Decrement number of section sizes */ + fspace->size_count--; } /* end if */ + else { + H5FS_node_t *fspace_node; /* Free list size node */ + H5FS_section_info_t *tmp_sect_node; /* Temporary section node */ + unsigned bin; /* Bin to put the free space section in */ + + /* Sanity check */ + HDassert(fspace->bins); + + /* Determine correct bin which holds items of at least the section's size */ + bin = H5V_log2_gen(sect->size); + HDassert(bin < fspace->nbins); + if(fspace->bins[bin].bin_list == NULL) + HGOTO_ERROR(H5E_FSPACE, H5E_NOTFOUND, FAIL, "node's bin is empty?") + + /* Find space node for section's size */ + if((fspace_node = H5SL_search(fspace->bins[bin].bin_list, §->size)) == NULL) + HGOTO_ERROR(H5E_FSPACE, H5E_NOTFOUND, FAIL, "can't find section size node") + + /* Remove the section's node from the list */ + tmp_sect_node = H5SL_remove(fspace_node->sect_list, §->addr); + if(tmp_sect_node == NULL || tmp_sect_node != sect) + HGOTO_ERROR(H5E_FSPACE, H5E_NOTFOUND, FAIL, "can't find section node on size list") + + /* Decrement # of sections in section size node */ + if(H5FS_size_node_decr(fspace, fspace_node, bin) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL, "can't remove free space size node from skip list") + } /* end else */ done: FUNC_LEAVE_NOAPI(ret_value) -} /* H5FS_sect_decrease() */ +} /* H5FS_sect_unlink_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5FS_sect_unlink_rest + * + * Purpose: Finish unlinking a section from the rest of the free space + * manager's data structures, after the section has been removed + * from the size tracking data structures + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Wednesday, May 17, 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FS_sect_unlink_rest(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, H5FS_section_info_t *sect) +{ + H5FS_section_info_t *tmp_sect_node; /* Temporary section node */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5FS_sect_unlink_rest) + + /* Check arguments. */ + HDassert(f); + HDassert(fspace); + HDassert(sect); + + /* Remove node from merge list */ + tmp_sect_node = H5SL_remove(fspace->merge_list, §->addr); + if(tmp_sect_node == NULL || tmp_sect_node != sect) + HGOTO_ERROR(H5E_FSPACE, H5E_NOTFOUND, FAIL, "can't find section node on size list") + + /* Decrement amount of space required to serialize all sections */ + fspace->serial_size -= fspace->sect_cls[sect->cls->type].serial_size; +#ifdef QAK +HDfprintf(stderr, "%s: fspace->serial_size = %Zu\n", FUNC, fspace->serial_size); +HDfprintf(stderr, "%s: fspace->sect_cls[(*node)->cls->type].serial_size = %Zu\n", FUNC, fspace->sect_cls[(*node)->cls->type].serial_size); +#endif /* QAK */ + + /* Update section info & check if we need less room for the serialized free space sections */ + if(H5FS_sect_decrease(f, dxpl_id, fspace) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't increase free space section size on disk") + + /* Decrement amount of free space managed */ + fspace->hdr->tot_space -= sect->size; + + /* Mark free space sections as changed */ + fspace->dirty = TRUE; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5FS_sect_unlink_rest() */ + + +/*------------------------------------------------------------------------- + * Function: H5FS_sect_unlink + * + * Purpose: Unlink a section from the internal data structures + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Wednesday, May 17, 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FS_sect_unlink(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, H5FS_section_info_t *sect) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5FS_sect_unlink) + + /* Check arguments. */ + HDassert(f); + HDassert(fspace); + HDassert(sect); + + /* Remove node from size tracked data structures */ + if(H5FS_sect_unlink_size(fspace, sect) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "can't remove section from size tracking data structures") + + /* Update rest of free space manager data structures for node removal */ + if(H5FS_sect_unlink_rest(f, dxpl_id, fspace, sect) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "can't remove section from non-size tracking data structures") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5FS_sect_unlink() */ /*------------------------------------------------------------------------- - * Function: H5FS_add_bin_node + * Function: H5FS_sect_link_size_bin * - * Purpose: Add a section of free space in a direct block to the free list - * bins + * Purpose: Add a section of free space to the free list bins * * Return: Success: non-negative * @@ -753,25 +959,25 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5FS_add_bin_node(H5FS_t *fspace, H5FS_section_info_t *node) +H5FS_sect_link_size_bin(H5FS_t *fspace, H5FS_section_info_t *sect) { H5FS_node_t *fspace_node = NULL; /* Pointer to free space node of the correct size */ unsigned bin; /* Bin to put the free space section in */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT(H5FS_add_bin_node) + FUNC_ENTER_NOAPI_NOINIT(H5FS_sect_link_size_bin) #ifdef QAK -HDfprintf(stderr, "%s: node->size = %Hu, node->addr = %a\n", FUNC, node->size, node->addr); +HDfprintf(stderr, "%s: sect->size = %Hu, sect->addr = %a\n", FUNC, sect->size, sect->addr); #endif /* QAK */ /* Check arguments. */ HDassert(fspace); - HDassert(node); - HDassert(H5F_addr_defined(node->addr)); - HDassert(node->size); + HDassert(sect); + HDassert(H5F_addr_defined(sect->addr)); + HDassert(sect->size); /* Determine correct bin which holds items of the section's size */ - bin = H5V_log2_gen(node->size); + bin = H5V_log2_gen(sect->size); HDassert(bin < fspace->nbins); if(fspace->bins[bin].bin_list == NULL) { if(NULL == (fspace->bins[bin].bin_list = H5SL_create(H5SL_TYPE_HSIZE, 0.5, H5FS_DEFAULT_SKIPLIST_HEIGHT))) @@ -779,7 +985,7 @@ HDfprintf(stderr, "%s: node->size = %Hu, node->addr = %a\n", FUNC, node->size, n } /* end if */ else { /* Check for node list of the correct size already */ - fspace_node = H5SL_search(fspace->bins[bin].bin_list, &node->size); + fspace_node = H5SL_search(fspace->bins[bin].bin_list, §->size); } /* end else */ /* Check if we need to create a new skip list for nodes of this size */ @@ -789,7 +995,7 @@ HDfprintf(stderr, "%s: node->size = %Hu, node->addr = %a\n", FUNC, node->size, n HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for free space node") /* Initialize the free list size node */ - fspace_node->sect_size = node->size; + fspace_node->sect_size = sect->size; if(NULL == (fspace_node->sect_list = H5SL_create(H5SL_TYPE_HADDR, 0.5, H5FS_DEFAULT_SKIPLIST_HEIGHT))) HGOTO_ERROR(H5E_FSPACE, H5E_CANTCREATE, FAIL, "can't create skip list for free space nodes") @@ -810,52 +1016,39 @@ HDfprintf(stderr, "%s: fspace->bins[%u].sect_count = %Zu\n", FUNC, bin, fspace-> #endif /* QAK */ fspace->bins[bin].sect_count++; - /* Increment amount of space required to serialize all sections */ -#ifdef QAK -HDfprintf(stderr, "%s: fspace->serial_size = %Zu\n", FUNC, fspace->serial_size); -HDfprintf(stderr, "%s: fspace->sect_cls[node->cls->type].serial_size = %Zu\n", FUNC, fspace->sect_cls[node->cls->type].serial_size); -#endif /* QAK */ - fspace->serial_size += fspace->sect_cls[node->cls->type].serial_size; - /* Insert free space node into correct skip list */ - if(H5SL_insert(fspace_node->sect_list, node, &node->addr) < 0) + if(H5SL_insert(fspace_node->sect_list, sect, §->addr) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't insert free space node into skip list") done: FUNC_LEAVE_NOAPI(ret_value) -} /* H5FS_add_bin_node() */ +} /* H5FS_sect_link_size_bin() */ /*------------------------------------------------------------------------- - * Function: H5FS_add + * Function: H5FS_sect_link_size * - * Purpose: Add a section of free space in a direct block to the free list + * Purpose: Link a section into size tracking data structures * * Return: Success: non-negative * * Failure: negative * * Programmer: Quincey Koziol - * Tuesday, March 7, 2006 + * Wednesday, May 17, 2006 * *------------------------------------------------------------------------- */ -herr_t -H5FS_add(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, H5FS_section_info_t *node) +static herr_t +H5FS_sect_link_size(H5FS_t *fspace, H5FS_section_info_t *sect) { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI(H5FS_add, FAIL) - -#ifdef QAK -HDfprintf(stderr, "%s: node->size = %Hu, node->addr = %a\n", FUNC, node->size, node->addr); -#endif /* QAK */ + FUNC_ENTER_NOAPI_NOINIT(H5FS_sect_link_size) /* Check arguments. */ HDassert(fspace); - HDassert(node); - HDassert(H5F_addr_defined(node->addr)); - HDassert(node->size); + HDassert(sect); /* Check for special cases of # of sections on free list */ #ifdef QAK @@ -865,24 +1058,14 @@ HDfprintf(stderr, "%s: fspace->hdr->sect_count = %Hu\n", FUNC, fspace->hdr->sect HDassert(fspace->single == NULL); /* Capture single section's information */ - fspace->single = node; - - /* Increment amount of space required to serialize all sections */ - fspace->serial_size += fspace->sect_cls[node->cls->type].serial_size; + fspace->single = sect; /* Increment number of section sizes */ fspace->size_count++; } /* end if */ else { /* Have a single section, put it into the bins */ -/* XXX: Take out the "&& !fspace->using_bins" when bins converted back into single section */ - if(fspace->hdr->sect_count == 1 && !fspace->using_bins) { - HDassert(fspace->single); - - /* Decrement amount of space required to serialize all sections */ - /* (will be re-incremented in the 'add bin node' routine) */ - fspace->serial_size -= fspace->sect_cls[fspace->single->cls->type].serial_size; - + if(fspace->single) { /* Check if we should allocate the bins */ if(fspace->bins == NULL) /* Allocate the bins for free space sizes */ @@ -890,33 +1073,283 @@ HDfprintf(stderr, "%s: fspace->hdr->sect_count = %Hu\n", FUNC, fspace->hdr->sect HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for free space bins") /* Insert the current single section into the bins */ - if(H5FS_add_bin_node(fspace, fspace->single) < 0) + if(H5FS_sect_link_size_bin(fspace, fspace->single) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't insert free space node into skip list") fspace->single = NULL; /* Decrement number of section sizes */ - /* (will be re-incremented in the 'add bin node' routine) */ + /* (from increment in H5FS_sect_link_size_bin for inserting the single section) */ fspace->size_count--; - - /* Using bins for storing nodes now */ - fspace->using_bins = TRUE; } /* end if */ HDassert(fspace->single == NULL); /* Put new section into bins */ - if(H5FS_add_bin_node(fspace, node) < 0) + if(H5FS_sect_link_size_bin(fspace, sect) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't insert free space node into skip list") } /* end else */ +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5FS_sect_link_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5FS_sect_link_rest + * + * Purpose: Link a section into the rest of the non-size tracking + * free space manager data structures + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Wednesday, May 17, 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FS_sect_link_rest(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, H5FS_section_info_t *sect) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5FS_sect_link_rest) + + /* Check arguments. */ + HDassert(f); + HDassert(fspace); + HDassert(sect); + + /* Add section to the address-ordered list of sections */ + if(fspace->merge_list == NULL) { + if(NULL == (fspace->merge_list = H5SL_create(H5SL_TYPE_HADDR, 0.5, H5FS_DEFAULT_SKIPLIST_HEIGHT))) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTCREATE, FAIL, "can't create skip list for merging free space sections") + } /* end if */ + if(H5SL_insert(fspace->merge_list, sect, §->addr) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't insert free space node into merging skip list") + + /* Increment amount of space required to serialize all sections */ +#ifdef QAK +HDfprintf(stderr, "%s: fspace->serial_size = %Zu\n", FUNC, fspace->serial_size); +HDfprintf(stderr, "%s: fspace->sect_cls[sect->cls->type].serial_size = %Zu\n", FUNC, fspace->sect_cls[sect->cls->type].serial_size); +#endif /* QAK */ + fspace->serial_size += fspace->sect_cls[sect->cls->type].serial_size; + /* Update section info & check if we need more room for the serialized free space sections */ if(H5FS_sect_increase(f, dxpl_id, fspace) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't increase free space section size on disk") /* Increment amount of free space managed */ - fspace->hdr->tot_space += node->size; + fspace->hdr->tot_space += sect->size; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5FS_sect_link_rest() */ + + +/*------------------------------------------------------------------------- + * Function: H5FS_sect_link + * + * Purpose: Link a section into the internal data structures + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Wednesday, May 17, 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FS_sect_link(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, H5FS_section_info_t *sect) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5FS_sect_link) + + /* Check arguments. */ + HDassert(f); + HDassert(fspace); + HDassert(sect); + + /* Add node to size tracked data structures */ + if(H5FS_sect_link_size(fspace, sect) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't add section to size tracking data structures") + + /* Update rest of free space manager data structures for section addition */ + if(H5FS_sect_link_rest(f, dxpl_id, fspace, sect) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't add section to non-size tracking data structures") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5FS_sect_link() */ + + +/*------------------------------------------------------------------------- + * Function: H5FS_sect_merge + * + * Purpose: Attempt to merge a returned free space section with existing + * free space. + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Wednesday, May 17, 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FS_sect_merge(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, + H5FS_section_info_t **sect, void *op_data) +{ + H5FS_section_info_t *tmp_sect_node; /* Temporary free space section */ + hbool_t merged; /* Flag to indicate merge occurred */ + htri_t status; /* Status value */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5FS_sect_merge) + + /* Check arguments. */ + HDassert(fspace); + HDassert(fspace->merge_list); + HDassert(*sect); + HDassert(H5F_addr_defined((*sect)->addr)); + HDassert((*sect)->size); + + /* Loop until no more merging */ + do { + /* Reset 'merge occurred' flag */ + merged = FALSE; + + /* Look for neighboring section before new section */ + tmp_sect_node = H5SL_less(fspace->merge_list, &(*sect)->addr); + + /* Check for node before new node able to merge with new node */ + if(tmp_sect_node && tmp_sect_node->cls->can_merge) { + /* Determine if the sections can merge */ + if((status = (*tmp_sect_node->cls->can_merge)(tmp_sect_node, *sect, op_data)) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTMERGE, FAIL, "can't check for merging sections") + if(status > 0) { + /* Sanity check */ + HDassert((*sect)->cls->merge); + + /* Remove 'less than' node from data structures */ + if(H5FS_sect_unlink(f, dxpl_id, fspace, tmp_sect_node) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't remove section from internal data structures") + + /* Merge the two sections together */ + if((*tmp_sect_node->cls->merge)(tmp_sect_node, *sect, op_data) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't merge two sections") + + /* Retarget section pointer to 'less than' node that was merged into */ + *sect = tmp_sect_node; + + /* Indicate successful merge occurred */ + merged = TRUE; + } /* end if */ + } /* end if */ + + /* Look for section after new (or merged) section */ + tmp_sect_node = H5SL_greater(fspace->merge_list, &(*sect)->addr); + + /* Check for node after new node able to merge with new node */ + if(tmp_sect_node && tmp_sect_node->cls->can_merge) { + /* Determine if the sections can merge */ + if((status = (*tmp_sect_node->cls->can_merge)(*sect, tmp_sect_node, op_data)) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTMERGE, FAIL, "can't check for merging sections") + if(status > 0) { + /* Sanity check */ + HDassert((*sect)->cls->merge); + + /* Remove 'greater than' node from data structures */ + if(H5FS_sect_unlink(f, dxpl_id, fspace, tmp_sect_node) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't remove section from internal data structures") + + /* Merge the two sections together */ + if((*(*sect)->cls->merge)(*sect, tmp_sect_node, op_data) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't merge two sections") + + /* Indicate successful merge occurred */ + merged = TRUE; + } /* end if */ + } /* end if */ + } while(merged); + + /* Check for (possibly merged) section able to shrink the size of the container */ + if((*sect)->cls->can_shrink) { + if((status = (*(*sect)->cls->can_shrink)(*sect, op_data)) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTSHRINK, FAIL, "can't check for shrinking container") + if(status > 0) { +#ifdef QAK +HDfprintf(stderr, "%s: Can shrink!\n", FUNC); +#endif /* QAK */ + /* Shrink the container */ + /* (callback can indicate that it has discarded the section by setting *sect to NULL) */ + if((*(*sect)->cls->shrink)(sect, op_data) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't shrink free space container") + } /* end if */ + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5FS_sect_merge() */ + + +/*------------------------------------------------------------------------- + * Function: H5FS_add + * + * Purpose: Add a section of free space to the free list + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Tuesday, March 7, 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5FS_add(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, H5FS_section_info_t *sect, + unsigned flags, void *op_data) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5FS_add, FAIL) + +#ifdef QAK +HDfprintf(stderr, "%s: sect->size = %Hu, sect->addr = %a, sect->cls->type = %u\n", FUNC, sect->size, sect->addr, sect->cls->type); +#endif /* QAK */ + + /* Check arguments. */ + HDassert(fspace); + HDassert(sect); + HDassert(H5F_addr_defined(sect->addr)); + HDassert(sect->size); + + /* Check for merging returned space with existing section node */ + if(flags & H5FS_ADD_RETURNED_SPACE && fspace->hdr->sect_count > 0) { +#ifdef QAK +HDfprintf(stderr, "%s: Returning space\n", FUNC); +#endif /* QAK */ + + /* Attempt to merge returned section with existing sections */ + if(H5FS_sect_merge(f, dxpl_id, fspace, §, op_data) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTMERGE, FAIL, "can't merge sections") + } /* end if */ + + /* Add new (possibly merged or even discarded) node to free sections */ + if(sect) + if(H5FS_sect_link(f, dxpl_id, fspace, sect) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't insert free space section into skip list") /* Mark free space sections as changed */ - fspace->dirty = TRUE; + /* (if we're not deserializing all the sections) */ + if(!(flags & H5FS_ADD_DESERIALIZING)) + fspace->dirty = TRUE; done: FUNC_LEAVE_NOAPI(ret_value) @@ -975,44 +1408,13 @@ HDfprintf(stderr, "%s: bin = %u\n", FUNC, bin); if((fspace_node = H5SL_greater(fspace->bins[bin].bin_list, &request))) { /* Take first node off of the list (ie. node w/lowest address) */ if(NULL == (*node = H5SL_remove_first(fspace_node->sect_list))) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTDELETE, FAIL, "can't remove free space node from skip list") - - /* Check for no more nodes on list of that size */ - if(H5SL_count(fspace_node->sect_list) == 0) { - H5FS_node_t *tmp_fspace_node; /* Free space list size node */ - - /* Remove size tracking list from bin */ - tmp_fspace_node = H5SL_remove(fspace->bins[bin].bin_list, &fspace_node->sect_size); - if(tmp_fspace_node == NULL || tmp_fspace_node != fspace_node) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTDELETE, FAIL, "can't remove free space node from skip list") - - /* Destroy skip list for size tracking node */ - if(H5SL_close(fspace_node->sect_list) < 0) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTCLOSEOBJ, FAIL, "can't destroy size tracking node's skip list") - - /* Release free space list node */ - H5FL_FREE(H5FS_node_t, fspace_node); + HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL, "can't remove free space node from skip list") - /* Decrement number of section sizes */ - fspace->size_count--; - } /* end if */ - - /* Decrement the # of sections in this bin */ - /* (Different from the # of items in the bin's skiplist, since each node on - * the bin's skiplist is also a skiplist...) - */ - fspace->bins[bin].sect_count--; -#ifdef QAK -HDfprintf(stderr, "%s: fspace->bins[%u].sect_count = %Zu\n", FUNC, bin, fspace->bins[bin].sect_count); -#endif /* QAK */ - - /* Decrement amount of space required to serialize all sections */ - fspace->serial_size -= fspace->sect_cls[(*node)->cls->type].serial_size; -#ifdef QAK -HDfprintf(stderr, "%s: fspace->serial_size = %Zu\n", FUNC, fspace->serial_size); -HDfprintf(stderr, "%s: fspace->sect_cls[(*node)->cls->type].serial_size = %Zu\n", FUNC, fspace->sect_cls[(*node)->cls->type].serial_size); -#endif /* QAK */ + /* Decrement # of sections in section size node */ + if(H5FS_size_node_decr(fspace, fspace_node, bin) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTREMOVE, FAIL, "can't remove free space size node from skip list") + /* Indicate that we found a node for the request */ HGOTO_DONE(TRUE) } /* end if */ @@ -1062,19 +1464,13 @@ HDfprintf(stderr, "%s: fspace->hdr->sect_count = %Hu\n", FUNC, fspace->hdr->sect #endif /* QAK */ if(fspace->hdr->sect_count > 0) { /* Check for single section */ -/* XXX: Take out the "&& !fspace->using_bins" when bins converted back into single section */ - if(fspace->hdr->sect_count == 1 && !fspace->using_bins) { - HDassert(fspace->single); - + if(fspace->single) { /* See if single section is large enough */ if(fspace->single->size >= request) { - /* Use 'single' section */ + /* 'single' section fulfills request */ *node = fspace->single; fspace->single = NULL; - /* Decrement amount of space required to serialize all sections */ - fspace->serial_size -= fspace->sect_cls[(*node)->cls->type].serial_size; - /* Decrement number of section sizes */ fspace->size_count--; @@ -1085,8 +1481,6 @@ HDfprintf(stderr, "%s: fspace->hdr->sect_count = %Hu\n", FUNC, fspace->hdr->sect HGOTO_DONE(FALSE) } /* end if */ else { - HDassert(fspace->single == NULL); - /* Look for node in bins */ if((ret_value = H5FS_find_bin_node(fspace, request, node)) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "can't remove section from bins") @@ -1094,15 +1488,12 @@ HDfprintf(stderr, "%s: fspace->hdr->sect_count = %Hu\n", FUNC, fspace->hdr->sect /* Decrement # of sections on free list, if we found an object */ if(ret_value > 0) { - /* Update section info & check if we need less room for the serialized free space sections */ - if(H5FS_sect_decrease(f, dxpl_id, fspace) < 0) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't increase free space section size on disk") - - /* Decrement amount of free space managed */ - fspace->hdr->tot_space -= (*node)->size; - - /* Mark free space sections as changed */ - fspace->dirty = TRUE; + /* Update rest of free space manager data structures for node removal */ + if(H5FS_sect_unlink_rest(f, dxpl_id, fspace, *node) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "can't remove section from non-size tracking data structures") +#ifdef QAK +HDfprintf(stderr, "%s: (*node)->size = %Hu, (*node)->addr = %a, (*node)->cls->type = %u\n", FUNC, (*node)->size, (*node)->addr, (*node)->cls->type); +#endif /* QAK */ } /* end if */ } /* end if */ @@ -1112,6 +1503,36 @@ done: /*------------------------------------------------------------------------- + * Function: H5FS_sect_free_cb + * + * Purpose: Free a size-tracking node for a bin + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Saturday, March 11, 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FS_sect_free_cb(void *_sect, void UNUSED *key, void UNUSED *op_data) +{ + H5FS_section_info_t *sect = (H5FS_section_info_t *)_sect; + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FS_sect_free_cb) + + HDassert(sect); + + /* Call the 'free' method for the section's class */ + (*sect->cls->free)(sect); + + FUNC_LEAVE_NOAPI(0) +} /* H5FS_sect_free_cb() */ + + +/*------------------------------------------------------------------------- * Function: H5FS_node_free_cb * * Purpose: Free a size-tracking node for a bin @@ -1126,7 +1547,7 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5FS_node_free_cb(void *item, void UNUSED *key, void *op_data) +H5FS_node_free_cb(void *item, void UNUSED *key, void UNUSED *op_data) { H5FS_node_t *fspace_node = (H5FS_node_t *)item; /* Temporary pointer to free space list node */ @@ -1135,7 +1556,7 @@ H5FS_node_free_cb(void *item, void UNUSED *key, void *op_data) HDassert(fspace_node); /* Release the skip list for sections of this size */ - H5SL_destroy(fspace_node->sect_list, (H5SL_operator_t)op_data, NULL); + H5SL_destroy(fspace_node->sect_list, H5FS_sect_free_cb, NULL); /* Release free space list node */ H5FL_FREE(H5FS_node_t, fspace_node); @@ -1333,55 +1754,147 @@ H5FS_serialize_bins(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace) HDassert(fspace->dirty); #ifdef QAK +HDfprintf(stderr, "%s: fspace->hdr->sect_addr = %a\n", FUNC, fspace->hdr->sect_addr); +HDfprintf(stderr, "%s: fspace->hdr->sect_size = %Hu\n", FUNC, fspace->hdr->sect_size); HDfprintf(stderr, "%s: fspace->hdr->sect_count = %Hu\n", FUNC, fspace->hdr->sect_count); HDfprintf(stderr, "%s: fspace->serial_size = %Zu\n", FUNC, fspace->serial_size); #endif /* QAK */ - /* Allocate space for the buffer to serialize the sections into */ - if(NULL == (sect_buf = H5FL_BLK_MALLOC(sect_block, (size_t)fspace->hdr->sect_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + /* Check for no free sections */ + if(fspace->hdr->sect_count == 0) { + /* Check for existing serialized sections on disk to release */ + if(H5F_addr_defined(fspace->hdr->sect_addr)) { + /* Free previous serialized sections disk space */ + if(H5MF_xfree(f, H5FD_MEM_FSPACE_SECTS, dxpl_id, fspace->hdr->sect_addr, (hsize_t)fspace->hdr->alloc_sect_size)<0) + HGOTO_ERROR(H5E_STORAGE, H5E_CANTFREE, FAIL, "unable to release free space sections") + + /* Reset address and size of serialized sections on disk */ + fspace->hdr->sect_addr = HADDR_UNDEF; + fspace->hdr->sect_size = 0; + } /* end if */ + } /* end if */ + else { + /* Check for no space on disk allocated for the serialized sections */ + if(!H5F_addr_defined(fspace->hdr->sect_addr)) { + /* Compute size to store sections on disk */ + fspace->hdr->alloc_sect_size = fspace->hdr->sect_size * (double)fspace->hdr->expand_percent / 100.0; + + /* Allocate space for the new serialized sections on disk */ + if(HADDR_UNDEF == (fspace->hdr->sect_addr = H5MF_alloc(f, H5FD_MEM_FSPACE_SECTS, dxpl_id, (hsize_t)fspace->hdr->alloc_sect_size))) + HGOTO_ERROR(H5E_STORAGE, H5E_NOSPACE, FAIL, "file allocation failed for free space sections") + } /* end if */ + else { +#ifdef QAK +HDfprintf(stderr, "%s: fspace->hdr->sect_size = %Hu\n", FUNC, fspace->hdr->sect_size); +HDfprintf(stderr, "%s: fspace->hdr->alloc_sect_size = %Hu\n", FUNC, fspace->hdr->alloc_sect_size); +#endif /* QAK */ + if(fspace->hdr->sect_size > fspace->hdr->alloc_sect_size) { + size_t new_size; /* New size of space for serialized sections */ +/* Currently, the old block data is "thrown away" after the space is reallocated, + * so avoid data copy in H5MF_realloc() call by just free'ing the space and + * allocating new space. + * + * This also keeps the file smaller, by freeing the space and then + * allocating new space, instead of vice versa (in H5MF_realloc). + * + * QAK - 5/ 8/2006 + */ + /* Free previous serialized sections disk space */ + if(H5MF_xfree(f, H5FD_MEM_FSPACE_SECTS, dxpl_id, fspace->hdr->sect_addr, (hsize_t)fspace->hdr->alloc_sect_size)<0) + HGOTO_ERROR(H5E_STORAGE, H5E_CANTFREE, FAIL, "unable to free free space sections") + + /* Compute new size */ + new_size = fspace->hdr->alloc_sect_size; + while(new_size < fspace->hdr->sect_size) + new_size *= (double)fspace->hdr->expand_percent / 100.0; + fspace->hdr->alloc_sect_size = new_size; + + /* Allocate space for the new serialized sections on disk */ + if(HADDR_UNDEF == (fspace->hdr->sect_addr = H5MF_alloc(f, H5FD_MEM_FSPACE_SECTS, dxpl_id, (hsize_t)fspace->hdr->alloc_sect_size))) + HGOTO_ERROR(H5E_STORAGE, H5E_NOSPACE, FAIL, "file allocation failed for free space sections") + } /* end if */ + else { + size_t decrease_threshold; /* Size threshold for decreasing serialized section size */ + hsize_t new_size; /* New size of space for serialized sections */ - /* Serialize free sections into buffer available */ - p = sect_buf; + /* Compute the threshold for decreasing the sections' serialized size */ + decrease_threshold = (fspace->hdr->alloc_sect_size * (double)fspace->hdr->shrink_percent) / 100.0; - /* Magic number */ - HDmemcpy(p, H5FS_SECTS_MAGIC, H5FS_SIZEOF_MAGIC); - p += H5FS_SIZEOF_MAGIC; +#ifdef QAK +HDfprintf(stderr, "%s: fspace->hdr->sect_size = %Hu\n", FUNC, fspace->hdr->sect_size); +HDfprintf(stderr, "%s: fspace->hdr->alloc_sect_size = %Hu\n", FUNC, fspace->hdr->alloc_sect_size); +#endif /* QAK */ + if(fspace->hdr->alloc_sect_size > H5FS_SECT_SIZE_DEFAULT && + fspace->hdr->sect_size < decrease_threshold) { +/* Currently, the old block data is "thrown away" after the space is reallocated, + * so avoid data copy in H5MF_realloc() call by just free'ing the space and + * allocating new space. + * + * This also keeps the file smaller, by freeing the space and then + * allocating new space, instead of vice versa (in H5MF_realloc). + * + * QAK - 5/ 8/2006 + */ + /* Free previous serialized sections disk space */ + if(H5MF_xfree(f, H5FD_MEM_FSPACE_SECTS, dxpl_id, fspace->hdr->sect_addr, (hsize_t)fspace->hdr->alloc_sect_size)<0) + HGOTO_ERROR(H5E_STORAGE, H5E_CANTFREE, FAIL, "unable to free free space sections") + + /* Compute new size */ + while(fspace->hdr->sect_size < decrease_threshold) { + new_size = decrease_threshold; + + decrease_threshold *= (double)fspace->hdr->shrink_percent / 100.0; + } /* end while */ + if(new_size < H5FS_SECT_SIZE_DEFAULT) + new_size = H5FS_SECT_SIZE_DEFAULT; + fspace->hdr->alloc_sect_size = new_size; + + /* Allocate space for the new serialized sections on disk */ + if(HADDR_UNDEF == (fspace->hdr->sect_addr = H5MF_alloc(f, H5FD_MEM_FSPACE_SECTS, dxpl_id, (hsize_t)fspace->hdr->alloc_sect_size))) + HGOTO_ERROR(H5E_STORAGE, H5E_NOSPACE, FAIL, "file allocation failed for free space sections") + } /* end if */ + } /* end else */ + } /* end else */ - /* Version # */ - *p++ = H5FS_SECTS_VERSION; + /* Allocate space for the buffer to serialize the sections into */ + if(NULL == (sect_buf = H5FL_BLK_MALLOC(sect_block, (size_t)fspace->hdr->sect_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") - /* Metadata status flags */ -/* XXX: Set this? */ - *p++ = 0; + /* Serialize free sections into buffer available */ + p = sect_buf; - /* Metadata checksum */ -/* XXX: Set this! (After all the metadata is in the buffer) */ - HDmemset(p, 0, 4); - p += 4; + /* Magic number */ + HDmemcpy(p, H5FS_SECTS_MAGIC, H5FS_SIZEOF_MAGIC); + p += H5FS_SIZEOF_MAGIC; - /* Address of free space header for these sections */ - H5F_addr_encode(f, &p, fspace->addr); + /* Version # */ + *p++ = H5FS_SECTS_VERSION; - /* Set up user data for iterator */ - udata.fspace = fspace; - udata.p = &p; - udata.sect_cnt_size = MAX(1, (H5V_log2_gen(fspace->hdr->sect_count) + 7) / 8); + /* Metadata status flags */ + /* XXX: Set this? */ + *p++ = 0; + + /* Metadata checksum */ + /* XXX: Set this! (After all the metadata is in the buffer) */ + HDmemset(p, 0, 4); + p += 4; + + /* Address of free space header for these sections */ + H5F_addr_encode(f, &p, fspace->addr); + + /* Set up user data for iterator */ + udata.fspace = fspace; + udata.p = &p; + udata.sect_cnt_size = MAX(1, (H5V_log2_gen(fspace->hdr->sect_count) + 7) / 8); #ifdef QAK HDfprintf(stderr, "%s: udata.sect_cnt_size = %u\n", FUNC, udata.sect_cnt_size); #endif /* QAK */ - /* Serialize sections, if there are any */ - if(fspace->hdr->sect_count) { /* Check for whether to serialize a single section */ -/* XXX: Take out the "&& !fspace->using_bins" when bins converted back into single section */ - if(fspace->hdr->sect_count == 1 && !fspace->using_bins) { + if(fspace->single) { #ifdef QAK HDfprintf(stderr, "%s: Serializing single section\n", FUNC); #endif /* QAK */ - /* Sanity check */ - HDassert(fspace->single != NULL); - /* The number of sections */ UINT64ENCODE_VAR(p, 1, udata.sect_cnt_size); @@ -1408,21 +1921,24 @@ HDfprintf(stderr, "%s: Serializing section bins\n", FUNC); } /* end if */ } /* end for */ } /* end else */ - } /* end if */ - /* Sanity check */ - HDassert((size_t)(p - sect_buf) == fspace->hdr->sect_size); + /* Sanity check */ + HDassert((size_t)(p - sect_buf) == fspace->hdr->sect_size); #ifdef QAK HDfprintf(stderr, "%s: fspace->hdr->sect_size = %Hu\n", FUNC, fspace->hdr->sect_size); #endif /* QAK */ - /* Write buffer to disk */ - HDassert(fspace->hdr->sect_size <= fspace->hdr->alloc_sect_size); + /* Write buffer to disk */ + HDassert(fspace->hdr->sect_size <= fspace->hdr->alloc_sect_size); #ifdef QAK HDfprintf(stderr, "%s: fspace->hdr->alloc_sect_size = %Hu\n", FUNC, fspace->hdr->alloc_sect_size); #endif /* QAK */ - if(H5F_block_write(f, H5FD_MEM_FSPACE_SECTS, fspace->hdr->sect_addr, (size_t)fspace->hdr->sect_size, dxpl_id, sect_buf) < 0) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTFLUSH, FAIL, "unable to save free space sections to disk") + if(H5F_block_write(f, H5FD_MEM_FSPACE_SECTS, fspace->hdr->sect_addr, (size_t)fspace->hdr->sect_size, dxpl_id, sect_buf) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTFLUSH, FAIL, "unable to save free space sections to disk") + } /* end else */ + + /* Mark free space as clean now */ + fspace->dirty = FALSE; done: if(sect_buf) @@ -1569,7 +2085,7 @@ HDfprintf(stderr, "%s: sect_type = %u\n", FUNC, sect_type); p += new_sect->cls->serial_size; /* Insert section in free space manager */ - if(H5FS_add(f, dxpl_id, fspace, new_sect) < 0) + if(H5FS_add(f, dxpl_id, fspace, new_sect, H5FS_ADD_DESERIALIZING, NULL) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't add section to free space manager") } /* end for */ } while(p < (sect_buf + old_sect_size)); @@ -1584,6 +2100,9 @@ done: if(sect_buf) H5FL_BLK_FREE(sect_block, sect_buf); +#ifdef QAK +HDfprintf(stderr, "%s: Leaving, ret_value = %d\n", FUNC, ret_value); +#endif /* QAK */ FUNC_LEAVE_NOAPI(ret_value) } /* H5FS_deserialize_bins() */ @@ -1703,14 +2222,10 @@ HDfprintf(stderr, "%s: fspace->hdr->sect_count = %Hu\n", FUNC, fspace->hdr->sect /* Iterate over sections, if there are any */ if(fspace->hdr->sect_count) { /* Check for whether to iterate over a single section */ -/* XXX: Take out the "&& !fspace->using_bins" when bins converted back into single section */ - if(fspace->hdr->sect_count == 1 && !fspace->using_bins) { + if(fspace->single) { #ifdef QAK -HDfprintf(stderr, "%s: Iterating over a single section\n", FUNC); +HDfprintf(stderr, "%s: 'Iterating' over a single section\n", FUNC); #endif /* QAK */ - /* Sanity check */ - HDassert(fspace->single != NULL); - /* "Iterate" over the single node */ if(H5FS_iterate_sect_cb(fspace->single, NULL, &udata) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "can't 'iterate' over single section") @@ -1854,10 +2369,8 @@ H5FS_close(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace) HGOTO_ERROR(H5E_FSPACE, H5E_CANTSERIALIZE, FAIL, "can't syncronize bins") /* Check for single section to free */ -/* XXX: Take out the "&& !fspace->using_bins" when bins converted back into single section */ - if(fspace->hdr->sect_count == 1 && !fspace->using_bins) { - HDassert(fspace->single != NULL); - fspace->node_free_op(fspace->single, &fspace->single->addr, NULL); + if(fspace->single) { + fspace->single->cls->free(fspace->single); fspace->single = NULL; } /* end if */ HDassert(fspace->single == NULL); @@ -1867,13 +2380,19 @@ H5FS_close(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace) /* Clear out lists of nodes */ for(u = 0; u < fspace->nbins; u++) if(fspace->bins[u].bin_list) { - H5SL_destroy(fspace->bins[u].bin_list, H5FS_node_free_cb, (void *)fspace->node_free_op); + H5SL_destroy(fspace->bins[u].bin_list, H5FS_node_free_cb, NULL); fspace->bins[u].bin_list = NULL; } /* end if */ H5FL_SEQ_FREE(H5FS_bin_t, fspace->bins); } /* end if */ + /* Release skip list for merging sections */ + if(fspace->merge_list) { + if(H5SL_close(fspace->merge_list) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTCLOSEOBJ, FAIL, "can't destroy section merging skip list") + } /* end if */ + /* Unpin the free space header in the cache */ if(H5AC_unpin_entry(f, fspace->hdr) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNPIN, FAIL, "unable to unpin free space header") |